From ad79b2043f2402859f80a82c3b20e16b1cf7c9da Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Jan 2023 16:38:58 +0100 Subject: [PATCH 01/12] std tests: use __OsLocalKeyInner from realstd --- library/std/src/thread/mod.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 7acda8e98f18f..692ff0cbca68b 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -177,6 +177,12 @@ use crate::sys_common::thread_parking::Parker; use crate::sys_common::{AsInner, IntoInner}; use crate::time::Duration; +#[stable(feature = "scoped_threads", since = "1.63.0")] +mod scoped; + +#[stable(feature = "scoped_threads", since = "1.63.0")] +pub use scoped::{scope, Scope, ScopedJoinHandle}; + //////////////////////////////////////////////////////////////////////////////// // Thread-local storage //////////////////////////////////////////////////////////////////////////////// @@ -184,12 +190,6 @@ use crate::time::Duration; #[macro_use] mod local; -#[stable(feature = "scoped_threads", since = "1.63.0")] -mod scoped; - -#[stable(feature = "scoped_threads", since = "1.63.0")] -pub use scoped::{scope, Scope, ScopedJoinHandle}; - #[stable(feature = "rust1", since = "1.0.0")] pub use self::local::{AccessError, LocalKey}; @@ -209,7 +209,6 @@ pub use self::local::{AccessError, LocalKey}; ))] #[doc(hidden)] pub use self::local::fast::Key as __FastLocalKeyInner; - // when building for tests, use real std's type #[unstable(feature = "libstd_thread_internals", issue = "none")] #[cfg(test)] @@ -220,12 +219,21 @@ pub use self::local::fast::Key as __FastLocalKeyInner; pub use realstd::thread::__FastLocalKeyInner; #[unstable(feature = "libstd_thread_internals", issue = "none")] +#[cfg(not(test))] #[cfg(all( not(target_thread_local), not(all(target_family = "wasm", not(target_feature = "atomics"))), ))] #[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner; +// when building for tests, use real std's type +#[unstable(feature = "libstd_thread_internals", issue = "none")] +#[cfg(test)] +#[cfg(all( + not(target_thread_local), + not(all(target_family = "wasm", not(target_feature = "atomics"))), +))] +pub use realstd::thread::__OsLocalKeyInner; #[unstable(feature = "libstd_thread_internals", issue = "none")] #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] From 1a993611d2f539eeea272694e5efbb30bdeff04e Mon Sep 17 00:00:00 2001 From: J Haigh Date: Wed, 11 Jan 2023 11:11:56 -0700 Subject: [PATCH 02/12] Revert "warn newer available version of the x tool" --- Cargo.lock | 21 +++++------ src/bootstrap/bootstrap.py | 3 +- src/tools/tidy/Cargo.toml | 1 - src/tools/tidy/src/lib.rs | 1 - src/tools/tidy/src/main.rs | 4 +- src/tools/tidy/src/x_version.rs | 65 --------------------------------- src/tools/x/src/main.rs | 8 ---- 7 files changed, 13 insertions(+), 90 deletions(-) delete mode 100644 src/tools/tidy/src/x_version.rs diff --git a/Cargo.lock b/Cargo.lock index 2a88152b5194a..4bea3af7f3bfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5034,18 +5034,18 @@ checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af" [[package]] name = "semver" -version = "1.0.14" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.152" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" dependencies = [ "serde_derive", ] @@ -5062,9 +5062,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ "proc-macro2", "quote", @@ -5082,9 +5082,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "indexmap", "itoa", @@ -5400,9 +5400,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.107" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" dependencies = [ "proc-macro2", "quote", @@ -5576,7 +5576,6 @@ dependencies = [ "lazy_static", "miropt-test-tools", "regex", - "semver", "termcolor", "walkdir", ] diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index f3998e98583ec..9cf43fc7a2193 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -934,7 +934,8 @@ def main(): if len(sys.argv) > 1 and sys.argv[1] == 'help': sys.argv = [sys.argv[0], '-h'] + sys.argv[2:] - help_triggered = len(sys.argv) == 1 or any(x in ["-h", "--help", "--version"] for x in sys.argv) + help_triggered = ( + '-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1) try: bootstrap(help_triggered) if not help_triggered: diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 5f5ae3a65efa8..fff83a1d097b3 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -11,7 +11,6 @@ miropt-test-tools = { path = "../miropt-test-tools" } lazy_static = "1" walkdir = "2" ignore = "0.4.18" -semver = "1.0.14" termcolor = "1.1.3" [[bin]] diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 15c641d748c8e..bf6e2cc250f3d 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -68,4 +68,3 @@ pub mod ui_tests; pub mod unit_tests; pub mod unstable_book; pub mod walk; -pub mod x_version; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 2a4853b37be39..e15a71422a864 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -60,7 +60,7 @@ fn main() { let handle = s.spawn(|| { let mut flag = false; - $p::check($($args, )* &mut flag); + $p::check($($args),* , &mut flag); if (flag) { bad.store(true, Ordering::Relaxed); } @@ -112,8 +112,6 @@ fn main() { check!(alphabetical, &compiler_path); check!(alphabetical, &library_path); - check!(x_version, &root_path, &cargo); - let collected = { drain_handles(&mut handles); diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs deleted file mode 100644 index 5dc6a0588c32b..0000000000000 --- a/src/tools/tidy/src/x_version.rs +++ /dev/null @@ -1,65 +0,0 @@ -use semver::Version; -use std::io::ErrorKind; -use std::path::Path; -use std::process::{Command, Stdio}; - -pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { - let result = Command::new("x").arg("--wrapper-version").stdout(Stdio::piped()).spawn(); - // This runs the command inside a temporary directory. - // This allows us to compare output of result to see if `--wrapper-version` is not a recognized argument to x. - let temp_result = Command::new("x") - .arg("--wrapper-version") - .current_dir(std::env::temp_dir()) - .stdout(Stdio::piped()) - .spawn(); - - let (child, temp_child) = match (result, temp_result) { - (Ok(child), Ok(temp_child)) => (child, temp_child), - (Err(e), _) | (_, Err(e)) => match e.kind() { - ErrorKind::NotFound => return, - _ => return tidy_error!(bad, "failed to run `x`: {}", e), - }, - }; - - let output = child.wait_with_output().unwrap(); - let temp_output = temp_child.wait_with_output().unwrap(); - - if output != temp_output { - return tidy_error!( - bad, - "Current version of x does not support the `--wrapper-version` argument\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`" - ); - } - - if output.status.success() { - let version = String::from_utf8_lossy(&output.stdout); - let version = Version::parse(version.trim_end()).unwrap(); - - if let Some(expected) = get_x_wrapper_version(root, cargo) { - if version < expected { - return tidy_error!( - bad, - "Current version of x is {version}, but the latest version is {expected}\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`" - ); - } - } else { - return tidy_error!( - bad, - "Unable to parse the latest version of `x` at `src/tools/x/Cargo.toml`" - ); - } - } else { - return tidy_error!(bad, "failed to check version of `x`: {}", output.status); - } -} - -// Parse latest version out of `x` Cargo.toml -fn get_x_wrapper_version(root: &Path, cargo: &Path) -> Option { - let mut cmd = cargo_metadata::MetadataCommand::new(); - cmd.cargo_path(cargo) - .manifest_path(root.join("src/tools/x/Cargo.toml")) - .no_deps() - .features(cargo_metadata::CargoOpt::AllFeatures); - let mut metadata = t!(cmd.exec()); - metadata.packages.pop().map(|x| x.version) -} diff --git a/src/tools/x/src/main.rs b/src/tools/x/src/main.rs index 01f7187851e38..f07ff43efe987 100644 --- a/src/tools/x/src/main.rs +++ b/src/tools/x/src/main.rs @@ -52,14 +52,6 @@ fn exec_or_status(command: &mut Command) -> io::Result { } fn main() { - match env::args().skip(1).next().as_deref() { - Some("--wrapper-version") => { - let version = env!("CARGO_PKG_VERSION"); - println!("{}", version); - return; - } - _ => {} - } let current = match env::current_dir() { Ok(dir) => dir, Err(err) => { From 0d834d9523930293e4d9755e82f064b835791785 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Wed, 11 Jan 2023 12:13:35 -0700 Subject: [PATCH 03/12] keep --wrapper-version argument in x --- src/tools/x/src/main.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/tools/x/src/main.rs b/src/tools/x/src/main.rs index f07ff43efe987..01f7187851e38 100644 --- a/src/tools/x/src/main.rs +++ b/src/tools/x/src/main.rs @@ -52,6 +52,14 @@ fn exec_or_status(command: &mut Command) -> io::Result { } fn main() { + match env::args().skip(1).next().as_deref() { + Some("--wrapper-version") => { + let version = env!("CARGO_PKG_VERSION"); + println!("{}", version); + return; + } + _ => {} + } let current = match env::current_dir() { Ok(dir) => dir, Err(err) => { From 4e30ad8d60e920f486fd1462939dbdaf3bd4c544 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 30 Dec 2022 21:51:12 +0000 Subject: [PATCH 04/12] Reuse ErrorGuaranteed during relation --- compiler/rustc_middle/src/ty/_match.rs | 4 +++- compiler/rustc_middle/src/ty/relate.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index cd147d7e55813..b9c5a4e0d0d49 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -89,7 +89,9 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { Err(TypeError::Sorts(relate::expected_found(self, a, b))) } - (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(self.tcx().ty_error()), + (&ty::Error(guar), _) | (_, &ty::Error(guar)) => { + Ok(self.tcx().ty_error_with_guaranteed(guar)) + } _ => relate::super_relate_tys(self, a, b), } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 4d34ca3d66b5f..65fd8d9753de1 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -414,7 +414,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( bug!("bound types encountered in super_relate_tys") } - (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(tcx.ty_error()), + (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(tcx.ty_error_with_guaranteed(guar)), (&ty::Never, _) | (&ty::Char, _) From 83fbc71d021d2aa741ad18890e7a51a28830d45e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 1 Jan 2023 23:48:10 +0000 Subject: [PATCH 05/12] Filter impl and where-clause candidates that reference errors --- .../src/traits/select/candidate_assembly.rs | 3 +- .../src/traits/select/mod.rs | 3 ++ tests/ui/c-variadic/issue-86053-1.rs | 2 +- tests/ui/c-variadic/issue-86053-1.stderr | 22 +--------- .../issue-72787.min.stderr | 43 ++----------------- .../generic_const_exprs/issue-72787.rs | 2 - tests/ui/traits/ignore-err-impls.rs | 9 ++++ tests/ui/traits/ignore-err-impls.stderr | 11 +++++ tests/ui/where-clauses/ignore-err-clauses.rs | 14 ++++++ .../where-clauses/ignore-err-clauses.stderr | 9 ++++ 10 files changed, 54 insertions(+), 64 deletions(-) create mode 100644 tests/ui/traits/ignore-err-impls.rs create mode 100644 tests/ui/traits/ignore-err-impls.stderr create mode 100644 tests/ui/where-clauses/ignore-err-clauses.rs create mode 100644 tests/ui/where-clauses/ignore-err-clauses.stderr diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index c54d901e9b10a..170c1673dbd77 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -174,7 +174,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .param_env .caller_bounds() .iter() - .filter_map(|o| o.to_opt_poly_trait_pred()); + .filter_map(|p| p.to_opt_poly_trait_pred()) + .filter(|p| !p.references_error()); // Micro-optimization: filter out predicates relating to different traits. let matching_bounds = diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3f14491f8032f..2615e2622821d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2377,6 +2377,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs); + if impl_trait_ref.references_error() { + return Err(()); + } debug!(?impl_trait_ref); diff --git a/tests/ui/c-variadic/issue-86053-1.rs b/tests/ui/c-variadic/issue-86053-1.rs index b30548e19f9ff..49d5c0390bc13 100644 --- a/tests/ui/c-variadic/issue-86053-1.rs +++ b/tests/ui/c-variadic/issue-86053-1.rs @@ -2,7 +2,7 @@ // error-pattern:unexpected `self` parameter in function // error-pattern:`...` must be the last argument of a C-variadic function // error-pattern:cannot find type `F` in this scope -// error-pattern:in type `&'a &'b usize`, reference has a longer lifetime than the data it references + #![feature(c_variadic)] #![crate_type="lib"] diff --git a/tests/ui/c-variadic/issue-86053-1.stderr b/tests/ui/c-variadic/issue-86053-1.stderr index d1f13d52362da..5a02f4aa93a95 100644 --- a/tests/ui/c-variadic/issue-86053-1.stderr +++ b/tests/ui/c-variadic/issue-86053-1.stderr @@ -76,24 +76,6 @@ help: you might be missing a type parameter LL | fn ordering4 < 'a , 'b, F > ( a : , self , self , self , | +++ -error[E0491]: in type `&'a &'b usize`, reference has a longer lifetime than the data it references - --> $DIR/issue-86053-1.rs:11:52 - | -LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the pointer is valid for the lifetime `'a` as defined here - --> $DIR/issue-86053-1.rs:10:16 - | -LL | fn ordering4 < 'a , 'b > ( a : , self , self , self , - | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined here - --> $DIR/issue-86053-1.rs:10:21 - | -LL | fn ordering4 < 'a , 'b > ( a : , self , self , self , - | ^^ - -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors -Some errors have detailed explanations: E0412, E0491. -For more information about an error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr index 0af5493f81675..ea6f5f6927659 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr @@ -17,7 +17,7 @@ LL | Condition<{ LHS <= RHS }>: True = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/issue-72787.rs:25:25 + --> $DIR/issue-72787.rs:23:25 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^ cannot perform const operation using `I` @@ -26,7 +26,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/issue-72787.rs:25:36 + --> $DIR/issue-72787.rs:23:36 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^ cannot perform const operation using `J` @@ -34,42 +34,5 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = help: const parameters may only be used as standalone arguments, i.e. `J` = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions -error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual: True` - --> $DIR/issue-72787.rs:21:26 - | -LL | IsLessOrEqual: True, - | ^^^^ - | -note: multiple `impl`s or `where` clauses satisfying `IsLessOrEqual: True` found - --> $DIR/issue-72787.rs:10:1 - | -LL | impl True for IsLessOrEqual where - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | IsLessOrEqual: True, - | ^^^^ -... -LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, - | ^^^^ - -error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual: True` - --> $DIR/issue-72787.rs:21:26 - | -LL | IsLessOrEqual: True, - | ^^^^ - | -note: multiple `impl`s or `where` clauses satisfying `IsLessOrEqual: True` found - --> $DIR/issue-72787.rs:10:1 - | -LL | impl True for IsLessOrEqual where - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | IsLessOrEqual: True, - | ^^^^ -... -LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, - | ^^^^ - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72787.rs b/tests/ui/const-generics/generic_const_exprs/issue-72787.rs index c651bf1c8de9d..657fec2e9cb70 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-72787.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-72787.rs @@ -19,8 +19,6 @@ struct S; impl S where IsLessOrEqual: True, -//[min]~^ Error type annotations needed -//[min]~| Error type annotations needed IsLessOrEqual: True, IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, //[min]~^ Error generic parameters may not be used in const operations diff --git a/tests/ui/traits/ignore-err-impls.rs b/tests/ui/traits/ignore-err-impls.rs new file mode 100644 index 0000000000000..67e880b006a7f --- /dev/null +++ b/tests/ui/traits/ignore-err-impls.rs @@ -0,0 +1,9 @@ +pub struct S; + +trait Generic {} + +impl<'a, T> Generic<&'a T> for S {} +impl Generic for S {} +//~^ ERROR cannot find type `Type` in this scope + +fn main() {} diff --git a/tests/ui/traits/ignore-err-impls.stderr b/tests/ui/traits/ignore-err-impls.stderr new file mode 100644 index 0000000000000..1390106a29125 --- /dev/null +++ b/tests/ui/traits/ignore-err-impls.stderr @@ -0,0 +1,11 @@ +error[E0412]: cannot find type `Type` in this scope + --> $DIR/ignore-err-impls.rs:6:14 + | +LL | impl Generic for S {} + | - ^^^^ not found in this scope + | | + | help: you might be missing a type parameter: `` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/where-clauses/ignore-err-clauses.rs b/tests/ui/where-clauses/ignore-err-clauses.rs new file mode 100644 index 0000000000000..c76f0e1a8b2b5 --- /dev/null +++ b/tests/ui/where-clauses/ignore-err-clauses.rs @@ -0,0 +1,14 @@ +use std::ops::Add; + +fn dbl(x: T) -> ::Output +where + T: Copy + Add, + UUU: Copy, + //~^ ERROR cannot find type `UUU` in this scope +{ + x + x +} + +fn main() { + println!("{}", dbl(3)); +} diff --git a/tests/ui/where-clauses/ignore-err-clauses.stderr b/tests/ui/where-clauses/ignore-err-clauses.stderr new file mode 100644 index 0000000000000..cfddc3e10b64a --- /dev/null +++ b/tests/ui/where-clauses/ignore-err-clauses.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `UUU` in this scope + --> $DIR/ignore-err-clauses.rs:6:5 + | +LL | UUU: Copy, + | ^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. From 24bb36e215c9102e48a5f0954b8db73ad0fea4a2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 27 Dec 2022 01:55:54 +0000 Subject: [PATCH 06/12] Consolidate two almost duplicated fn info extraction routines --- compiler/rustc_hir_typeck/src/callee.rs | 3 +- .../src/fn_ctxt/suggestions.rs | 103 +------- .../rustc_hir_typeck/src/method/suggest.rs | 6 +- .../src/traits/error_reporting/mod.rs | 1 + .../src/traits/error_reporting/suggestions.rs | 223 +++++++++++------- .../call-on-unimplemented-with-autoderef.rs | 13 + ...all-on-unimplemented-with-autoderef.stderr | 21 ++ 7 files changed, 185 insertions(+), 185 deletions(-) create mode 100644 src/test/ui/suggestions/call-on-unimplemented-with-autoderef.rs create mode 100644 src/test/ui/suggestions/call-on-unimplemented-with-autoderef.stderr diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 3b664363d232f..745eb8e6e1499 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -659,8 +659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) { - if let Some((maybe_def, output_ty, _)) = - self.extract_callable_info(callee_expr, callee_ty) + if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty) && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span) { let descr = match maybe_def { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 91498265259de..36742275186b6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -11,7 +11,6 @@ use rustc_hir::{ Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate, }; use rustc_hir_analysis::astconv::AstConv; -use rustc_infer::infer; use rustc_infer::traits::{self, StatementAsExpression}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{ @@ -23,9 +22,9 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::DefIdOrName; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::NormalizeExt; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn body_fn_sig(&self) -> Option> { @@ -94,7 +93,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found: Ty<'tcx>, can_satisfy: impl FnOnce(Ty<'tcx>) -> bool, ) -> bool { - let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(expr, found) + let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found) else { return false; }; if can_satisfy(output) { let (sugg_call, mut applicability) = match inputs.len() { @@ -163,99 +162,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// because the callable type must also be well-formed to be called. pub(in super::super) fn extract_callable_info( &self, - expr: &Expr<'_>, - found: Ty<'tcx>, + ty: Ty<'tcx>, ) -> Option<(DefIdOrName, Ty<'tcx>, Vec>)> { - // Autoderef is useful here because sometimes we box callables, etc. - let Some((def_id_or_name, output, inputs)) = self.autoderef(expr.span, found).silence_errors().find_map(|(found, _)| { - match *found.kind() { - ty::FnPtr(fn_sig) => - Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())), - ty::FnDef(def_id, _) => { - let fn_sig = found.fn_sig(self.tcx); - Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs())) - } - ty::Closure(def_id, substs) => { - let fn_sig = substs.as_closure().sig(); - Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..]))) - } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() - && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() - // args tuple will always be substs[1] - && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() - { - Some(( - DefIdOrName::DefId(def_id), - pred.kind().rebind(proj.term.ty().unwrap()), - pred.kind().rebind(args.as_slice()), - )) - } else { - None - } - }) - } - ty::Dynamic(data, _, ty::Dyn) => { - data.iter().find_map(|pred| { - if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() - && Some(proj.def_id) == self.tcx.lang_items().fn_once_output() - // for existential projection, substs are shifted over by 1 - && let ty::Tuple(args) = proj.substs.type_at(0).kind() - { - Some(( - DefIdOrName::Name("trait object"), - pred.rebind(proj.term.ty().unwrap()), - pred.rebind(args.as_slice()), - )) - } else { - None - } - }) - } - ty::Param(param) => { - let def_id = self.tcx.generics_of(self.body_id.owner).type_param(¶m, self.tcx).def_id; - self.tcx.predicates_of(self.body_id.owner).predicates.iter().find_map(|(pred, _)| { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() - && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() - && proj.projection_ty.self_ty() == found - // args tuple will always be substs[1] - && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() - { - Some(( - DefIdOrName::DefId(def_id), - pred.kind().rebind(proj.term.ty().unwrap()), - pred.kind().rebind(args.as_slice()), - )) - } else { - None - } - }) - } - _ => None, - } - }) else { return None; }; - - let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output); - let inputs = inputs - .skip_binder() - .iter() - .map(|ty| { - self.replace_bound_vars_with_fresh_vars( - expr.span, - infer::FnCall, - inputs.rebind(*ty), - ) - }) - .collect(); - - // We don't want to register any extra obligations, which should be - // implied by wf, but also because that would possibly result in - // erroneous errors later on. - let infer::InferOk { value: output, obligations: _ } = - self.at(&self.misc(expr.span), self.param_env).normalize(output); - - if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) } + self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty) } pub fn suggest_two_fn_call( @@ -267,9 +176,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_ty: Ty<'tcx>, can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool, ) -> bool { - let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_expr, lhs_ty) + let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty) else { return false; }; - let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_expr, rhs_ty) + let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty) else { return false; }; if can_satisfy(lhs_output_ty, rhs_output_ty) { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 62e80659486a8..963f18447c05b 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2655,8 +2655,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found: Ty<'tcx>, expected: Ty<'tcx>, ) -> bool { - let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(expr, found) - else { return false; }; + let Some((_def_id_or_name, output, _inputs)) = + self.extract_callable_info(found) else { + return false; + }; if !self.can_coerce(output, expected) { return false; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 5f06c4d82828e..e11db925a6270 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2884,6 +2884,7 @@ impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor { } } +#[derive(Copy, Clone)] pub enum DefIdOrName { DefId(DefId), Name(&'static str), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 439854958270c..81e5c10e94b58 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -213,6 +213,13 @@ pub trait TypeErrCtxtExt<'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool; + fn extract_callable_info( + &self, + hir_id: HirId, + param_env: ty::ParamEnv<'tcx>, + found: Ty<'tcx>, + ) -> Option<(DefIdOrName, Ty<'tcx>, Vec>)>; + fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, @@ -882,92 +889,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return false; } - // This is duplicated from `extract_callable_info` in typeck, which - // relies on autoderef, so we can't use it here. - let found = trait_pred.self_ty().skip_binder().peel_refs(); - let Some((def_id_or_name, output, inputs)) = (match *found.kind() - { - ty::FnPtr(fn_sig) => { - Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())) - } - ty::FnDef(def_id, _) => { - let fn_sig = found.fn_sig(self.tcx); - Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs())) - } - ty::Closure(def_id, substs) => { - let fn_sig = substs.as_closure().sig(); - Some(( - DefIdOrName::DefId(def_id), - fn_sig.output(), - fn_sig.inputs().map_bound(|inputs| &inputs[1..]), - )) - } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() - && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() - // args tuple will always be substs[1] - && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() - { - Some(( - DefIdOrName::DefId(def_id), - pred.kind().rebind(proj.term.ty().unwrap()), - pred.kind().rebind(args.as_slice()), - )) - } else { - None - } - }) - } - ty::Dynamic(data, _, ty::Dyn) => { - data.iter().find_map(|pred| { - if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() - && Some(proj.def_id) == self.tcx.lang_items().fn_once_output() - // for existential projection, substs are shifted over by 1 - && let ty::Tuple(args) = proj.substs.type_at(0).kind() - { - Some(( - DefIdOrName::Name("trait object"), - pred.rebind(proj.term.ty().unwrap()), - pred.rebind(args.as_slice()), - )) - } else { - None - } - }) - } - ty::Param(_) => { - obligation.param_env.caller_bounds().iter().find_map(|pred| { - if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() - && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() - && proj.projection_ty.self_ty() == found - // args tuple will always be substs[1] - && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() - { - Some(( - DefIdOrName::Name("type parameter"), - pred.kind().rebind(proj.term.ty().unwrap()), - pred.kind().rebind(args.as_slice()), - )) - } else { - None - } - }) - } - _ => None, - }) else { return false; }; - let output = self.replace_bound_vars_with_fresh_vars( - obligation.cause.span, + let self_ty = self.replace_bound_vars_with_fresh_vars( + DUMMY_SP, LateBoundRegionConversionTime::FnCall, - output, + trait_pred.self_ty(), ); - let inputs = inputs.skip_binder().iter().map(|ty| { - self.replace_bound_vars_with_fresh_vars( - obligation.cause.span, - LateBoundRegionConversionTime::FnCall, - inputs.rebind(*ty), - ) - }); + + // This is duplicated from `extract_callable_info` in typeck, which + // relies on autoderef, so we can't use it here. + let Some((def_id_or_name, output, inputs)) = self.extract_callable_info( + obligation.cause.body_id, + obligation.param_env, + self_ty, + ) else { return false; }; // Remapping bound vars here let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output)); @@ -995,6 +929,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }; let args = inputs + .into_iter() .map(|ty| { if ty.is_suggestable(self.tcx, false) { format!("/* {ty} */") @@ -1158,6 +1093,126 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { false } + /// Extracts information about a callable type for diagnostics. This is a + /// heuristic -- it doesn't necessarily mean that a type is always callable, + /// because the callable type must also be well-formed to be called. + fn extract_callable_info( + &self, + hir_id: HirId, + param_env: ty::ParamEnv<'tcx>, + found: Ty<'tcx>, + ) -> Option<(DefIdOrName, Ty<'tcx>, Vec>)> { + // Autoderef is useful here because sometimes we box callables, etc. + let Some((def_id_or_name, output, inputs)) = Autoderef::new( + self, + param_env, + hir_id, + DUMMY_SP, + found, + ).silence_errors().find_map(|(found, _)| { + match *found.kind() { + ty::FnPtr(fn_sig) => + Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())), + ty::FnDef(def_id, _) => { + let fn_sig = found.fn_sig(self.tcx); + Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs())) + } + ty::Closure(def_id, substs) => { + let fn_sig = substs.as_closure().sig(); + Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..]))) + } + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| { + if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() + && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() + // args tuple will always be substs[1] + && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() + { + Some(( + DefIdOrName::DefId(def_id), + pred.kind().rebind(proj.term.ty().unwrap()), + pred.kind().rebind(args.as_slice()), + )) + } else { + None + } + }) + } + ty::Dynamic(data, _, ty::Dyn) => { + data.iter().find_map(|pred| { + if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() + && Some(proj.def_id) == self.tcx.lang_items().fn_once_output() + // for existential projection, substs are shifted over by 1 + && let ty::Tuple(args) = proj.substs.type_at(0).kind() + { + Some(( + DefIdOrName::Name("trait object"), + pred.rebind(proj.term.ty().unwrap()), + pred.rebind(args.as_slice()), + )) + } else { + None + } + }) + } + ty::Param(param) => { + let generics = self.tcx.generics_of(hir_id.owner.to_def_id()); + let name = if generics.count() > param.index as usize + && let def = generics.param_at(param.index as usize, self.tcx) + && matches!(def.kind, ty::GenericParamDefKind::Type { .. }) + && def.name == param.name + { + DefIdOrName::DefId(def.def_id) + } else { + DefIdOrName::Name("type parameter") + }; + param_env.caller_bounds().iter().find_map(|pred| { + if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder() + && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() + && proj.projection_ty.self_ty() == found + // args tuple will always be substs[1] + && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind() + { + Some(( + name, + pred.kind().rebind(proj.term.ty().unwrap()), + pred.kind().rebind(args.as_slice()), + )) + } else { + None + } + }) + } + _ => None, + } + }) else { return None; }; + + let output = self.replace_bound_vars_with_fresh_vars( + DUMMY_SP, + LateBoundRegionConversionTime::FnCall, + output, + ); + let inputs = inputs + .skip_binder() + .iter() + .map(|ty| { + self.replace_bound_vars_with_fresh_vars( + DUMMY_SP, + LateBoundRegionConversionTime::FnCall, + inputs.rebind(*ty), + ) + }) + .collect(); + + // We don't want to register any extra obligations, which should be + // implied by wf, but also because that would possibly result in + // erroneous errors later on. + let InferOk { value: output, obligations: _ } = + self.at(&ObligationCause::dummy(), param_env).normalize(output); + + if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) } + } + fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, diff --git a/src/test/ui/suggestions/call-on-unimplemented-with-autoderef.rs b/src/test/ui/suggestions/call-on-unimplemented-with-autoderef.rs new file mode 100644 index 0000000000000..9021dd752e7e9 --- /dev/null +++ b/src/test/ui/suggestions/call-on-unimplemented-with-autoderef.rs @@ -0,0 +1,13 @@ +trait Foo {} + +impl Foo for i32 {} + +fn needs_foo(_: impl Foo) {} + +fn test(x: &Box i32>) { + needs_foo(x); + //~^ ERROR the trait bound + //~| HELP use parentheses to call this trait object +} + +fn main() {} diff --git a/src/test/ui/suggestions/call-on-unimplemented-with-autoderef.stderr b/src/test/ui/suggestions/call-on-unimplemented-with-autoderef.stderr new file mode 100644 index 0000000000000..90f44cce06e44 --- /dev/null +++ b/src/test/ui/suggestions/call-on-unimplemented-with-autoderef.stderr @@ -0,0 +1,21 @@ +error[E0277]: the trait bound `&Box i32>: Foo` is not satisfied + --> $DIR/call-on-unimplemented-with-autoderef.rs:8:15 + | +LL | needs_foo(x); + | --------- ^ the trait `Foo` is not implemented for `&Box i32>` + | | + | required by a bound introduced by this call + | +note: required by a bound in `needs_foo` + --> $DIR/call-on-unimplemented-with-autoderef.rs:5:22 + | +LL | fn needs_foo(_: impl Foo) {} + | ^^^ required by this bound in `needs_foo` +help: use parentheses to call this trait object + | +LL | needs_foo(x()); + | ++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 2024aa48b4e92894e6f780a13c03db7605e1a5f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 1 Jan 2023 18:43:47 -0800 Subject: [PATCH 07/12] Make `&`-removal suggestion verbose --- .../src/traits/error_reporting/suggestions.rs | 71 ++++++++++++------- .../impl-trait/in-trait/issue-102140.stderr | 12 ++-- tests/ui/not-panic/not-panic-safe.stderr | 5 +- .../suggestions/suggest-remove-refs-1.stderr | 10 +-- .../suggestions/suggest-remove-refs-2.stderr | 10 +-- .../suggestions/suggest-remove-refs-3.stderr | 20 +++--- .../suggestions/suggest-remove-refs-4.fixed | 5 ++ tests/ui/suggestions/suggest-remove-refs-4.rs | 5 ++ .../suggestions/suggest-remove-refs-4.stderr | 17 +++++ tests/ui/typeck/issue-57404.stderr | 11 +-- 10 files changed, 113 insertions(+), 53 deletions(-) create mode 100644 tests/ui/suggestions/suggest-remove-refs-4.fixed create mode 100644 tests/ui/suggestions/suggest-remove-refs-4.rs create mode 100644 tests/ui/suggestions/suggest-remove-refs-4.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 439854958270c..553144078ee4d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1358,26 +1358,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { - let span = obligation.cause.span; - + let mut span = obligation.cause.span; + while span.desugaring_kind().is_some() { + // Remove all the hir desugaring contexts while maintaining the macro contexts. + span.remove_mark(); + } let mut suggested = false; - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - let refs_number = - snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count(); - if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) { - // Do not suggest removal of borrow from type arguments. - return false; - } - // Skipping binder here, remapping below - let mut suggested_ty = trait_pred.self_ty().skip_binder(); + let mut expr_finder = super::FindExprBySpan { span, result: None }; + let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else { + return false; + }; + expr_finder.visit_expr(&body); + let mut count = 0; + let mut suggestions = vec![]; + let Some(mut expr) = expr_finder.result else { return false; }; + // Skipping binder here, remapping below + let mut suggested_ty = trait_pred.self_ty().skip_binder(); + + 'outer: loop { + while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind { + count += 1; + let span = if expr.span.eq_ctxt(borrowed.span) { + expr.span.until(borrowed.span) + } else { + expr.span.with_hi(expr.span.lo() + BytePos(1)) + }; + suggestions.push((span, String::new())); - for refs_remaining in 0..refs_number { let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else { break; }; suggested_ty = *inner_ty; + expr = borrowed; + // Remapping bound vars here let trait_pred_and_suggested_ty = trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty)); @@ -1388,25 +1403,33 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); if self.predicate_may_hold(&new_obligation) { - let sp = self - .tcx - .sess - .source_map() - .span_take_while(span, |c| c.is_whitespace() || *c == '&'); - - let remove_refs = refs_remaining + 1; - - let msg = if remove_refs == 1 { + let msg = if count == 1 { "consider removing the leading `&`-reference".to_string() } else { - format!("consider removing {} leading `&`-references", remove_refs) + format!("consider removing {count} leading `&`-references") }; - err.span_suggestion_short(sp, &msg, "", Applicability::MachineApplicable); + err.multipart_suggestion_verbose( + &msg, + suggestions, + Applicability::MachineApplicable, + ); suggested = true; - break; + break 'outer; } } + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind + && let hir::def::Res::Local(hir_id) = path.res + && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id) + && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id) + && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id) + && let None = local.ty + && let Some(binding_expr) = local.init + { + expr = binding_expr; + } else { + break 'outer; + } } suggested } diff --git a/tests/ui/impl-trait/in-trait/issue-102140.stderr b/tests/ui/impl-trait/in-trait/issue-102140.stderr index 08602185f50ca..18bb63745d7a5 100644 --- a/tests/ui/impl-trait/in-trait/issue-102140.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102140.stderr @@ -2,11 +2,15 @@ error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied --> $DIR/issue-102140.rs:23:22 | LL | MyTrait::foo(&self) - | ------------ -^^^^ - | | | - | | the trait `MyTrait` is not implemented for `&dyn MyTrait` - | | help: consider removing the leading `&`-reference + | ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` + | | | required by a bound introduced by this call + | +help: consider removing the leading `&`-reference + | +LL - MyTrait::foo(&self) +LL + MyTrait::foo(self) + | error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied --> $DIR/issue-102140.rs:23:9 diff --git a/tests/ui/not-panic/not-panic-safe.stderr b/tests/ui/not-panic/not-panic-safe.stderr index 2cd51a439988d..013c5ee704458 100644 --- a/tests/ui/not-panic/not-panic-safe.stderr +++ b/tests/ui/not-panic/not-panic-safe.stderr @@ -2,10 +2,7 @@ error[E0277]: the type `&mut i32` may not be safely transferred across an unwind --> $DIR/not-panic-safe.rs:8:14 | LL | assert::<&mut i32>(); - | -^^^^^^^ - | | - | `&mut i32` may not be safely transferred across an unwind boundary - | help: consider removing the leading `&`-reference + | ^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary | = help: the trait `UnwindSafe` is not implemented for `&mut i32` = note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32` diff --git a/tests/ui/suggestions/suggest-remove-refs-1.stderr b/tests/ui/suggestions/suggest-remove-refs-1.stderr index 1a843f3f5097b..387770535f689 100644 --- a/tests/ui/suggestions/suggest-remove-refs-1.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-1.stderr @@ -2,13 +2,15 @@ error[E0277]: `&Enumerate>` is not an iterator --> $DIR/suggest-remove-refs-1.rs:6:19 | LL | for (i, _) in &v.iter().enumerate() { - | -^^^^^^^^^^^^^^^^^^^^ - | | - | `&Enumerate>` is not an iterator - | help: consider removing the leading `&`-reference + | ^^^^^^^^^^^^^^^^^^^^^ `&Enumerate>` is not an iterator | = help: the trait `Iterator` is not implemented for `&Enumerate>` = note: required for `&Enumerate>` to implement `IntoIterator` +help: consider removing the leading `&`-reference + | +LL - for (i, _) in &v.iter().enumerate() { +LL + for (i, _) in v.iter().enumerate() { + | error: aborting due to previous error diff --git a/tests/ui/suggestions/suggest-remove-refs-2.stderr b/tests/ui/suggestions/suggest-remove-refs-2.stderr index f39361d529fbf..1632b2abb2f87 100644 --- a/tests/ui/suggestions/suggest-remove-refs-2.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-2.stderr @@ -2,13 +2,15 @@ error[E0277]: `&&&&&Enumerate>` is not an iterat --> $DIR/suggest-remove-refs-2.rs:6:19 | LL | for (i, _) in & & & & &v.iter().enumerate() { - | ---------^^^^^^^^^^^^^^^^^^^^ - | | - | `&&&&&Enumerate>` is not an iterator - | help: consider removing 5 leading `&`-references + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&&&&&Enumerate>` is not an iterator | = help: the trait `Iterator` is not implemented for `&&&&&Enumerate>` = note: required for `&&&&&Enumerate>` to implement `IntoIterator` +help: consider removing 5 leading `&`-references + | +LL - for (i, _) in & & & & &v.iter().enumerate() { +LL + for (i, _) in v.iter().enumerate() { + | error: aborting due to previous error diff --git a/tests/ui/suggestions/suggest-remove-refs-3.stderr b/tests/ui/suggestions/suggest-remove-refs-3.stderr index 31cca323d0e42..7bf421a7729df 100644 --- a/tests/ui/suggestions/suggest-remove-refs-3.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-3.stderr @@ -1,18 +1,20 @@ error[E0277]: `&&&&&Enumerate>` is not an iterator --> $DIR/suggest-remove-refs-3.rs:6:19 | -LL | for (i, _) in & & & - | ____________________^ - | | ___________________| - | || -LL | || & &v - | ||___________- help: consider removing 5 leading `&`-references -LL | | .iter() -LL | | .enumerate() { - | |_____________________^ `&&&&&Enumerate>` is not an iterator +LL | for (i, _) in & & & + | ___________________^ +LL | | & &v +LL | | .iter() +LL | | .enumerate() { + | |____________________^ `&&&&&Enumerate>` is not an iterator | = help: the trait `Iterator` is not implemented for `&&&&&Enumerate>` = note: required for `&&&&&Enumerate>` to implement `IntoIterator` +help: consider removing 5 leading `&`-references + | +LL - for (i, _) in & & & +LL + for (i, _) in v + | error: aborting due to previous error diff --git a/tests/ui/suggestions/suggest-remove-refs-4.fixed b/tests/ui/suggestions/suggest-remove-refs-4.fixed new file mode 100644 index 0000000000000..dd63d21597243 --- /dev/null +++ b/tests/ui/suggestions/suggest-remove-refs-4.fixed @@ -0,0 +1,5 @@ +// run-rustfix +fn main() { + let foo = [1,2,3].iter(); + for _i in foo {} //~ ERROR E0277 +} diff --git a/tests/ui/suggestions/suggest-remove-refs-4.rs b/tests/ui/suggestions/suggest-remove-refs-4.rs new file mode 100644 index 0000000000000..3c3d9b1b3f981 --- /dev/null +++ b/tests/ui/suggestions/suggest-remove-refs-4.rs @@ -0,0 +1,5 @@ +// run-rustfix +fn main() { + let foo = &[1,2,3].iter(); + for _i in &foo {} //~ ERROR E0277 +} diff --git a/tests/ui/suggestions/suggest-remove-refs-4.stderr b/tests/ui/suggestions/suggest-remove-refs-4.stderr new file mode 100644 index 0000000000000..e4ad17e06716f --- /dev/null +++ b/tests/ui/suggestions/suggest-remove-refs-4.stderr @@ -0,0 +1,17 @@ +error[E0277]: `&&std::slice::Iter<'_, {integer}>` is not an iterator + --> $DIR/suggest-remove-refs-4.rs:4:15 + | +LL | for _i in &foo {} + | ^^^^ `&&std::slice::Iter<'_, {integer}>` is not an iterator + | + = help: the trait `Iterator` is not implemented for `&&std::slice::Iter<'_, {integer}>` + = note: required for `&&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` +help: consider removing 2 leading `&`-references + | +LL ~ let foo = [1,2,3].iter(); +LL ~ for _i in foo {} + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/typeck/issue-57404.stderr b/tests/ui/typeck/issue-57404.stderr index 5065ac32ad2b0..a631dbb39fb8f 100644 --- a/tests/ui/typeck/issue-57404.stderr +++ b/tests/ui/typeck/issue-57404.stderr @@ -2,14 +2,17 @@ error[E0277]: `&mut ()` is not a tuple --> $DIR/issue-57404.rs:6:41 | LL | handlers.unwrap().as_mut().call_mut(&mut ()); - | -------- -^^^^^^ - | | | - | | the trait `Tuple` is not implemented for `&mut ()` - | | help: consider removing the leading `&`-reference + | -------- ^^^^^^^ the trait `Tuple` is not implemented for `&mut ()` + | | | required by a bound introduced by this call | note: required by a bound in `call_mut` --> $SRC_DIR/core/src/ops/function.rs:LL:COL +help: consider removing the leading `&`-reference + | +LL - handlers.unwrap().as_mut().call_mut(&mut ()); +LL + handlers.unwrap().as_mut().call_mut(()); + | error: aborting due to previous error From ce83be4af8462d8d6fadb2829c8ca7f4353fca9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 1 Jan 2023 19:35:53 -0800 Subject: [PATCH 08/12] Account for type params --- .../src/traits/error_reporting/suggestions.rs | 88 +++++++++++++------ tests/ui/kindck/kindck-copy.stderr | 12 ++- tests/ui/not-panic/not-panic-safe.rs | 4 +- tests/ui/not-panic/not-panic-safe.stderr | 15 ++-- 4 files changed, 81 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 553144078ee4d..bcc8200480497 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1363,19 +1363,70 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Remove all the hir desugaring contexts while maintaining the macro contexts. span.remove_mark(); } - let mut suggested = false; - - let mut expr_finder = super::FindExprBySpan { span, result: None }; + let mut expr_finder = super::FindExprBySpan::new(span); let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else { return false; }; expr_finder.visit_expr(&body); + let mut maybe_suggest = |suggested_ty, count, suggestions| { + // Remapping bound vars here + let trait_pred_and_suggested_ty = + trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty)); + + let new_obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + trait_pred_and_suggested_ty, + ); + + if self.predicate_may_hold(&new_obligation) { + let msg = if count == 1 { + "consider removing the leading `&`-reference".to_string() + } else { + format!("consider removing {count} leading `&`-references") + }; + + err.multipart_suggestion_verbose( + &msg, + suggestions, + Applicability::MachineApplicable, + ); + true + } else { + false + } + }; + + // Maybe suggest removal of borrows from types in type parameters, like in + // `src/test/ui/not-panic/not-panic-safe.rs`. let mut count = 0; let mut suggestions = vec![]; - let Some(mut expr) = expr_finder.result else { return false; }; // Skipping binder here, remapping below let mut suggested_ty = trait_pred.self_ty().skip_binder(); + if let Some(mut hir_ty) = expr_finder.ty_result { + while let hir::TyKind::Ref(_, mut_ty) = &hir_ty.kind { + count += 1; + let span = hir_ty.span.until(mut_ty.ty.span); + suggestions.push((span, String::new())); + + let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else { + break; + }; + suggested_ty = *inner_ty; + + hir_ty = mut_ty.ty; + + if maybe_suggest(suggested_ty, count, suggestions.clone()) { + return true; + } + } + } + // Maybe suggest removal of borrows from expressions, like in `for i in &&&foo {}`. + let Some(mut expr) = expr_finder.result else { return false; }; + let mut count = 0; + let mut suggestions = vec![]; + // Skipping binder here, remapping below + let mut suggested_ty = trait_pred.self_ty().skip_binder(); 'outer: loop { while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind { count += 1; @@ -1387,35 +1438,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { suggestions.push((span, String::new())); let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else { - break; + break 'outer; }; suggested_ty = *inner_ty; expr = borrowed; - // Remapping bound vars here - let trait_pred_and_suggested_ty = - trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty)); - - let new_obligation = self.mk_trait_obligation_with_new_self_ty( - obligation.param_env, - trait_pred_and_suggested_ty, - ); - - if self.predicate_may_hold(&new_obligation) { - let msg = if count == 1 { - "consider removing the leading `&`-reference".to_string() - } else { - format!("consider removing {count} leading `&`-references") - }; - - err.multipart_suggestion_verbose( - &msg, - suggestions, - Applicability::MachineApplicable, - ); - suggested = true; - break 'outer; + if maybe_suggest(suggested_ty, count, suggestions.clone()) { + return true; } } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind @@ -1431,7 +1461,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { break 'outer; } } - suggested + false } fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) { diff --git a/tests/ui/kindck/kindck-copy.stderr b/tests/ui/kindck/kindck-copy.stderr index 9af89159a8cfc..aee2aa98a60c2 100644 --- a/tests/ui/kindck/kindck-copy.stderr +++ b/tests/ui/kindck/kindck-copy.stderr @@ -4,12 +4,16 @@ error[E0277]: the trait bound `&'static mut isize: Copy` is not satisfied LL | assert_copy::<&'static mut isize>(); | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize` | - = help: the trait `Copy` is implemented for `isize` note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 | LL | fn assert_copy() { } | ^^^^ required by this bound in `assert_copy` +help: consider removing the leading `&`-reference + | +LL - assert_copy::<&'static mut isize>(); +LL + assert_copy::(); + | error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied --> $DIR/kindck-copy.rs:28:19 @@ -17,12 +21,16 @@ error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied LL | assert_copy::<&'a mut isize>(); | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize` | - = help: the trait `Copy` is implemented for `isize` note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 | LL | fn assert_copy() { } | ^^^^ required by this bound in `assert_copy` +help: consider removing the leading `&`-reference + | +LL - assert_copy::<&'a mut isize>(); +LL + assert_copy::(); + | error[E0277]: the trait bound `Box: Copy` is not satisfied --> $DIR/kindck-copy.rs:31:19 diff --git a/tests/ui/not-panic/not-panic-safe.rs b/tests/ui/not-panic/not-panic-safe.rs index 4165c5dc13aaa..1b3c6482ce94f 100644 --- a/tests/ui/not-panic/not-panic-safe.rs +++ b/tests/ui/not-panic/not-panic-safe.rs @@ -5,6 +5,6 @@ use std::panic::UnwindSafe; fn assert() {} fn main() { - assert::<&mut i32>(); - //~^ ERROR the type `&mut i32` may not be safely transferred across an unwind boundary + assert::<&mut &mut &i32>(); + //~^ ERROR the type `&mut &mut &i32` may not be safely transferred across an unwind boundary } diff --git a/tests/ui/not-panic/not-panic-safe.stderr b/tests/ui/not-panic/not-panic-safe.stderr index 013c5ee704458..37a6aee390669 100644 --- a/tests/ui/not-panic/not-panic-safe.stderr +++ b/tests/ui/not-panic/not-panic-safe.stderr @@ -1,16 +1,21 @@ -error[E0277]: the type `&mut i32` may not be safely transferred across an unwind boundary +error[E0277]: the type `&mut &mut &i32` may not be safely transferred across an unwind boundary --> $DIR/not-panic-safe.rs:8:14 | -LL | assert::<&mut i32>(); - | ^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary +LL | assert::<&mut &mut &i32>(); + | ^^^^^^^^^^^^^^ `&mut &mut &i32` may not be safely transferred across an unwind boundary | - = help: the trait `UnwindSafe` is not implemented for `&mut i32` - = note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32` + = help: the trait `UnwindSafe` is not implemented for `&mut &mut &i32` + = note: `UnwindSafe` is implemented for `&&mut &i32`, but not for `&mut &mut &i32` note: required by a bound in `assert` --> $DIR/not-panic-safe.rs:5:14 | LL | fn assert() {} | ^^^^^^^^^^ required by this bound in `assert` +help: consider removing 2 leading `&`-references + | +LL - assert::<&mut &mut &i32>(); +LL + assert::<&i32>(); + | error: aborting due to previous error From bb7211702e17dd2d10a6d04962d37331ea032010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 7 Jan 2023 19:35:40 +0000 Subject: [PATCH 09/12] fix rebase --- .../src/traits/error_reporting/suggestions.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index bcc8200480497..7e900fe0034b4 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1451,8 +1451,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind && let hir::def::Res::Local(hir_id) = path.res && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id) - && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id) - && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id) + && let Some(hir::Node::Local(local)) = self.tcx.hir().find_parent(binding.hir_id) && let None = local.ty && let Some(binding_expr) = local.init { From 8b8cce16bfb74bcb06250ed3b9b3dc8c97e1ee4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 9 Jan 2023 04:43:18 +0000 Subject: [PATCH 10/12] Use the root trait predicate to determine whether to remove references Fix #84837. --- .../src/traits/error_reporting/suggestions.rs | 8 ++++ ...ypeck-default-trait-impl-precedence.stderr | 6 ++- tests/ui/not-panic/not-panic-safe-4.stderr | 10 +++++ .../suggestions/suggest-remove-refs-5.fixed | 8 ++++ tests/ui/suggestions/suggest-remove-refs-5.rs | 8 ++++ .../suggestions/suggest-remove-refs-5.stderr | 37 +++++++++++++++++++ 6 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 tests/ui/suggestions/suggest-remove-refs-5.fixed create mode 100644 tests/ui/suggestions/suggest-remove-refs-5.rs create mode 100644 tests/ui/suggestions/suggest-remove-refs-5.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 7e900fe0034b4..678e7b8782989 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1359,6 +1359,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { let mut span = obligation.cause.span; + let mut trait_pred = trait_pred; + let mut code = obligation.cause.code(); + while let Some((c, Some(parent_trait_pred))) = code.parent() { + // We want the root obligation, in order to detect properly handle + // `for _ in &mut &mut vec![] {}`. + code = c; + trait_pred = parent_trait_pred; + } while span.desugaring_kind().is_some() { // Remove all the hir desugaring contexts while maintaining the macro contexts. span.remove_mark(); diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr index ce7095664c11a..32256ed69a769 100644 --- a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr +++ b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr @@ -4,7 +4,6 @@ error[E0277]: the trait bound `u32: Signed` is not satisfied LL | is_defaulted::<&'static u32>(); | ^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32` | - = help: the trait `Signed` is implemented for `i32` note: required for `&'static u32` to implement `Defaulted` --> $DIR/typeck-default-trait-impl-precedence.rs:10:19 | @@ -15,6 +14,11 @@ note: required by a bound in `is_defaulted` | LL | fn is_defaulted() { } | ^^^^^^^^^ required by this bound in `is_defaulted` +help: consider removing the leading `&`-reference + | +LL - is_defaulted::<&'static u32>(); +LL + is_defaulted::(); + | error: aborting due to previous error diff --git a/tests/ui/not-panic/not-panic-safe-4.stderr b/tests/ui/not-panic/not-panic-safe-4.stderr index fc1c594d0d422..9428c125651ec 100644 --- a/tests/ui/not-panic/not-panic-safe-4.stderr +++ b/tests/ui/not-panic/not-panic-safe-4.stderr @@ -12,6 +12,11 @@ note: required by a bound in `assert` | LL | fn assert() {} | ^^^^^^^^^^ required by this bound in `assert` +help: consider removing the leading `&`-reference + | +LL - assert::<&RefCell>(); +LL + assert::>(); + | error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-4.rs:9:14 @@ -28,6 +33,11 @@ note: required by a bound in `assert` | LL | fn assert() {} | ^^^^^^^^^^ required by this bound in `assert` +help: consider removing the leading `&`-reference + | +LL - assert::<&RefCell>(); +LL + assert::>(); + | error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/suggest-remove-refs-5.fixed b/tests/ui/suggestions/suggest-remove-refs-5.fixed new file mode 100644 index 0000000000000..9f59f9c199a33 --- /dev/null +++ b/tests/ui/suggestions/suggest-remove-refs-5.fixed @@ -0,0 +1,8 @@ +// run-rustfix +fn main() { + let v = &mut Vec::::new(); + for _ in v {} //~ ERROR E0277 + + let v = &mut [1u8]; + for _ in v {} //~ ERROR E0277 +} diff --git a/tests/ui/suggestions/suggest-remove-refs-5.rs b/tests/ui/suggestions/suggest-remove-refs-5.rs new file mode 100644 index 0000000000000..d56aa0c9ca479 --- /dev/null +++ b/tests/ui/suggestions/suggest-remove-refs-5.rs @@ -0,0 +1,8 @@ +// run-rustfix +fn main() { + let v = &mut &mut Vec::::new(); + for _ in &mut &mut v {} //~ ERROR E0277 + + let v = &mut &mut [1u8]; + for _ in &mut v {} //~ ERROR E0277 +} diff --git a/tests/ui/suggestions/suggest-remove-refs-5.stderr b/tests/ui/suggestions/suggest-remove-refs-5.stderr new file mode 100644 index 0000000000000..7de84d6122b58 --- /dev/null +++ b/tests/ui/suggestions/suggest-remove-refs-5.stderr @@ -0,0 +1,37 @@ +error[E0277]: `Vec` is not an iterator + --> $DIR/suggest-remove-refs-5.rs:4:14 + | +LL | for _ in &mut &mut v {} + | ^^^^^^^^^^^ `Vec` is not an iterator; try calling `.into_iter()` or `.iter()` + | + = help: the trait `Iterator` is not implemented for `Vec` + = note: required for `&mut Vec` to implement `Iterator` + = note: 3 redundant requirements hidden + = note: required for `&mut &mut &mut &mut Vec` to implement `Iterator` + = note: required for `&mut &mut &mut &mut Vec` to implement `IntoIterator` +help: consider removing 3 leading `&`-references + | +LL ~ let v = &mut Vec::::new(); +LL ~ for _ in v {} + | + +error[E0277]: `[u8; 1]` is not an iterator + --> $DIR/suggest-remove-refs-5.rs:7:14 + | +LL | for _ in &mut v {} + | ^^^^^^ `[u8; 1]` is not an iterator; try calling `.into_iter()` or `.iter()` + | + = help: the trait `Iterator` is not implemented for `[u8; 1]` + = note: required for `&mut [u8; 1]` to implement `Iterator` + = note: 2 redundant requirements hidden + = note: required for `&mut &mut &mut [u8; 1]` to implement `Iterator` + = note: required for `&mut &mut &mut [u8; 1]` to implement `IntoIterator` +help: consider removing 2 leading `&`-references + | +LL ~ let v = &mut [1u8]; +LL ~ for _ in v {} + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From 48b7e2a5b93e01fbf30484a8dd4f8ead24db0196 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Mon, 31 Oct 2022 13:07:40 +0100 Subject: [PATCH 11/12] Stabilize `::{core,std}::pin::pin!` --- library/core/src/pin.rs | 10 +++------- library/core/tests/lib.rs | 1 - src/tools/miri/tests/pass/issues/issue-miri-2068.rs | 2 -- .../pass/stacked-borrows/future-self-referential.rs | 2 -- tests/ui/pin-macro/cant_access_internals.rs | 1 - tests/ui/pin-macro/cant_access_internals.stderr | 2 +- .../pin-macro/lifetime_errors_on_promotion_misusage.rs | 1 - .../lifetime_errors_on_promotion_misusage.stderr | 4 ++-- 8 files changed, 6 insertions(+), 17 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 3f8acc8505ff1..2eb29d4f9c574 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -622,9 +622,8 @@ impl Pin

