Skip to content

Commit

Permalink
Rollup merge of rust-lang#106363 - estebank:mutability-mismatch-arg, …
Browse files Browse the repository at this point in the history
…r=Nilstrieb

Structured suggestion for `&mut dyn Iterator` when possible

Fix rust-lang#37914.
  • Loading branch information
compiler-errors committed Jan 9, 2023
2 parents 2c6368f + b693365 commit 388444b
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 30 deletions.
11 changes: 8 additions & 3 deletions compiler/rustc_hir_typeck/src/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@ 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 {
candidates: Vec<DefId>,
needs_mut: bool,
bound_span: Span,
self_expr: &'tcx hir::Expr<'tcx>,
},

// Found a match, but the return type is wrong
BadReturnType,
Expand Down Expand Up @@ -112,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Err(NoMatch(..)) => false,
Err(Ambiguity(..)) => true,
Err(PrivateMatch(..)) => allow_private,
Err(IllegalSizedBound(..)) => true,
Err(IllegalSizedBound { .. }) => true,
Err(BadReturnType) => bug!("no return type expectations but got BadReturnType"),
}
}
Expand Down Expand Up @@ -236,7 +241,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => Vec::new(),
};

return Err(IllegalSizedBound(candidates, needs_mut, span));
return Err(IllegalSizedBound { candidates, needs_mut, bound_span: span, self_expr });
}

Ok(result.callee)
Expand Down
41 changes: 37 additions & 4 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.emit();
}

MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
MethodError::IllegalSizedBound { candidates, needs_mut, bound_span, self_expr } => {
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);
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() {
let help = format!(
"{an}other candidate{s} {were} found in the following trait{s}, perhaps \
Expand All @@ -197,7 +205,32 @@ 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(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();
Expand Down
9 changes: 9 additions & 0 deletions src/test/ui/illegal-sized-bound/mutability-mismatch-arg.fixed
Original file line number Diff line number Diff line change
@@ -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());
}
9 changes: 9 additions & 0 deletions src/test/ui/illegal-sized-bound/mutability-mismatch-arg.rs
Original file line number Diff line number Diff line change
@@ -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());
}
13 changes: 13 additions & 0 deletions src/test/ui/illegal-sized-bound/mutability-mismatch-arg.stderr
Original file line number Diff line number Diff line change
@@ -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

10 changes: 4 additions & 6 deletions src/test/ui/illegal-sized-bound/mutability-mismatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ pub trait MutTrait {
fn function(&mut self)
where
Self: Sized;
//~^ this has a `Sized` requirement
}

impl MutTrait for MutType {
Expand All @@ -17,7 +16,6 @@ pub trait Trait {
fn function(&self)
where
Self: Sized;
//~^ this has a `Sized` requirement
}

impl Trait for Type {
Expand All @@ -26,9 +24,9 @@ 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`
//~^ ERROR the `function` method cannot be invoked on `&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`
//~^ ERROR the `function` method cannot be invoked on `&mut dyn Trait`
//~| HELP you need `&dyn Trait` instead of `&mut dyn Trait`
}
18 changes: 6 additions & 12 deletions src/test/ui/illegal-sized-bound/mutability-mismatch.stderr
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
error: the `function` method cannot be invoked on a trait object
--> $DIR/mutability-mismatch.rs:28:33
error: the `function` method cannot be invoked on `&dyn MutTrait`
--> $DIR/mutability-mismatch.rs:26:33
|
LL | Self: Sized;
| ----- this has a `Sized` requirement
...
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
error: the `function` method cannot be invoked on `&mut dyn Trait`
--> $DIR/mutability-mismatch.rs:29:35
|
LL | Self: Sized;
| ----- this has a `Sized` requirement
...
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

2 changes: 1 addition & 1 deletion src/test/ui/suggestions/imm-ref-trait-object.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
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() {
Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/suggestions/imm-ref-trait-object.stderr
Original file line number Diff line number Diff line change
@@ -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
|
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

0 comments on commit 388444b

Please sign in to comment.