Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2972,8 +2972,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
let expr = expr.peel_drop_temps();

match (&expr.kind, expected.kind(), checked_ty.kind()) {
// Handle call arguments that need another shared or mutable reference, such as
// `&T` to `&&T` or `&T` to `&mut &T`.
// Keep ordinary `T` to `&T` cases on later path so its more
// specific suggestions, such as `Option::as_ref()`, are preserved.
(_, &ty::Ref(_, exp, mutability), _)
if exp.is_ref()
&& matches!(
self.tcx.parent_hir_node(expr.hir_id),
hir::Node::Expr(hir::Expr {
kind:
hir::ExprKind::Call(_, args)
| hir::ExprKind::MethodCall(_, _, args, _),
..
}) if args.iter().any(|arg| arg.hir_id == expr.hir_id)
)
&& self.can_eq(self.param_env, exp, checked_ty) =>
{
let borrow = mutability.ref_prefix_str();
let sugg = if expr_needs_parens(expr) {
vec![
(sp.shrink_to_lo(), format!("{borrow}(")),
(sp.shrink_to_hi(), ")".to_string()),
]
} else {
vec![(sp.shrink_to_lo(), borrow.to_string())]
};
return Some((
sugg,
format!("consider {}borrowing here", mutability.mutably_str()),
Applicability::MachineApplicable,
false,
));
}
(_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (exp.kind(), check.kind()) {
(&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind
Expand Down
44 changes: 44 additions & 0 deletions tests/ui/mismatched_types/suggest-extra-borrow-issue-78613.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//! Regression test for https://github.com/rust-lang/rust/issues/78613.
//! A call argument that needs one more reference should suggest borrowing it.

//@ run-rustfix

fn takes_nested_ref(_: &&str) {}

fn takes_generic_nested_ref<T>(_: &&T) {}

fn takes_nested_mut_ref(_: &mut &str) {}

fn takes_ref(_: &i32) {}

struct Foo;

fn takes_foo_ref(_: &Foo) {}

fn main() {
let haystack = [&["A1", "A2"][..], &["B1", "B2"], &["C1", "C2"]];
let needle: &[&str] = &["D1", "D2"];
let _ = haystack.contains(&needle);
//~^ ERROR mismatched types

let text = "text";
takes_nested_ref(&text);
//~^ ERROR mismatched types

let number = &1;
takes_generic_nested_ref(&number);
//~^ ERROR mismatched types

let mut mutable_text = text;
takes_nested_mut_ref(&mut mutable_text);
//~^ ERROR mismatched types

takes_ref(if true { &1 } else { &2 });
//~^ ERROR mismatched types
//~| ERROR mismatched types

// Ordinary `T` to `&T` cases should retain more specific suggestions from the existing path.
let ref opt = Some(Foo);
opt.as_ref().map(|arg| takes_foo_ref(arg));
//~^ ERROR mismatched types
}
44 changes: 44 additions & 0 deletions tests/ui/mismatched_types/suggest-extra-borrow-issue-78613.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//! Regression test for https://github.com/rust-lang/rust/issues/78613.
//! A call argument that needs one more reference should suggest borrowing it.

//@ run-rustfix

fn takes_nested_ref(_: &&str) {}

fn takes_generic_nested_ref<T>(_: &&T) {}

fn takes_nested_mut_ref(_: &mut &str) {}

fn takes_ref(_: &i32) {}

struct Foo;

fn takes_foo_ref(_: &Foo) {}

fn main() {
let haystack = [&["A1", "A2"][..], &["B1", "B2"], &["C1", "C2"]];
let needle: &[&str] = &["D1", "D2"];
let _ = haystack.contains(needle);
//~^ ERROR mismatched types

let text = "text";
takes_nested_ref(text);
//~^ ERROR mismatched types

let number = &1;
takes_generic_nested_ref(number);
//~^ ERROR mismatched types

let mut mutable_text = text;
takes_nested_mut_ref(mutable_text);
//~^ ERROR mismatched types

takes_ref(if true { 1 } else { 2 });
//~^ ERROR mismatched types
//~| ERROR mismatched types

// Ordinary `T` to `&T` cases should retain more specific suggestions from the existing path.
let ref opt = Some(Foo);
opt.map(|arg| takes_foo_ref(arg));
//~^ ERROR mismatched types
}
120 changes: 120 additions & 0 deletions tests/ui/mismatched_types/suggest-extra-borrow-issue-78613.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
error[E0308]: mismatched types
--> $DIR/suggest-extra-borrow-issue-78613.rs:21:31
|
LL | let _ = haystack.contains(needle);
| -------- ^^^^^^ expected `&&[&str]`, found `&[&str]`
| |
| arguments to this method are incorrect
|
= note: expected reference `&&[&str]`
found reference `&[&str]`
note: method defined here
--> $SRC_DIR/core/src/slice/mod.rs:LL:COL
help: consider borrowing here
|
LL | let _ = haystack.contains(&needle);
| +

error[E0308]: mismatched types
--> $DIR/suggest-extra-borrow-issue-78613.rs:25:22
|
LL | takes_nested_ref(text);
| ---------------- ^^^^ expected `&&str`, found `&str`
| |
| arguments to this function are incorrect
|
= note: expected reference `&&_`
found reference `&_`
note: function defined here
--> $DIR/suggest-extra-borrow-issue-78613.rs:6:4
|
LL | fn takes_nested_ref(_: &&str) {}
| ^^^^^^^^^^^^^^^^ --------
help: consider borrowing here
|
LL | takes_nested_ref(&text);
| +

error[E0308]: mismatched types
--> $DIR/suggest-extra-borrow-issue-78613.rs:29:30
|
LL | takes_generic_nested_ref(number);
| ------------------------ ^^^^^^ expected `&&_`, found `&{integer}`
| |
| arguments to this function are incorrect
|
= note: expected reference `&&_`
found reference `&{integer}`
note: function defined here
--> $DIR/suggest-extra-borrow-issue-78613.rs:8:4
|
LL | fn takes_generic_nested_ref<T>(_: &&T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ ------
help: consider borrowing here
|
LL | takes_generic_nested_ref(&number);
| +

error[E0308]: mismatched types
--> $DIR/suggest-extra-borrow-issue-78613.rs:33:26
|
LL | takes_nested_mut_ref(mutable_text);
| -------------------- ^^^^^^^^^^^^ types differ in mutability
| |
| arguments to this function are incorrect
|
= note: expected mutable reference `&mut &_`
found reference `&_`
note: function defined here
--> $DIR/suggest-extra-borrow-issue-78613.rs:10:4
|
LL | fn takes_nested_mut_ref(_: &mut &str) {}
| ^^^^^^^^^^^^^^^^^^^^ ------------
help: consider mutably borrowing here
|
LL | takes_nested_mut_ref(&mut mutable_text);
| ++++

error[E0308]: mismatched types
--> $DIR/suggest-extra-borrow-issue-78613.rs:36:25
|
LL | takes_ref(if true { 1 } else { 2 });
| ^ expected `&i32`, found integer
|
help: consider borrowing here
|
LL | takes_ref(if true { &1 } else { 2 });
| +

error[E0308]: mismatched types
--> $DIR/suggest-extra-borrow-issue-78613.rs:36:36
|
LL | takes_ref(if true { 1 } else { 2 });
| ^ expected `&i32`, found integer
|
help: consider borrowing here
|
LL | takes_ref(if true { 1 } else { &2 });
| +

error[E0308]: mismatched types
--> $DIR/suggest-extra-borrow-issue-78613.rs:42:33
|
LL | opt.map(|arg| takes_foo_ref(arg));
| ------------- ^^^ expected `&Foo`, found `Foo`
| |
| arguments to this function are incorrect
|
note: function defined here
--> $DIR/suggest-extra-borrow-issue-78613.rs:16:4
|
LL | fn takes_foo_ref(_: &Foo) {}
| ^^^^^^^^^^^^^ -------
help: consider using `as_ref` instead
|
LL | opt.as_ref().map(|arg| takes_foo_ref(arg));
| +++++++++

error: aborting due to 7 previous errors

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