Skip to content

Commit fa2cd94

Browse files
authored
Rollup merge of #107306 - compiler-errors:correct-sugg-for-closure-arg-needs-borrow, r=oli-obk
Correct suggestions for closure arguments that need a borrow Fixes #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 260e048 + b83ab0c commit fa2cd94

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
@@ -3807,13 +3807,13 @@ fn hint_missing_borrow<'tcx>(
38073807
err: &mut Diagnostic,
38083808
) {
38093809
let found_args = match found.kind() {
3810-
ty::FnPtr(f) => f.inputs().skip_binder().iter(),
3810+
ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
38113811
kind => {
38123812
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
38133813
}
38143814
};
38153815
let expected_args = match expected.kind() {
3816-
ty::FnPtr(f) => f.inputs().skip_binder().iter(),
3816+
ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
38173817
kind => {
38183818
span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
38193819
}
@@ -3824,12 +3824,12 @@ fn hint_missing_borrow<'tcx>(
38243824

38253825
let args = fn_decl.inputs.iter().map(|ty| ty);
38263826

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

3830-
while let ty::Ref(_, new_ty, _) = ty.kind() {
3830+
while let ty::Ref(_, new_ty, mutbl) = ty.kind() {
38313831
ty = *new_ty;
3832-
refs += 1;
3832+
refs.push(*mutbl);
38333833
}
38343834

38353835
(ty, refs)
@@ -3843,11 +3843,21 @@ fn hint_missing_borrow<'tcx>(
38433843
let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
38443844

38453845
if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() {
3846-
if found_refs < expected_refs {
3847-
to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs)));
3848-
} else if found_refs > expected_refs {
3846+
// FIXME: This could handle more exotic cases like mutability mismatches too!
3847+
if found_refs.len() < expected_refs.len()
3848+
&& found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..]
3849+
{
3850+
to_borrow.push((
3851+
arg.span.shrink_to_lo(),
3852+
expected_refs[..expected_refs.len() - found_refs.len()]
3853+
.iter()
3854+
.map(|mutbl| format!("&{}", mutbl.prefix_str()))
3855+
.collect::<Vec<_>>()
3856+
.join(""),
3857+
));
3858+
} else if found_refs.len() > expected_refs.len() {
38493859
let mut span = arg.span.shrink_to_lo();
3850-
let mut left = found_refs - expected_refs;
3860+
let mut left = found_refs.len() - expected_refs.len();
38513861
let mut ty = arg;
38523862
while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 {
38533863
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)