-
Notifications
You must be signed in to change notification settings - Fork 13k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of #85369 - FabianWolff:issue-84973, r=jackh726
Suggest borrowing if a trait implementation is found for &/&mut <type> This pull request fixes #84973 by suggesting to borrow if a trait is not implemented for some type `T`, but it is for `&T` or `&mut T`. For instance: ```rust trait Ti {} impl<T> Ti for &T {} fn foo<T: Ti>(_: T) {} trait Tm {} impl<T> Tm for &mut T {} fn bar<T: Tm>(_: T) {} fn main() { let a: i32 = 5; foo(a); let b: Box<i32> = Box::new(42); bar(b); } ``` gives, on current nightly: ``` error[E0277]: the trait bound `i32: Ti` is not satisfied --> t2.rs:11:9 | 3 | fn foo<T: Ti>(_: T) {} | -- required by this bound in `foo` ... 11 | foo(a); | ^ the trait `Ti` is not implemented for `i32` error[E0277]: the trait bound `Box<i32>: Tm` is not satisfied --> t2.rs:14:9 | 7 | fn bar<T: Tm>(_: T) {} | -- required by this bound in `bar` ... 14 | bar(b); | ^ the trait `Tm` is not implemented for `Box<i32>` error: aborting due to 2 previous errors ``` whereas with my changes, I get: ``` error[E0277]: the trait bound `i32: Ti` is not satisfied --> t2.rs:11:9 | 3 | fn foo<T: Ti>(_: T) {} | -- required by this bound in `foo` ... 11 | foo(a); | ^ | | | expected an implementor of trait `Ti` | help: consider borrowing here: `&a` error[E0277]: the trait bound `Box<i32>: Tm` is not satisfied --> t2.rs:14:9 | 7 | fn bar<T: Tm>(_: T) {} | -- required by this bound in `bar` ... 14 | bar(b); | ^ | | | expected an implementor of trait `Tm` | help: consider borrowing mutably here: `&mut b` error: aborting due to 2 previous errors ``` In my implementation, I have added a "blacklist" to make these suggestions flexible. In particular, suggesting to borrow can interfere with other suggestions, such as to add another trait bound to a generic argument. I have tried to configure this blacklist to cause the least amount of test case failures, i.e. to model the current behavior as closely as possible (I only had to change one existing test case, and this change was quite clearly an improvement).
- Loading branch information
Showing
10 changed files
with
277 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// A slight variation of issue-84973.rs. Here, a mutable borrow is | ||
// required (and the obligation kind is different). | ||
|
||
trait Tr {} | ||
impl Tr for &mut i32 {} | ||
|
||
fn foo<T: Tr>(i: T) {} | ||
|
||
fn main() { | ||
let a: i32 = 32; | ||
foo(a); | ||
//~^ ERROR: the trait bound `i32: Tr` is not satisfied [E0277] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
error[E0277]: the trait bound `i32: Tr` is not satisfied | ||
--> $DIR/issue-84973-2.rs:11:9 | ||
| | ||
LL | fn foo<T: Tr>(i: T) {} | ||
| -- required by this bound in `foo` | ||
... | ||
LL | foo(a); | ||
| ^ | ||
| | | ||
| expected an implementor of trait `Tr` | ||
| help: consider mutably borrowing here: `&mut a` | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0277`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Checks that certain traits for which we don't want to suggest borrowing | ||
// are blacklisted and don't cause the suggestion to be issued. | ||
|
||
#![feature(generators)] | ||
|
||
fn f_copy<T: Copy>(t: T) {} | ||
fn f_clone<T: Clone>(t: T) {} | ||
fn f_unpin<T: Unpin>(t: T) {} | ||
fn f_sized<T: Sized>(t: T) {} | ||
fn f_send<T: Send>(t: T) {} | ||
|
||
struct S; | ||
|
||
fn main() { | ||
f_copy("".to_string()); //~ ERROR: the trait bound `String: Copy` is not satisfied [E0277] | ||
f_clone(S); //~ ERROR: the trait bound `S: Clone` is not satisfied [E0277] | ||
f_unpin(static || { yield; }); | ||
//~^ ERROR: cannot be unpinned [E0277] | ||
|
||
let cl = || (); | ||
let ref_cl: &dyn Fn() -> () = &cl; | ||
f_sized(*ref_cl); | ||
//~^ ERROR: the size for values of type `dyn Fn()` cannot be known at compilation time [E0277] | ||
//~| ERROR: the size for values of type `dyn Fn()` cannot be known at compilation time [E0277] | ||
|
||
use std::rc::Rc; | ||
let rc = Rc::new(0); | ||
f_send(rc); //~ ERROR: `Rc<{integer}>` cannot be sent between threads safely [E0277] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
error[E0277]: the trait bound `String: Copy` is not satisfied | ||
--> $DIR/issue-84973-blacklist.rs:15:12 | ||
| | ||
LL | fn f_copy<T: Copy>(t: T) {} | ||
| ---- required by this bound in `f_copy` | ||
... | ||
LL | f_copy("".to_string()); | ||
| ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | ||
|
||
error[E0277]: the trait bound `S: Clone` is not satisfied | ||
--> $DIR/issue-84973-blacklist.rs:16:13 | ||
| | ||
LL | fn f_clone<T: Clone>(t: T) {} | ||
| ----- required by this bound in `f_clone` | ||
... | ||
LL | f_clone(S); | ||
| ^ the trait `Clone` is not implemented for `S` | ||
|
||
error[E0277]: `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:33]` cannot be unpinned | ||
--> $DIR/issue-84973-blacklist.rs:17:5 | ||
| | ||
LL | fn f_unpin<T: Unpin>(t: T) {} | ||
| ----- required by this bound in `f_unpin` | ||
... | ||
LL | f_unpin(static || { yield; }); | ||
| ^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:33]` | ||
| | ||
= note: consider using `Box::pin` | ||
|
||
error[E0277]: the size for values of type `dyn Fn()` cannot be known at compilation time | ||
--> $DIR/issue-84973-blacklist.rs:22:13 | ||
| | ||
LL | fn f_sized<T: Sized>(t: T) {} | ||
| - required by this bound in `f_sized` | ||
... | ||
LL | f_sized(*ref_cl); | ||
| ^^^^^^^ doesn't have a size known at compile-time | ||
| | ||
= help: the trait `Sized` is not implemented for `dyn Fn()` | ||
|
||
error[E0277]: `Rc<{integer}>` cannot be sent between threads safely | ||
--> $DIR/issue-84973-blacklist.rs:28:12 | ||
| | ||
LL | fn f_send<T: Send>(t: T) {} | ||
| ---- required by this bound in `f_send` | ||
... | ||
LL | f_send(rc); | ||
| ^^ `Rc<{integer}>` cannot be sent between threads safely | ||
| | ||
= help: the trait `Send` is not implemented for `Rc<{integer}>` | ||
|
||
error[E0277]: the size for values of type `dyn Fn()` cannot be known at compilation time | ||
--> $DIR/issue-84973-blacklist.rs:22:5 | ||
| | ||
LL | f_sized(*ref_cl); | ||
| ^^^^^^^ doesn't have a size known at compile-time | ||
| | ||
= help: the trait `Sized` is not implemented for `dyn Fn()` | ||
= note: all function arguments must have a statically known size | ||
= help: unsized fn params are gated as an unstable feature | ||
|
||
error: aborting due to 6 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0277`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Checks that we only suggest borrowing if &T actually implements the trait. | ||
|
||
trait Tr {} | ||
impl Tr for &f32 {} | ||
fn bar<T: Tr>(t: T) {} | ||
|
||
fn main() { | ||
let a = 0i32; | ||
let b = 0.0f32; | ||
bar(a); //~ ERROR: the trait bound `i32: Tr` is not satisfied [E0277] | ||
bar(b); //~ ERROR: the trait bound `f32: Tr` is not satisfied [E0277] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
error[E0277]: the trait bound `i32: Tr` is not satisfied | ||
--> $DIR/issue-84973-negative.rs:10:9 | ||
| | ||
LL | fn bar<T: Tr>(t: T) {} | ||
| -- required by this bound in `bar` | ||
... | ||
LL | bar(a); | ||
| ^ the trait `Tr` is not implemented for `i32` | ||
|
||
error[E0277]: the trait bound `f32: Tr` is not satisfied | ||
--> $DIR/issue-84973-negative.rs:11:9 | ||
| | ||
LL | fn bar<T: Tr>(t: T) {} | ||
| -- required by this bound in `bar` | ||
... | ||
LL | bar(b); | ||
| ^ | ||
| | | ||
| expected an implementor of trait `Tr` | ||
| help: consider borrowing here: `&b` | ||
|
||
error: aborting due to 2 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0277`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Checks whether borrowing is suggested when a trait bound is not satisfied | ||
// for found type `T`, but is for `&/&mut T`. | ||
|
||
fn main() { | ||
let f = Fancy{}; | ||
let o = Other::new(f); | ||
//~^ ERROR: the trait bound `Fancy: SomeTrait` is not satisfied [E0277] | ||
} | ||
|
||
struct Fancy {} | ||
|
||
impl <'a> SomeTrait for &'a Fancy { | ||
} | ||
|
||
trait SomeTrait {} | ||
|
||
struct Other<'a, G> { | ||
a: &'a str, | ||
g: G, | ||
} | ||
|
||
// Broadly copied from https://docs.rs/petgraph/0.5.1/src/petgraph/dot.rs.html#70 | ||
impl<'a, G> Other<'a, G> | ||
where | ||
G: SomeTrait, | ||
{ | ||
pub fn new(g: G) -> Self { | ||
Other { | ||
a: "hi", | ||
g: g, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
error[E0277]: the trait bound `Fancy: SomeTrait` is not satisfied | ||
--> $DIR/issue-84973.rs:6:24 | ||
| | ||
LL | let o = Other::new(f); | ||
| ^ | ||
| | | ||
| expected an implementor of trait `SomeTrait` | ||
| help: consider borrowing here: `&f` | ||
... | ||
LL | pub fn new(g: G) -> Self { | ||
| ------------------------ required by `Other::<'a, G>::new` | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0277`. |