Skip to content

Commit

Permalink
Rollup merge of rust-lang#107306 - compiler-errors:correct-sugg-for-c…
Browse files Browse the repository at this point in the history
…losure-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
  • Loading branch information
matthiaskrgr authored Jan 27, 2023
2 parents ba33c23 + b83ab0c commit 82422c8
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3759,13 +3759,13 @@ fn hint_missing_borrow<'tcx>(
err: &mut Diagnostic,
) {
let found_args = match found.kind() {
ty::FnPtr(f) => f.inputs().skip_binder().iter(),
ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
kind => {
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
}
};
let expected_args = match expected.kind() {
ty::FnPtr(f) => f.inputs().skip_binder().iter(),
ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
kind => {
span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
}
Expand All @@ -3776,12 +3776,12 @@ fn hint_missing_borrow<'tcx>(

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

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

while let ty::Ref(_, new_ty, _) = ty.kind() {
while let ty::Ref(_, new_ty, mutbl) = ty.kind() {
ty = *new_ty;
refs += 1;
refs.push(*mutbl);
}

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

if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() {
if found_refs < expected_refs {
to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs)));
} else if found_refs > expected_refs {
// FIXME: This could handle more exotic cases like mutability mismatches too!
if found_refs.len() < expected_refs.len()
&& found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..]
{
to_borrow.push((
arg.span.shrink_to_lo(),
expected_refs[..expected_refs.len() - found_refs.len()]
.iter()
.map(|mutbl| format!("&{}", mutbl.prefix_str()))
.collect::<Vec<_>>()
.join(""),
));
} else if found_refs.len() > expected_refs.len() {
let mut span = arg.span.shrink_to_lo();
let mut left = found_refs - expected_refs;
let mut left = found_refs.len() - expected_refs.len();
let mut ty = arg;
while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 {
span = span.with_hi(mut_ty.ty.span.lo());
Expand Down
28 changes: 28 additions & 0 deletions tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

pub struct Trader<'a> {
closure: Box<dyn Fn(&mut Trader) + 'a>,
}

impl<'a> Trader<'a> {
pub fn new() -> Self {
Trader {
closure: Box::new(|_| {}),
}
}
pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) {
//foo
}
}

fn main() {
let closure = |trader : Trader| {
println!("Woooosh!");
};

let mut trader = Trader::new();
trader.set_closure(closure);
//~^ ERROR type mismatch in closure arguments
}
26 changes: 26 additions & 0 deletions tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
error[E0631]: type mismatch in closure arguments
--> $DIR/late-bound-in-borrow-closure-sugg.rs:26:24
|
LL | let closure = |trader : Trader| {
| ----------------- found signature defined here
...
LL | trader.set_closure(closure);
| ----------- ^^^^^^^ expected due to this
| |
| required by a bound introduced by this call
|
= note: expected closure signature `for<'a, 'b> fn(&'a mut Trader<'b>) -> _`
found closure signature `for<'a> fn(Trader<'a>) -> _`
note: required by a bound in `Trader::<'a>::set_closure`
--> $DIR/late-bound-in-borrow-closure-sugg.rs:15:50
|
LL | pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) {
| ^^^^^^^^^^^^^^^ required by this bound in `Trader::<'a>::set_closure`
help: consider borrowing the argument
|
LL | let closure = |trader : &mut Trader| {
| ++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0631`.

0 comments on commit 82422c8

Please sign in to comment.