Skip to content

Commit 334426b

Browse files
Rollup merge of #106363 - estebank:mutability-mismatch-arg, r=Nilstrieb
Structured suggestion for `&mut dyn Iterator` when possible Fix #37914.
2 parents 6afd161 + b693365 commit 334426b

File tree

9 files changed

+91
-30
lines changed

9 files changed

+91
-30
lines changed

compiler/rustc_hir_typeck/src/method/mod.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,12 @@ 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 {
61+
candidates: Vec<DefId>,
62+
needs_mut: bool,
63+
bound_span: Span,
64+
self_expr: &'tcx hir::Expr<'tcx>,
65+
},
6166

6267
// Found a match, but the return type is wrong
6368
BadReturnType,
@@ -112,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
112117
Err(NoMatch(..)) => false,
113118
Err(Ambiguity(..)) => true,
114119
Err(PrivateMatch(..)) => allow_private,
115-
Err(IllegalSizedBound(..)) => true,
120+
Err(IllegalSizedBound { .. }) => true,
116121
Err(BadReturnType) => bug!("no return type expectations but got BadReturnType"),
117122
}
118123
}
@@ -236,7 +241,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
236241
_ => Vec::new(),
237242
};
238243

239-
return Err(IllegalSizedBound(candidates, needs_mut, span));
244+
return Err(IllegalSizedBound { candidates, needs_mut, bound_span: span, self_expr });
240245
}
241246

242247
Ok(result.callee)

compiler/rustc_hir_typeck/src/method/suggest.rs

+37-4
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
176176
err.emit();
177177
}
178178

179-
MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
180-
let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
179+
MethodError::IllegalSizedBound { candidates, needs_mut, bound_span, self_expr } => {
180+
let msg = if needs_mut {
181+
with_forced_trimmed_paths!(format!(
182+
"the `{item_name}` method cannot be invoked on `{rcvr_ty}`"
183+
))
184+
} else {
185+
format!("the `{item_name}` method cannot be invoked on a trait object")
186+
};
181187
let mut err = self.sess().struct_span_err(span, &msg);
182-
err.span_label(bound_span, "this has a `Sized` requirement");
188+
if !needs_mut {
189+
err.span_label(bound_span, "this has a `Sized` requirement");
190+
}
183191
if !candidates.is_empty() {
184192
let help = format!(
185193
"{an}other candidate{s} {were} found in the following trait{s}, perhaps \
@@ -197,7 +205,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
197205
*region,
198206
ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
199207
);
200-
err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
208+
let msg = format!("you need `{}` instead of `{}`", trait_type, rcvr_ty);
209+
let mut kind = &self_expr.kind;
210+
while let hir::ExprKind::AddrOf(_, _, expr)
211+
| hir::ExprKind::Unary(hir::UnOp::Deref, expr) = kind
212+
{
213+
kind = &expr.kind;
214+
}
215+
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind
216+
&& let hir::def::Res::Local(hir_id) = path.res
217+
&& let Some(hir::Node::Pat(b)) = self.tcx.hir().find(hir_id)
218+
&& let Some(hir::Node::Param(p)) = self.tcx.hir().find_parent(b.hir_id)
219+
&& let Some(node) = self.tcx.hir().find_parent(p.hir_id)
220+
&& let Some(decl) = node.fn_decl()
221+
&& let Some(ty) = decl.inputs.iter().find(|ty| ty.span == p.ty_span)
222+
&& let hir::TyKind::Ref(_, mut_ty) = &ty.kind
223+
&& let hir::Mutability::Not = mut_ty.mutbl
224+
{
225+
err.span_suggestion_verbose(
226+
mut_ty.ty.span.shrink_to_lo(),
227+
&msg,
228+
"mut ",
229+
Applicability::MachineApplicable,
230+
);
231+
} else {
232+
err.help(&msg);
233+
}
201234
}
202235
}
203236
err.emit();
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
4+
}
5+
6+
fn main() {
7+
let array = [0u64];
8+
test(&mut array.iter());
9+
}
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
4+
}
5+
6+
fn main() {
7+
let array = [0u64];
8+
test(&mut array.iter());
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: the `min` method cannot be invoked on `&dyn Iterator<Item = &u64>`
2+
--> $DIR/mutability-mismatch-arg.rs:3:9
3+
|
4+
LL | *t.min().unwrap()
5+
| ^^^
6+
|
7+
help: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
8+
|
9+
LL | fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
10+
| +++
11+
12+
error: aborting due to previous error
13+

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

+4-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ pub trait MutTrait {
44
fn function(&mut self)
55
where
66
Self: Sized;
7-
//~^ this has a `Sized` requirement
87
}
98

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

2321
impl Trait for Type {
@@ -26,9 +24,9 @@ impl Trait for Type {
2624

2725
fn main() {
2826
(&MutType as &dyn MutTrait).function();
29-
//~^ ERROR the `function` method cannot be invoked on a trait object
30-
//~| NOTE you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
27+
//~^ ERROR the `function` method cannot be invoked on `&dyn MutTrait`
28+
//~| HELP you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
3129
(&mut Type as &mut dyn Trait).function();
32-
//~^ ERROR the `function` method cannot be invoked on a trait object
33-
//~| NOTE you need `&dyn Trait` instead of `&mut dyn Trait`
30+
//~^ ERROR the `function` method cannot be invoked on `&mut dyn Trait`
31+
//~| HELP you need `&dyn Trait` instead of `&mut dyn Trait`
3432
}
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,18 @@
1-
error: the `function` method cannot be invoked on a trait object
2-
--> $DIR/mutability-mismatch.rs:28:33
1+
error: the `function` method cannot be invoked on `&dyn MutTrait`
2+
--> $DIR/mutability-mismatch.rs:26:33
33
|
4-
LL | Self: Sized;
5-
| ----- this has a `Sized` requirement
6-
...
74
LL | (&MutType as &dyn MutTrait).function();
85
| ^^^^^^^^
96
|
10-
= note: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
7+
= help: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
118

12-
error: the `function` method cannot be invoked on a trait object
13-
--> $DIR/mutability-mismatch.rs:31:35
9+
error: the `function` method cannot be invoked on `&mut dyn Trait`
10+
--> $DIR/mutability-mismatch.rs:29:35
1411
|
15-
LL | Self: Sized;
16-
| ----- this has a `Sized` requirement
17-
...
1812
LL | (&mut Type as &mut dyn Trait).function();
1913
| ^^^^^^^^
2014
|
21-
= note: you need `&dyn Trait` instead of `&mut dyn Trait`
15+
= help: you need `&dyn Trait` instead of `&mut dyn Trait`
2216

2317
error: aborting due to 2 previous errors
2418

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
fn test(t: &dyn Iterator<Item=&u64>) -> u64 {
2-
t.min().unwrap() //~ ERROR the `min` method cannot be invoked on a trait object
2+
t.min().unwrap() //~ ERROR the `min` method cannot be invoked on `&dyn Iterator<Item = &u64>`
33
}
44

55
fn main() {
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
error: the `min` method cannot be invoked on a trait object
1+
error: the `min` method cannot be invoked on `&dyn Iterator<Item = &u64>`
22
--> $DIR/imm-ref-trait-object.rs:2:8
33
|
44
LL | t.min().unwrap()
55
| ^^^
6-
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
76
|
8-
= note: this has a `Sized` requirement
7+
help: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
98
|
10-
= note: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
9+
LL | fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
10+
| +++
1111

1212
error: aborting due to previous error
1313

0 commit comments

Comments
 (0)