Skip to content

Commit 76f440c

Browse files
authored
Rollup merge of rust-lang#107306 - compiler-errors:correct-sugg-for-closure-arg-needs-borrow, r=oli-obk
Correct suggestions for closure arguments that need a borrow Fixes rust-lang#107301 by dealing with binders correctly Fixes another issue where we were suggesting adding just `&` when we expected `&mut _` in a closure arg
2 parents bbb3f31 + b83ab0c commit 76f440c

File tree

3 files changed

+74
-10
lines changed

3 files changed

+74
-10
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+20-10
Original file line numberDiff line numberDiff line change
@@ -3759,13 +3759,13 @@ fn hint_missing_borrow<'tcx>(
37593759
err: &mut Diagnostic,
37603760
) {
37613761
let found_args = match found.kind() {
3762-
ty::FnPtr(f) => f.inputs().skip_binder().iter(),
3762+
ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
37633763
kind => {
37643764
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
37653765
}
37663766
};
37673767
let expected_args = match expected.kind() {
3768-
ty::FnPtr(f) => f.inputs().skip_binder().iter(),
3768+
ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
37693769
kind => {
37703770
span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
37713771
}
@@ -3776,12 +3776,12 @@ fn hint_missing_borrow<'tcx>(
37763776

37773777
let args = fn_decl.inputs.iter().map(|ty| ty);
37783778

3779-
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
3780-
let mut refs = 0;
3779+
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
3780+
let mut refs = vec![];
37813781

3782-
while let ty::Ref(_, new_ty, _) = ty.kind() {
3782+
while let ty::Ref(_, new_ty, mutbl) = ty.kind() {
37833783
ty = *new_ty;
3784-
refs += 1;
3784+
refs.push(*mutbl);
37853785
}
37863786

37873787
(ty, refs)
@@ -3795,11 +3795,21 @@ fn hint_missing_borrow<'tcx>(
37953795
let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
37963796

37973797
if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() {
3798-
if found_refs < expected_refs {
3799-
to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs)));
3800-
} else if found_refs > expected_refs {
3798+
// FIXME: This could handle more exotic cases like mutability mismatches too!
3799+
if found_refs.len() < expected_refs.len()
3800+
&& found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..]
3801+
{
3802+
to_borrow.push((
3803+
arg.span.shrink_to_lo(),
3804+
expected_refs[..expected_refs.len() - found_refs.len()]
3805+
.iter()
3806+
.map(|mutbl| format!("&{}", mutbl.prefix_str()))
3807+
.collect::<Vec<_>>()
3808+
.join(""),
3809+
));
3810+
} else if found_refs.len() > expected_refs.len() {
38013811
let mut span = arg.span.shrink_to_lo();
3802-
let mut left = found_refs - expected_refs;
3812+
let mut left = found_refs.len() - expected_refs.len();
38033813
let mut ty = arg;
38043814
while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 {
38053815
span = span.with_hi(mut_ty.ty.span.lo());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use std::cell::RefCell;
2+
use std::collections::HashMap;
3+
use std::rc::Rc;
4+
5+
pub struct Trader<'a> {
6+
closure: Box<dyn Fn(&mut Trader) + 'a>,
7+
}
8+
9+
impl<'a> Trader<'a> {
10+
pub fn new() -> Self {
11+
Trader {
12+
closure: Box::new(|_| {}),
13+
}
14+
}
15+
pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) {
16+
//foo
17+
}
18+
}
19+
20+
fn main() {
21+
let closure = |trader : Trader| {
22+
println!("Woooosh!");
23+
};
24+
25+
let mut trader = Trader::new();
26+
trader.set_closure(closure);
27+
//~^ ERROR type mismatch in closure arguments
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error[E0631]: type mismatch in closure arguments
2+
--> $DIR/late-bound-in-borrow-closure-sugg.rs:26:24
3+
|
4+
LL | let closure = |trader : Trader| {
5+
| ----------------- found signature defined here
6+
...
7+
LL | trader.set_closure(closure);
8+
| ----------- ^^^^^^^ expected due to this
9+
| |
10+
| required by a bound introduced by this call
11+
|
12+
= note: expected closure signature `for<'a, 'b> fn(&'a mut Trader<'b>) -> _`
13+
found closure signature `for<'a> fn(Trader<'a>) -> _`
14+
note: required by a bound in `Trader::<'a>::set_closure`
15+
--> $DIR/late-bound-in-borrow-closure-sugg.rs:15:50
16+
|
17+
LL | pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) {
18+
| ^^^^^^^^^^^^^^^ required by this bound in `Trader::<'a>::set_closure`
19+
help: consider borrowing the argument
20+
|
21+
LL | let closure = |trader : &mut Trader| {
22+
| ++++
23+
24+
error: aborting due to previous error
25+
26+
For more information about this error, try `rustc --explain E0631`.

0 commit comments

Comments
 (0)