From fa91980d2d686d3f426a2cae1d0e8fd6825d2d94 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Fri, 19 Aug 2022 06:27:31 -0400 Subject: [PATCH 01/25] Add long description and test for E0311 Adds a long description and unit test for the E0311 compiler error. --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../src/error_codes/E0311.md | 49 +++++++++++++++++++ src/test/ui/error-codes/E0311.rs | 18 +++++++ src/test/ui/error-codes/E0311.stderr | 45 +++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0311.md create mode 100644 src/test/ui/error-codes/E0311.rs create mode 100644 src/test/ui/error-codes/E0311.stderr diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 854625579ee7b..1e86d159668ff 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -159,6 +159,7 @@ E0307: include_str!("./error_codes/E0307.md"), E0308: include_str!("./error_codes/E0308.md"), E0309: include_str!("./error_codes/E0309.md"), E0310: include_str!("./error_codes/E0310.md"), +E0311: include_str!("./error_codes/E0311.md"), E0312: include_str!("./error_codes/E0312.md"), E0316: include_str!("./error_codes/E0316.md"), E0317: include_str!("./error_codes/E0317.md"), @@ -568,7 +569,6 @@ E0790: include_str!("./error_codes/E0790.md"), // E0300, // unexpanded macro // E0304, // expected signed integer constant // E0305, // expected constant - E0311, // thing may not live long enough E0313, // lifetime of borrowed pointer outlives lifetime of captured // variable // E0314, // closure outlives stack frame diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md new file mode 100644 index 0000000000000..8b5daaaa17865 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -0,0 +1,49 @@ +E0311 occurs when there is insufficient information for the rust compiler to +prove that some time has a long enough lifetime. + +Erroneous code example: + +```compile_fail, E0311 +use std::borrow::BorrowMut; + +trait NestedBorrowMut { + fn nested_borrow_mut(&mut self) -> &mut V; +} + +impl NestedBorrowMut for T +where + T: BorrowMut, + U: BorrowMut, // missing lifetime specifier here --> compile fail +{ + fn nested_borrow_mut(&mut self) -> &mut V { + self.borrow_mut().borrow_mut() + } +} +``` + +In this example we have a trait that borrows some inner data element of type V +from an outer type T, through an intermediate type U. The compiler is unable to +prove that the livetime of U is long enough to support the reference, so it +throws E0311. To fix the issue we can explicitly add lifetime specifiers to the +trait, which link the lifetimes of the various data types and allow the code +to compile. + +Working implementation of the `NestedBorrowMut` trait: + +``` +use std::borrow::BorrowMut; + +trait NestedBorrowMut<'a, U, V> { + fn nested_borrow_mut(& 'a mut self) -> &'a mut V; +} + +impl<'a, T, U, V> NestedBorrowMut<'a, U, V> for T +where + T: BorrowMut, + U: BorrowMut + 'a, +{ + fn nested_borrow_mut(&'a mut self) -> &'a mut V { + self.borrow_mut().borrow_mut() + } +} +``` diff --git a/src/test/ui/error-codes/E0311.rs b/src/test/ui/error-codes/E0311.rs new file mode 100644 index 0000000000000..eb9a473e9a2d1 --- /dev/null +++ b/src/test/ui/error-codes/E0311.rs @@ -0,0 +1,18 @@ +use std::borrow::BorrowMut; + +trait NestedBorrowMut { + fn nested_borrow_mut(&mut self) -> &mut V; +} + +impl NestedBorrowMut for T +where + T: BorrowMut, + U: BorrowMut, // Error is caused by missing lifetime here +{ + fn nested_borrow_mut(&mut self) -> &mut V { + let u_ref = self.borrow_mut(); //~ ERROR E0311 + u_ref.borrow_mut() //~ ERROR E0311 + } +} + +fn main() {} diff --git a/src/test/ui/error-codes/E0311.stderr b/src/test/ui/error-codes/E0311.stderr new file mode 100644 index 0000000000000..a219a6352adc8 --- /dev/null +++ b/src/test/ui/error-codes/E0311.stderr @@ -0,0 +1,45 @@ +error[E0311]: the parameter type `U` may not live long enough + --> $DIR/E0311.rs:13:21 + | +LL | let u_ref = self.borrow_mut(); + | ^^^^^^^^^^^^^^^^^ + | +note: the parameter type `U` must be valid for the anonymous lifetime defined here... + --> $DIR/E0311.rs:12:26 + | +LL | fn nested_borrow_mut(&mut self) -> &mut V { + | ^^^^^^^^^ +note: ...so that the type `U` will meet its required lifetime bounds + --> $DIR/E0311.rs:13:21 + | +LL | let u_ref = self.borrow_mut(); + | ^^^^^^^^^^^^^^^^^ +help: consider adding an explicit lifetime bound... + | +LL | U: BorrowMut + 'a, // Error is caused by missing lifetime here + | ++++ + +error[E0311]: the parameter type `U` may not live long enough + --> $DIR/E0311.rs:14:9 + | +LL | u_ref.borrow_mut() + | ^^^^^^^^^^^^^^^^^^ + | +note: the parameter type `U` must be valid for the anonymous lifetime defined here... + --> $DIR/E0311.rs:12:26 + | +LL | fn nested_borrow_mut(&mut self) -> &mut V { + | ^^^^^^^^^ +note: ...so that the type `U` will meet its required lifetime bounds + --> $DIR/E0311.rs:14:9 + | +LL | u_ref.borrow_mut() + | ^^^^^^^^^^^^^^^^^^ +help: consider adding an explicit lifetime bound... + | +LL | U: BorrowMut + 'a, // Error is caused by missing lifetime here + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0311`. From 08fa70e5c5beb8d84c528d8effb481c4f830b28d Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Fri, 19 Aug 2022 07:06:47 -0400 Subject: [PATCH 02/25] fix updated stderr outputs --- .../lifetimes/missing-lifetimes-in-signature-2.stderr | 1 + .../suggestions/lifetimes/missing-lifetimes-in-signature.stderr | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr index 0212c2d712cb3..5dcbb86cbdf79 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr @@ -27,3 +27,4 @@ LL | fn func(foo: &Foo, t: T) { error: aborting due to previous error +For more information about this error, try `rustc --explain E0311`. diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 0d749f04bea77..bd5b3b5340ab3 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -162,5 +162,5 @@ LL | G: Get + 'a, error: aborting due to 8 previous errors -Some errors have detailed explanations: E0261, E0309, E0621, E0700. +Some errors have detailed explanations: E0261, E0309, E0311, E0621, E0700. For more information about an error, try `rustc --explain E0261`. From 63de1ec0706ddbb8e4d3aacba71ad47308d8dfa9 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Fri, 19 Aug 2022 09:34:20 -0400 Subject: [PATCH 03/25] Apply suggestions from code review Co-authored-by: Guillaume Gomez --- .../src/error_codes/E0311.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index 8b5daaaa17865..a5975c4f472be 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -1,9 +1,9 @@ -E0311 occurs when there is insufficient information for the rust compiler to +This error occurs when there is insufficient information for the rust compiler to prove that some time has a long enough lifetime. Erroneous code example: -```compile_fail, E0311 +```compile_fail,E0311 use std::borrow::BorrowMut; trait NestedBorrowMut { @@ -13,7 +13,7 @@ trait NestedBorrowMut { impl NestedBorrowMut for T where T: BorrowMut, - U: BorrowMut, // missing lifetime specifier here --> compile fail + U: BorrowMut, // error: missing lifetime specifier { fn nested_borrow_mut(&mut self) -> &mut V { self.borrow_mut().borrow_mut() @@ -21,12 +21,11 @@ where } ``` -In this example we have a trait that borrows some inner data element of type V -from an outer type T, through an intermediate type U. The compiler is unable to -prove that the livetime of U is long enough to support the reference, so it -throws E0311. To fix the issue we can explicitly add lifetime specifiers to the -trait, which link the lifetimes of the various data types and allow the code -to compile. +In this example we have a trait that borrows some inner data element of type `V` +from an outer type `T`, through an intermediate type `U`. The compiler is unable to +prove that the livetime of `U` is long enough to support the reference. To fix the +issue we can explicitly add lifetime specifiers to the `NestedBorrowMut` trait, which +link the lifetimes of the various data types and allow the code to compile. Working implementation of the `NestedBorrowMut` trait: @@ -40,7 +39,7 @@ trait NestedBorrowMut<'a, U, V> { impl<'a, T, U, V> NestedBorrowMut<'a, U, V> for T where T: BorrowMut, - U: BorrowMut + 'a, + U: BorrowMut + 'a, // Adding lifetime specifier { fn nested_borrow_mut(&'a mut self) -> &'a mut V { self.borrow_mut().borrow_mut() From a9cefd04411611e72417ee2762979e300aac8749 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Fri, 19 Aug 2022 10:53:14 -0400 Subject: [PATCH 04/25] fix line lengths --- compiler/rustc_error_codes/src/error_codes/E0311.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index a5975c4f472be..9477a0b1fb76a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -1,5 +1,5 @@ -This error occurs when there is insufficient information for the rust compiler to -prove that some time has a long enough lifetime. +This error occurs when there is insufficient information for the rust compiler +to prove that some time has a long enough lifetime. Erroneous code example: @@ -22,10 +22,11 @@ where ``` In this example we have a trait that borrows some inner data element of type `V` -from an outer type `T`, through an intermediate type `U`. The compiler is unable to -prove that the livetime of `U` is long enough to support the reference. To fix the -issue we can explicitly add lifetime specifiers to the `NestedBorrowMut` trait, which -link the lifetimes of the various data types and allow the code to compile. +from an outer type `T`, through an intermediate type `U`. The compiler is unable +to prove that the livetime of `U` is long enough to support the reference. To +fix the issue we can explicitly add lifetime specifiers to the `NestedBorrowMut` +trait, which link the lifetimes of the various data types and allow the code to +compile. Working implementation of the `NestedBorrowMut` trait: From dbcc4095560a3ddcbdfe3359641b4da00634dcde Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Tue, 23 Aug 2022 05:19:04 -0400 Subject: [PATCH 05/25] Improve E0311.md description --- .../src/error_codes/E0311.md | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index 9477a0b1fb76a..00b23c420529f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -21,14 +21,35 @@ where } ``` -In this example we have a trait that borrows some inner data element of type `V` -from an outer type `T`, through an intermediate type `U`. The compiler is unable -to prove that the livetime of `U` is long enough to support the reference. To -fix the issue we can explicitly add lifetime specifiers to the `NestedBorrowMut` -trait, which link the lifetimes of the various data types and allow the code to -compile. - -Working implementation of the `NestedBorrowMut` trait: +Why doesn't this code compile? The problem has to do with Rust's rules for +lifetime elision in functions (Chapter 10.3 in the Rust book). One of the +inputs is a reference to `self`, so the compiler attempts to assign the +the same lifetime to the `&mut self` input and `&mut V` output to the +`nested_borrow_mut()` function. The problem is that there is no way for the +compiler to directly figure out how these two lifetimes are related in the +implementation of the function. We're implementing the `NextedBorrowMut` +trait for a type `T`, so the `&mut self` reference has the lifetime of `T`. +We know that `T` implements the `BorrowMut` trait returning a reference to `U`, +and that `U` implements the `BorrowMut` trait returning a reference to `V`. +The key is that we have not told the compiler that those two `U` lifetimes +are the same: for all it knows, we could be that the first `BorrowMut` trait +on `T` works with a lifetime `'a` and the second `BorrowMut` trait on `U` +works on a lifetime `'b`. + +The fix here is to add explicit lifetime annotations that tell the compiler +that the lifetime of the output is in fact the same as the lifetime of the +input (`self`). There are three references involved, to objects of type `T` +(`self`), `U` (the intermediate type), and `V` (the return type). In the +working code below, we see that all have been given the same lifetime `'a`: +- `&'a mut self` in the function argument list for `T` +- `U: BorrowMut + 'a` in the trait bounds for `U` +- `&'a mut V` in the function return for `V`. + +The compiler can the check that the implementation of the +`nested_borrow_mut()` function satisfies these lifetimes. There are two +functions being called inside of `nested_borrow_mut()`, both of which are +the `borrow_mut()` function, which promises that the output lifetime is +the same as the input lifetime (see lifetime elision rules), which checks out. ``` use std::borrow::BorrowMut; From 231e3a041512027b13c87b07fe2a22c89b290adb Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Tue, 23 Aug 2022 05:26:47 -0400 Subject: [PATCH 06/25] actually fix typo this time --- compiler/rustc_error_codes/src/error_codes/E0311.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index 00b23c420529f..e73d5f16f9bf3 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -1,5 +1,5 @@ This error occurs when there is insufficient information for the rust compiler -to prove that some time has a long enough lifetime. +to prove that a type has a long enough lifetime. Erroneous code example: From dd7c48e52937dade956379f3faf7a1bff1b95a5f Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Wed, 24 Aug 2022 20:44:09 -0400 Subject: [PATCH 07/25] Improve description again -- update summary based on review -- rewrite explanation to be more clear and correct --- .../src/error_codes/E0311.md | 73 ++++++++++--------- src/test/ui/error-codes/E0311.rs | 3 +- src/test/ui/error-codes/E0311.stderr | 12 +-- 3 files changed, 47 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index e73d5f16f9bf3..a9d44dcdcee82 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -1,5 +1,5 @@ -This error occurs when there is insufficient information for the rust compiler -to prove that a type has a long enough lifetime. +This error occurs when there is an unsatisfied outlives bound on a generic +type parameter or associated type. Erroneous code example: @@ -13,58 +13,63 @@ trait NestedBorrowMut { impl NestedBorrowMut for T where T: BorrowMut, - U: BorrowMut, // error: missing lifetime specifier + U: BorrowMut, { fn nested_borrow_mut(&mut self) -> &mut V { - self.borrow_mut().borrow_mut() + let u_ref = self.borrow_mut(); + let v_ref = u_ref.borrow_mut(); + v_ref } } ``` -Why doesn't this code compile? The problem has to do with Rust's rules for -lifetime elision in functions (Chapter 10.3 in the Rust book). One of the -inputs is a reference to `self`, so the compiler attempts to assign the -the same lifetime to the `&mut self` input and `&mut V` output to the -`nested_borrow_mut()` function. The problem is that there is no way for the -compiler to directly figure out how these two lifetimes are related in the -implementation of the function. We're implementing the `NextedBorrowMut` -trait for a type `T`, so the `&mut self` reference has the lifetime of `T`. -We know that `T` implements the `BorrowMut` trait returning a reference to `U`, -and that `U` implements the `BorrowMut` trait returning a reference to `V`. -The key is that we have not told the compiler that those two `U` lifetimes -are the same: for all it knows, we could be that the first `BorrowMut` trait -on `T` works with a lifetime `'a` and the second `BorrowMut` trait on `U` -works on a lifetime `'b`. +Why doesn't this code compile? It helps to look at the lifetime bounds that +the compiler is automatically adding ("Lifetime Ellision", Chapter 10.3 in the +Rust book) to the `nested_borrow_mut` and `borrow_mut` functions. In both cases +the input is a reference to `self`, so the compiler attempts to assign the +the same lifetime to the input and output. -The fix here is to add explicit lifetime annotations that tell the compiler -that the lifetime of the output is in fact the same as the lifetime of the -input (`self`). There are three references involved, to objects of type `T` -(`self`), `U` (the intermediate type), and `V` (the return type). In the -working code below, we see that all have been given the same lifetime `'a`: -- `&'a mut self` in the function argument list for `T` -- `U: BorrowMut + 'a` in the trait bounds for `U` -- `&'a mut V` in the function return for `V`. +Looking specifically at `nested_borrow_mut`, +we see that there are three object references to keep track of, +along with their associated lifetimes: +- `self` (which is a `&mut T`) +- `u_ref` (which is a `&mut U`) +- `v_ref` (which is a `&mut V`) -The compiler can the check that the implementation of the -`nested_borrow_mut()` function satisfies these lifetimes. There are two -functions being called inside of `nested_borrow_mut()`, both of which are -the `borrow_mut()` function, which promises that the output lifetime is -the same as the input lifetime (see lifetime elision rules), which checks out. +The `borrow_mut()` method implicitly requires that that the input and output +have the same lifetime bounds. Thus: +```rust + let u_ref = self.borrow_mut(); + let v_ref = u_ref.borrow_mut(); ``` + +Imply that `u_ref` and `self` must share a lifetime bound, and also that +`v_ref` and `u_ref` share a lifetime bound. The problem is that the function +signature for `nested_borrow_mut` only gives the compiler information about the +lifetimes of `self` and `v_ref` -- nothing about `u_ref`. + +The way to fix this error is then to explicitly tell the compiler that the +lifetime of `u_ref` is the same as `self` and `v_ref`, which then allows it +to satisfy the two lifetime bound requirements described above. + +Here is the working version of the code: +```rust use std::borrow::BorrowMut; trait NestedBorrowMut<'a, U, V> { - fn nested_borrow_mut(& 'a mut self) -> &'a mut V; + fn nested_borrow_mut(&'a mut self) -> &'a mut V; } impl<'a, T, U, V> NestedBorrowMut<'a, U, V> for T where T: BorrowMut, - U: BorrowMut + 'a, // Adding lifetime specifier + U: BorrowMut + 'a, { fn nested_borrow_mut(&'a mut self) -> &'a mut V { - self.borrow_mut().borrow_mut() + let u_ref = self.borrow_mut(); + let v_ref = u_ref.borrow_mut(); + v_ref } } ``` diff --git a/src/test/ui/error-codes/E0311.rs b/src/test/ui/error-codes/E0311.rs index eb9a473e9a2d1..95f8602306cde 100644 --- a/src/test/ui/error-codes/E0311.rs +++ b/src/test/ui/error-codes/E0311.rs @@ -11,7 +11,8 @@ where { fn nested_borrow_mut(&mut self) -> &mut V { let u_ref = self.borrow_mut(); //~ ERROR E0311 - u_ref.borrow_mut() //~ ERROR E0311 + let v_ref = u_ref.borrow_mut(); //~ ERROR E0311 + v_ref } } diff --git a/src/test/ui/error-codes/E0311.stderr b/src/test/ui/error-codes/E0311.stderr index a219a6352adc8..2cf6404f2f1c0 100644 --- a/src/test/ui/error-codes/E0311.stderr +++ b/src/test/ui/error-codes/E0311.stderr @@ -20,10 +20,10 @@ LL | U: BorrowMut + 'a, // Error is caused by missing lifetime here | ++++ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/E0311.rs:14:9 + --> $DIR/E0311.rs:14:21 | -LL | u_ref.borrow_mut() - | ^^^^^^^^^^^^^^^^^^ +LL | let v_ref = u_ref.borrow_mut(); + | ^^^^^^^^^^^^^^^^^^ | note: the parameter type `U` must be valid for the anonymous lifetime defined here... --> $DIR/E0311.rs:12:26 @@ -31,10 +31,10 @@ note: the parameter type `U` must be valid for the anonymous lifetime defined he LL | fn nested_borrow_mut(&mut self) -> &mut V { | ^^^^^^^^^ note: ...so that the type `U` will meet its required lifetime bounds - --> $DIR/E0311.rs:14:9 + --> $DIR/E0311.rs:14:21 | -LL | u_ref.borrow_mut() - | ^^^^^^^^^^^^^^^^^^ +LL | let v_ref = u_ref.borrow_mut(); + | ^^^^^^^^^^^^^^^^^^ help: consider adding an explicit lifetime bound... | LL | U: BorrowMut + 'a, // Error is caused by missing lifetime here From fc02eee8f6b433c8485086d3e97ae499b53b240b Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Wed, 24 Aug 2022 20:50:02 -0400 Subject: [PATCH 08/25] fix wrapping --- compiler/rustc_error_codes/src/error_codes/E0311.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index a9d44dcdcee82..9521adc252225 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -29,22 +29,21 @@ Rust book) to the `nested_borrow_mut` and `borrow_mut` functions. In both cases the input is a reference to `self`, so the compiler attempts to assign the the same lifetime to the input and output. -Looking specifically at `nested_borrow_mut`, -we see that there are three object references to keep track of, -along with their associated lifetimes: +Looking specifically at `nested_borrow_mut`, we see that there are three object +references to keep track of, along with their associated lifetimes: - `self` (which is a `&mut T`) - `u_ref` (which is a `&mut U`) - `v_ref` (which is a `&mut V`) The `borrow_mut()` method implicitly requires that that the input and output -have the same lifetime bounds. Thus: +have the same lifetime bounds. Thus the lines: ```rust let u_ref = self.borrow_mut(); let v_ref = u_ref.borrow_mut(); ``` -Imply that `u_ref` and `self` must share a lifetime bound, and also that +imply that `u_ref` and `self` must share a lifetime bound, and also that `v_ref` and `u_ref` share a lifetime bound. The problem is that the function signature for `nested_borrow_mut` only gives the compiler information about the lifetimes of `self` and `v_ref` -- nothing about `u_ref`. From 4f194a76c8482ffcd16526a08b1dc489a5a75e96 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Thu, 25 Aug 2022 05:43:59 -0400 Subject: [PATCH 09/25] Fix rust-doc error There was a partial rust code block in the readme that was invalid because of a missing line. I inlined the code snippet into the text to fix the error. This also improves readability a bit. --- .../src/error_codes/E0311.md | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index 9521adc252225..f8c04d54db70a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -25,35 +25,30 @@ where Why doesn't this code compile? It helps to look at the lifetime bounds that the compiler is automatically adding ("Lifetime Ellision", Chapter 10.3 in the -Rust book) to the `nested_borrow_mut` and `borrow_mut` functions. In both cases -the input is a reference to `self`, so the compiler attempts to assign the +Rust book) to the `nested_borrow_mut()` and `borrow_mut()` functions. In both +cases the input is a reference to `self`, so the compiler attempts to assign the same lifetime to the input and output. -Looking specifically at `nested_borrow_mut`, we see that there are three object -references to keep track of, along with their associated lifetimes: +Looking specifically at `nested_borrow_mut()`, we see that there are three +object references to keep track of, along with their associated lifetimes: - `self` (which is a `&mut T`) - `u_ref` (which is a `&mut U`) - `v_ref` (which is a `&mut V`) The `borrow_mut()` method implicitly requires that that the input and output -have the same lifetime bounds. Thus the lines: - -```rust - let u_ref = self.borrow_mut(); - let v_ref = u_ref.borrow_mut(); -``` - -imply that `u_ref` and `self` must share a lifetime bound, and also that -`v_ref` and `u_ref` share a lifetime bound. The problem is that the function -signature for `nested_borrow_mut` only gives the compiler information about the -lifetimes of `self` and `v_ref` -- nothing about `u_ref`. +have the same lifetime bounds. Thus the lines: `let u_ref = self.borrow_mut();` +and `let v_ref = u_ref.borrow_mut();` in `nested_borrow_mut()` above imply that +`u_ref` and `self` must share a lifetime bound, and also that `v_ref` and +`u_ref` share a lifetime bound. The problem is that the function signature for +`nested_borrow_mut()` only gives the compiler information about the lifetimes +of `self` and `v_ref` -- nothing about `u_ref`. The way to fix this error is then to explicitly tell the compiler that the lifetime of `u_ref` is the same as `self` and `v_ref`, which then allows it to satisfy the two lifetime bound requirements described above. Here is the working version of the code: -```rust +``` use std::borrow::BorrowMut; trait NestedBorrowMut<'a, U, V> { From de3e95b56c3c1af339a6c13dc8875599e553aa98 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Fri, 26 Aug 2022 15:01:49 -0400 Subject: [PATCH 10/25] Review updates: simpler MWE and docs - use the simpler minimum working example from the review - add an alterate "fix" that helps make the cause of the error more clear - attempt to add an improved description of what is going on --- .../src/error_codes/E0311.md | 83 ++++++++----------- src/test/ui/error-codes/E0311.rs | 18 +--- src/test/ui/error-codes/E0311.stderr | 51 ++++-------- 3 files changed, 52 insertions(+), 100 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index f8c04d54db70a..b1fa61d365c73 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -1,69 +1,52 @@ -This error occurs when there is an unsatisfied outlives bound on a generic -type parameter or associated type. +This error occurs when there is an unsatisfied outlives bound involving an +elided region on a generic type parameter or associated type. Erroneous code example: ```compile_fail,E0311 -use std::borrow::BorrowMut; - -trait NestedBorrowMut { - fn nested_borrow_mut(&mut self) -> &mut V; +fn no_restriction(x: &()) -> &() { + with_restriction::(x) } -impl NestedBorrowMut for T -where - T: BorrowMut, - U: BorrowMut, -{ - fn nested_borrow_mut(&mut self) -> &mut V { - let u_ref = self.borrow_mut(); - let v_ref = u_ref.borrow_mut(); - v_ref - } +fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () { + x } ``` -Why doesn't this code compile? It helps to look at the lifetime bounds that -the compiler is automatically adding ("Lifetime Ellision", Chapter 10.3 in the -Rust book) to the `nested_borrow_mut()` and `borrow_mut()` functions. In both -cases the input is a reference to `self`, so the compiler attempts to assign -the same lifetime to the input and output. +Why doesn't this code compile? It helps to look at the lifetime bounds that are +automatically adding by the compiler. For more details see the Rust +Documentation for Lifetime Elision: +https://doc.rust-lang.org/reference/lifetime-elision.html] -Looking specifically at `nested_borrow_mut()`, we see that there are three -object references to keep track of, along with their associated lifetimes: -- `self` (which is a `&mut T`) -- `u_ref` (which is a `&mut U`) -- `v_ref` (which is a `&mut V`) +There are two lifetimes being passed into the `no_restriction()` function: one +associated with the generic type `T` parameter and the other with the input +argument `x`. The compiler does not know which of these lifetimes can be +assigned to the output reference, so we get an error. -The `borrow_mut()` method implicitly requires that that the input and output -have the same lifetime bounds. Thus the lines: `let u_ref = self.borrow_mut();` -and `let v_ref = u_ref.borrow_mut();` in `nested_borrow_mut()` above imply that -`u_ref` and `self` must share a lifetime bound, and also that `v_ref` and -`u_ref` share a lifetime bound. The problem is that the function signature for -`nested_borrow_mut()` only gives the compiler information about the lifetimes -of `self` and `v_ref` -- nothing about `u_ref`. +One way to "fix" this code would be to remove the generic type argument `T`. +In this case, the lifetime elision works because there is a single input +lifetime, which is associated with `x`. -The way to fix this error is then to explicitly tell the compiler that the -lifetime of `u_ref` is the same as `self` and `v_ref`, which then allows it -to satisfy the two lifetime bound requirements described above. +``` +fn no_restriction(x: &()) -> &() { + with_restriction(x) +} -Here is the working version of the code: +fn with_restriction<'a>(x: &'a ()) -> &'a () { + x +} ``` -use std::borrow::BorrowMut; -trait NestedBorrowMut<'a, U, V> { - fn nested_borrow_mut(&'a mut self) -> &'a mut V; +The "correct" way to resolve this error is to explicitly tell the compiler +which input lifetime should be assigned to the output. In this case we give +both the generic type `T` parameter and the argument `x` the same lifetime +requirement as the output reference, producing a working version of the code: +``` +fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () { + with_restriction::(x) } -impl<'a, T, U, V> NestedBorrowMut<'a, U, V> for T -where - T: BorrowMut, - U: BorrowMut + 'a, -{ - fn nested_borrow_mut(&'a mut self) -> &'a mut V { - let u_ref = self.borrow_mut(); - let v_ref = u_ref.borrow_mut(); - v_ref - } +fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () { + x } ``` diff --git a/src/test/ui/error-codes/E0311.rs b/src/test/ui/error-codes/E0311.rs index 95f8602306cde..566b518b4331d 100644 --- a/src/test/ui/error-codes/E0311.rs +++ b/src/test/ui/error-codes/E0311.rs @@ -1,19 +1,9 @@ -use std::borrow::BorrowMut; - -trait NestedBorrowMut { - fn nested_borrow_mut(&mut self) -> &mut V; +fn no_restriction(x: &()) -> &() { + with_restriction::(x) //~ ERROR E0311 } -impl NestedBorrowMut for T -where - T: BorrowMut, - U: BorrowMut, // Error is caused by missing lifetime here -{ - fn nested_borrow_mut(&mut self) -> &mut V { - let u_ref = self.borrow_mut(); //~ ERROR E0311 - let v_ref = u_ref.borrow_mut(); //~ ERROR E0311 - v_ref - } +fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () { + x } fn main() {} diff --git a/src/test/ui/error-codes/E0311.stderr b/src/test/ui/error-codes/E0311.stderr index 2cf6404f2f1c0..bc0182555af86 100644 --- a/src/test/ui/error-codes/E0311.stderr +++ b/src/test/ui/error-codes/E0311.stderr @@ -1,45 +1,24 @@ -error[E0311]: the parameter type `U` may not live long enough - --> $DIR/E0311.rs:13:21 +error[E0311]: the parameter type `T` may not live long enough + --> $DIR/E0311.rs:2:5 | -LL | let u_ref = self.borrow_mut(); - | ^^^^^^^^^^^^^^^^^ +LL | with_restriction::(x) + | ^^^^^^^^^^^^^^^^^^^^^ | -note: the parameter type `U` must be valid for the anonymous lifetime defined here... - --> $DIR/E0311.rs:12:26 +note: the parameter type `T` must be valid for the anonymous lifetime defined here... + --> $DIR/E0311.rs:1:25 | -LL | fn nested_borrow_mut(&mut self) -> &mut V { - | ^^^^^^^^^ -note: ...so that the type `U` will meet its required lifetime bounds - --> $DIR/E0311.rs:13:21 +LL | fn no_restriction(x: &()) -> &() { + | ^^^ +note: ...so that the type `T` will meet its required lifetime bounds + --> $DIR/E0311.rs:2:5 | -LL | let u_ref = self.borrow_mut(); - | ^^^^^^^^^^^^^^^^^ +LL | with_restriction::(x) + | ^^^^^^^^^^^^^^^^^^^^^ help: consider adding an explicit lifetime bound... | -LL | U: BorrowMut + 'a, // Error is caused by missing lifetime here - | ++++ +LL | fn no_restriction(x: &()) -> &() { + | ++++ -error[E0311]: the parameter type `U` may not live long enough - --> $DIR/E0311.rs:14:21 - | -LL | let v_ref = u_ref.borrow_mut(); - | ^^^^^^^^^^^^^^^^^^ - | -note: the parameter type `U` must be valid for the anonymous lifetime defined here... - --> $DIR/E0311.rs:12:26 - | -LL | fn nested_borrow_mut(&mut self) -> &mut V { - | ^^^^^^^^^ -note: ...so that the type `U` will meet its required lifetime bounds - --> $DIR/E0311.rs:14:21 - | -LL | let v_ref = u_ref.borrow_mut(); - | ^^^^^^^^^^^^^^^^^^ -help: consider adding an explicit lifetime bound... - | -LL | U: BorrowMut + 'a, // Error is caused by missing lifetime here - | ++++ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0311`. From deadf071edf4b397523739e41b6006ee278d5341 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Sat, 27 Aug 2022 14:36:17 -0400 Subject: [PATCH 11/25] fix trailing `]` --- compiler/rustc_error_codes/src/error_codes/E0311.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index b1fa61d365c73..bc75a1f7f5e6a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -16,7 +16,7 @@ fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () { Why doesn't this code compile? It helps to look at the lifetime bounds that are automatically adding by the compiler. For more details see the Rust Documentation for Lifetime Elision: -https://doc.rust-lang.org/reference/lifetime-elision.html] +https://doc.rust-lang.org/reference/lifetime-elision.html. There are two lifetimes being passed into the `no_restriction()` function: one associated with the generic type `T` parameter and the other with the input From 4a443dfb8227d407ff3f0542cb6e688833708ba9 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Mon, 29 Aug 2022 06:05:01 -0400 Subject: [PATCH 12/25] review updates to E0311 description --- .../src/error_codes/E0311.md | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index bc75a1f7f5e6a..638c3e0a4373f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -14,33 +14,25 @@ fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () { ``` Why doesn't this code compile? It helps to look at the lifetime bounds that are -automatically adding by the compiler. For more details see the Rust -Documentation for Lifetime Elision: -https://doc.rust-lang.org/reference/lifetime-elision.html. +automatically added by the compiler. For more details see the documentation for +[lifetime elision]( https://doc.rust-lang.org/reference/lifetime-elision.html). -There are two lifetimes being passed into the `no_restriction()` function: one -associated with the generic type `T` parameter and the other with the input -argument `x`. The compiler does not know which of these lifetimes can be -assigned to the output reference, so we get an error. +The compiler elides the lifetime of `x` and the return type to some arbitrary +lifetime `'anon` in `no_restriction()`. The only information available to the +compiler is that `'anon` is valid for the duration of the function. When +calling `with_restriction()`, the compiler requires the completely unrelated +type parameter `T` to outlive `'anon` because of the `T: 'a bound` in +`with_restriction()`. This causes an error because `T` is not required to +outlive `'anon` in `no_restriction()`. -One way to "fix" this code would be to remove the generic type argument `T`. -In this case, the lifetime elision works because there is a single input -lifetime, which is associated with `x`. +If `no_restriction()` were to use `&T` instead of `&()` as an argument, the +compiler would have added an implied bound [implied +bound](https://rust-lang.github.io/rfcs/2089-implied-bounds.html), causing this +to compile. -``` -fn no_restriction(x: &()) -> &() { - with_restriction(x) -} - -fn with_restriction<'a>(x: &'a ()) -> &'a () { - x -} -``` +This error can be resolved by explicitly naming the elided lifetime for `x` and +then explicily requiring that the generic parameter `T` outlives that lifetime: -The "correct" way to resolve this error is to explicitly tell the compiler -which input lifetime should be assigned to the output. In this case we give -both the generic type `T` parameter and the argument `x` the same lifetime -requirement as the output reference, producing a working version of the code: ``` fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () { with_restriction::(x) From 0d9c01480b9142e9c0aea24500a9461c2bee5a68 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Mon, 26 Sep 2022 20:50:33 -0400 Subject: [PATCH 13/25] remove implied link bound per review also update .stderr outputs --- compiler/rustc_error_codes/src/error_codes/E0311.md | 4 +--- src/test/ui/error-codes/E0311.stderr | 4 ++-- .../suggest-introducing-and-adding-missing-lifetime.stderr | 1 + 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index 638c3e0a4373f..768b849817db5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -26,9 +26,7 @@ type parameter `T` to outlive `'anon` because of the `T: 'a bound` in outlive `'anon` in `no_restriction()`. If `no_restriction()` were to use `&T` instead of `&()` as an argument, the -compiler would have added an implied bound [implied -bound](https://rust-lang.github.io/rfcs/2089-implied-bounds.html), causing this -to compile. +compiler would have added an implied bound, causing this to compile. This error can be resolved by explicitly naming the elided lifetime for `x` and then explicily requiring that the generic parameter `T` outlives that lifetime: diff --git a/src/test/ui/error-codes/E0311.stderr b/src/test/ui/error-codes/E0311.stderr index bc0182555af86..9873b5ae6ff13 100644 --- a/src/test/ui/error-codes/E0311.stderr +++ b/src/test/ui/error-codes/E0311.stderr @@ -16,8 +16,8 @@ LL | with_restriction::(x) | ^^^^^^^^^^^^^^^^^^^^^ help: consider adding an explicit lifetime bound... | -LL | fn no_restriction(x: &()) -> &() { - | ++++ +LL | fn no_restriction<'a, T: 'a>(x: &()) -> &() { + | +++ ++++ error: aborting due to previous error diff --git a/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr b/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr index a8b0996d8b0c7..31fd8a4d633e9 100644 --- a/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr +++ b/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr @@ -21,3 +21,4 @@ LL | fn no_restriction<'a, T: 'a>(x: &()) -> &() { error: aborting due to previous error +For more information about this error, try `rustc --explain E0311`. From c91c64708b1acf3c262a2a6d6551f4bc0acfa656 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 Sep 2022 15:25:34 +1000 Subject: [PATCH 14/25] Fix an incorrect comment. If a `\x` escape occurs in a non-byte literals (e.g. char literal, string literal), it must be <= 0xff. --- compiler/rustc_lexer/src/unescape.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index 3da6bc14622a0..25d5f2772de40 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -184,7 +184,7 @@ fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result { let value = hi * 16 + lo; - // For a byte literal verify that it is within ASCII range. + // For a non-byte literal verify that it is within ASCII range. if !mode.is_bytes() && !is_ascii(value) { return Err(EscapeError::OutOfRangeHexEscape); } From b69c335327de660e495e09bce324bf364c937f6f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 Sep 2022 13:24:49 +1000 Subject: [PATCH 15/25] Tweak `FulfillProcessor`. Avoids some unnecessary references and lifetimes. --- .../src/traits/fulfill.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 6f3a9412dde7a..f13736a76b214 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -102,7 +102,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { } /// Attempts to select obligations using `selcx`. - fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec> { + fn select(&mut self, selcx: SelectionContext<'a, 'tcx>) -> Vec> { let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); let _enter = span.enter(); @@ -197,8 +197,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { &mut self, infcx: &InferCtxt<'_, 'tcx>, ) -> Vec> { - let mut selcx = SelectionContext::new(infcx); - self.select(&mut selcx) + let selcx = SelectionContext::new(infcx); + self.select(selcx) } fn pending_obligations(&self) -> Vec> { @@ -210,8 +210,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { } } -struct FulfillProcessor<'a, 'b, 'tcx> { - selcx: &'a mut SelectionContext<'b, 'tcx>, +struct FulfillProcessor<'a, 'tcx> { + selcx: SelectionContext<'a, 'tcx>, } fn mk_pending(os: Vec>) -> Vec> { @@ -220,7 +220,7 @@ fn mk_pending(os: Vec>) -> Vec ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { +impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { type Obligation = PendingPredicateObligation<'tcx>; type Error = FulfillmentErrorCode<'tcx>; type OUT = Outcome; @@ -291,7 +291,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { if obligation.predicate.has_projections() { let mut obligations = Vec::new(); let predicate = crate::traits::project::try_normalize_with_depth_to( - self.selcx, + &mut self.selcx, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, @@ -608,7 +608,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } -impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { +impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { #[instrument(level = "debug", skip(self, obligation, stalled_on))] fn process_trait_obligation( &mut self, @@ -643,7 +643,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { // information about the types in the trait. stalled_on.clear(); stalled_on.extend(substs_infer_vars( - self.selcx, + &self.selcx, trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs), )); @@ -695,12 +695,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } } - match project::poly_project_and_unify_type(self.selcx, &project_obligation) { + match project::poly_project_and_unify_type(&mut self.selcx, &project_obligation) { ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)), ProjectAndUnifyResult::FailedNormalization => { stalled_on.clear(); stalled_on.extend(substs_infer_vars( - self.selcx, + &self.selcx, project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs), )); ProcessResult::Unchanged @@ -718,7 +718,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { /// Returns the set of inference variables contained in `substs`. fn substs_infer_vars<'a, 'tcx>( - selcx: &mut SelectionContext<'a, 'tcx>, + selcx: &SelectionContext<'a, 'tcx>, substs: ty::Binder<'tcx, SubstsRef<'tcx>>, ) -> impl Iterator> { selcx From 9ad2f00f6a9ba359f35b270162a7ca6c412876eb Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 24 Sep 2022 12:34:56 +0200 Subject: [PATCH 16/25] Stabilize bench_black_box --- compiler/rustc_codegen_cranelift/example/std_example.rs | 2 +- compiler/rustc_codegen_gcc/tests/run/int.rs | 2 +- compiler/rustc_index/src/lib.rs | 1 - library/alloc/tests/lib.rs | 1 - library/core/src/hint.rs | 2 +- library/core/tests/lib.rs | 1 - library/std/src/lib.rs | 1 - library/test/src/lib.rs | 1 - src/test/incremental/spans_significant_w_panic.rs | 1 - src/test/ui/box/issue-95036.rs | 2 +- src/test/ui/consts/cast-discriminant-zst-enum.rs | 1 - src/test/ui/consts/const_discriminant.rs | 1 - src/test/ui/issues/issue-99838.rs | 2 +- src/test/ui/oom_unwind.rs | 2 -- src/test/ui/process/process-panic-after-fork.rs | 1 - src/test/ui/sanitize/address.rs | 4 +--- src/test/ui/sanitize/hwaddress.rs | 2 -- src/test/ui/sanitize/leak.rs | 2 -- src/test/ui/sanitize/memory-eager.rs | 1 - src/test/ui/sanitize/memory.rs | 1 - src/tools/miri/tests/fail/invalid_bool.rs | 2 +- src/tools/miri/tests/pass/float.rs | 2 +- src/tools/miri/tests/pass/u128.rs | 1 - 23 files changed, 8 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 0b5b6cd55d720..ad108c34992e3 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -1,4 +1,4 @@ -#![feature(core_intrinsics, generators, generator_trait, is_sorted, bench_black_box)] +#![feature(core_intrinsics, generators, generator_trait, is_sorted)] #[cfg(target_arch = "x86_64")] use std::arch::x86_64::*; diff --git a/compiler/rustc_codegen_gcc/tests/run/int.rs b/compiler/rustc_codegen_gcc/tests/run/int.rs index 2b90e4ae8d82b..75779622b54cd 100644 --- a/compiler/rustc_codegen_gcc/tests/run/int.rs +++ b/compiler/rustc_codegen_gcc/tests/run/int.rs @@ -3,7 +3,7 @@ // Run-time: // status: 0 -#![feature(bench_black_box, const_black_box, core_intrinsics, start)] +#![feature(const_black_box, core_intrinsics, start)] #![no_std] diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index a00d7bd680147..51d30f2868990 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -1,7 +1,6 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #![feature(allow_internal_unstable)] -#![feature(bench_black_box)] #![feature(extend_one)] #![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 490c0d8f76cda..f83d58bd1b5e0 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -41,7 +41,6 @@ #![feature(pointer_is_aligned)] #![feature(slice_flatten)] #![feature(thin_box)] -#![feature(bench_black_box)] #![feature(strict_provenance)] #![feature(once_cell)] #![feature(drain_keep_rest)] diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 764e2796202c9..f9267371aa745 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -217,7 +217,7 @@ pub fn spin_loop() { /// /// [`std::convert::identity`]: crate::convert::identity #[inline] -#[unstable(feature = "bench_black_box", issue = "64102")] +#[stable(feature = "bench_black_box", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_black_box", issue = "none")] pub const fn black_box(dummy: T) -> T { crate::intrinsics::black_box(dummy) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 46f603eaebaca..6d58ed9743d6a 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -2,7 +2,6 @@ #![feature(array_chunks)] #![feature(array_methods)] #![feature(array_windows)] -#![feature(bench_black_box)] #![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(const_assume)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 3131dd4726984..8e924608d436e 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -351,7 +351,6 @@ #![feature(trace_macros)] // // Only used in tests/benchmarks: -#![feature(bench_black_box)] // // Only for const-ness: #![feature(const_io_structs)] diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 3b7193adcc758..33c6ea5853227 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -15,7 +15,6 @@ #![unstable(feature = "test", issue = "50297")] #![doc(test(attr(deny(warnings))))] -#![feature(bench_black_box)] #![feature(internal_output_capture)] #![feature(staged_api)] #![feature(process_exitcode_internals)] diff --git a/src/test/incremental/spans_significant_w_panic.rs b/src/test/incremental/spans_significant_w_panic.rs index e9e35791aa158..6f51c9729e370 100644 --- a/src/test/incremental/spans_significant_w_panic.rs +++ b/src/test/incremental/spans_significant_w_panic.rs @@ -8,7 +8,6 @@ // compile-flags: -C overflow-checks=on -Z query-dep-graph #![feature(rustc_attrs)] -#![feature(bench_black_box)] #![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass2")] #![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass4")] diff --git a/src/test/ui/box/issue-95036.rs b/src/test/ui/box/issue-95036.rs index c2d4275aa49d3..0611fabc15c08 100644 --- a/src/test/ui/box/issue-95036.rs +++ b/src/test/ui/box/issue-95036.rs @@ -1,7 +1,7 @@ // compile-flags: -O // build-pass -#![feature(allocator_api, bench_black_box)] +#![feature(allocator_api)] #[inline(never)] pub fn by_ref(node: &mut Box<[u8; 1], &std::alloc::Global>) { diff --git a/src/test/ui/consts/cast-discriminant-zst-enum.rs b/src/test/ui/consts/cast-discriminant-zst-enum.rs index e59ae297da1a7..2767f178fb664 100644 --- a/src/test/ui/consts/cast-discriminant-zst-enum.rs +++ b/src/test/ui/consts/cast-discriminant-zst-enum.rs @@ -1,6 +1,5 @@ // run-pass // Test a ZST enum whose dicriminant is ~0i128. This caused an ICE when casting to an i32. -#![feature(bench_black_box)] use std::hint::black_box; #[derive(Copy, Clone)] diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs index f623c5101f4cd..79e68590e85d4 100644 --- a/src/test/ui/consts/const_discriminant.rs +++ b/src/test/ui/consts/const_discriminant.rs @@ -1,6 +1,5 @@ // run-pass #![feature(const_discriminant)] -#![feature(bench_black_box)] #![allow(dead_code)] use std::mem::{discriminant, Discriminant}; diff --git a/src/test/ui/issues/issue-99838.rs b/src/test/ui/issues/issue-99838.rs index eaeeac72b25e1..2e81d5e8221c4 100644 --- a/src/test/ui/issues/issue-99838.rs +++ b/src/test/ui/issues/issue-99838.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(bench_black_box)] + use std::hint; struct U16(u16); diff --git a/src/test/ui/oom_unwind.rs b/src/test/ui/oom_unwind.rs index d036c817a0e83..21a8fb2b22bee 100644 --- a/src/test/ui/oom_unwind.rs +++ b/src/test/ui/oom_unwind.rs @@ -4,8 +4,6 @@ // needs-unwind // only-linux -#![feature(bench_black_box)] - use std::hint::black_box; use std::mem::forget; use std::panic::catch_unwind; diff --git a/src/test/ui/process/process-panic-after-fork.rs b/src/test/ui/process/process-panic-after-fork.rs index 1ccf6bb051c20..08b30b600e737 100644 --- a/src/test/ui/process/process-panic-after-fork.rs +++ b/src/test/ui/process/process-panic-after-fork.rs @@ -7,7 +7,6 @@ // ignore-sgx no processes // ignore-android: FIXME(#85261) -#![feature(bench_black_box)] #![feature(rustc_private)] #![feature(never_type)] #![feature(panic_always_abort)] diff --git a/src/test/ui/sanitize/address.rs b/src/test/ui/sanitize/address.rs index 9a26a351d992c..5b2cea87560fd 100644 --- a/src/test/ui/sanitize/address.rs +++ b/src/test/ui/sanitize/address.rs @@ -5,9 +5,7 @@ // // run-fail // error-pattern: AddressSanitizer: stack-buffer-overflow -// error-pattern: 'xs' (line 15) <== Memory access at offset - -#![feature(bench_black_box)] +// error-pattern: 'xs' (line 13) <== Memory access at offset use std::hint::black_box; diff --git a/src/test/ui/sanitize/hwaddress.rs b/src/test/ui/sanitize/hwaddress.rs index b988035f75e4c..f9b37a155aad7 100644 --- a/src/test/ui/sanitize/hwaddress.rs +++ b/src/test/ui/sanitize/hwaddress.rs @@ -10,8 +10,6 @@ // run-fail // error-pattern: HWAddressSanitizer: tag-mismatch -#![feature(bench_black_box)] - use std::hint::black_box; fn main() { diff --git a/src/test/ui/sanitize/leak.rs b/src/test/ui/sanitize/leak.rs index f63f81352dada..cbb44ae8acd60 100644 --- a/src/test/ui/sanitize/leak.rs +++ b/src/test/ui/sanitize/leak.rs @@ -6,8 +6,6 @@ // run-fail // error-pattern: LeakSanitizer: detected memory leaks -#![feature(bench_black_box)] - use std::hint::black_box; use std::mem; diff --git a/src/test/ui/sanitize/memory-eager.rs b/src/test/ui/sanitize/memory-eager.rs index cc0593ec07dcd..0018c2f758182 100644 --- a/src/test/ui/sanitize/memory-eager.rs +++ b/src/test/ui/sanitize/memory-eager.rs @@ -17,7 +17,6 @@ #![feature(core_intrinsics)] #![feature(start)] -#![feature(bench_black_box)] use std::hint::black_box; use std::mem::MaybeUninit; diff --git a/src/test/ui/sanitize/memory.rs b/src/test/ui/sanitize/memory.rs index 14d4de65dd378..1a9ac3a4f3c32 100644 --- a/src/test/ui/sanitize/memory.rs +++ b/src/test/ui/sanitize/memory.rs @@ -16,7 +16,6 @@ #![feature(core_intrinsics)] #![feature(start)] -#![feature(bench_black_box)] #![allow(invalid_value)] use std::hint::black_box; diff --git a/src/tools/miri/tests/fail/invalid_bool.rs b/src/tools/miri/tests/fail/invalid_bool.rs index 525f8831c1c00..dde414f417740 100644 --- a/src/tools/miri/tests/fail/invalid_bool.rs +++ b/src/tools/miri/tests/fail/invalid_bool.rs @@ -1,7 +1,7 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -#![feature(bench_black_box)] + fn main() { let b = unsafe { std::mem::transmute::(2) }; diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 48dd99441ebff..ce62fb0de04f8 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1,4 +1,4 @@ -#![feature(stmt_expr_attributes, bench_black_box)] +#![feature(stmt_expr_attributes)] #![allow(arithmetic_overflow)] use std::fmt::Debug; use std::hint::black_box; diff --git a/src/tools/miri/tests/pass/u128.rs b/src/tools/miri/tests/pass/u128.rs index 0ef7a514cb653..6def529dbe7c3 100644 --- a/src/tools/miri/tests/pass/u128.rs +++ b/src/tools/miri/tests/pass/u128.rs @@ -1,4 +1,3 @@ -#![feature(bench_black_box)] use std::hint::black_box as b; fn main() { From ca2e0bb51ad1a00190430134c67da5cda356745e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 27 Sep 2022 00:45:50 +0000 Subject: [PATCH 17/25] Deny associated type bindings within associated type bindings --- compiler/rustc_hir_analysis/src/astconv/mod.rs | 12 +++++++++--- src/test/ui/associated-consts/issue-102335-const.rs | 12 ++++++++++++ .../ui/associated-consts/issue-102335-const.stderr | 9 +++++++++ .../ui/associated-type-bounds/issue-102335-ty.rs | 12 ++++++++++++ .../ui/associated-type-bounds/issue-102335-ty.stderr | 9 +++++++++ .../ui/generic-associated-types/issue-102335-gat.rs | 12 ++++++++++++ .../generic-associated-types/issue-102335-gat.stderr | 9 +++++++++ src/test/ui/suggestions/issue-85347.rs | 1 + src/test/ui/suggestions/issue-85347.stderr | 11 +++++++++-- 9 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/associated-consts/issue-102335-const.rs create mode 100644 src/test/ui/associated-consts/issue-102335-const.stderr create mode 100644 src/test/ui/associated-type-bounds/issue-102335-ty.rs create mode 100644 src/test/ui/associated-type-bounds/issue-102335-ty.stderr create mode 100644 src/test/ui/generic-associated-types/issue-102335-gat.rs create mode 100644 src/test/ui/generic-associated-types/issue-102335-gat.stderr diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index b3cbb606c728d..244018ebbeb74 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -595,7 +595,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { "create_substs_for_associated_item(span: {:?}, item_def_id: {:?}, item_segment: {:?}", span, item_def_id, item_segment ); - self.create_substs_for_ast_path( + let (args, _) = self.create_substs_for_ast_path( span, item_def_id, parent_substs, @@ -603,8 +603,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { item_segment.args(), item_segment.infer_args, None, - ) - .0 + ); + + let assoc_bindings = self.create_assoc_bindings_for_generic_args(item_segment.args()); + if let Some(b) = assoc_bindings.first() { + Self::prohibit_assoc_ty_binding(self.tcx(), b.span); + } + + args } /// Instantiates the path for the given trait reference, assuming that it's diff --git a/src/test/ui/associated-consts/issue-102335-const.rs b/src/test/ui/associated-consts/issue-102335-const.rs new file mode 100644 index 0000000000000..f60cb92da7f6b --- /dev/null +++ b/src/test/ui/associated-consts/issue-102335-const.rs @@ -0,0 +1,12 @@ +#![feature(associated_const_equality)] + +trait T { + type A: S = 34>; + //~^ ERROR associated type bindings are not allowed here +} + +trait S { + const C: i32; +} + +fn main() {} diff --git a/src/test/ui/associated-consts/issue-102335-const.stderr b/src/test/ui/associated-consts/issue-102335-const.stderr new file mode 100644 index 0000000000000..531d15c5900c5 --- /dev/null +++ b/src/test/ui/associated-consts/issue-102335-const.stderr @@ -0,0 +1,9 @@ +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-102335-const.rs:4:17 + | +LL | type A: S = 34>; + | ^^^^^^^^ associated type not allowed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0229`. diff --git a/src/test/ui/associated-type-bounds/issue-102335-ty.rs b/src/test/ui/associated-type-bounds/issue-102335-ty.rs new file mode 100644 index 0000000000000..363df73c1ffd7 --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-102335-ty.rs @@ -0,0 +1,12 @@ +trait T { + type A: S = ()>; + //~^ ERROR associated type bindings are not allowed here +} + +trait Q {} + +trait S { + type C: Q; +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/issue-102335-ty.stderr b/src/test/ui/associated-type-bounds/issue-102335-ty.stderr new file mode 100644 index 0000000000000..8777b2965153a --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-102335-ty.stderr @@ -0,0 +1,9 @@ +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-102335-ty.rs:2:17 + | +LL | type A: S = ()>; + | ^^^^^^^^^ associated type not allowed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0229`. diff --git a/src/test/ui/generic-associated-types/issue-102335-gat.rs b/src/test/ui/generic-associated-types/issue-102335-gat.rs new file mode 100644 index 0000000000000..a7255fdcbf5e1 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-102335-gat.rs @@ -0,0 +1,12 @@ +trait T { + type A: S = ()>; + //~^ ERROR associated type bindings are not allowed here +} + +trait Q {} + +trait S { + type C: Q; +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-102335-gat.stderr b/src/test/ui/generic-associated-types/issue-102335-gat.stderr new file mode 100644 index 0000000000000..7a7900a1e656a --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-102335-gat.stderr @@ -0,0 +1,9 @@ +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-102335-gat.rs:2:21 + | +LL | type A: S = ()>; + | ^^^^^^^^ associated type not allowed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0229`. diff --git a/src/test/ui/suggestions/issue-85347.rs b/src/test/ui/suggestions/issue-85347.rs index dd52b3150551a..02b5fb61894e9 100644 --- a/src/test/ui/suggestions/issue-85347.rs +++ b/src/test/ui/suggestions/issue-85347.rs @@ -2,6 +2,7 @@ use std::ops::Deref; trait Foo { type Bar<'a>: Deref::Bar>; //~^ ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied + //~| ERROR associated type bindings are not allowed here //~| HELP add missing } diff --git a/src/test/ui/suggestions/issue-85347.stderr b/src/test/ui/suggestions/issue-85347.stderr index de853de27e40e..17c1b7dc4cce9 100644 --- a/src/test/ui/suggestions/issue-85347.stderr +++ b/src/test/ui/suggestions/issue-85347.stderr @@ -14,6 +14,13 @@ help: add missing lifetime argument LL | type Bar<'a>: Deref::Bar<'a, Target = Self>>; | +++ -error: aborting due to previous error +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-85347.rs:3:46 + | +LL | type Bar<'a>: Deref::Bar>; + | ^^^^^^^^^^^^^ associated type not allowed here + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0107, E0229. +For more information about an error, try `rustc --explain E0107`. From c4c94151321b8018ceb06ccff359109b8fed6bfe Mon Sep 17 00:00:00 2001 From: mejrs <> Date: Mon, 26 Sep 2022 00:55:35 +0200 Subject: [PATCH 18/25] Wrapper suggestions --- .../src/check/method/suggest.rs | 213 ++++++++++++------ compiler/rustc_span/src/symbol.rs | 2 + library/core/src/cell.rs | 1 + library/std/src/thread/local.rs | 1 + src/test/ui/suggestions/inner_type.fixed | 30 +++ src/test/ui/suggestions/inner_type.rs | 30 +++ src/test/ui/suggestions/inner_type.stderr | 51 +++++ src/test/ui/suggestions/inner_type2.rs | 26 +++ src/test/ui/suggestions/inner_type2.stderr | 29 +++ 9 files changed, 316 insertions(+), 67 deletions(-) create mode 100644 src/test/ui/suggestions/inner_type.fixed create mode 100644 src/test/ui/suggestions/inner_type.rs create mode 100644 src/test/ui/suggestions/inner_type.stderr create mode 100644 src/test/ui/suggestions/inner_type2.rs create mode 100644 src/test/ui/suggestions/inner_type2.stderr diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_analysis/src/check/method/suggest.rs index 0e77ed0a4fe28..1ff2575bcc5dd 100644 --- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs +++ b/compiler/rustc_hir_analysis/src/check/method/suggest.rs @@ -2,6 +2,7 @@ //! found or is otherwise invalid. use crate::check::FnCtxt; +use rustc_ast::ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, @@ -30,7 +31,7 @@ use rustc_trait_selection::traits::{ use std::cmp::Ordering; use std::iter; -use super::probe::{IsSuggestion, Mode, ProbeScope}; +use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope}; use super::{CandidateSource, MethodError, NoMatchData}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -983,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_for_field_method(&mut err, source, span, actual, item_name); } - self.check_for_unwrap_self(&mut err, source, span, actual, item_name); + self.check_for_inner_self(&mut err, source, span, actual, item_name); bound_spans.sort(); bound_spans.dedup(); @@ -1395,7 +1396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_for_unwrap_self( + fn check_for_inner_self( &self, err: &mut Diagnostic, source: SelfSource<'tcx>, @@ -1408,81 +1409,159 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id)); let ty::Adt(kind, substs) = actual.kind() else { return; }; - if !kind.is_enum() { - return; - } + match kind.adt_kind() { + ty::AdtKind::Enum => { + let matching_variants: Vec<_> = kind + .variants() + .iter() + .flat_map(|variant| { + let [field] = &variant.fields[..] else { return None; }; + let field_ty = field.ty(tcx, substs); + + // Skip `_`, since that'll just lead to ambiguity. + if self.resolve_vars_if_possible(field_ty).is_ty_var() { + return None; + } - let matching_variants: Vec<_> = kind - .variants() - .iter() - .flat_map(|variant| { - let [field] = &variant.fields[..] else { return None; }; - let field_ty = field.ty(tcx, substs); + self.lookup_probe( + span, + item_name, + field_ty, + call_expr, + ProbeScope::AllTraits, + ) + .ok() + .map(|pick| (variant, field, pick)) + }) + .collect(); + + let ret_ty_matches = |diagnostic_item| { + if let Some(ret_ty) = self + .ret_coercion + .as_ref() + .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty())) + && let ty::Adt(kind, _) = ret_ty.kind() + && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did()) + { + true + } else { + false + } + }; - // Skip `_`, since that'll just lead to ambiguity. - if self.resolve_vars_if_possible(field_ty).is_ty_var() { - return None; + match &matching_variants[..] { + [(_, field, pick)] => { + let self_ty = field.ty(tcx, substs); + err.span_note( + tcx.def_span(pick.item.def_id), + &format!("the method `{item_name}` exists on the type `{self_ty}`"), + ); + let (article, kind, variant, question) = + if tcx.is_diagnostic_item(sym::Result, kind.did()) { + ("a", "Result", "Err", ret_ty_matches(sym::Result)) + } else if tcx.is_diagnostic_item(sym::Option, kind.did()) { + ("an", "Option", "None", ret_ty_matches(sym::Option)) + } else { + return; + }; + if question { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "use the `?` operator to extract the `{self_ty}` value, propagating \ + {article} `{kind}::{variant}` value to the caller" + ), + "?", + Applicability::MachineApplicable, + ); + } else { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \ + panicking if the value is {article} `{kind}::{variant}`" + ), + ".expect(\"REASON\")", + Applicability::HasPlaceholders, + ); + } + } + // FIXME(compiler-errors): Support suggestions for other matching enum variants + _ => {} } - - self.lookup_probe(span, item_name, field_ty, call_expr, ProbeScope::AllTraits) - .ok() - .map(|pick| (variant, field, pick)) - }) - .collect(); - - let ret_ty_matches = |diagnostic_item| { - if let Some(ret_ty) = self - .ret_coercion - .as_ref() - .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty())) - && let ty::Adt(kind, _) = ret_ty.kind() - && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did()) - { - true - } else { - false } - }; - - match &matching_variants[..] { - [(_, field, pick)] => { - let self_ty = field.ty(tcx, substs); - err.span_note( - tcx.def_span(pick.item.def_id), - &format!("the method `{item_name}` exists on the type `{self_ty}`"), - ); - let (article, kind, variant, question) = - if Some(kind.did()) == tcx.get_diagnostic_item(sym::Result) { - ("a", "Result", "Err", ret_ty_matches(sym::Result)) - } else if Some(kind.did()) == tcx.get_diagnostic_item(sym::Option) { - ("an", "Option", "None", ret_ty_matches(sym::Option)) - } else { - return; - }; - if question { + // Target wrapper types - types that wrap or pretend to wrap another type, + // perhaps this inner type is meant to be called? + ty::AdtKind::Struct | ty::AdtKind::Union => { + let [first] = ***substs else { return; }; + let ty::GenericArgKind::Type(ty) = first.unpack() else { return; }; + let Ok(pick) = self.lookup_probe( + span, + item_name, + ty, + call_expr, + ProbeScope::AllTraits, + ) else { return; }; + + let name = self.ty_to_value_string(actual); + let inner_id = kind.did(); + + if tcx.is_diagnostic_item(sym::LocalKey, inner_id) { + err.help("use `with` or `try_with` to access the contents of threadlocals"); + } else if Some(kind.did()) == tcx.lang_items().maybe_uninit() { + err.help(format!( + "if this `{name}` has been initialized, \ + use one of the `assume_init` methods to access the inner value" + )); + } else if tcx.is_diagnostic_item(sym::RefCell, inner_id) { + match pick.autoref_or_ptr_adjustment { + Some(AutorefOrPtrAdjustment::Autoref { + mutbl: Mutability::Not, .. + }) => { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "use `.borrow()` to borrow the {ty}, \ + panicking if any outstanding mutable borrows exist." + ), + ".borrow()", + Applicability::MaybeIncorrect, + ); + } + Some(AutorefOrPtrAdjustment::Autoref { + mutbl: Mutability::Mut, .. + }) => { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "use `.borrow_mut()` to mutably borrow the {ty}, \ + panicking if any outstanding borrows exist." + ), + ".borrow_mut()", + Applicability::MaybeIncorrect, + ); + } + _ => return, + } + } else if tcx.is_diagnostic_item(sym::Mutex, inner_id) { err.span_suggestion_verbose( expr.span.shrink_to_hi(), format!( - "use the `?` operator to extract the `{self_ty}` value, propagating \ - {article} `{kind}::{variant}` value to the caller" + "use `.lock()` to borrow the {ty}, \ + blocking the current thread until it can be acquired" ), - "?", - Applicability::MachineApplicable, + ".lock().unwrap()", + Applicability::MaybeIncorrect, ); } else { - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - format!( - "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \ - panicking if the value is {article} `{kind}::{variant}`" - ), - ".expect(\"REASON\")", - Applicability::HasPlaceholders, - ); - } + return; + }; + + err.span_note( + tcx.def_span(pick.item.def_id), + &format!("the method `{item_name}` exists on the type `{ty}`"), + ); } - // FIXME(compiler-errors): Support suggestions for other matching enum variants - _ => {} } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 502ef67fc6767..6101c1c47e380 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -224,6 +224,7 @@ symbols! { Left, LinkedList, LintPass, + LocalKey, Mutex, MutexGuard, N, @@ -266,6 +267,7 @@ symbols! { Rc, Ready, Receiver, + RefCell, Relaxed, Release, Result, diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 1abbb39497a0f..cf7b1b358c940 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -614,6 +614,7 @@ impl Cell<[T; N]> { /// A mutable memory location with dynamically checked borrow rules /// /// See the [module-level documentation](self) for more. +#[rustc_diagnostic_item = "RefCell"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RefCell { borrow: Cell, diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 8aedfc4a6b819..1d728349951bf 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -95,6 +95,7 @@ use crate::fmt; /// [loader lock]: https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices /// [`JoinHandle::join`]: crate::thread::JoinHandle::join /// [`with`]: LocalKey::with +#[rustc_diagnostic_item = "LocalKey"] #[stable(feature = "rust1", since = "1.0.0")] pub struct LocalKey { // This outer `LocalKey` type is what's going to be stored in statics, diff --git a/src/test/ui/suggestions/inner_type.fixed b/src/test/ui/suggestions/inner_type.fixed new file mode 100644 index 0000000000000..f6dc7c4ce1722 --- /dev/null +++ b/src/test/ui/suggestions/inner_type.fixed @@ -0,0 +1,30 @@ +// compile-flags: --edition=2021 +// run-rustfix + +pub struct Struct { + pub p: T, +} + +impl Struct { + pub fn method(&self) {} + + pub fn some_mutable_method(&mut self) {} +} + +fn main() { + let other_item = std::cell::RefCell::new(Struct { p: 42_u32 }); + + other_item.borrow().method(); + //~^ ERROR no method named `method` found for struct `RefCell` in the current scope [E0599] + //~| HELP use `.borrow()` to borrow the Struct, panicking if any outstanding mutable borrows exist. + + other_item.borrow_mut().some_mutable_method(); + //~^ ERROR no method named `some_mutable_method` found for struct `RefCell` in the current scope [E0599] + //~| HELP use `.borrow_mut()` to mutably borrow the Struct, panicking if any outstanding borrows exist. + + let another_item = std::sync::Mutex::new(Struct { p: 42_u32 }); + + another_item.lock().unwrap().method(); + //~^ ERROR no method named `method` found for struct `Mutex` in the current scope [E0599] + //~| HELP use `.lock()` to borrow the Struct, blocking the current thread until it can be acquired +} \ No newline at end of file diff --git a/src/test/ui/suggestions/inner_type.rs b/src/test/ui/suggestions/inner_type.rs new file mode 100644 index 0000000000000..b42067c047c04 --- /dev/null +++ b/src/test/ui/suggestions/inner_type.rs @@ -0,0 +1,30 @@ +// compile-flags: --edition=2021 +// run-rustfix + +pub struct Struct { + pub p: T, +} + +impl Struct { + pub fn method(&self) {} + + pub fn some_mutable_method(&mut self) {} +} + +fn main() { + let other_item = std::cell::RefCell::new(Struct { p: 42_u32 }); + + other_item.method(); + //~^ ERROR no method named `method` found for struct `RefCell` in the current scope [E0599] + //~| HELP use `.borrow()` to borrow the Struct, panicking if any outstanding mutable borrows exist. + + other_item.some_mutable_method(); + //~^ ERROR no method named `some_mutable_method` found for struct `RefCell` in the current scope [E0599] + //~| HELP use `.borrow_mut()` to mutably borrow the Struct, panicking if any outstanding borrows exist. + + let another_item = std::sync::Mutex::new(Struct { p: 42_u32 }); + + another_item.method(); + //~^ ERROR no method named `method` found for struct `Mutex` in the current scope [E0599] + //~| HELP use `.lock()` to borrow the Struct, blocking the current thread until it can be acquired +} \ No newline at end of file diff --git a/src/test/ui/suggestions/inner_type.stderr b/src/test/ui/suggestions/inner_type.stderr new file mode 100644 index 0000000000000..f2b25944c8b2d --- /dev/null +++ b/src/test/ui/suggestions/inner_type.stderr @@ -0,0 +1,51 @@ +error[E0599]: no method named `method` found for struct `RefCell` in the current scope + --> $DIR/inner_type.rs:17:16 + | +LL | other_item.method(); + | ^^^^^^ method not found in `RefCell>` + | +note: the method `method` exists on the type `Struct` + --> $DIR/inner_type.rs:9:5 + | +LL | pub fn method(&self) {} + | ^^^^^^^^^^^^^^^^^^^^ +help: use `.borrow()` to borrow the Struct, panicking if any outstanding mutable borrows exist. + | +LL | other_item.borrow().method(); + | +++++++++ + +error[E0599]: no method named `some_mutable_method` found for struct `RefCell` in the current scope + --> $DIR/inner_type.rs:21:16 + | +LL | other_item.some_mutable_method(); + | ^^^^^^^^^^^^^^^^^^^ method not found in `RefCell>` + | +note: the method `some_mutable_method` exists on the type `Struct` + --> $DIR/inner_type.rs:11:5 + | +LL | pub fn some_mutable_method(&mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use `.borrow_mut()` to mutably borrow the Struct, panicking if any outstanding borrows exist. + | +LL | other_item.borrow_mut().some_mutable_method(); + | +++++++++++++ + +error[E0599]: no method named `method` found for struct `Mutex` in the current scope + --> $DIR/inner_type.rs:27:18 + | +LL | another_item.method(); + | ^^^^^^ method not found in `Mutex>` + | +note: the method `method` exists on the type `Struct` + --> $DIR/inner_type.rs:9:5 + | +LL | pub fn method(&self) {} + | ^^^^^^^^^^^^^^^^^^^^ +help: use `.lock()` to borrow the Struct, blocking the current thread until it can be acquired + | +LL | another_item.lock().unwrap().method(); + | ++++++++++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/suggestions/inner_type2.rs b/src/test/ui/suggestions/inner_type2.rs new file mode 100644 index 0000000000000..694c0adfd06c2 --- /dev/null +++ b/src/test/ui/suggestions/inner_type2.rs @@ -0,0 +1,26 @@ +pub struct Struct { + pub p: T, +} + +impl Struct { + pub fn method(&self) {} + + pub fn some_mutable_method(&mut self) {} +} + +thread_local! { + static STRUCT: Struct = Struct { + p: 42_u32 + }; +} + +fn main() { + STRUCT.method(); + //~^ ERROR no method named `method` found for struct `LocalKey` in the current scope [E0599] + //~| HELP use `with` or `try_with` to access the contents of threadlocals + + let item = std::mem::MaybeUninit::new(Struct { p: 42_u32 }); + item.method(); + //~^ ERROR no method named `method` found for union `MaybeUninit` in the current scope [E0599] + //~| HELP if this `MaybeUninit::>` has been initialized, use one of the `assume_init` methods to access the inner value +} \ No newline at end of file diff --git a/src/test/ui/suggestions/inner_type2.stderr b/src/test/ui/suggestions/inner_type2.stderr new file mode 100644 index 0000000000000..40e7a7ab41e44 --- /dev/null +++ b/src/test/ui/suggestions/inner_type2.stderr @@ -0,0 +1,29 @@ +error[E0599]: no method named `method` found for struct `LocalKey` in the current scope + --> $DIR/inner_type2.rs:18:12 + | +LL | STRUCT.method(); + | ^^^^^^ method not found in `LocalKey>` + | + = help: use `with` or `try_with` to access the contents of threadlocals +note: the method `method` exists on the type `Struct` + --> $DIR/inner_type2.rs:6:5 + | +LL | pub fn method(&self) {} + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0599]: no method named `method` found for union `MaybeUninit` in the current scope + --> $DIR/inner_type2.rs:23:10 + | +LL | item.method(); + | ^^^^^^ method not found in `MaybeUninit>` + | + = help: if this `MaybeUninit::>` has been initialized, use one of the `assume_init` methods to access the inner value +note: the method `method` exists on the type `Struct` + --> $DIR/inner_type2.rs:6:5 + | +LL | pub fn method(&self) {} + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. From f3ac328d584b83bb7f0b4faa0f7a5699151b3ce9 Mon Sep 17 00:00:00 2001 From: mejrs <> Date: Tue, 27 Sep 2022 13:06:31 +0200 Subject: [PATCH 19/25] Address feedback --- .../src/check/method/suggest.rs | 61 ++++++++++++++----- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/cell.rs | 2 +- library/std/src/sync/rwlock.rs | 1 + library/std/src/thread/local.rs | 2 +- src/test/ui/suggestions/inner_type.fixed | 16 ++++- src/test/ui/suggestions/inner_type.rs | 16 ++++- src/test/ui/suggestions/inner_type.stderr | 40 ++++++++++-- src/test/ui/suggestions/inner_type2.rs | 2 +- src/test/ui/suggestions/inner_type2.stderr | 2 +- 10 files changed, 113 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_analysis/src/check/method/suggest.rs index 1ff2575bcc5dd..c43dc8c134dd3 100644 --- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs +++ b/compiler/rustc_hir_analysis/src/check/method/suggest.rs @@ -1428,7 +1428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name, field_ty, call_expr, - ProbeScope::AllTraits, + ProbeScope::TraitsInScope, ) .ok() .map(|pick| (variant, field, pick)) @@ -1500,59 +1500,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name, ty, call_expr, - ProbeScope::AllTraits, + ProbeScope::TraitsInScope, ) else { return; }; let name = self.ty_to_value_string(actual); let inner_id = kind.did(); + let mutable = if let Some(AutorefOrPtrAdjustment::Autoref { mutbl, .. }) = + pick.autoref_or_ptr_adjustment + { + Some(mutbl) + } else { + None + }; if tcx.is_diagnostic_item(sym::LocalKey, inner_id) { - err.help("use `with` or `try_with` to access the contents of threadlocals"); + err.help("use `with` or `try_with` to access thread local storage"); } else if Some(kind.did()) == tcx.lang_items().maybe_uninit() { err.help(format!( "if this `{name}` has been initialized, \ use one of the `assume_init` methods to access the inner value" )); } else if tcx.is_diagnostic_item(sym::RefCell, inner_id) { - match pick.autoref_or_ptr_adjustment { - Some(AutorefOrPtrAdjustment::Autoref { - mutbl: Mutability::Not, .. - }) => { + match mutable { + Some(Mutability::Not) => { err.span_suggestion_verbose( expr.span.shrink_to_hi(), format!( - "use `.borrow()` to borrow the {ty}, \ - panicking if any outstanding mutable borrows exist." + "use `.borrow()` to borrow the `{ty}`, \ + panicking if any outstanding mutable borrows exist." ), ".borrow()", Applicability::MaybeIncorrect, ); } - Some(AutorefOrPtrAdjustment::Autoref { - mutbl: Mutability::Mut, .. - }) => { + Some(Mutability::Mut) => { err.span_suggestion_verbose( expr.span.shrink_to_hi(), format!( - "use `.borrow_mut()` to mutably borrow the {ty}, \ - panicking if any outstanding borrows exist." + "use `.borrow_mut()` to mutably borrow the `{ty}`, \ + panicking if any outstanding borrows exist." ), ".borrow_mut()", Applicability::MaybeIncorrect, ); } - _ => return, + None => return, } } else if tcx.is_diagnostic_item(sym::Mutex, inner_id) { err.span_suggestion_verbose( expr.span.shrink_to_hi(), format!( - "use `.lock()` to borrow the {ty}, \ + "use `.lock()` to borrow the `{ty}`, \ blocking the current thread until it can be acquired" ), ".lock().unwrap()", Applicability::MaybeIncorrect, ); + } else if tcx.is_diagnostic_item(sym::RwLock, inner_id) { + match mutable { + Some(Mutability::Not) => { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "use `.read()` to borrow the `{ty}`, \ + blocking the current thread until it can be acquired" + ), + ".read().unwrap()", + Applicability::MaybeIncorrect, + ); + } + Some(Mutability::Mut) => { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "use `.write()` to mutably borrow the `{ty}`, \ + blocking the current thread until it can be acquired" + ), + ".write().unwrap()", + Applicability::MaybeIncorrect, + ); + } + None => return, + } } else { return; }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6101c1c47e380..67ffc573b990a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -276,6 +276,7 @@ symbols! { Rust, RustcDecodable, RustcEncodable, + RwLock, RwLockReadGuard, RwLockWriteGuard, Send, diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index cf7b1b358c940..288cab1ef3994 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -614,7 +614,7 @@ impl Cell<[T; N]> { /// A mutable memory location with dynamically checked borrow rules /// /// See the [module-level documentation](self) for more. -#[rustc_diagnostic_item = "RefCell"] +#[cfg_attr(not(test), rustc_diagnostic_item = "RefCell")] #[stable(feature = "rust1", since = "1.0.0")] pub struct RefCell { borrow: Cell, diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 9ab781561e9b1..ee2c79b6669b8 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -76,6 +76,7 @@ use crate::sys_common::rwlock as sys; /// /// [`Mutex`]: super::Mutex #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "RwLock")] pub struct RwLock { inner: sys::MovableRwLock, poison: poison::Flag, diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 1d728349951bf..ffd17dc99093a 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -95,7 +95,7 @@ use crate::fmt; /// [loader lock]: https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices /// [`JoinHandle::join`]: crate::thread::JoinHandle::join /// [`with`]: LocalKey::with -#[rustc_diagnostic_item = "LocalKey"] +#[cfg_attr(not(test), rustc_diagnostic_item = "LocalKey")] #[stable(feature = "rust1", since = "1.0.0")] pub struct LocalKey { // This outer `LocalKey` type is what's going to be stored in statics, diff --git a/src/test/ui/suggestions/inner_type.fixed b/src/test/ui/suggestions/inner_type.fixed index f6dc7c4ce1722..327bf7caa7257 100644 --- a/src/test/ui/suggestions/inner_type.fixed +++ b/src/test/ui/suggestions/inner_type.fixed @@ -16,15 +16,25 @@ fn main() { other_item.borrow().method(); //~^ ERROR no method named `method` found for struct `RefCell` in the current scope [E0599] - //~| HELP use `.borrow()` to borrow the Struct, panicking if any outstanding mutable borrows exist. + //~| HELP use `.borrow()` to borrow the `Struct`, panicking if any outstanding mutable borrows exist. other_item.borrow_mut().some_mutable_method(); //~^ ERROR no method named `some_mutable_method` found for struct `RefCell` in the current scope [E0599] - //~| HELP use `.borrow_mut()` to mutably borrow the Struct, panicking if any outstanding borrows exist. + //~| HELP use `.borrow_mut()` to mutably borrow the `Struct`, panicking if any outstanding borrows exist. let another_item = std::sync::Mutex::new(Struct { p: 42_u32 }); another_item.lock().unwrap().method(); //~^ ERROR no method named `method` found for struct `Mutex` in the current scope [E0599] - //~| HELP use `.lock()` to borrow the Struct, blocking the current thread until it can be acquired + //~| HELP use `.lock()` to borrow the `Struct`, blocking the current thread until it can be acquired + + let another_item = std::sync::RwLock::new(Struct { p: 42_u32 }); + + another_item.read().unwrap().method(); + //~^ ERROR no method named `method` found for struct `RwLock` in the current scope [E0599] + //~| HELP use `.read()` to borrow the `Struct`, blocking the current thread until it can be acquired + + another_item.write().unwrap().some_mutable_method(); + //~^ ERROR no method named `some_mutable_method` found for struct `RwLock` in the current scope [E0599] + //~| HELP use `.write()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired } \ No newline at end of file diff --git a/src/test/ui/suggestions/inner_type.rs b/src/test/ui/suggestions/inner_type.rs index b42067c047c04..a8c1c5d386a1e 100644 --- a/src/test/ui/suggestions/inner_type.rs +++ b/src/test/ui/suggestions/inner_type.rs @@ -16,15 +16,25 @@ fn main() { other_item.method(); //~^ ERROR no method named `method` found for struct `RefCell` in the current scope [E0599] - //~| HELP use `.borrow()` to borrow the Struct, panicking if any outstanding mutable borrows exist. + //~| HELP use `.borrow()` to borrow the `Struct`, panicking if any outstanding mutable borrows exist. other_item.some_mutable_method(); //~^ ERROR no method named `some_mutable_method` found for struct `RefCell` in the current scope [E0599] - //~| HELP use `.borrow_mut()` to mutably borrow the Struct, panicking if any outstanding borrows exist. + //~| HELP use `.borrow_mut()` to mutably borrow the `Struct`, panicking if any outstanding borrows exist. let another_item = std::sync::Mutex::new(Struct { p: 42_u32 }); another_item.method(); //~^ ERROR no method named `method` found for struct `Mutex` in the current scope [E0599] - //~| HELP use `.lock()` to borrow the Struct, blocking the current thread until it can be acquired + //~| HELP use `.lock()` to borrow the `Struct`, blocking the current thread until it can be acquired + + let another_item = std::sync::RwLock::new(Struct { p: 42_u32 }); + + another_item.method(); + //~^ ERROR no method named `method` found for struct `RwLock` in the current scope [E0599] + //~| HELP use `.read()` to borrow the `Struct`, blocking the current thread until it can be acquired + + another_item.some_mutable_method(); + //~^ ERROR no method named `some_mutable_method` found for struct `RwLock` in the current scope [E0599] + //~| HELP use `.write()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired } \ No newline at end of file diff --git a/src/test/ui/suggestions/inner_type.stderr b/src/test/ui/suggestions/inner_type.stderr index f2b25944c8b2d..00d52f0f1d33a 100644 --- a/src/test/ui/suggestions/inner_type.stderr +++ b/src/test/ui/suggestions/inner_type.stderr @@ -9,7 +9,7 @@ note: the method `method` exists on the type `Struct` | LL | pub fn method(&self) {} | ^^^^^^^^^^^^^^^^^^^^ -help: use `.borrow()` to borrow the Struct, panicking if any outstanding mutable borrows exist. +help: use `.borrow()` to borrow the `Struct`, panicking if any outstanding mutable borrows exist. | LL | other_item.borrow().method(); | +++++++++ @@ -25,7 +25,7 @@ note: the method `some_mutable_method` exists on the type `Struct` | LL | pub fn some_mutable_method(&mut self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: use `.borrow_mut()` to mutably borrow the Struct, panicking if any outstanding borrows exist. +help: use `.borrow_mut()` to mutably borrow the `Struct`, panicking if any outstanding borrows exist. | LL | other_item.borrow_mut().some_mutable_method(); | +++++++++++++ @@ -41,11 +41,43 @@ note: the method `method` exists on the type `Struct` | LL | pub fn method(&self) {} | ^^^^^^^^^^^^^^^^^^^^ -help: use `.lock()` to borrow the Struct, blocking the current thread until it can be acquired +help: use `.lock()` to borrow the `Struct`, blocking the current thread until it can be acquired | LL | another_item.lock().unwrap().method(); | ++++++++++++++++ -error: aborting due to 3 previous errors +error[E0599]: no method named `method` found for struct `RwLock` in the current scope + --> $DIR/inner_type.rs:33:18 + | +LL | another_item.method(); + | ^^^^^^ method not found in `RwLock>` + | +note: the method `method` exists on the type `Struct` + --> $DIR/inner_type.rs:9:5 + | +LL | pub fn method(&self) {} + | ^^^^^^^^^^^^^^^^^^^^ +help: use `.read()` to borrow the `Struct`, blocking the current thread until it can be acquired + | +LL | another_item.read().unwrap().method(); + | ++++++++++++++++ + +error[E0599]: no method named `some_mutable_method` found for struct `RwLock` in the current scope + --> $DIR/inner_type.rs:37:18 + | +LL | another_item.some_mutable_method(); + | ^^^^^^^^^^^^^^^^^^^ method not found in `RwLock>` + | +note: the method `some_mutable_method` exists on the type `Struct` + --> $DIR/inner_type.rs:11:5 + | +LL | pub fn some_mutable_method(&mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use `.write()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired + | +LL | another_item.write().unwrap().some_mutable_method(); + | +++++++++++++++++ + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/suggestions/inner_type2.rs b/src/test/ui/suggestions/inner_type2.rs index 694c0adfd06c2..8dea8100c289c 100644 --- a/src/test/ui/suggestions/inner_type2.rs +++ b/src/test/ui/suggestions/inner_type2.rs @@ -17,7 +17,7 @@ thread_local! { fn main() { STRUCT.method(); //~^ ERROR no method named `method` found for struct `LocalKey` in the current scope [E0599] - //~| HELP use `with` or `try_with` to access the contents of threadlocals + //~| HELP use `with` or `try_with` to access thread local storage let item = std::mem::MaybeUninit::new(Struct { p: 42_u32 }); item.method(); diff --git a/src/test/ui/suggestions/inner_type2.stderr b/src/test/ui/suggestions/inner_type2.stderr index 40e7a7ab41e44..eddfd9d63409d 100644 --- a/src/test/ui/suggestions/inner_type2.stderr +++ b/src/test/ui/suggestions/inner_type2.stderr @@ -4,7 +4,7 @@ error[E0599]: no method named `method` found for struct `LocalKey` in the curren LL | STRUCT.method(); | ^^^^^^ method not found in `LocalKey>` | - = help: use `with` or `try_with` to access the contents of threadlocals + = help: use `with` or `try_with` to access thread local storage note: the method `method` exists on the type `Struct` --> $DIR/inner_type2.rs:6:5 | From e5776c690328a373ec812471f7a257e6c0920881 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 27 Sep 2022 20:00:24 +0000 Subject: [PATCH 20/25] Use already resolved self_ty in confirm_fn_pointer_candidate --- .../src/traits/select/confirmation.rs | 3 +- src/test/ui/function-pointer/issue-102289.rs | 54 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/function-pointer/issue-102289.rs diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 27fbfb6dd21fb..dd49dcecf77e3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -626,7 +626,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // the signature, as evidenced by how we treat it during projection. // The safe thing to do here is to liberate it, though, which should // have no worse effect than skipping the binder here. - let liberated_fn_ty = self.infcx.replace_bound_vars_with_placeholders(obligation.self_ty()); + let liberated_fn_ty = + self.infcx.replace_bound_vars_with_placeholders(obligation.predicate.rebind(self_ty)); let output_ty = self .infcx .replace_bound_vars_with_placeholders(liberated_fn_ty.fn_sig(self.tcx()).output()); diff --git a/src/test/ui/function-pointer/issue-102289.rs b/src/test/ui/function-pointer/issue-102289.rs new file mode 100644 index 0000000000000..de394ca9ad6d4 --- /dev/null +++ b/src/test/ui/function-pointer/issue-102289.rs @@ -0,0 +1,54 @@ +// check-pass + +pub(crate) trait Parser: Sized { + type Output; + fn parse(&mut self, _input: &str) -> Result<(), ()> { + loop {} + } + fn map(self, _f: F) -> Map + where + F: FnMut(Self::Output) -> B, + { + todo!() + } +} + +pub(crate) struct Chainl1(P, Op); +impl Parser for Chainl1 +where + P: Parser, + Op: Parser, + Op::Output: FnOnce(P::Output, P::Output) -> P::Output, +{ + type Output = P::Output; +} +pub(crate) fn chainl1(_parser: P, _op: Op) -> Chainl1 +where + P: Parser, + Op: Parser, + Op::Output: FnOnce(P::Output, P::Output) -> P::Output, +{ + loop {} +} + +pub(crate) struct Map(P, F); +impl Parser for Map +where + P: Parser, + F: FnMut(A) -> B, +{ + type Output = B; +} + +impl Parser for u32 { + type Output = (); +} + +pub fn chainl1_error_consume() { + fn first(t: T, _: U) -> T { + t + } + let _ = chainl1(1, 1.map(|_| first)).parse(""); +} + +fn main() {} From e9224b37968f8bf56c0bbac206312ef84dad3b74 Mon Sep 17 00:00:00 2001 From: mejrs <> Date: Tue, 27 Sep 2022 23:12:52 +0200 Subject: [PATCH 21/25] Add newline --- src/test/ui/suggestions/inner_type.fixed | 2 +- src/test/ui/suggestions/inner_type.rs | 2 +- src/test/ui/suggestions/inner_type2.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/ui/suggestions/inner_type.fixed b/src/test/ui/suggestions/inner_type.fixed index 327bf7caa7257..811b959b8c04d 100644 --- a/src/test/ui/suggestions/inner_type.fixed +++ b/src/test/ui/suggestions/inner_type.fixed @@ -37,4 +37,4 @@ fn main() { another_item.write().unwrap().some_mutable_method(); //~^ ERROR no method named `some_mutable_method` found for struct `RwLock` in the current scope [E0599] //~| HELP use `.write()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired -} \ No newline at end of file +} diff --git a/src/test/ui/suggestions/inner_type.rs b/src/test/ui/suggestions/inner_type.rs index a8c1c5d386a1e..96c797a6d81d7 100644 --- a/src/test/ui/suggestions/inner_type.rs +++ b/src/test/ui/suggestions/inner_type.rs @@ -37,4 +37,4 @@ fn main() { another_item.some_mutable_method(); //~^ ERROR no method named `some_mutable_method` found for struct `RwLock` in the current scope [E0599] //~| HELP use `.write()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired -} \ No newline at end of file +} diff --git a/src/test/ui/suggestions/inner_type2.rs b/src/test/ui/suggestions/inner_type2.rs index 8dea8100c289c..c56ea7c030d8e 100644 --- a/src/test/ui/suggestions/inner_type2.rs +++ b/src/test/ui/suggestions/inner_type2.rs @@ -23,4 +23,4 @@ fn main() { item.method(); //~^ ERROR no method named `method` found for union `MaybeUninit` in the current scope [E0599] //~| HELP if this `MaybeUninit::>` has been initialized, use one of the `assume_init` methods to access the inner value -} \ No newline at end of file +} From c0245b16baf98f88cba708c19b5a8fc514781b34 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 27 Sep 2022 14:25:48 -0700 Subject: [PATCH 22/25] rustdoc: remove redundant mobile `.source > .sidebar` CSS When the source sidebar and standard sidebar had most of their code merged in 07e3f998b1ceb4b8d2a7992782e60f5e776aa114, the properties `z-index: 11`, `margin: 0`, and `position: fixed` were already being set on the `.sidebar` class, so no need to repeat them. --- src/librustdoc/html/static/css/rustdoc.css | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index e7a05b80c127f..c4ce599aa559c 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1770,9 +1770,6 @@ in storage.js plus the media query with (min-width: 701px) } .rustdoc.source > .sidebar { - position: fixed; - margin: 0; - z-index: 11; width: 0; } From 94cb5e86ea50ec878b1a5de9b0b64bb35e8027e3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 Sep 2022 16:32:22 +1000 Subject: [PATCH 23/25] Small cleanups in unescaping code. - Rename `unescape_raw_str_or_raw_byte_str` as `unescape_raw_str_or_byte_str`, which is more accurate. - Remove the unused `Mode::in_single_quotes` method. - Make some assertions more precise, and add a missing one to `unescape_char_or_byte`. - Change all the assertions to `debug_assert!`, because this code is reasonably hot, and the assertions aren't required for memory safety, and any violations are likely to be sufficiently obvious that normal tests will trigger them. --- compiler/rustc_lexer/src/unescape.rs | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index 25d5f2772de40..8f64b5f5158e4 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -93,7 +93,7 @@ where // NOTE: Raw strings do not perform any explicit character escaping, here we // only translate CRLF to LF and produce errors on bare CR. Mode::RawStr | Mode::RawByteStr => { - unescape_raw_str_or_byte_str(literal_text, mode, callback) + unescape_raw_str_or_raw_byte_str(literal_text, mode, callback) } } } @@ -105,7 +105,7 @@ pub fn unescape_byte_literal(literal_text: &str, mode: Mode, callback: &mut F where F: FnMut(Range, Result), { - assert!(mode.is_bytes()); + debug_assert!(mode.is_bytes()); unescape_literal(literal_text, mode, &mut |range, result| { callback(range, result.map(byte_from_char)); }) @@ -129,7 +129,7 @@ pub fn unescape_byte(literal_text: &str) -> Result { } /// What kind of literal do we parse. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum Mode { Char, Str, @@ -140,17 +140,13 @@ pub enum Mode { } impl Mode { - pub fn in_single_quotes(self) -> bool { + pub fn in_double_quotes(self) -> bool { match self { - Mode::Char | Mode::Byte => true, - Mode::Str | Mode::ByteStr | Mode::RawStr | Mode::RawByteStr => false, + Mode::Str | Mode::ByteStr | Mode::RawStr | Mode::RawByteStr => true, + Mode::Char | Mode::Byte => false, } } - pub fn in_double_quotes(self) -> bool { - !self.in_single_quotes() - } - pub fn is_bytes(self) -> bool { match self { Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true, @@ -263,6 +259,7 @@ fn ascii_check(first_char: char, mode: Mode) -> Result { } fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result { + debug_assert!(mode == Mode::Char || mode == Mode::Byte); let first_char = chars.next().ok_or(EscapeError::ZeroChars)?; let res = match first_char { '\\' => scan_escape(chars, mode), @@ -282,7 +279,7 @@ fn unescape_str_or_byte_str(src: &str, mode: Mode, callback: &mut F) where F: FnMut(Range, Result), { - assert!(mode.in_double_quotes()); + debug_assert!(mode == Mode::Str || mode == Mode::ByteStr); let initial_len = src.len(); let mut chars = src.chars(); while let Some(first_char) = chars.next() { @@ -344,11 +341,11 @@ where /// sequence of characters or errors. /// NOTE: Raw strings do not perform any explicit character escaping, here we /// only translate CRLF to LF and produce errors on bare CR. -fn unescape_raw_str_or_byte_str(literal_text: &str, mode: Mode, callback: &mut F) +fn unescape_raw_str_or_raw_byte_str(literal_text: &str, mode: Mode, callback: &mut F) where F: FnMut(Range, Result), { - assert!(mode.in_double_quotes()); + debug_assert!(mode == Mode::RawStr || mode == Mode::RawByteStr); let initial_len = literal_text.len(); let mut chars = literal_text.chars(); @@ -368,7 +365,7 @@ where fn byte_from_char(c: char) -> u8 { let res = c as u32; - assert!(res <= u8::MAX as u32, "guaranteed because of Mode::ByteStr"); + debug_assert!(res <= u8::MAX as u32, "guaranteed because of Mode::ByteStr"); res as u8 } From c0d32fd2cc4eafe4f621490e7c44b7af04d1f2be Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Tue, 27 Sep 2022 19:23:59 -0400 Subject: [PATCH 24/25] review updates --- compiler/rustc_error_codes/src/error_codes/E0311.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index 768b849817db5..08159d3f469ac 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -1,5 +1,5 @@ This error occurs when there is an unsatisfied outlives bound involving an -elided region on a generic type parameter or associated type. +elided region and a generic type parameter or associated type. Erroneous code example: @@ -21,7 +21,7 @@ The compiler elides the lifetime of `x` and the return type to some arbitrary lifetime `'anon` in `no_restriction()`. The only information available to the compiler is that `'anon` is valid for the duration of the function. When calling `with_restriction()`, the compiler requires the completely unrelated -type parameter `T` to outlive `'anon` because of the `T: 'a bound` in +type parameter `T` to outlive `'anon` because of the `T: 'a` bound in `with_restriction()`. This causes an error because `T` is not required to outlive `'anon` in `no_restriction()`. From 4ff83cee95cf73708cc5455f4ecce5eb1c21ffc6 Mon Sep 17 00:00:00 2001 From: mejrs <> Date: Wed, 28 Sep 2022 02:36:58 +0200 Subject: [PATCH 25/25] Deduplicate some logic --- .../src/check/method/suggest.rs | 74 +++++++------------ src/test/ui/suggestions/inner_type.fixed | 10 +-- src/test/ui/suggestions/inner_type.rs | 10 +-- src/test/ui/suggestions/inner_type.stderr | 10 +-- 4 files changed, 42 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_analysis/src/check/method/suggest.rs index c43dc8c134dd3..0e82e4956c7c1 100644 --- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs +++ b/compiler/rustc_hir_analysis/src/check/method/suggest.rs @@ -1521,67 +1521,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { use one of the `assume_init` methods to access the inner value" )); } else if tcx.is_diagnostic_item(sym::RefCell, inner_id) { - match mutable { - Some(Mutability::Not) => { - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - format!( - "use `.borrow()` to borrow the `{ty}`, \ - panicking if any outstanding mutable borrows exist." - ), - ".borrow()", - Applicability::MaybeIncorrect, - ); - } + let (suggestion, borrow_kind, panic_if) = match mutable { + Some(Mutability::Not) => (".borrow()", "borrow", "a mutable borrow exists"), Some(Mutability::Mut) => { - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - format!( - "use `.borrow_mut()` to mutably borrow the `{ty}`, \ - panicking if any outstanding borrows exist." - ), - ".borrow_mut()", - Applicability::MaybeIncorrect, - ); + (".borrow_mut()", "mutably borrow", "any borrows exist") } None => return, - } + }; + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "use `{suggestion}` to {borrow_kind} the `{ty}`, \ + panicking if {panic_if}" + ), + suggestion, + Applicability::MaybeIncorrect, + ); } else if tcx.is_diagnostic_item(sym::Mutex, inner_id) { err.span_suggestion_verbose( expr.span.shrink_to_hi(), format!( - "use `.lock()` to borrow the `{ty}`, \ + "use `.lock().unwrap()` to borrow the `{ty}`, \ blocking the current thread until it can be acquired" ), ".lock().unwrap()", Applicability::MaybeIncorrect, ); } else if tcx.is_diagnostic_item(sym::RwLock, inner_id) { - match mutable { - Some(Mutability::Not) => { - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - format!( - "use `.read()` to borrow the `{ty}`, \ - blocking the current thread until it can be acquired" - ), - ".read().unwrap()", - Applicability::MaybeIncorrect, - ); - } - Some(Mutability::Mut) => { - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - format!( - "use `.write()` to mutably borrow the `{ty}`, \ - blocking the current thread until it can be acquired" - ), - ".write().unwrap()", - Applicability::MaybeIncorrect, - ); - } + let (suggestion, borrow_kind) = match mutable { + Some(Mutability::Not) => (".read().unwrap()", "borrow"), + Some(Mutability::Mut) => (".write().unwrap()", "mutably borrow"), None => return, - } + }; + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "use `{suggestion}` to {borrow_kind} the `{ty}`, \ + blocking the current thread until it can be acquired" + ), + suggestion, + Applicability::MaybeIncorrect, + ); } else { return; }; diff --git a/src/test/ui/suggestions/inner_type.fixed b/src/test/ui/suggestions/inner_type.fixed index 811b959b8c04d..7af7391ca851d 100644 --- a/src/test/ui/suggestions/inner_type.fixed +++ b/src/test/ui/suggestions/inner_type.fixed @@ -16,25 +16,25 @@ fn main() { other_item.borrow().method(); //~^ ERROR no method named `method` found for struct `RefCell` in the current scope [E0599] - //~| HELP use `.borrow()` to borrow the `Struct`, panicking if any outstanding mutable borrows exist. + //~| HELP use `.borrow()` to borrow the `Struct`, panicking if a mutable borrow exists other_item.borrow_mut().some_mutable_method(); //~^ ERROR no method named `some_mutable_method` found for struct `RefCell` in the current scope [E0599] - //~| HELP use `.borrow_mut()` to mutably borrow the `Struct`, panicking if any outstanding borrows exist. + //~| HELP .borrow_mut()` to mutably borrow the `Struct`, panicking if any borrows exist let another_item = std::sync::Mutex::new(Struct { p: 42_u32 }); another_item.lock().unwrap().method(); //~^ ERROR no method named `method` found for struct `Mutex` in the current scope [E0599] - //~| HELP use `.lock()` to borrow the `Struct`, blocking the current thread until it can be acquired + //~| HELP use `.lock().unwrap()` to borrow the `Struct`, blocking the current thread until it can be acquired let another_item = std::sync::RwLock::new(Struct { p: 42_u32 }); another_item.read().unwrap().method(); //~^ ERROR no method named `method` found for struct `RwLock` in the current scope [E0599] - //~| HELP use `.read()` to borrow the `Struct`, blocking the current thread until it can be acquired + //~| HELP use `.read().unwrap()` to borrow the `Struct`, blocking the current thread until it can be acquired another_item.write().unwrap().some_mutable_method(); //~^ ERROR no method named `some_mutable_method` found for struct `RwLock` in the current scope [E0599] - //~| HELP use `.write()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired + //~| HELP use `.write().unwrap()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired } diff --git a/src/test/ui/suggestions/inner_type.rs b/src/test/ui/suggestions/inner_type.rs index 96c797a6d81d7..4aca50716258a 100644 --- a/src/test/ui/suggestions/inner_type.rs +++ b/src/test/ui/suggestions/inner_type.rs @@ -16,25 +16,25 @@ fn main() { other_item.method(); //~^ ERROR no method named `method` found for struct `RefCell` in the current scope [E0599] - //~| HELP use `.borrow()` to borrow the `Struct`, panicking if any outstanding mutable borrows exist. + //~| HELP use `.borrow()` to borrow the `Struct`, panicking if a mutable borrow exists other_item.some_mutable_method(); //~^ ERROR no method named `some_mutable_method` found for struct `RefCell` in the current scope [E0599] - //~| HELP use `.borrow_mut()` to mutably borrow the `Struct`, panicking if any outstanding borrows exist. + //~| HELP .borrow_mut()` to mutably borrow the `Struct`, panicking if any borrows exist let another_item = std::sync::Mutex::new(Struct { p: 42_u32 }); another_item.method(); //~^ ERROR no method named `method` found for struct `Mutex` in the current scope [E0599] - //~| HELP use `.lock()` to borrow the `Struct`, blocking the current thread until it can be acquired + //~| HELP use `.lock().unwrap()` to borrow the `Struct`, blocking the current thread until it can be acquired let another_item = std::sync::RwLock::new(Struct { p: 42_u32 }); another_item.method(); //~^ ERROR no method named `method` found for struct `RwLock` in the current scope [E0599] - //~| HELP use `.read()` to borrow the `Struct`, blocking the current thread until it can be acquired + //~| HELP use `.read().unwrap()` to borrow the `Struct`, blocking the current thread until it can be acquired another_item.some_mutable_method(); //~^ ERROR no method named `some_mutable_method` found for struct `RwLock` in the current scope [E0599] - //~| HELP use `.write()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired + //~| HELP use `.write().unwrap()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired } diff --git a/src/test/ui/suggestions/inner_type.stderr b/src/test/ui/suggestions/inner_type.stderr index 00d52f0f1d33a..5ac3d04f10414 100644 --- a/src/test/ui/suggestions/inner_type.stderr +++ b/src/test/ui/suggestions/inner_type.stderr @@ -9,7 +9,7 @@ note: the method `method` exists on the type `Struct` | LL | pub fn method(&self) {} | ^^^^^^^^^^^^^^^^^^^^ -help: use `.borrow()` to borrow the `Struct`, panicking if any outstanding mutable borrows exist. +help: use `.borrow()` to borrow the `Struct`, panicking if a mutable borrow exists | LL | other_item.borrow().method(); | +++++++++ @@ -25,7 +25,7 @@ note: the method `some_mutable_method` exists on the type `Struct` | LL | pub fn some_mutable_method(&mut self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: use `.borrow_mut()` to mutably borrow the `Struct`, panicking if any outstanding borrows exist. +help: use `.borrow_mut()` to mutably borrow the `Struct`, panicking if any borrows exist | LL | other_item.borrow_mut().some_mutable_method(); | +++++++++++++ @@ -41,7 +41,7 @@ note: the method `method` exists on the type `Struct` | LL | pub fn method(&self) {} | ^^^^^^^^^^^^^^^^^^^^ -help: use `.lock()` to borrow the `Struct`, blocking the current thread until it can be acquired +help: use `.lock().unwrap()` to borrow the `Struct`, blocking the current thread until it can be acquired | LL | another_item.lock().unwrap().method(); | ++++++++++++++++ @@ -57,7 +57,7 @@ note: the method `method` exists on the type `Struct` | LL | pub fn method(&self) {} | ^^^^^^^^^^^^^^^^^^^^ -help: use `.read()` to borrow the `Struct`, blocking the current thread until it can be acquired +help: use `.read().unwrap()` to borrow the `Struct`, blocking the current thread until it can be acquired | LL | another_item.read().unwrap().method(); | ++++++++++++++++ @@ -73,7 +73,7 @@ note: the method `some_mutable_method` exists on the type `Struct` | LL | pub fn some_mutable_method(&mut self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: use `.write()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired +help: use `.write().unwrap()` to mutably borrow the `Struct`, blocking the current thread until it can be acquired | LL | another_item.write().unwrap().some_mutable_method(); | +++++++++++++++++