From bf135de3bc451573e9f84703cf9dda2e669bb2a7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Oct 2022 13:57:32 +1100 Subject: [PATCH 01/12] Clean up rustdoc startup. rustc's startup has several layers, including: - `interface::run_compiler` passes a closure, `f`, to `run_in_thread_pool_with_globals`, which creates a thread pool, sets up session globals, and passes `f` to `create_compiler_and_run`. - `create_compiler_and_run` creates a `Session`, a `Compiler`, sets the source map, and calls `f`. rustdoc is a bit different. - `main_args` calls `main_options` via `run_in_thread_pool_with_globals`, which (again) creates a thread pool (hardcoded to a single thread!) and sets up session globals. - `main_options` has four different paths. - The second one calls `interface::run_compiler`, which redoes the `run_in_thread_pool_with_globals`! This is bad. - The fourth one calls `interface::create_compiler_and_run`, which is reasonable. - The first and third ones don't do anything of note involving the above functions, except for some symbol interning which requires session globals. In other words, rustdoc calls into `rustc_interface` at three different levels. It's a bit confused, and feels like code where functionality has been added by different people at different times without fully understanding how the globally accessible stuff is set up. This commit tidies things up. It removes the `run_in_thread_pool_with_globals` call in `main_args`, and adjust the four paths in `main_options` as follows. - `markdown::test` calls `test::test_main`, which provides its own parallelism and so doesn't need a thread pool. It had one small use of symbol interning, which required session globals, but the commit removes this. - `doctest::run` already calls `interface::run_compiler`, so it doesn't need further adjustment. - `markdown::render` is simple but needs session globals for interning (which can't easily be removed), so it's now wrapped in `create_session_globals_then`. - The fourth path now uses `interface::run_compiler`, which is equivalent to the old `run_in_thread_pool_with_globals` + `create_compiler_and_run` pairing. --- src/librustdoc/doctest.rs | 9 ++++----- src/librustdoc/lib.rs | 14 +++++++------- src/librustdoc/markdown.rs | 5 +++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index f4ec60735a8dd..d9160e8abd4e3 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -18,7 +18,6 @@ use rustc_session::{lint, DiagnosticOutput, Session}; use rustc_span::edition::Edition; use rustc_span::source_map::SourceMap; use rustc_span::symbol::sym; -use rustc_span::Symbol; use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP}; use rustc_target::spec::TargetTriple; use tempfile::Builder as TempFileBuilder; @@ -125,7 +124,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { let opts = scrape_test_config(crate_attrs); let enable_per_target_ignores = options.enable_per_target_ignores; let mut collector = Collector::new( - tcx.crate_name(LOCAL_CRATE), + tcx.crate_name(LOCAL_CRATE).to_string(), options, false, opts, @@ -909,7 +908,7 @@ pub(crate) struct Collector { rustdoc_options: RustdocOptions, use_headers: bool, enable_per_target_ignores: bool, - crate_name: Symbol, + crate_name: String, opts: GlobalTestOptions, position: Span, source_map: Option>, @@ -921,7 +920,7 @@ pub(crate) struct Collector { impl Collector { pub(crate) fn new( - crate_name: Symbol, + crate_name: String, rustdoc_options: RustdocOptions, use_headers: bool, opts: GlobalTestOptions, @@ -984,7 +983,7 @@ impl Tester for Collector { fn add_test(&mut self, test: String, config: LangString, line: usize) { let filename = self.get_filename(); let name = self.generate_name(line, &filename); - let crate_name = self.crate_name.to_string(); + let crate_name = self.crate_name.clone(); let opts = self.opts.clone(); let edition = config.edition.unwrap_or(self.rustdoc_options.edition); let rustdoc_options = self.rustdoc_options.clone(); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ef01b854e5a69..ce6f7e817c620 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -700,11 +700,7 @@ fn main_args(at_args: &[String]) -> MainResult { }; } }; - rustc_interface::util::run_in_thread_pool_with_globals( - options.edition, - 1, // this runs single-threaded, even in a parallel compiler - move || main_options(options), - ) + main_options(options) } fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainResult { @@ -749,9 +745,12 @@ fn main_options(options: config::Options) -> MainResult { (true, true) => return wrap_return(&diag, markdown::test(options)), (true, false) => return doctest::run(options), (false, true) => { + // Session globals are required for symbol interning. return wrap_return( &diag, - markdown::render(&options.input, options.render_options, options.edition), + rustc_span::create_session_globals_then(options.edition, || { + markdown::render(&options.input, options.render_options, options.edition) + }), ); } (false, false) => {} @@ -777,9 +776,10 @@ fn main_options(options: config::Options) -> MainResult { let render_options = options.render_options.clone(); let scrape_examples_options = options.scrape_examples_options.clone(); let document_private = options.render_options.document_private; + let config = core::create_config(options); - interface::create_compiler_and_run(config, |compiler| { + interface::run_compiler(config, |compiler| { let sess = compiler.session(); if sess.opts.describe_lints { diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 0b557ef244e94..eb64ac455dc4c 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -5,7 +5,6 @@ use std::path::Path; use rustc_span::edition::Edition; use rustc_span::source_map::DUMMY_SP; -use rustc_span::Symbol; use crate::config::{Options, RenderOptions}; use crate::doctest::{Collector, GlobalTestOptions}; @@ -36,6 +35,8 @@ fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { /// Render `input` (e.g., "foo.md") into an HTML file in `output` /// (e.g., output = "bar" => "bar/foo.html"). +/// +/// Requires session globals to be available, for symbol interning. pub(crate) fn render>( input: P, options: RenderOptions, @@ -133,7 +134,7 @@ pub(crate) fn test(options: Options) -> Result<(), String> { let mut opts = GlobalTestOptions::default(); opts.no_crate_inject = true; let mut collector = Collector::new( - Symbol::intern(&options.input.display().to_string()), + options.input.display().to_string(), options.clone(), true, opts, From c461f3a760f4a7eeef82bd1a9389d68210abaf4a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Oct 2022 15:36:44 +1100 Subject: [PATCH 02/12] Merge `main_options` into `main_args`. There is no longer any need for them to be separate. --- src/librustdoc/lib.rs | 57 ++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ce6f7e817c620..7e0cc668d7b59 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -674,35 +674,6 @@ fn usage(argv0: &str) { /// A result type used by several functions under `main()`. type MainResult = Result<(), ErrorGuaranteed>; -fn main_args(at_args: &[String]) -> MainResult { - let args = rustc_driver::args::arg_expand_all(at_args); - - let mut options = getopts::Options::new(); - for option in opts() { - (option.apply)(&mut options); - } - let matches = match options.parse(&args[1..]) { - Ok(m) => m, - Err(err) => { - early_error(ErrorOutputType::default(), &err.to_string()); - } - }; - - // Note that we discard any distinction between different non-zero exit - // codes from `from_matches` here. - let options = match config::Options::from_matches(&matches, args) { - Ok(opts) => opts, - Err(code) => { - return if code == 0 { - Ok(()) - } else { - Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()) - }; - } - }; - main_options(options) -} - fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainResult { match res { Ok(()) => Ok(()), @@ -733,7 +704,33 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( } } -fn main_options(options: config::Options) -> MainResult { +fn main_args(at_args: &[String]) -> MainResult { + let args = rustc_driver::args::arg_expand_all(at_args); + + let mut options = getopts::Options::new(); + for option in opts() { + (option.apply)(&mut options); + } + let matches = match options.parse(&args[1..]) { + Ok(m) => m, + Err(err) => { + early_error(ErrorOutputType::default(), &err.to_string()); + } + }; + + // Note that we discard any distinction between different non-zero exit + // codes from `from_matches` here. + let options = match config::Options::from_matches(&matches, args) { + Ok(opts) => opts, + Err(code) => { + return if code == 0 { + Ok(()) + } else { + Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()) + }; + } + }; + let diag = core::new_handler( options.error_format, None, From d156a9092738b3f1fb5e665f532613ab06380162 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Oct 2022 11:57:25 +1100 Subject: [PATCH 03/12] Inline and remove `scoped_thread`. It has a single call site, and removing it slightly improves the confusing tangle of nested closures present at startup. --- compiler/rustc_interface/src/util.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index f7e70d355cf86..c07bfb9c23e4a 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -132,33 +132,27 @@ fn get_stack_size() -> Option { env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE) } -/// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need -/// for `'static` bounds. -#[cfg(not(parallel_compiler))] -fn scoped_thread R + Send, R: Send>(cfg: thread::Builder, f: F) -> R { - // SAFETY: join() is called immediately, so any closure captures are still - // alive. - match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() { - Ok(v) => v, - Err(e) => panic::resume_unwind(e), - } -} - #[cfg(not(parallel_compiler))] pub fn run_in_thread_pool_with_globals R + Send, R: Send>( edition: Edition, _threads: usize, f: F, ) -> R { + // The thread pool is a single thread in the non-parallel compiler. let mut cfg = thread::Builder::new().name("rustc".to_string()); - if let Some(size) = get_stack_size() { cfg = cfg.stack_size(size); } - let main_handler = move || rustc_span::create_session_globals_then(edition, f); + let f = move || rustc_span::create_session_globals_then(edition, f); - scoped_thread(cfg, main_handler) + // This avoids the need for `'static` bounds. + // + // SAFETY: join() is called immediately, so any closure captures are still alive. + match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() { + Ok(v) => v, + Err(e) => panic::resume_unwind(e), + } } /// Creates a new thread and forwards information in thread locals to it. From 226387a4039082b2df687c645acb4bde08f2939d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Oct 2022 15:35:42 +1100 Subject: [PATCH 04/12] Reduce visibility of some functions. --- compiler/rustc_interface/src/interface.rs | 2 +- compiler/rustc_interface/src/util.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 949bd02ad6839..d0555f3db0c9b 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -276,7 +276,7 @@ pub struct Config { pub registry: Registry, } -pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R) -> R { +fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R) -> R { crate::callbacks::setup_callbacks(); let registry = &config.registry; diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index c07bfb9c23e4a..7ec0d4d73f7a4 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -133,7 +133,7 @@ fn get_stack_size() -> Option { } #[cfg(not(parallel_compiler))] -pub fn run_in_thread_pool_with_globals R + Send, R: Send>( +pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( edition: Edition, _threads: usize, f: F, @@ -171,7 +171,7 @@ unsafe fn handle_deadlock() { } #[cfg(parallel_compiler)] -pub fn run_in_thread_pool_with_globals R + Send, R: Send>( +pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( edition: Edition, threads: usize, f: F, From c00937f2d9b2ea994e5841c5f6047a603eeffe85 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Oct 2022 16:17:57 +1100 Subject: [PATCH 05/12] Inline and remove `create_compiler_and_run`. It has a single call site. --- compiler/rustc_interface/src/interface.rs | 106 +++++++++++----------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index d0555f3db0c9b..bee2e91c74730 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -276,59 +276,6 @@ pub struct Config { pub registry: Registry, } -fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R) -> R { - crate::callbacks::setup_callbacks(); - - let registry = &config.registry; - let (mut sess, codegen_backend) = util::create_session( - config.opts, - config.crate_cfg, - config.crate_check_cfg, - config.diagnostic_output, - config.file_loader, - config.input_path.clone(), - config.lint_caps, - config.make_codegen_backend, - registry.clone(), - ); - - if let Some(parse_sess_created) = config.parse_sess_created { - parse_sess_created( - &mut Lrc::get_mut(&mut sess) - .expect("create_session() should never share the returned session") - .parse_sess, - ); - } - - let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o)); - - let compiler = Compiler { - sess, - codegen_backend, - input: config.input, - input_path: config.input_path, - output_dir: config.output_dir, - output_file: config.output_file, - temps_dir, - register_lints: config.register_lints, - override_queries: config.override_queries, - }; - - rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || { - let r = { - let _sess_abort_error = OnDrop(|| { - compiler.sess.finish_diagnostics(registry); - }); - - f(&compiler) - }; - - let prof = compiler.sess.prof.clone(); - prof.generic_activity("drop_compiler").run(move || drop(compiler)); - r - }) -} - // JUSTIFICATION: before session exists, only config #[allow(rustc::bad_opt_access)] pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { @@ -336,7 +283,58 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se util::run_in_thread_pool_with_globals( config.opts.edition, config.opts.unstable_opts.threads, - || create_compiler_and_run(config, f), + || { + crate::callbacks::setup_callbacks(); + + let registry = &config.registry; + let (mut sess, codegen_backend) = util::create_session( + config.opts, + config.crate_cfg, + config.crate_check_cfg, + config.diagnostic_output, + config.file_loader, + config.input_path.clone(), + config.lint_caps, + config.make_codegen_backend, + registry.clone(), + ); + + if let Some(parse_sess_created) = config.parse_sess_created { + parse_sess_created( + &mut Lrc::get_mut(&mut sess) + .expect("create_session() should never share the returned session") + .parse_sess, + ); + } + + let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o)); + + let compiler = Compiler { + sess, + codegen_backend, + input: config.input, + input_path: config.input_path, + output_dir: config.output_dir, + output_file: config.output_file, + temps_dir, + register_lints: config.register_lints, + override_queries: config.override_queries, + }; + + rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || { + let r = { + let _sess_abort_error = OnDrop(|| { + compiler.sess.finish_diagnostics(registry); + }); + + f(&compiler) + }; + + let prof = compiler.sess.prof.clone(); + prof.generic_activity("drop_compiler").run(move || drop(compiler)); + r + }) + }, ) } From 806701607285b6a61c6169797b5e22ef9a18d5de Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Oct 2022 16:20:20 +1100 Subject: [PATCH 06/12] Apply `Lrc` later to `sess` and `codegen_backend`. This avoids the need for a degenerate `Lrc::get_mut` call. --- compiler/rustc_interface/src/interface.rs | 10 +++------- compiler/rustc_interface/src/util.rs | 5 ++--- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index bee2e91c74730..a697f8071b4b3 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -300,18 +300,14 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se ); if let Some(parse_sess_created) = config.parse_sess_created { - parse_sess_created( - &mut Lrc::get_mut(&mut sess) - .expect("create_session() should never share the returned session") - .parse_sess, - ); + parse_sess_created(&mut sess.parse_sess); } let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o)); let compiler = Compiler { - sess, - codegen_backend, + sess: Lrc::new(sess), + codegen_backend: Lrc::new(codegen_backend), input: config.input, input_path: config.input_path, output_dir: config.output_dir, diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 7ec0d4d73f7a4..ae7a240d81cb4 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -5,7 +5,6 @@ use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; #[cfg(parallel_compiler)] use rustc_data_structures::jobserver; -use rustc_data_structures::sync::Lrc; use rustc_errors::registry::Registry; #[cfg(parallel_compiler)] use rustc_middle::ty::tls; @@ -73,7 +72,7 @@ pub fn create_session( Box Box + Send>, >, descriptions: Registry, -) -> (Lrc, Lrc>) { +) -> (Session, Box) { let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend { make_codegen_backend(&sopts) } else { @@ -121,7 +120,7 @@ pub fn create_session( sess.parse_sess.config = cfg; sess.parse_sess.check_config = check_cfg; - (Lrc::new(sess), Lrc::new(codegen_backend)) + (sess, codegen_backend) } const STACK_SIZE: usize = 8 * 1024 * 1024; From 1f0463a7b5ed89cedf25842e7c2917efc9200939 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 8 Oct 2022 07:43:15 +1100 Subject: [PATCH 07/12] Replace a `spawn_unchecked` with `spawn_scoped`. --- compiler/rustc_interface/src/util.rs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index ae7a240d81cb4..1bbfb9a415699 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -138,20 +138,24 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( f: F, ) -> R { // The thread pool is a single thread in the non-parallel compiler. - let mut cfg = thread::Builder::new().name("rustc".to_string()); - if let Some(size) = get_stack_size() { - cfg = cfg.stack_size(size); - } + thread::scope(|s| { + let mut builder = thread::Builder::new().name("rustc".to_string()); + if let Some(size) = get_stack_size() { + builder = builder.stack_size(size); + } - let f = move || rustc_span::create_session_globals_then(edition, f); + // `unwrap` is ok here because `spawn_scoped` only panics if the thread + // name contains null bytes. + let r = builder + .spawn_scoped(s, move || rustc_span::create_session_globals_then(edition, f)) + .unwrap() + .join(); - // This avoids the need for `'static` bounds. - // - // SAFETY: join() is called immediately, so any closure captures are still alive. - match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() { - Ok(v) => v, - Err(e) => panic::resume_unwind(e), - } + match r { + Ok(v) => v, + Err(e) => panic::resume_unwind(e), + } + }) } /// Creates a new thread and forwards information in thread locals to it. From 0571b0af65dcc0dd97cce4b976887ab436e5780d Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Mon, 10 Oct 2022 11:14:32 +0800 Subject: [PATCH 08/12] suggest candidates for unresolved import --- compiler/rustc_resolve/src/diagnostics.rs | 38 ++++++++++++++++++- compiler/rustc_resolve/src/imports.rs | 28 +++++++++++++- src/test/ui/extenv/issue-55897.stderr | 5 +++ src/test/ui/imports/issue-56125.stderr | 12 ++++++ src/test/ui/imports/issue-57015.stderr | 5 +++ .../not-allowed.stderr | 7 ++++ .../portable-intrinsics-arent-exposed.stderr | 5 +++ .../inaccessible-test-modules.stderr | 14 +++++-- .../ui/unresolved/unresolved-candidates.rs | 13 +++++++ .../unresolved/unresolved-candidates.stderr | 26 +++++++++++++ 10 files changed, 145 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/unresolved/unresolved-candidates.rs create mode 100644 src/test/ui/unresolved/unresolved-candidates.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 98982240af27f..9a3eac2f86622 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -70,6 +70,7 @@ impl TypoSuggestion { } /// A free importable items suggested in case of resolution failure. +#[derive(Debug, Clone)] pub(crate) struct ImportSuggestion { pub did: Option, pub descr: &'static str, @@ -139,6 +140,7 @@ impl<'a> Resolver<'a> { if instead { Instead::Yes } else { Instead::No }, found_use, IsPattern::No, + IsImport::No, path, ); err.emit(); @@ -698,6 +700,7 @@ impl<'a> Resolver<'a> { Instead::No, FoundUse::Yes, IsPattern::Yes, + IsImport::No, vec![], ); } @@ -1481,6 +1484,7 @@ impl<'a> Resolver<'a> { Instead::No, FoundUse::Yes, IsPattern::No, + IsImport::No, vec![], ); @@ -2449,6 +2453,34 @@ enum IsPattern { No, } +/// Whether a binding is part of a use statement. Used for diagnostics. +enum IsImport { + Yes, + No, +} + +pub(crate) fn import_candidates( + session: &Session, + source_span: &IndexVec, + err: &mut Diagnostic, + // This is `None` if all placement locations are inside expansions + use_placement_span: Option, + candidates: &[ImportSuggestion], +) { + show_candidates( + session, + source_span, + err, + use_placement_span, + candidates, + Instead::Yes, + FoundUse::Yes, + IsPattern::No, + IsImport::Yes, + vec![], + ); +} + /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way @@ -2462,6 +2494,7 @@ fn show_candidates( instead: Instead, found_use: FoundUse, is_pattern: IsPattern, + is_import: IsImport, path: Vec, ) { if candidates.is_empty() { @@ -2521,7 +2554,8 @@ fn show_candidates( // produce an additional newline to separate the new use statement // from the directly following item. let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" }; - candidate.0 = format!("use {};\n{}", &candidate.0, additional_newline); + let add_use = if let IsImport::Yes = is_import { "" } else { "use " }; + candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline); } err.span_suggestions( @@ -2551,7 +2585,7 @@ fn show_candidates( err.note(&msg); } - } else { + } else if matches!(is_import, IsImport::No) { assert!(!inaccessible_path_strings.is_empty()); let prefix = diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 5bdb427478199..9e2234ae4a54f 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1,9 +1,9 @@ //! A bunch of methods and structures more or less related to resolving imports. -use crate::diagnostics::Suggestion; +use crate::diagnostics::{import_candidates, Suggestion}; use crate::Determinacy::{self, *}; use crate::Namespace::{self, *}; -use crate::{module_to_string, names_to_string}; +use crate::{module_to_string, names_to_string, ImportSuggestion}; use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment}; use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet}; use crate::{NameBinding, NameBindingKind, PathResult}; @@ -406,6 +406,7 @@ struct UnresolvedImportError { label: Option, note: Option, suggestion: Option, + candidate: Option>, } pub struct ImportResolver<'a, 'b> { @@ -497,6 +498,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { label: None, note: None, suggestion: None, + candidate: None, }; if path.contains("::") { errors.push((path, err)) @@ -547,6 +549,16 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } diag.multipart_suggestion(&msg, suggestions, applicability); } + + if let Some(candidate) = &err.candidate { + import_candidates( + self.r.session, + &self.r.source_span, + &mut diag, + Some(err.span), + &candidate, + ) + } } diag.emit(); @@ -664,6 +676,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { Some(finalize), ignore_binding, ); + let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len; import.vis.set(orig_vis); let module = match path_res { @@ -706,12 +719,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> { String::from("a similar path exists"), Applicability::MaybeIncorrect, )), + candidate: None, }, None => UnresolvedImportError { span, label: Some(label), note: None, suggestion, + candidate: None, }, }; return Some(err); @@ -754,6 +769,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { label: Some(String::from("cannot glob-import a module into itself")), note: None, suggestion: None, + candidate: None, }); } } @@ -919,11 +935,19 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } }; + let parent_suggestion = + self.r.lookup_import_candidates(ident, TypeNS, &import.parent_scope, |_| true); + Some(UnresolvedImportError { span: import.span, label: Some(label), note, suggestion, + candidate: if !parent_suggestion.is_empty() { + Some(parent_suggestion) + } else { + None + }, }) } else { // `resolve_ident_in_module` reported a privacy error. diff --git a/src/test/ui/extenv/issue-55897.stderr b/src/test/ui/extenv/issue-55897.stderr index e2afe6f34c121..63797d4a71bce 100644 --- a/src/test/ui/extenv/issue-55897.stderr +++ b/src/test/ui/extenv/issue-55897.stderr @@ -26,6 +26,11 @@ error[E0432]: unresolved import `env` | LL | use env; | ^^^ no `env` in the root + | +help: consider importing this module instead + | +LL | use std::env; + | ~~~~~~~~~ error: cannot determine resolution for the macro `env` --> $DIR/issue-55897.rs:6:22 diff --git a/src/test/ui/imports/issue-56125.stderr b/src/test/ui/imports/issue-56125.stderr index 2e4ba86237676..059ca96808d9a 100644 --- a/src/test/ui/imports/issue-56125.stderr +++ b/src/test/ui/imports/issue-56125.stderr @@ -3,6 +3,18 @@ error[E0432]: unresolved import `empty::issue_56125` | LL | use empty::issue_56125; | ^^^^^^^^^^^^^^^^^^ no `issue_56125` in `m3::empty` + | +help: consider importing one of these items instead + | +LL | use crate::m3::last_segment::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | use crate::m3::non_last_segment::non_last_segment::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | use issue_56125::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | use issue_56125::last_segment::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + and 1 other candidate error[E0659]: `issue_56125` is ambiguous --> $DIR/issue-56125.rs:6:9 diff --git a/src/test/ui/imports/issue-57015.stderr b/src/test/ui/imports/issue-57015.stderr index d200d23ab28ef..3b72d57fee41e 100644 --- a/src/test/ui/imports/issue-57015.stderr +++ b/src/test/ui/imports/issue-57015.stderr @@ -3,6 +3,11 @@ error[E0432]: unresolved import `single_err::something` | LL | use single_err::something; | ^^^^^^^^^^^^^^^^^^^^^ no `something` in `single_err` + | +help: consider importing this module instead + | +LL | use glob_ok::something; + | ~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr index a66330ccc46ec..761089cd3871a 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr @@ -3,6 +3,13 @@ error[E0432]: unresolved import `alloc` | LL | use alloc; | ^^^^^ no external crate `alloc` + | +help: consider importing one of these items instead + | +LL | use core::alloc; + | ~~~~~~~~~~~~ +LL | use std::alloc; + | ~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr b/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr index 870f4064de49b..8881ede0dbca7 100644 --- a/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr +++ b/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr @@ -11,6 +11,11 @@ error[E0432]: unresolved import `std::simd::intrinsics` | LL | use std::simd::intrinsics; | ^^^^^^^^^^^^^^^^^^^^^ no `intrinsics` in `simd` + | +help: consider importing this module instead + | +LL | use std::intrinsics; + | ~~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/test-attrs/inaccessible-test-modules.stderr b/src/test/ui/test-attrs/inaccessible-test-modules.stderr index a94ea1e79bc51..0c16ecd4c862e 100644 --- a/src/test/ui/test-attrs/inaccessible-test-modules.stderr +++ b/src/test/ui/test-attrs/inaccessible-test-modules.stderr @@ -11,10 +11,16 @@ error[E0432]: unresolved import `test` --> $DIR/inaccessible-test-modules.rs:6:5 | LL | use test as y; - | ----^^^^^ - | | - | no `test` in the root - | help: a similar name exists in the module: `test` + | ^^^^^^^^^ no `test` in the root + | +help: a similar name exists in the module + | +LL | use test as y; + | ~~~~ +help: consider importing this module instead + | +LL | use test::test; + | ~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/unresolved/unresolved-candidates.rs b/src/test/ui/unresolved/unresolved-candidates.rs new file mode 100644 index 0000000000000..38b227f609b26 --- /dev/null +++ b/src/test/ui/unresolved/unresolved-candidates.rs @@ -0,0 +1,13 @@ +mod a { + pub trait Trait {} +} + +mod b { + use Trait; //~ ERROR unresolved import `Trait` +} + +mod c { + impl Trait for () {} //~ ERROR cannot find trait `Trait` in this scope +} + +fn main() {} diff --git a/src/test/ui/unresolved/unresolved-candidates.stderr b/src/test/ui/unresolved/unresolved-candidates.stderr new file mode 100644 index 0000000000000..bbd3eec2a5431 --- /dev/null +++ b/src/test/ui/unresolved/unresolved-candidates.stderr @@ -0,0 +1,26 @@ +error[E0432]: unresolved import `Trait` + --> $DIR/unresolved-candidates.rs:6:9 + | +LL | use Trait; + | ^^^^^ no `Trait` in the root + | +help: consider importing this trait instead + | +LL | use a::Trait; + | ~~~~~~~~~ + +error[E0405]: cannot find trait `Trait` in this scope + --> $DIR/unresolved-candidates.rs:10:10 + | +LL | impl Trait for () {} + | ^^^^^ not found in this scope + | +help: consider importing this trait + | +LL | use a::Trait; + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0405, E0432. +For more information about an error, try `rustc --explain E0405`. From 693485373b971d1574388b9da785b66c19dc86d2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 3 Sep 2022 04:57:21 +0000 Subject: [PATCH 09/12] Point out incompatible closure bounds --- .../src/traits/error_reporting/mod.rs | 1 + .../src/traits/error_reporting/suggestions.rs | 67 +++++++++++++++++++ src/test/ui/closures/multiple-fn-bounds.rs | 15 +++++ .../ui/closures/multiple-fn-bounds.stderr | 24 +++++++ 4 files changed, 107 insertions(+) create mode 100644 src/test/ui/closures/multiple-fn-bounds.rs create mode 100644 src/test/ui/closures/multiple-fn-bounds.stderr 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 490b0e863225d..4e8baa2dfab6c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1255,6 +1255,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { found_span, found_trait_ref, expected_trait_ref, + obligation.cause.code(), ) } else { let (closure_span, found) = found_did 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 980e85b45262d..fda6a2236b195 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -254,8 +254,15 @@ pub trait TypeErrCtxtExt<'tcx> { found_span: Option, found: ty::PolyTraitRef<'tcx>, expected: ty::PolyTraitRef<'tcx>, + cause: &ObligationCauseCode<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + fn note_conflicting_closure_bounds( + &self, + cause: &ObligationCauseCode<'tcx>, + err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + ); + fn suggest_fully_qualified_path( &self, err: &mut Diagnostic, @@ -1584,6 +1591,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { found_span: Option, found: ty::PolyTraitRef<'tcx>, expected: ty::PolyTraitRef<'tcx>, + cause: &ObligationCauseCode<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { pub(crate) fn build_fn_sig_ty<'tcx>( infcx: &InferCtxt<'tcx>, @@ -1645,9 +1653,68 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let signature_kind = format!("{argument_kind} signature"); err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str); + self.note_conflicting_closure_bounds(cause, &mut err); + err } + // Add a note if there are two `Fn`-family bounds that have conflicting argument + // requirements, which will always cause a closure to have a type error. + fn note_conflicting_closure_bounds( + &self, + cause: &ObligationCauseCode<'tcx>, + err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + ) { + // First, look for an `ExprBindingObligation`, which means we can get + // the unsubstituted predicate list of the called function. And check + // that the predicate that we failed to satisfy is a `Fn`-like trait. + if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause + && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx) + && let Some(pred) = predicates.predicates.get(*idx) + && let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() + && ty::ClosureKind::from_def_id(self.tcx, trait_pred.def_id()).is_some() + { + let expected_self = + self.tcx.anonymize_late_bound_regions(pred.kind().rebind(trait_pred.self_ty())); + let expected_substs = self + .tcx + .anonymize_late_bound_regions(pred.kind().rebind(trait_pred.trait_ref.substs)); + + // Find another predicate whose self-type is equal to the expected self type, + // but whose substs don't match. + let other_pred = std::iter::zip(&predicates.predicates, &predicates.spans) + .enumerate() + .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() { + ty::PredicateKind::Trait(trait_pred) + if ty::ClosureKind::from_def_id(self.tcx, trait_pred.def_id()) + .is_some() + && other_idx != idx + // Make sure that the self type matches + // (i.e. constraining this closure) + && expected_self + == self.tcx.anonymize_late_bound_regions( + pred.kind().rebind(trait_pred.self_ty()), + ) + // But the substs don't match (i.e. incompatible args) + && expected_substs + != self.tcx.anonymize_late_bound_regions( + pred.kind().rebind(trait_pred.trait_ref.substs), + ) => + { + true + } + _ => false, + }); + // If we found one, then it's very likely the cause of the error. + if let Some((_, (_, other_pred_span))) = other_pred { + err.span_note( + *other_pred_span, + "closure inferred to have a different signature due to this bound", + ); + } + } + } + fn suggest_fully_qualified_path( &self, err: &mut Diagnostic, diff --git a/src/test/ui/closures/multiple-fn-bounds.rs b/src/test/ui/closures/multiple-fn-bounds.rs new file mode 100644 index 0000000000000..6bb4098e2bbe5 --- /dev/null +++ b/src/test/ui/closures/multiple-fn-bounds.rs @@ -0,0 +1,15 @@ +fn foo bool + Fn(char) -> bool>(f: F) { + //~^ NOTE required by a bound in `foo` + //~| NOTE required by this bound in `foo` + //~| NOTE closure inferred to have a different signature due to this bound + todo!(); +} + +fn main() { + let v = true; + foo(move |x| v); + //~^ ERROR type mismatch in closure arguments + //~| NOTE expected closure signature + //~| NOTE expected due to this + //~| NOTE found signature defined here +} diff --git a/src/test/ui/closures/multiple-fn-bounds.stderr b/src/test/ui/closures/multiple-fn-bounds.stderr new file mode 100644 index 0000000000000..eefc123fed7ac --- /dev/null +++ b/src/test/ui/closures/multiple-fn-bounds.stderr @@ -0,0 +1,24 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/multiple-fn-bounds.rs:10:5 + | +LL | foo(move |x| v); + | ^^^ -------- found signature defined here + | | + | expected due to this + | + = note: expected closure signature `fn(char) -> _` + found closure signature `for<'a> fn(&'a char) -> _` +note: closure inferred to have a different signature due to this bound + --> $DIR/multiple-fn-bounds.rs:1:11 + | +LL | fn foo bool + Fn(char) -> bool>(f: F) { + | ^^^^^^^^^^^^^^^^^ +note: required by a bound in `foo` + --> $DIR/multiple-fn-bounds.rs:1:31 + | +LL | fn foo bool + Fn(char) -> bool>(f: F) { + | ^^^^^^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0631`. From c1c159fe86317eee433ed77bcc6bb349cc941828 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 9 Oct 2022 06:54:00 +0000 Subject: [PATCH 10/12] Unify tcx.constness and param env constness checks --- .../src/const_eval/fn_queries.rs | 72 ++++++++++++++----- compiler/rustc_metadata/src/rmeta/encoder.rs | 56 +++++++++++---- compiler/rustc_ty_utils/src/ty.rs | 69 +----------------- 3 files changed, 98 insertions(+), 99 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index f1674d04f8d15..cdcebb61c2e8c 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -25,12 +25,10 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { /// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return /// `Constness::NotConst`. fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness { - let def_id = def_id.expect_local(); - let node = tcx.hir().get_by_def_id(def_id); - - match node { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + match tcx.hir().get(hir_id) { hir::Node::Ctor(_) => hir::Constness::Const, - hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness, + hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other // foreign items cannot be evaluated at compile-time. @@ -41,20 +39,62 @@ fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness { }; if is_const { hir::Constness::Const } else { hir::Constness::NotConst } } - _ => { - if let Some(fn_kind) = node.fn_kind() { - if fn_kind.constness() == hir::Constness::Const { - return hir::Constness::Const; - } - // If the function itself is not annotated with `const`, it may still be a `const fn` - // if it resides in a const trait impl. - let is_const = is_parent_const_impl_raw(tcx, def_id); - if is_const { hir::Constness::Const } else { hir::Constness::NotConst } - } else { - hir::Constness::NotConst + hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) + if tcx.is_const_default_method(def_id) => + { + hir::Constness::Const + } + + hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. }) + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. }) + | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. }) + | hir::Node::AnonConst(_) + | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) + | hir::Node::ImplItem(hir::ImplItem { + kind: + hir::ImplItemKind::Fn( + hir::FnSig { + header: hir::FnHeader { constness: hir::Constness::Const, .. }, + .. + }, + .., + ), + .. + }) => hir::Constness::Const, + + hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..), + .. + }) => { + let parent_hir_id = tcx.hir().get_parent_node(hir_id); + match tcx.hir().get(parent_hir_id) { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), + .. + }) => *constness, + _ => span_bug!( + tcx.def_span(parent_hir_id.owner), + "impl item's parent node is not an impl", + ), } } + + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..), + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: + hir::TraitItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..), + .. + }) + | hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), + .. + }) => *constness, + + _ => hir::Constness::NotConst, } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3fc10197b9129..ab4ecec2af36e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1059,6 +1059,43 @@ fn should_encode_const(def_kind: DefKind) -> bool { } } +fn should_encode_constness(def_kind: DefKind) -> bool { + match def_kind { + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Trait + | DefKind::AssocTy + | DefKind::Fn + | DefKind::Const + | DefKind::Static(..) + | DefKind::Ctor(..) + | DefKind::AssocFn + | DefKind::AssocConst + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder + | DefKind::Impl + | DefKind::Closure + | DefKind::Generator => true, + DefKind::Variant + | DefKind::TyAlias + | DefKind::TraitAlias + | DefKind::ForeignTy + | DefKind::Field + | DefKind::TyParam + | DefKind::Mod + | DefKind::ForeignMod + | DefKind::ConstParam + | DefKind::Macro(..) + | DefKind::Use + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::ExternCrate => false, + } +} + fn should_encode_trait_impl_trait_tys<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { if tcx.def_kind(def_id) != DefKind::AssocFn { return false; @@ -1165,6 +1202,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { { record!(self.tables.trait_impl_trait_tys[def_id] <- table); } + if should_encode_constness(def_kind) { + self.tables.constness.set(def_id.index, tcx.constness(def_id)); + } } let inherent_impls = tcx.crate_inherent_impls(()); for (def_id, implementations) in inherent_impls.inherent_impls.iter() { @@ -1192,7 +1232,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.variant_data[def_id] <- data); - self.tables.constness.set(def_id.index, hir::Constness::Const); record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index @@ -1220,7 +1259,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.variant_data[def_id] <- data); - self.tables.constness.set(def_id.index, hir::Constness::Const); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1284,7 +1322,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.repr_options[def_id] <- adt_def.repr()); record!(self.tables.variant_data[def_id] <- data); - self.tables.constness.set(def_id.index, hir::Constness::Const); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1320,7 +1357,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } }; self.tables.asyncness.set(def_id.index, m_sig.header.asyncness); - self.tables.constness.set(def_id.index, hir::Constness::NotConst); } ty::AssocKind::Type => { self.encode_explicit_item_bounds(def_id); @@ -1345,13 +1381,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() }; self.tables.asyncness.set(def_id.index, sig.header.asyncness); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); - // Can be inside `impl const Trait`, so using sig.header.constness is not reliable - let constness = if self.tcx.is_const_fn_raw(def_id) { - hir::Constness::Const - } else { - hir::Constness::NotConst - }; - self.tables.constness.set(def_id.index, constness); } ty::AssocKind::Const | ty::AssocKind::Type => {} } @@ -1474,7 +1503,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Fn(ref sig, .., body) => { self.tables.asyncness.set(def_id.index, sig.header.asyncness); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); - self.tables.constness.set(def_id.index, sig.header.constness); } hir::ItemKind::Macro(ref macro_def, _) => { if macro_def.macro_rules { @@ -1495,7 +1523,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Struct(ref struct_def, _) => { let adt_def = self.tcx.adt_def(def_id); record!(self.tables.repr_options[def_id] <- adt_def.repr()); - self.tables.constness.set(def_id.index, hir::Constness::Const); // Encode def_ids for each field and method // for methods, write all the stuff get_trait_method @@ -1524,9 +1551,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { is_non_exhaustive: variant.is_field_list_non_exhaustive(), }); } - hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { + hir::ItemKind::Impl(hir::Impl { defaultness, .. }) => { self.tables.impl_defaultness.set(def_id.index, *defaultness); - self.tables.constness.set(def_id.index, *constness); let trait_ref = self.tcx.impl_trait_ref(def_id); if let Some(trait_ref) = trait_ref { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 30efbf6617598..344426a18bca5 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -133,77 +133,10 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { let local_did = def_id.as_local(); let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)); - let constness = match hir_id { - Some(hir_id) => match tcx.hir().get(hir_id) { - hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) - if tcx.is_const_default_method(def_id) => - { - hir::Constness::Const - } - - hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. }) - | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. }) - | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Const(..), .. - }) - | hir::Node::AnonConst(_) - | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) - | hir::Node::ImplItem(hir::ImplItem { - kind: - hir::ImplItemKind::Fn( - hir::FnSig { - header: hir::FnHeader { constness: hir::Constness::Const, .. }, - .. - }, - .., - ), - .. - }) => hir::Constness::Const, - - hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..), - .. - }) => { - let parent_hir_id = tcx.hir().get_parent_node(hir_id); - match tcx.hir().get(parent_hir_id) { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), - .. - }) => *constness, - _ => span_bug!( - tcx.def_span(parent_hir_id.owner), - "impl item's parent node is not an impl", - ), - } - } - - hir::Node::Item(hir::Item { - kind: - hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..), - .. - }) - | hir::Node::TraitItem(hir::TraitItem { - kind: - hir::TraitItemKind::Fn( - hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, - .., - ), - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), - .. - }) => *constness, - - _ => hir::Constness::NotConst, - }, - None => hir::Constness::NotConst, - }; - let unnormalized_env = ty::ParamEnv::new( tcx.intern_predicates(&predicates), traits::Reveal::UserFacing, - constness, + tcx.constness(def_id), ); let body_id = From 03fe005f4967439c09b538f1dcf5e38ca5d27019 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 9 Oct 2022 23:19:50 -0700 Subject: [PATCH 11/12] rustdoc: clean up overly complex `.trait-impl` CSS selectors When added in 45964368f4a2e31c94e9bcf1cef933c087d21544, these multi-class selectors were present in the initial commit, but no reason was given why the shorter selector wouldn't work. --- src/librustdoc/html/static/css/rustdoc.css | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index eb64147d90677..d4228a2ebc638 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -734,9 +734,7 @@ a { display: initial; } -.impl:hover > .anchor, .method.trait-impl:hover > .anchor, -.type.trait-impl:hover > .anchor, .associatedconstant.trait-impl:hover > .anchor, -.associatedtype.trait-impl:hover > .anchor { +.impl:hover > .anchor, .trait-impl:hover > .anchor { display: inline-block; position: absolute; } From 6071b4b8a64571312017d5eaba01276b90ffe0dc Mon Sep 17 00:00:00 2001 From: gimbles Date: Mon, 10 Oct 2022 16:53:13 +0530 Subject: [PATCH 12/12] `let` is not allowed in struct field definitions Co-authored-by: jyn514 Co-authored-by: Esteban Kuber --- compiler/rustc_parse/src/parser/item.rs | 18 +++++++++++++++++- .../ui/parser/removed-syntax-field-let.stderr | 10 ++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 25425fbb2c6a6..e82044a89c479 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1788,7 +1788,23 @@ impl<'a> Parser<'a> { } } } else { - self.expected_ident_found() + let mut err = self.expected_ident_found(); + if let Some((ident, _)) = self.token.ident() && ident.as_str() == "let" { + self.bump(); // `let` + let span = self.prev_token.span.until(self.token.span); + err.span_suggestion( + span, + "remove the let, the `let` keyword is not allowed in struct field definitions", + String::new(), + Applicability::MachineApplicable, + ); + err.note("the `let` keyword is not allowed in `struct` fields"); + err.note("see for more information"); + err.emit(); + self.bump(); + return Ok(ident); + } + err }; return Err(err); } diff --git a/src/test/ui/parser/removed-syntax-field-let.stderr b/src/test/ui/parser/removed-syntax-field-let.stderr index ab3d2056581b6..bd1b23f7e3bbb 100644 --- a/src/test/ui/parser/removed-syntax-field-let.stderr +++ b/src/test/ui/parser/removed-syntax-field-let.stderr @@ -1,10 +1,16 @@ error: expected identifier, found keyword `let` --> $DIR/removed-syntax-field-let.rs:2:5 | -LL | struct S { - | - while parsing this struct LL | let foo: (), | ^^^ expected identifier, found keyword + | + = note: the `let` keyword is not allowed in `struct` fields + = note: see for more information +help: remove the let, the `let` keyword is not allowed in struct field definitions + | +LL - let foo: (), +LL + foo: (), + | error: aborting due to previous error