Skip to content

Commit 1eb828e

Browse files
committed
Structured suggestion for &mut dyn Iterator when possible
Fix #37914.
1 parent afe8c45 commit 1eb828e

File tree

8 files changed

+73
-9
lines changed

8 files changed

+73
-9
lines changed

compiler/rustc_hir_typeck/src/method/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub enum MethodError<'tcx> {
5757
PrivateMatch(DefKind, DefId, Vec<DefId>),
5858

5959
// Found a `Self: Sized` bound where `Self` is a trait object.
60-
IllegalSizedBound(Vec<DefId>, bool, Span),
60+
IllegalSizedBound(Vec<DefId>, bool, Span, &'tcx hir::Expr<'tcx>),
6161

6262
// Found a match, but the return type is wrong
6363
BadReturnType,
@@ -236,7 +236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
236236
_ => Vec::new(),
237237
};
238238

239-
return Err(IllegalSizedBound(candidates, needs_mut, span));
239+
return Err(IllegalSizedBound(candidates, needs_mut, span, self_expr));
240240
}
241241

242242
Ok(result.callee)

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
176176
err.emit();
177177
}
178178

179-
MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
179+
MethodError::IllegalSizedBound(candidates, needs_mut, bound_span, self_expr) => {
180180
let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
181181
let mut err = self.sess().struct_span_err(span, &msg);
182182
err.span_label(bound_span, "this has a `Sized` requirement");
@@ -197,7 +197,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
197197
*region,
198198
ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
199199
);
200-
err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
200+
let msg = format!("you need `{}` instead of `{}`", trait_type, rcvr_ty);
201+
let mut kind = &self_expr.kind;
202+
while let hir::ExprKind::AddrOf(_, _, expr)
203+
| hir::ExprKind::Unary(hir::UnOp::Deref, expr) = kind
204+
{
205+
kind = &expr.kind;
206+
}
207+
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind
208+
&& let hir::def::Res::Local(hir_id) = path.res
209+
&& let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id)
210+
&& let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
211+
&& let Some(hir::Node::Param(param)) = self.tcx.hir().find(parent_hir_id)
212+
&& let parent_hir_id = self.tcx.hir().get_parent_node(param.hir_id)
213+
&& let Some(node) = self.tcx.hir().find(parent_hir_id)
214+
&& let Some(decl) = node.fn_decl()
215+
&& let Some(ty) = decl.inputs.iter().find(|ty| ty.span == param.ty_span)
216+
&& let hir::TyKind::Ref(_, mut_ty) = &ty.kind
217+
&& let hir::Mutability::Not = mut_ty.mutbl
218+
{
219+
err.span_suggestion_verbose(
220+
mut_ty.ty.span.shrink_to_lo(),
221+
&msg,
222+
"mut ",
223+
Applicability::MachineApplicable,
224+
);
225+
} else {
226+
err.help(&msg);
227+
}
201228
}
202229
}
203230
err.emit();
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// run-rustfix
2+
fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
3+
*t.min().unwrap() //~ ERROR the `min` method cannot be invoked on a trait object
4+
}
5+
6+
fn main() {
7+
let array = [0u64];
8+
test(&mut array.iter());
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// run-rustfix
2+
fn test(t: &dyn Iterator<Item=&u64>) -> u64 {
3+
*t.min().unwrap() //~ ERROR the `min` method cannot be invoked on a trait object
4+
}
5+
6+
fn main() {
7+
let array = [0u64];
8+
test(&mut array.iter());
9+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: the `min` method cannot be invoked on a trait object
2+
--> $DIR/mutability-mismatch-arg.rs:3:9
3+
|
4+
LL | *t.min().unwrap()
5+
| ^^^
6+
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
7+
|
8+
= note: this has a `Sized` requirement
9+
|
10+
help: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
11+
|
12+
LL | fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
13+
| +++
14+
15+
error: aborting due to previous error
16+

src/test/ui/illegal-sized-bound/mutability-mismatch.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ impl Trait for Type {
2727
fn main() {
2828
(&MutType as &dyn MutTrait).function();
2929
//~^ ERROR the `function` method cannot be invoked on a trait object
30-
//~| NOTE you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
30+
//~| HELP you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
3131
(&mut Type as &mut dyn Trait).function();
3232
//~^ ERROR the `function` method cannot be invoked on a trait object
33-
//~| NOTE you need `&dyn Trait` instead of `&mut dyn Trait`
33+
//~| HELP you need `&dyn Trait` instead of `&mut dyn Trait`
3434
}

src/test/ui/illegal-sized-bound/mutability-mismatch.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | Self: Sized;
77
LL | (&MutType as &dyn MutTrait).function();
88
| ^^^^^^^^
99
|
10-
= note: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
10+
= help: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
1111

1212
error: the `function` method cannot be invoked on a trait object
1313
--> $DIR/mutability-mismatch.rs:31:35
@@ -18,7 +18,7 @@ LL | Self: Sized;
1818
LL | (&mut Type as &mut dyn Trait).function();
1919
| ^^^^^^^^
2020
|
21-
= note: you need `&dyn Trait` instead of `&mut dyn Trait`
21+
= help: you need `&dyn Trait` instead of `&mut dyn Trait`
2222

2323
error: aborting due to 2 previous errors
2424

src/test/ui/suggestions/imm-ref-trait-object.stderr

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ LL | t.min().unwrap()
77
|
88
= note: this has a `Sized` requirement
99
|
10-
= note: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
10+
help: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
11+
|
12+
LL | fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
13+
| +++
1114

1215
error: aborting due to previous error
1316

0 commit comments

Comments
 (0)