{ /// that the closure is pinned. /// /// The better alternative is to avoid all that trouble and do the pinning in the outer function - /// instead (here using the unstable `pin` macro): + /// instead (here using the [`pin!`][crate::pin::pin] macro): /// ``` - /// #![feature(pin_macro)] /// use std::pin::pin; /// use std::task::Context; /// use std::future::Future; @@ -1026,7 +1025,6 @@ impl DispatchFromDyn> for Pin

where P: DispatchFromDyn {} /// ### Basic usage /// /// ```rust -/// #![feature(pin_macro)] /// # use core::marker::PhantomPinned as Foo; /// use core::pin::{pin, Pin}; /// @@ -1044,7 +1042,6 @@ impl DispatchFromDyn> for Pin

where P: DispatchFromDyn {} /// ### Manually polling a `Future` (without `Unpin` bounds) /// /// ```rust -/// #![feature(pin_macro)] /// use std::{ /// future::Future, /// pin::pin, @@ -1083,7 +1080,7 @@ impl DispatchFromDyn> for Pin

where P: DispatchFromDyn {} /// ### With `Generator`s /// /// ```rust -/// #![feature(generators, generator_trait, pin_macro)] +/// #![feature(generators, generator_trait)] /// use core::{ /// ops::{Generator, GeneratorState}, /// pin::pin, @@ -1126,7 +1123,6 @@ impl DispatchFromDyn> for Pin

where P: DispatchFromDyn {} /// The following, for instance, fails to compile: /// /// ```rust,compile_fail -/// #![feature(pin_macro)] /// use core::pin::{pin, Pin}; /// # use core::{marker::PhantomPinned as Foo, mem::drop as stuff}; /// @@ -1168,7 +1164,7 @@ impl DispatchFromDyn> for Pin

where P: DispatchFromDyn {} /// constructor. /// /// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin -#[unstable(feature = "pin_macro", issue = "93178")] +#[stable(feature = "pin_macro", since = "CURRENT_RUSTC_VERSION")] #[rustc_macro_transparency = "semitransparent"] #[allow_internal_unstable(unsafe_pin_internals)] pub macro pin($value:expr $(,)?) { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index c910cb65c55de..42a26ae1675c1 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -48,7 +48,6 @@ #![feature(is_sorted)] #![feature(layout_for_ptr)] #![feature(pattern)] -#![feature(pin_macro)] #![feature(sort_internals)] #![feature(slice_take)] #![feature(slice_from_ptr_range)] diff --git a/src/tools/miri/tests/pass/issues/issue-miri-2068.rs b/src/tools/miri/tests/pass/issues/issue-miri-2068.rs index 7576ba78f607d..fe4078f77107b 100644 --- a/src/tools/miri/tests/pass/issues/issue-miri-2068.rs +++ b/src/tools/miri/tests/pass/issues/issue-miri-2068.rs @@ -1,5 +1,3 @@ -#![feature(pin_macro)] - use core::future::Future; use core::pin::Pin; use core::task::{Context, Poll}; diff --git a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs index 3ba21552fd362..96fc0be344dbf 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs @@ -1,5 +1,3 @@ -#![feature(pin_macro)] - use std::future::*; use std::marker::PhantomPinned; use std::pin::*; diff --git a/tests/ui/pin-macro/cant_access_internals.rs b/tests/ui/pin-macro/cant_access_internals.rs index 120d08894f8f7..5826a18b5718b 100644 --- a/tests/ui/pin-macro/cant_access_internals.rs +++ b/tests/ui/pin-macro/cant_access_internals.rs @@ -1,5 +1,4 @@ // edition:2018 -#![feature(pin_macro)] use core::{ marker::PhantomPinned, diff --git a/tests/ui/pin-macro/cant_access_internals.stderr b/tests/ui/pin-macro/cant_access_internals.stderr index 060c9c48c21c8..d43027657f046 100644 --- a/tests/ui/pin-macro/cant_access_internals.stderr +++ b/tests/ui/pin-macro/cant_access_internals.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'unsafe_pin_internals' - --> $DIR/cant_access_internals.rs:12:15 + --> $DIR/cant_access_internals.rs:11:15 | LL | mem::take(phantom_pinned.pointer); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs index ca2b6cf759376..59774bc753dc9 100644 --- a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs +++ b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs @@ -1,5 +1,4 @@ // edition:2018 -#![feature(pin_macro)] use core::{ convert::identity, diff --git a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr index fc1be052fb791..4ecc6370d3caa 100644 --- a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr +++ b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/lifetime_errors_on_promotion_misusage.rs:12:35 + --> $DIR/lifetime_errors_on_promotion_misusage.rs:11:35 | LL | let phantom_pinned = identity(pin!(PhantomPinned)); | ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -13,7 +13,7 @@ LL | stuff(phantom_pinned) = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0716]: temporary value dropped while borrowed - --> $DIR/lifetime_errors_on_promotion_misusage.rs:19:30 + --> $DIR/lifetime_errors_on_promotion_misusage.rs:18:30 | LL | let phantom_pinned = { | -------------- borrow later stored here From 621d4122413b371b0aaa53480d8efd80c4b5f0ba Mon Sep 17 00:00:00 2001 From: yanchen4791 Date: Mon, 26 Dec 2022 15:43:31 -0800 Subject: [PATCH 12/12] Fix invalid syntax in impl Trait parameter type suggestions for E0311 --- .../src/infer/error_reporting/mod.rs | 94 ++++++++++++--- tests/ui/error-codes/E0311.fixed | 13 +++ tests/ui/error-codes/E0311.rs | 4 + tests/ui/error-codes/E0311.stderr | 10 +- ...roducing-and-adding-missing-lifetime.fixed | 13 +++ ...introducing-and-adding-missing-lifetime.rs | 4 + ...oducing-and-adding-missing-lifetime.stderr | 10 +- .../suggestions/lifetimes/issue-105544.fixed | 45 +++++++ .../ui/suggestions/lifetimes/issue-105544.rs | 45 +++++++ .../suggestions/lifetimes/issue-105544.stderr | 110 ++++++++++++++++++ .../missing-lifetimes-in-signature-2.fixed | 29 +++++ .../missing-lifetimes-in-signature-2.rs | 3 + .../missing-lifetimes-in-signature-2.stderr | 10 +- .../missing-lifetimes-in-signature.stderr | 14 +-- 14 files changed, 365 insertions(+), 39 deletions(-) create mode 100644 tests/ui/error-codes/E0311.fixed create mode 100644 tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.fixed create mode 100644 tests/ui/suggestions/lifetimes/issue-105544.fixed create mode 100644 tests/ui/suggestions/lifetimes/issue-105544.rs create mode 100644 tests/ui/suggestions/lifetimes/issue-105544.stderr create mode 100644 tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.fixed diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 66db1a2f92890..9747f360eca48 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2144,18 +2144,21 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // suggest adding an explicit lifetime bound to it. let generics = self.tcx.generics_of(generic_param_scope); // type_param_span is (span, has_bounds) + let mut is_synthetic = false; + let mut ast_generics = None; let type_param_span = match bound_kind { GenericKind::Param(ref param) => { // Account for the case where `param` corresponds to `Self`, // which doesn't have the expected type argument. if !(generics.has_self && param.index == 0) { let type_param = generics.type_param(param, self.tcx); + is_synthetic = type_param.kind.is_synthetic(); type_param.def_id.as_local().map(|def_id| { // Get the `hir::Param` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: 'a'b`, // instead we suggest `T: 'a + 'b` in that case. let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - let ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id); + ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id); let bounds = ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id)); // `sp` only covers `T`, change it so that it covers @@ -2187,11 +2190,64 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .unwrap_or("'lt".to_string()) }; - let add_lt_sugg = generics - .params - .first() - .and_then(|param| param.def_id.as_local()) - .map(|def_id| (self.tcx.def_span(def_id).shrink_to_lo(), format!("{}, ", new_lt))); + let mut add_lt_suggs: Vec> = vec![]; + if is_synthetic { + if let Some(ast_generics) = ast_generics { + let named_lifetime_param_exist = ast_generics.params.iter().any(|p| { + matches!( + p.kind, + hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } + ) + }); + if named_lifetime_param_exist && let [param, ..] = ast_generics.params + { + add_lt_suggs.push(Some(( + self.tcx.def_span(param.def_id).shrink_to_lo(), + format!("{new_lt}, "), + ))); + } else { + add_lt_suggs + .push(Some((ast_generics.span.shrink_to_hi(), format!("<{new_lt}>")))); + } + } + } else { + if let [param, ..] = &generics.params[..] && let Some(def_id) = param.def_id.as_local() + { + add_lt_suggs + .push(Some((self.tcx.def_span(def_id).shrink_to_lo(), format!("{new_lt}, ")))); + } + } + + if let Some(ast_generics) = ast_generics { + for p in ast_generics.params { + if p.is_elided_lifetime() { + if self + .tcx + .sess + .source_map() + .span_to_prev_source(p.span.shrink_to_hi()) + .ok() + .map_or(false, |s| *s.as_bytes().last().unwrap() == b'&') + { + add_lt_suggs + .push(Some( + ( + p.span.shrink_to_hi(), + if let Ok(snip) = self.tcx.sess.source_map().span_to_next_source(p.span) + && snip.starts_with(' ') + { + format!("{new_lt}") + } else { + format!("{new_lt} ") + } + ) + )); + } else { + add_lt_suggs.push(Some((p.span.shrink_to_hi(), format!("<{new_lt}>")))); + } + } + } + } let labeled_user_string = match bound_kind { GenericKind::Param(ref p) => format!("the parameter type `{}`", p), @@ -2215,20 +2271,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); } - fn binding_suggestion( + fn binding_suggestion<'tcx, S: fmt::Display>( err: &mut Diagnostic, type_param_span: Option<(Span, bool)>, - bound_kind: GenericKind<'_>, + bound_kind: GenericKind<'tcx>, sub: S, - add_lt_sugg: Option<(Span, String)>, + add_lt_suggs: Vec>, ) { let msg = "consider adding an explicit lifetime bound"; if let Some((sp, has_lifetimes)) = type_param_span { let suggestion = if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) }; let mut suggestions = vec![(sp, suggestion)]; - if let Some(add_lt_sugg) = add_lt_sugg { - suggestions.push(add_lt_sugg); + for add_lt_sugg in add_lt_suggs { + if let Some(add_lt_sugg) = add_lt_sugg { + suggestions.push(add_lt_sugg); + } } err.multipart_suggestion_verbose( format!("{msg}..."), @@ -2252,9 +2310,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; let mut sugg = vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))]; - if let Some(lt) = add_lt_sugg.clone() { - sugg.push(lt); - sugg.rotate_right(1); + for add_lt_sugg in add_lt_suggs.clone() { + if let Some(lt) = add_lt_sugg { + sugg.push(lt); + sugg.rotate_right(1); + } } // `MaybeIncorrect` due to issue #41966. err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); @@ -2358,7 +2418,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // for the bound is not suitable for suggestions when `-Zverbose` is set because it // uses `Debug` output, so we handle it specially here so that suggestions are // always correct. - binding_suggestion(&mut err, type_param_span, bound_kind, name, None); + binding_suggestion(&mut err, type_param_span, bound_kind, name, vec![]); err } @@ -2371,7 +2431,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { "{} may not live long enough", labeled_user_string ); - binding_suggestion(&mut err, type_param_span, bound_kind, "'static", None); + binding_suggestion(&mut err, type_param_span, bound_kind, "'static", vec![]); err } @@ -2410,7 +2470,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { type_param_span, bound_kind, new_lt, - add_lt_sugg, + add_lt_suggs, ); } } diff --git a/tests/ui/error-codes/E0311.fixed b/tests/ui/error-codes/E0311.fixed new file mode 100644 index 0000000000000..4410a4d707af4 --- /dev/null +++ b/tests/ui/error-codes/E0311.fixed @@ -0,0 +1,13 @@ +// run-rustfix + +#![allow(warnings)] + +fn no_restriction<'a, T: 'a>(x: &'a ()) -> &() { + with_restriction::(x) //~ ERROR E0311 +} + +fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () { + x +} + +fn main() {} diff --git a/tests/ui/error-codes/E0311.rs b/tests/ui/error-codes/E0311.rs index 566b518b4331d..99e454f4d75c2 100644 --- a/tests/ui/error-codes/E0311.rs +++ b/tests/ui/error-codes/E0311.rs @@ -1,3 +1,7 @@ +// run-rustfix + +#![allow(warnings)] + fn no_restriction(x: &()) -> &() { with_restriction::(x) //~ ERROR E0311 } diff --git a/tests/ui/error-codes/E0311.stderr b/tests/ui/error-codes/E0311.stderr index 9873b5ae6ff13..b0e6dd1e2727c 100644 --- a/tests/ui/error-codes/E0311.stderr +++ b/tests/ui/error-codes/E0311.stderr @@ -1,23 +1,23 @@ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/E0311.rs:2:5 + --> $DIR/E0311.rs:6:5 | LL | with_restriction::(x) | ^^^^^^^^^^^^^^^^^^^^^ | note: the parameter type `T` must be valid for the anonymous lifetime defined here... - --> $DIR/E0311.rs:1:25 + --> $DIR/E0311.rs:5:25 | LL | fn no_restriction(x: &()) -> &() { | ^^^ note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/E0311.rs:2:5 + --> $DIR/E0311.rs:6:5 | LL | with_restriction::(x) | ^^^^^^^^^^^^^^^^^^^^^ help: consider adding an explicit lifetime bound... | -LL | fn no_restriction<'a, T: 'a>(x: &()) -> &() { - | +++ ++++ +LL | fn no_restriction<'a, T: 'a>(x: &'a ()) -> &() { + | +++ ++++ ++ error: aborting due to previous error diff --git a/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.fixed b/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.fixed new file mode 100644 index 0000000000000..f977f0bd3a8c2 --- /dev/null +++ b/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.fixed @@ -0,0 +1,13 @@ +// run-rustfix + +#![allow(warnings)] + +fn no_restriction<'a, T: 'a>(x: &'a ()) -> &() { + with_restriction::(x) //~ ERROR the parameter type `T` may not live long enough +} + +fn with_restriction<'b, T: 'b>(x: &'b ()) -> &'b () { + x +} + +fn main() {} diff --git a/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs b/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs index 645bc7db0ddac..d6ce112ec93d4 100644 --- a/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs +++ b/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs @@ -1,3 +1,7 @@ +// run-rustfix + +#![allow(warnings)] + fn no_restriction(x: &()) -> &() { with_restriction::(x) //~ ERROR the parameter type `T` may not live long enough } diff --git a/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr b/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr index 31fd8a4d633e9..2d58d3a02f35e 100644 --- a/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr +++ b/tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr @@ -1,23 +1,23 @@ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:2:5 + --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:6:5 | LL | with_restriction::(x) | ^^^^^^^^^^^^^^^^^^^^^ | note: the parameter type `T` must be valid for the anonymous lifetime defined here... - --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:1:25 + --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:5:25 | LL | fn no_restriction(x: &()) -> &() { | ^^^ note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:2:5 + --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:6:5 | LL | with_restriction::(x) | ^^^^^^^^^^^^^^^^^^^^^ help: consider adding an explicit lifetime bound... | -LL | fn no_restriction<'a, T: 'a>(x: &()) -> &() { - | +++ ++++ +LL | fn no_restriction<'a, T: 'a>(x: &'a ()) -> &() { + | +++ ++++ ++ error: aborting due to previous error diff --git a/tests/ui/suggestions/lifetimes/issue-105544.fixed b/tests/ui/suggestions/lifetimes/issue-105544.fixed new file mode 100644 index 0000000000000..47087eb474972 --- /dev/null +++ b/tests/ui/suggestions/lifetimes/issue-105544.fixed @@ -0,0 +1,45 @@ +// run-rustfix + +#![allow(warnings)] + +fn foo<'a>(d: impl Sized + 'a, p: &'a mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `impl Sized` must be valid for the anonymous lifetime defined here... +//~^ HELP consider adding an explicit lifetime bound + (d, p) + //~^ ERROR the parameter type `impl Sized` may not live long enough + //~| NOTE ...so that the type `impl Sized` will meet its required lifetime bounds +} + +fn foo1<'b>(d: impl Sized + 'b, p: &'b mut ()) -> impl Sized + '_ { +//~^ HELP consider adding an explicit lifetime bound... + (d, p) //~ NOTE ...so that the type `impl Sized` will meet its required lifetime bounds + //~^ ERROR the parameter type `impl Sized` may not live long enough +} + +fn foo2<'b, 'a>(d: impl Sized + 'a + 'b, p: &'b mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `impl Sized + 'a` must be valid for the anonymous lifetime defined here... +//~^ HELP consider adding an explicit lifetime bound + (d, p) + //~^ ERROR the parameter type `impl Sized + 'a` may not live long enough + //~| NOTE ...so that the type `impl Sized + 'a` will meet its required lifetime bounds +} + +fn bar<'a, T : Sized + 'a>(d: T, p: &'a mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `T` must be valid for the anonymous lifetime defined here... +//~^ HELP consider adding an explicit lifetime bound + (d, p) + //~^ ERROR the parameter type `T` may not live long enough + //~| NOTE ...so that the type `T` will meet its required lifetime bounds +} + +fn bar1<'b, T : Sized + 'b>(d: T, p: &'b mut ()) -> impl Sized + '_ { +//~^ HELP consider adding an explicit lifetime bound... + (d, p) //~ NOTE ...so that the type `T` will meet its required lifetime bounds + //~^ ERROR the parameter type `T` may not live long enough +} + +fn bar2<'b, 'a, T : Sized + 'a + 'b>(d: T, p: &'b mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `T` must be valid for the anonymous lifetime defined here... +//~^ HELP consider adding an explicit lifetime bound + (d, p) + //~^ ERROR the parameter type `T` may not live long enough + //~| NOTE ...so that the type `T` will meet its required lifetime bounds +} + +fn main() {} diff --git a/tests/ui/suggestions/lifetimes/issue-105544.rs b/tests/ui/suggestions/lifetimes/issue-105544.rs new file mode 100644 index 0000000000000..bd3bc1ef9bd2d --- /dev/null +++ b/tests/ui/suggestions/lifetimes/issue-105544.rs @@ -0,0 +1,45 @@ +// run-rustfix + +#![allow(warnings)] + +fn foo(d: impl Sized, p: &mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `impl Sized` must be valid for the anonymous lifetime defined here... +//~^ HELP consider adding an explicit lifetime bound + (d, p) + //~^ ERROR the parameter type `impl Sized` may not live long enough + //~| NOTE ...so that the type `impl Sized` will meet its required lifetime bounds +} + +fn foo1<'b>(d: impl Sized, p: &'b mut ()) -> impl Sized + '_ { +//~^ HELP consider adding an explicit lifetime bound... + (d, p) //~ NOTE ...so that the type `impl Sized` will meet its required lifetime bounds + //~^ ERROR the parameter type `impl Sized` may not live long enough +} + +fn foo2<'a>(d: impl Sized + 'a, p: &mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `impl Sized + 'a` must be valid for the anonymous lifetime defined here... +//~^ HELP consider adding an explicit lifetime bound + (d, p) + //~^ ERROR the parameter type `impl Sized + 'a` may not live long enough + //~| NOTE ...so that the type `impl Sized + 'a` will meet its required lifetime bounds +} + +fn bar(d: T, p: & mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `T` must be valid for the anonymous lifetime defined here... +//~^ HELP consider adding an explicit lifetime bound + (d, p) + //~^ ERROR the parameter type `T` may not live long enough + //~| NOTE ...so that the type `T` will meet its required lifetime bounds +} + +fn bar1<'b, T : Sized>(d: T, p: &'b mut ()) -> impl Sized + '_ { +//~^ HELP consider adding an explicit lifetime bound... + (d, p) //~ NOTE ...so that the type `T` will meet its required lifetime bounds + //~^ ERROR the parameter type `T` may not live long enough +} + +fn bar2<'a, T : Sized + 'a>(d: T, p: &mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `T` must be valid for the anonymous lifetime defined here... +//~^ HELP consider adding an explicit lifetime bound + (d, p) + //~^ ERROR the parameter type `T` may not live long enough + //~| NOTE ...so that the type `T` will meet its required lifetime bounds +} + +fn main() {} diff --git a/tests/ui/suggestions/lifetimes/issue-105544.stderr b/tests/ui/suggestions/lifetimes/issue-105544.stderr new file mode 100644 index 0000000000000..08fe21b11b501 --- /dev/null +++ b/tests/ui/suggestions/lifetimes/issue-105544.stderr @@ -0,0 +1,110 @@ +error[E0311]: the parameter type `impl Sized` may not live long enough + --> $DIR/issue-105544.rs:7:5 + | +LL | (d, p) + | ^^^^^^ + | +note: the parameter type `impl Sized` must be valid for the anonymous lifetime defined here... + --> $DIR/issue-105544.rs:5:26 + | +LL | fn foo(d: impl Sized, p: &mut ()) -> impl Sized + '_ { + | ^^^^^^^ +note: ...so that the type `impl Sized` will meet its required lifetime bounds + --> $DIR/issue-105544.rs:7:5 + | +LL | (d, p) + | ^^^^^^ +help: consider adding an explicit lifetime bound... + | +LL | fn foo<'a>(d: impl Sized + 'a, p: &'a mut ()) -> impl Sized + '_ { + | ++++ ++++ ++ + +error[E0309]: the parameter type `impl Sized` may not live long enough + --> $DIR/issue-105544.rs:14:5 + | +LL | (d, p) + | ^^^^^^ ...so that the type `impl Sized` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn foo1<'b>(d: impl Sized + 'b, p: &'b mut ()) -> impl Sized + '_ { + | ++++ + +error[E0311]: the parameter type `impl Sized + 'a` may not live long enough + --> $DIR/issue-105544.rs:20:5 + | +LL | (d, p) + | ^^^^^^ + | +note: the parameter type `impl Sized + 'a` must be valid for the anonymous lifetime defined here... + --> $DIR/issue-105544.rs:18:36 + | +LL | fn foo2<'a>(d: impl Sized + 'a, p: &mut ()) -> impl Sized + '_ { + | ^^^^^^^ +note: ...so that the type `impl Sized + 'a` will meet its required lifetime bounds + --> $DIR/issue-105544.rs:20:5 + | +LL | (d, p) + | ^^^^^^ +help: consider adding an explicit lifetime bound... + | +LL | fn foo2<'b, 'a>(d: impl Sized + 'a + 'b, p: &'b mut ()) -> impl Sized + '_ { + | +++ ++++ ++ + +error[E0311]: the parameter type `T` may not live long enough + --> $DIR/issue-105544.rs:27:5 + | +LL | (d, p) + | ^^^^^^ + | +note: the parameter type `T` must be valid for the anonymous lifetime defined here... + --> $DIR/issue-105544.rs:25:28 + | +LL | fn bar(d: T, p: & mut ()) -> impl Sized + '_ { + | ^^^^^^^^ +note: ...so that the type `T` will meet its required lifetime bounds + --> $DIR/issue-105544.rs:27:5 + | +LL | (d, p) + | ^^^^^^ +help: consider adding an explicit lifetime bound... + | +LL | fn bar<'a, T : Sized + 'a>(d: T, p: &'a mut ()) -> impl Sized + '_ { + | +++ ++++ ++ + +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/issue-105544.rs:34:5 + | +LL | (d, p) + | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn bar1<'b, T : Sized + 'b>(d: T, p: &'b mut ()) -> impl Sized + '_ { + | ++++ + +error[E0311]: the parameter type `T` may not live long enough + --> $DIR/issue-105544.rs:40:5 + | +LL | (d, p) + | ^^^^^^ + | +note: the parameter type `T` must be valid for the anonymous lifetime defined here... + --> $DIR/issue-105544.rs:38:38 + | +LL | fn bar2<'a, T : Sized + 'a>(d: T, p: &mut ()) -> impl Sized + '_ { + | ^^^^^^^ +note: ...so that the type `T` will meet its required lifetime bounds + --> $DIR/issue-105544.rs:40:5 + | +LL | (d, p) + | ^^^^^^ +help: consider adding an explicit lifetime bound... + | +LL | fn bar2<'b, 'a, T : Sized + 'a + 'b>(d: T, p: &'b mut ()) -> impl Sized + '_ { + | +++ ++++ ++ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0309, E0311. +For more information about an error, try `rustc --explain E0309`. diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.fixed b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.fixed new file mode 100644 index 0000000000000..4013d98c3cfe7 --- /dev/null +++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.fixed @@ -0,0 +1,29 @@ +// Regression test for #81650 +// run-rustfix + +#![allow(warnings)] + +struct Foo<'a> { + x: &'a mut &'a i32, +} + +impl<'a> Foo<'a> { + fn bar(&self, f: F) + where + F: FnOnce(&Foo<'a>) -> T, + F: 'a, + {} +} + +trait Test { + fn test(&self); +} + +fn func<'a, T: Test + 'a>(foo: &'a Foo<'a>, t: T) { + foo.bar(move |_| { + //~^ ERROR the parameter type `T` may not live long enough + t.test(); + }); +} + +fn main() {} diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.rs b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.rs index c6802ac6cc704..4096d95e5fd7f 100644 --- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.rs +++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.rs @@ -1,4 +1,7 @@ // Regression test for #81650 +// run-rustfix + +#![allow(warnings)] struct Foo<'a> { x: &'a mut &'a i32, diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr index 872263fd7311b..936d87f796824 100644 --- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr +++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr @@ -1,5 +1,5 @@ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/missing-lifetimes-in-signature-2.rs:20:5 + --> $DIR/missing-lifetimes-in-signature-2.rs:23:5 | LL | / foo.bar(move |_| { LL | | @@ -8,12 +8,12 @@ LL | | }); | |______^ | note: the parameter type `T` must be valid for the anonymous lifetime defined here... - --> $DIR/missing-lifetimes-in-signature-2.rs:19:24 + --> $DIR/missing-lifetimes-in-signature-2.rs:22:24 | LL | fn func(foo: &Foo, t: T) { | ^^^ note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/missing-lifetimes-in-signature-2.rs:20:5 + --> $DIR/missing-lifetimes-in-signature-2.rs:23:5 | LL | / foo.bar(move |_| { LL | | @@ -22,8 +22,8 @@ LL | | }); | |______^ help: consider adding an explicit lifetime bound... | -LL | fn func<'a, T: Test + 'a>(foo: &Foo, t: T) { - | +++ ++++ +LL | fn func<'a, T: Test + 'a>(foo: &'a Foo<'a>, t: T) { + | +++ ++++ ++ ++++ error: aborting due to previous error diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index fa758bf05df5a..c5c3f7b468c8b 100644 --- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -47,7 +47,7 @@ LL | | } | |_____^ help: consider adding an explicit lifetime bound... | -LL ~ fn bar<'a, G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ +LL ~ fn bar<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ LL | where LL ~ G: Get + 'a, | @@ -76,8 +76,8 @@ LL | | } | |_____^ help: consider adding an explicit lifetime bound... | -LL | fn qux<'b, 'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | +++ ++++ +LL | fn qux<'b, 'a, G: 'a + 'b, T>(g: G, dest: &'b mut T) -> impl FnOnce() + '_ + | +++ ++++ ++ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:61:9 @@ -103,8 +103,8 @@ LL | | } | |_________^ help: consider adding an explicit lifetime bound... | -LL | fn qux<'c, 'b, G: Get + 'b + 'c, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | +++ ++++ +LL | fn qux<'c, 'b, G: Get + 'b + 'c, T>(g: G, dest: &'c mut T) -> impl FnOnce() + '_ { + | +++ ++++ ++ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:73:5 @@ -132,8 +132,8 @@ LL | | } | |_____^ help: consider adding an explicit lifetime bound... | -LL | fn bat<'b, 'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | +++ ++++ +LL | fn bat<'b, 'a, G: 'a + 'b, T>(g: G, dest: &'b mut T) -> impl FnOnce() + '_ + 'a + | +++ ++++ ++ error[E0621]: explicit lifetime required in the type of `dest` --> $DIR/missing-lifetimes-in-signature.rs:73:5