From a63b5d3c846b74b917b8029aa00cb448faba409f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 18 Jul 2022 20:30:07 +0200 Subject: [PATCH 0001/2442] feat: Only flycheck workspace that belongs to saved file --- crates/flycheck/src/lib.rs | 7 ++- crates/paths/src/lib.rs | 8 ++++ crates/rust-analyzer/src/main_loop.rs | 62 ++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index f683fe61fe38..973f2a53c1ad 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -55,6 +55,7 @@ pub struct FlycheckHandle { // XXX: drop order is significant sender: Sender, _thread: jod_thread::JoinHandle, + id: usize, } impl FlycheckHandle { @@ -70,13 +71,17 @@ impl FlycheckHandle { .name("Flycheck".to_owned()) .spawn(move || actor.run(receiver)) .expect("failed to spawn thread"); - FlycheckHandle { sender, _thread: thread } + FlycheckHandle { id, sender, _thread: thread } } /// Schedule a re-start of the cargo check worker. pub fn update(&self) { self.sender.send(Restart).unwrap(); } + + pub fn id(&self) -> usize { + self.id + } } pub enum Message { diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs index b4beb40e7469..cf06bf0c27b8 100644 --- a/crates/paths/src/lib.rs +++ b/crates/paths/src/lib.rs @@ -103,6 +103,14 @@ impl AsRef for AbsPath { } } +impl ToOwned for AbsPath { + type Owned = AbsPathBuf; + + fn to_owned(&self) -> Self::Owned { + AbsPathBuf(self.0.to_owned()) + } +} + impl<'a> TryFrom<&'a Path> for &'a AbsPath { type Error = &'a Path; fn try_from(path: &'a Path) -> Result<&'a AbsPath, &'a Path> { diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 49b83941119f..262c30f132c1 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -2,6 +2,7 @@ //! requests/replies and notifications back to the client. use std::{ fmt, + ops::Deref, sync::Arc, time::{Duration, Instant}, }; @@ -720,13 +721,62 @@ impl GlobalState { Ok(()) })? .on::(|this, params| { - for flycheck in &this.flycheck { - flycheck.update(); + let mut updated = false; + if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) { + let (vfs, _) = &*this.vfs.read(); + if let Some(file_id) = vfs.file_id(&vfs_path) { + let analysis = this.analysis_host.analysis(); + let crate_ids = analysis.crate_for(file_id)?; + + let paths: Vec<_> = crate_ids + .iter() + .filter_map(|&crate_id| { + analysis + .crate_root(crate_id) + .map(|file_id| { + vfs.file_path(file_id).as_path().map(ToOwned::to_owned) + }) + .transpose() + }) + .collect::>()?; + let paths: Vec<_> = paths.iter().map(Deref::deref).collect(); + + let workspace_ids = + this.workspaces.iter().enumerate().filter(|(_, ws)| match ws { + project_model::ProjectWorkspace::Cargo { cargo, .. } => { + cargo.packages().filter(|&pkg| cargo[pkg].is_member).any( + |pkg| { + cargo[pkg].targets.iter().any(|&it| { + paths.contains(&cargo[it].root.as_path()) + }) + }, + ) + } + project_model::ProjectWorkspace::Json { project, .. } => project + .crates() + .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)), + project_model::ProjectWorkspace::DetachedFiles { .. } => false, + }); + 'workspace: for (id, _) in workspace_ids { + for flycheck in &this.flycheck { + if id == flycheck.id() { + updated = true; + flycheck.update(); + continue 'workspace; + } + } + } + } + if let Some(abs_path) = vfs_path.as_path() { + if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) { + this.fetch_workspaces_queue + .request_op(format!("DidSaveTextDocument {}", abs_path.display())); + } + } } - if let Ok(abs_path) = from_proto::abs_path(¶ms.text_document.uri) { - if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) { - this.fetch_workspaces_queue - .request_op(format!("DidSaveTextDocument {}", abs_path.display())); + if !updated { + for flycheck in &this.flycheck { + flycheck.update(); } } Ok(()) From 25391e6d44e3dc740349198c309e08782691da7e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 20 Jul 2022 11:49:36 +0200 Subject: [PATCH 0002/2442] Only clear diagnostics of workspaces who have been flychecked --- crates/flycheck/src/lib.rs | 8 ++++--- crates/rust-analyzer/src/diagnostics.rs | 27 ++++++++++++++++++------ crates/rust-analyzer/src/global_state.rs | 1 + crates/rust-analyzer/src/handlers.rs | 4 +++- crates/rust-analyzer/src/main_loop.rs | 5 +++-- crates/rust-analyzer/src/reload.rs | 2 +- 6 files changed, 33 insertions(+), 14 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 973f2a53c1ad..7f14fe5798a0 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -86,7 +86,7 @@ impl FlycheckHandle { pub enum Message { /// Request adding a diagnostic with fixes included to a file - AddDiagnostic { workspace_root: AbsPathBuf, diagnostic: Diagnostic }, + AddDiagnostic { id: usize, workspace_root: AbsPathBuf, diagnostic: Diagnostic }, /// Request check progress notification to client Progress { @@ -99,8 +99,9 @@ pub enum Message { impl fmt::Debug for Message { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Message::AddDiagnostic { workspace_root, diagnostic } => f + Message::AddDiagnostic { id, workspace_root, diagnostic } => f .debug_struct("AddDiagnostic") + .field("id", id) .field("workspace_root", workspace_root) .field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code)) .finish(), @@ -186,7 +187,7 @@ impl FlycheckActor { } } Event::CheckEvent(None) => { - tracing::debug!("flycheck finished"); + tracing::debug!(flycheck_id = self.id, "flycheck finished"); // Watcher finished let cargo_handle = self.cargo_handle.take().unwrap(); @@ -206,6 +207,7 @@ impl FlycheckActor { CargoMessage::Diagnostic(msg) => { self.send(Message::AddDiagnostic { + id: self.id, workspace_root: self.workspace_root.clone(), diagnostic: msg, }); diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs index 202a01adf710..7917ced666a8 100644 --- a/crates/rust-analyzer/src/diagnostics.rs +++ b/crates/rust-analyzer/src/diagnostics.rs @@ -8,7 +8,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; use crate::lsp_ext; -pub(crate) type CheckFixes = Arc>>; +pub(crate) type CheckFixes = Arc>>>; #[derive(Debug, Default, Clone)] pub struct DiagnosticsMapConfig { @@ -22,7 +22,7 @@ pub(crate) struct DiagnosticCollection { // FIXME: should be FxHashMap> pub(crate) native: FxHashMap>, // FIXME: should be Vec - pub(crate) check: FxHashMap>, + pub(crate) check: FxHashMap>>, pub(crate) check_fixes: CheckFixes, changes: FxHashSet, } @@ -35,9 +35,19 @@ pub(crate) struct Fix { } impl DiagnosticCollection { - pub(crate) fn clear_check(&mut self) { + pub(crate) fn clear_check(&mut self, flycheck_id: usize) { + if let Some(it) = Arc::make_mut(&mut self.check_fixes).get_mut(&flycheck_id) { + it.clear(); + } + if let Some(it) = self.check.get_mut(&flycheck_id) { + self.changes.extend(it.drain().map(|(key, _value)| key)); + } + } + + pub(crate) fn clear_check_all(&mut self) { Arc::make_mut(&mut self.check_fixes).clear(); - self.changes.extend(self.check.drain().map(|(key, _value)| key)) + self.changes + .extend(self.check.values_mut().flat_map(|it| it.drain().map(|(key, _value)| key))) } pub(crate) fn clear_native_for(&mut self, file_id: FileId) { @@ -47,11 +57,12 @@ impl DiagnosticCollection { pub(crate) fn add_check_diagnostic( &mut self, + flycheck_id: usize, file_id: FileId, diagnostic: lsp_types::Diagnostic, fix: Option, ) { - let diagnostics = self.check.entry(file_id).or_default(); + let diagnostics = self.check.entry(flycheck_id).or_default().entry(file_id).or_default(); for existing_diagnostic in diagnostics.iter() { if are_diagnostics_equal(existing_diagnostic, &diagnostic) { return; @@ -59,8 +70,9 @@ impl DiagnosticCollection { } let check_fixes = Arc::make_mut(&mut self.check_fixes); - check_fixes.entry(file_id).or_default().extend(fix); + check_fixes.entry(flycheck_id).or_default().entry(file_id).or_default().extend(fix); diagnostics.push(diagnostic); + tracing::warn!(?flycheck_id, ?file_id, "add_check_diagnostic changes pushed"); self.changes.insert(file_id); } @@ -89,7 +101,8 @@ impl DiagnosticCollection { file_id: FileId, ) -> impl Iterator { let native = self.native.get(&file_id).into_iter().flatten(); - let check = self.check.get(&file_id).into_iter().flatten(); + let check = + self.check.values().filter_map(move |it| it.get(&file_id)).into_iter().flatten(); native.chain(check) } diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 4af60035a20e..2cd2044aeff0 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -201,6 +201,7 @@ impl GlobalState { } } + // Clear native diagnostics when their file gets deleted if !file.exists() { self.diagnostics.clear_native_for(file.file_id); } diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index e3875228a187..a64dc57ec644 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -1094,7 +1094,9 @@ pub(crate) fn handle_code_action( } // Fixes from `cargo check`. - for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() { + for fix in + snap.check_fixes.values().filter_map(|it| it.get(&frange.file_id)).into_iter().flatten() + { // FIXME: this mapping is awkward and shouldn't exist. Refactor // `snap.check_fixes` to not convert to LSP prematurely. let intersect_fix_range = fix diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 262c30f132c1..572466cdfa7f 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -372,7 +372,7 @@ impl GlobalState { let _p = profile::span("GlobalState::handle_event/flycheck"); loop { match task { - flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { + flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => { let snap = self.snapshot(); let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( @@ -384,6 +384,7 @@ impl GlobalState { for diag in diagnostics { match url_to_file_id(&self.vfs.read().0, &diag.url) { Ok(file_id) => self.diagnostics.add_check_diagnostic( + id, file_id, diag.diagnostic, diag.fix, @@ -401,7 +402,7 @@ impl GlobalState { flycheck::Message::Progress { id, progress } => { let (state, message) = match progress { flycheck::Progress::DidStart => { - self.diagnostics.clear_check(); + self.diagnostics.clear_check(id); (Progress::Begin, None) } flycheck::Progress::DidCheckCrate(target) => { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 13bcb7dfa23b..579ba380273a 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -417,7 +417,7 @@ impl GlobalState { Some(it) => it, None => { self.flycheck = Vec::new(); - self.diagnostics.clear_check(); + self.diagnostics.clear_check_all(); return; } }; From d73b0d5fc6c6be434bd0e31ddc6572a6efaf6400 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 20 Jul 2022 11:52:44 +0200 Subject: [PATCH 0003/2442] Don't filter flychecks by package member status --- crates/rust-analyzer/src/main_loop.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 572466cdfa7f..561c2d7aef77 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -745,25 +745,24 @@ impl GlobalState { let workspace_ids = this.workspaces.iter().enumerate().filter(|(_, ws)| match ws { project_model::ProjectWorkspace::Cargo { cargo, .. } => { - cargo.packages().filter(|&pkg| cargo[pkg].is_member).any( - |pkg| { - cargo[pkg].targets.iter().any(|&it| { - paths.contains(&cargo[it].root.as_path()) - }) - }, - ) + cargo.packages().any(|pkg| { + cargo[pkg] + .targets + .iter() + .any(|&it| paths.contains(&cargo[it].root.as_path())) + }) } project_model::ProjectWorkspace::Json { project, .. } => project .crates() .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)), project_model::ProjectWorkspace::DetachedFiles { .. } => false, }); - 'workspace: for (id, _) in workspace_ids { - for flycheck in &this.flycheck { + for flycheck in &this.flycheck { + for (id, _) in workspace_ids.clone() { if id == flycheck.id() { updated = true; flycheck.update(); - continue 'workspace; + continue; } } } From 7e0bd377c2ffe55a1f014ce932a7218a9b4dc639 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Wed, 20 Jul 2022 22:30:16 +0900 Subject: [PATCH 0004/2442] fix: don't replace default members' body --- .../src/handlers/add_missing_impl_members.rs | 17 ++++++++++------- .../ide-assists/src/utils/gen_trait_fn_body.rs | 11 ++++++----- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 6e6fd96a684f..036bdd3a21f5 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -142,13 +142,16 @@ fn add_missing_impl_members_inner( Some(cap) => { let mut cursor = Cursor::Before(first_new_item.syntax()); let placeholder; - if let ast::AssocItem::Fn(func) = &first_new_item { - if try_gen_trait_body(ctx, func, &trait_, &impl_def).is_none() { - if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) - { - if m.syntax().text() == "todo!()" { - placeholder = m; - cursor = Cursor::Replace(placeholder.syntax()); + if let DefaultMethods::No = mode { + if let ast::AssocItem::Fn(func) = &first_new_item { + if try_gen_trait_body(ctx, func, &trait_, &impl_def).is_none() { + if let Some(m) = + func.syntax().descendants().find_map(ast::MacroCall::cast) + { + if m.syntax().text() == "todo!()" { + placeholder = m; + cursor = Cursor::Replace(placeholder.syntax()); + } } } } diff --git a/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/crates/ide-assists/src/utils/gen_trait_fn_body.rs index ec4835969f88..43aaad3150ce 100644 --- a/crates/ide-assists/src/utils/gen_trait_fn_body.rs +++ b/crates/ide-assists/src/utils/gen_trait_fn_body.rs @@ -5,7 +5,7 @@ use syntax::{ ted, }; -/// Generate custom trait bodies where possible. +/// Generate custom trait bodies without default implementation where possible. /// /// Returns `Option` so that we can use `?` rather than `if let Some`. Returning /// `None` means that generating a custom trait body failed, and the body will remain @@ -28,6 +28,7 @@ pub(crate) fn gen_trait_fn_body( /// Generate a `Clone` impl based on the fields and members of the target type. fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { + debug_assert!(func.name().map_or(false, |name| name.text() == "clone")); fn gen_clone_call(target: ast::Expr) -> ast::Expr { let method = make::name_ref("clone"); make::expr_method_call(target, method, make::arg_list(None)) @@ -339,6 +340,7 @@ fn gen_default_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { /// Generate a `Hash` impl based on the fields and members of the target type. fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { + debug_assert!(func.name().map_or(false, |name| name.text() == "hash")); fn gen_hash_call(target: ast::Expr) -> ast::Stmt { let method = make::name_ref("hash"); let arg = make::expr_path(make::ext::ident_path("state")); @@ -394,9 +396,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { /// Generate a `PartialEq` impl based on the fields and members of the target type. fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - if func.name().map_or(false, |name| name.text() == "ne") { - return None; - } + debug_assert!(func.name().map_or(false, |name| name.text() == "eq")); fn gen_eq_chain(expr: Option, cmp: ast::Expr) -> Option { match expr { Some(expr) => Some(make::expr_bin_op(expr, BinaryOp::LogicOp(LogicOp::And), cmp)), @@ -573,6 +573,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { } fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { + debug_assert!(func.name().map_or(false, |name| name.text() == "partial_cmp")); fn gen_partial_eq_match(match_target: ast::Expr) -> Option { let mut arms = vec![]; @@ -643,7 +644,7 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { make::block_expr(stmts.into_iter(), tail).indent(ast::edit::IndentLevel(1)) } - // No fields in the body means there's nothing to hash. + // No fields in the body means there's nothing to compare. None => { let expr = make::expr_literal("true").into(); make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1)) From aeb07745d53a90cc8447c45328eed51e941d9307 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 23 Jul 2022 20:10:10 +0200 Subject: [PATCH 0005/2442] Spawn a proc-macro-srv instance per workspace --- crates/rust-analyzer/src/global_state.rs | 4 +-- crates/rust-analyzer/src/handlers.rs | 2 +- crates/rust-analyzer/src/reload.rs | 43 +++++++++++++----------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 4af60035a20e..700e3e19bb96 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -61,7 +61,7 @@ pub(crate) struct GlobalState { pub(crate) proc_macro_changed: bool, pub(crate) last_reported_status: Option, pub(crate) source_root_config: SourceRootConfig, - pub(crate) proc_macro_client: Option, + pub(crate) proc_macro_clients: Vec>, pub(crate) flycheck: Vec, pub(crate) flycheck_sender: Sender, @@ -151,7 +151,7 @@ impl GlobalState { proc_macro_changed: false, last_reported_status: None, source_root_config: SourceRootConfig::default(), - proc_macro_client: None, + proc_macro_clients: vec![], flycheck: Vec::new(), flycheck_sender, diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 520aa7d1dd48..deb777c952fd 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -44,7 +44,7 @@ use crate::{ }; pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<()> { - state.proc_macro_client = None; + state.proc_macro_clients.clear(); state.proc_macro_changed = false; state.fetch_workspaces_queue.request_op("reload workspace request".to_string()); state.fetch_build_data_queue.request_op("reload workspace request".to_string()); diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 77125f88f473..d69b2be25650 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -303,18 +303,21 @@ impl GlobalState { let files_config = self.config.files(); let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude); - if self.proc_macro_client.is_none() { + if self.proc_macro_clients.is_empty() { if let Some((path, args)) = self.config.proc_macro_srv() { - match ProcMacroServer::spawn(path.clone(), args) { - Ok(it) => self.proc_macro_client = Some(it), - Err(err) => { - tracing::error!( - "Failed to run proc_macro_srv from path {}, error: {:?}", - path.display(), - err - ); - } - } + self.proc_macro_clients = (0..self.workspaces.len()) + .map(|_| match ProcMacroServer::spawn(path.clone(), args.clone()) { + Ok(it) => Some(it), + Err(err) => { + tracing::error!( + "Failed to run proc_macro_srv from path {}, error: {:?}", + path.display(), + err + ); + None + } + }) + .collect(); } } @@ -331,15 +334,7 @@ impl GlobalState { // Create crate graph from all the workspaces let crate_graph = { - let proc_macro_client = self.proc_macro_client.as_ref(); let dummy_replacements = self.config.dummy_replacements(); - let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| { - load_proc_macro( - proc_macro_client, - path, - dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(), - ) - }; let vfs = &mut self.vfs.write().0; let loader = &mut self.loader; @@ -359,7 +354,15 @@ impl GlobalState { }; let mut crate_graph = CrateGraph::default(); - for ws in self.workspaces.iter() { + for (idx, ws) in self.workspaces.iter().enumerate() { + let proc_macro_client = self.proc_macro_clients[idx].as_ref(); + let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| { + load_proc_macro( + proc_macro_client, + path, + dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(), + ) + }; crate_graph.extend(ws.to_crate_graph(&mut load_proc_macro, &mut load)); } crate_graph From 50b27e57baa83d63fecf77c712c345d480f2c3c6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 23 Jul 2022 20:24:01 +0200 Subject: [PATCH 0006/2442] Better error messages when the proc-macro-server fails to start --- crates/rust-analyzer/src/cli/load_cargo.rs | 6 +++--- crates/rust-analyzer/src/global_state.rs | 2 +- crates/rust-analyzer/src/reload.rs | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 4243af25ff1a..0ada4b73e842 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -60,9 +60,9 @@ pub fn load_workspace( let proc_macro_client = if load_config.with_proc_macro { let path = AbsPathBuf::assert(std::env::current_exe()?); - Some(ProcMacroServer::spawn(path, &["proc-macro"]).unwrap()) + Ok(ProcMacroServer::spawn(path, &["proc-macro"]).unwrap()) } else { - None + Err("proc macro server not started".to_owned()) }; let crate_graph = ws.to_crate_graph( @@ -89,7 +89,7 @@ pub fn load_workspace( if load_config.prefill_caches { host.analysis().parallel_prime_caches(1, |_| {})?; } - Ok((host, vfs, proc_macro_client)) + Ok((host, vfs, proc_macro_client.ok())) } fn load_crate_graph( diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 700e3e19bb96..8f881cba4dbd 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -61,7 +61,7 @@ pub(crate) struct GlobalState { pub(crate) proc_macro_changed: bool, pub(crate) last_reported_status: Option, pub(crate) source_root_config: SourceRootConfig, - pub(crate) proc_macro_clients: Vec>, + pub(crate) proc_macro_clients: Vec>, pub(crate) flycheck: Vec, pub(crate) flycheck_sender: Sender, diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index d69b2be25650..e5802773e747 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -306,16 +306,16 @@ impl GlobalState { if self.proc_macro_clients.is_empty() { if let Some((path, args)) = self.config.proc_macro_srv() { self.proc_macro_clients = (0..self.workspaces.len()) - .map(|_| match ProcMacroServer::spawn(path.clone(), args.clone()) { - Ok(it) => Some(it), - Err(err) => { - tracing::error!( + .map(|_| { + ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| { + let error = format!( "Failed to run proc_macro_srv from path {}, error: {:?}", path.display(), err ); - None - } + tracing::error!(error); + error + }) }) .collect(); } @@ -539,14 +539,14 @@ impl SourceRootConfig { /// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace` /// with an identity dummy expander. pub(crate) fn load_proc_macro( - server: Option<&ProcMacroServer>, + server: Result<&ProcMacroServer, &String>, path: &AbsPath, dummy_replace: &[Box], ) -> ProcMacroLoadResult { let res: Result, String> = (|| { let dylib = MacroDylib::new(path.to_path_buf()) .map_err(|io| format!("Proc-macro dylib loading failed: {io}"))?; - let server = server.ok_or_else(|| format!("Proc-macro server not started"))?; + let server = server.map_err(ToOwned::to_owned)?; let vec = server.load_dylib(dylib).map_err(|e| format!("{e}"))?; if vec.is_empty() { return Err("proc macro library returned no proc macros".to_string()); From fb063d360ce66e9f1316c3e64885e00344062e55 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 22 Jul 2022 18:12:21 +0900 Subject: [PATCH 0007/2442] Add `ellipsis` to HIR `RecordLit` --- crates/hir-def/src/body/lower.rs | 5 +++-- crates/hir-def/src/expr.rs | 1 + crates/hir-ty/src/diagnostics/expr.rs | 2 +- crates/hir-ty/src/infer/expr.rs | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index c3f261122784..b43699de1203 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -378,9 +378,10 @@ impl ExprCollector<'_> { }) .collect(); let spread = nfl.spread().map(|s| self.collect_expr(s)); - Expr::RecordLit { path, fields, spread } + let ellipsis = nfl.dotdot_token().is_some(); + Expr::RecordLit { path, fields, spread, ellipsis } } else { - Expr::RecordLit { path, fields: Box::default(), spread: None } + Expr::RecordLit { path, fields: Box::default(), spread: None, ellipsis: false } }; self.alloc_expr(record_lit, syntax_ptr) diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs index a991365d6bf4..145fe4c19db4 100644 --- a/crates/hir-def/src/expr.rs +++ b/crates/hir-def/src/expr.rs @@ -138,6 +138,7 @@ pub enum Expr { path: Option>, fields: Box<[RecordLitField]>, spread: Option, + ellipsis: bool, }, Field { expr: ExprId, diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs index 8cca522aef62..1fcb4c2976eb 100644 --- a/crates/hir-ty/src/diagnostics/expr.rs +++ b/crates/hir-ty/src/diagnostics/expr.rs @@ -305,7 +305,7 @@ pub fn record_literal_missing_fields( expr: &Expr, ) -> Option<(VariantId, Vec, /*exhaustive*/ bool)> { let (fields, exhaustive) = match expr { - Expr::RecordLit { path: _, fields, spread } => (fields, spread.is_none()), + Expr::RecordLit { fields, spread, .. } => (fields, spread.is_none()), _ => return None, }; diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 2f3346707209..9debe835473a 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -421,7 +421,7 @@ impl<'a> InferenceContext<'a> { } TyKind::Never.intern(Interner) } - Expr::RecordLit { path, fields, spread } => { + Expr::RecordLit { path, fields, spread, .. } => { let (ty, def_id) = self.resolve_variant(path.as_deref(), false); if let Some(variant) = def_id { self.write_variant_resolution(tgt_expr.into(), variant); From 64758bd48195241dbf39a63974ecbcdcd151f399 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Sun, 24 Jul 2022 22:32:49 +0900 Subject: [PATCH 0008/2442] Add info whether it's assignee expr to relevant HIR `Expr` variants --- crates/hir-def/src/body/lower.rs | 41 +++++++++++++++++++++++++------- crates/hir-def/src/expr.rs | 11 +++++---- crates/hir-ty/src/infer/expr.rs | 16 ++++++------- 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index b43699de1203..66f9c24e8724 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -96,6 +96,7 @@ pub(super) fn lower( expander, name_to_pat_grouping: Default::default(), is_lowering_inside_or_pat: false, + is_lowering_assignee_expr: false, } .collect(params, body) } @@ -109,6 +110,7 @@ struct ExprCollector<'a> { // a poor-mans union-find? name_to_pat_grouping: FxHashMap>, is_lowering_inside_or_pat: bool, + is_lowering_assignee_expr: bool, } impl ExprCollector<'_> { @@ -283,7 +285,10 @@ impl ExprCollector<'_> { } else { Box::default() }; - self.alloc_expr(Expr::Call { callee, args }, syntax_ptr) + self.alloc_expr( + Expr::Call { callee, args, is_assignee_expr: self.is_lowering_assignee_expr }, + syntax_ptr, + ) } ast::Expr::MethodCallExpr(e) => { let receiver = self.collect_expr_opt(e.receiver()); @@ -359,6 +364,7 @@ impl ExprCollector<'_> { ast::Expr::RecordExpr(e) => { let path = e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); + let is_assignee_expr = self.is_lowering_assignee_expr; let record_lit = if let Some(nfl) = e.record_expr_field_list() { let fields = nfl .fields() @@ -379,9 +385,15 @@ impl ExprCollector<'_> { .collect(); let spread = nfl.spread().map(|s| self.collect_expr(s)); let ellipsis = nfl.dotdot_token().is_some(); - Expr::RecordLit { path, fields, spread, ellipsis } + Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr } } else { - Expr::RecordLit { path, fields: Box::default(), spread: None, ellipsis: false } + Expr::RecordLit { + path, + fields: Box::default(), + spread: None, + ellipsis: false, + is_assignee_expr, + } }; self.alloc_expr(record_lit, syntax_ptr) @@ -459,14 +471,21 @@ impl ExprCollector<'_> { ) } ast::Expr::BinExpr(e) => { - let lhs = self.collect_expr_opt(e.lhs()); - let rhs = self.collect_expr_opt(e.rhs()); let op = e.op_kind(); + if let Some(ast::BinaryOp::Assignment { op: None }) = op { + self.is_lowering_assignee_expr = true; + } + let lhs = self.collect_expr_opt(e.lhs()); + self.is_lowering_assignee_expr = false; + let rhs = self.collect_expr_opt(e.rhs()); self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr) } ast::Expr::TupleExpr(e) => { let exprs = e.fields().map(|expr| self.collect_expr(expr)).collect(); - self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr) + self.alloc_expr( + Expr::Tuple { exprs, is_assignee_expr: self.is_lowering_assignee_expr }, + syntax_ptr, + ) } ast::Expr::BoxExpr(e) => { let expr = self.collect_expr_opt(e.expr()); @@ -478,8 +497,14 @@ impl ExprCollector<'_> { match kind { ArrayExprKind::ElementList(e) => { - let exprs = e.map(|expr| self.collect_expr(expr)).collect(); - self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr) + let elements = e.map(|expr| self.collect_expr(expr)).collect(); + self.alloc_expr( + Expr::Array(Array::ElementList { + elements, + is_assignee_expr: self.is_lowering_assignee_expr, + }), + syntax_ptr, + ) } ArrayExprKind::Repeat { initializer, repeat } => { let initializer = self.collect_expr_opt(initializer); diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs index 145fe4c19db4..c1b3788acb7d 100644 --- a/crates/hir-def/src/expr.rs +++ b/crates/hir-def/src/expr.rs @@ -110,6 +110,7 @@ pub enum Expr { Call { callee: ExprId, args: Box<[ExprId]>, + is_assignee_expr: bool, }, MethodCall { receiver: ExprId, @@ -139,6 +140,7 @@ pub enum Expr { fields: Box<[RecordLitField]>, spread: Option, ellipsis: bool, + is_assignee_expr: bool, }, Field { expr: ExprId, @@ -197,6 +199,7 @@ pub enum Expr { }, Tuple { exprs: Box<[ExprId]>, + is_assignee_expr: bool, }, Unsafe { body: ExprId, @@ -212,7 +215,7 @@ pub enum Expr { #[derive(Debug, Clone, Eq, PartialEq)] pub enum Array { - ElementList(Box<[ExprId]>), + ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool }, Repeat { initializer: ExprId, repeat: ExprId }, } @@ -286,7 +289,7 @@ impl Expr { f(*iterable); f(*body); } - Expr::Call { callee, args } => { + Expr::Call { callee, args, .. } => { f(*callee); args.iter().copied().for_each(f); } @@ -340,9 +343,9 @@ impl Expr { | Expr::Box { expr } => { f(*expr); } - Expr::Tuple { exprs } => exprs.iter().copied().for_each(f), + Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f), Expr::Array(a) => match a { - Array::ElementList(exprs) => exprs.iter().copied().for_each(f), + Array::ElementList { elements, .. } => elements.iter().copied().for_each(f), Array::Repeat { initializer, repeat } => { f(*initializer); f(*repeat) diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 9debe835473a..d164e64a8be0 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -276,7 +276,7 @@ impl<'a> InferenceContext<'a> { closure_ty } - Expr::Call { callee, args } => { + Expr::Call { callee, args, .. } => { let callee_ty = self.infer_expr(*callee, &Expectation::none()); let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone()); let mut res = None; @@ -693,7 +693,7 @@ impl<'a> InferenceContext<'a> { self.err_ty() } } - Expr::Tuple { exprs } => { + Expr::Tuple { exprs, .. } => { let mut tys = match expected .only_has_type(&mut self.table) .as_ref() @@ -724,12 +724,12 @@ impl<'a> InferenceContext<'a> { let expected = Expectation::has_type(elem_ty.clone()); let len = match array { - Array::ElementList(items) => { - for &expr in items.iter() { + Array::ElementList { elements, .. } => { + for &expr in elements.iter() { let cur_elem_ty = self.infer_expr_inner(expr, &expected); coerce.coerce(self, Some(expr), &cur_elem_ty); } - consteval::usize_const(Some(items.len() as u128)) + consteval::usize_const(Some(elements.len() as u128)) } &Array::Repeat { initializer, repeat } => { self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty)); @@ -850,7 +850,7 @@ impl<'a> InferenceContext<'a> { let rhs_ty = self.resolve_ty_shallow(rhs_ty); let ty = match &self.body[lhs] { - Expr::Tuple { exprs } => { + Expr::Tuple { exprs, .. } => { // We don't consider multiple ellipses. This is analogous to // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`. let ellipsis = exprs.iter().position(|e| is_rest_expr(*e)); @@ -858,7 +858,7 @@ impl<'a> InferenceContext<'a> { self.infer_tuple_pat_like(&rhs_ty, (), ellipsis, &exprs) } - Expr::Call { callee, args } => { + Expr::Call { callee, args, .. } => { // Tuple structs let path = match &self.body[*callee] { Expr::Path(path) => Some(path), @@ -872,7 +872,7 @@ impl<'a> InferenceContext<'a> { self.infer_tuple_struct_pat_like(path, &rhs_ty, (), lhs, ellipsis, &args) } - Expr::Array(Array::ElementList(elements)) => { + Expr::Array(Array::ElementList { elements, .. }) => { let elem_ty = match rhs_ty.kind(Interner) { TyKind::Array(st, _) => st.clone(), _ => self.err_ty(), From 805ac666ca8cb2b643026ff454951e9ce3834d94 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Sun, 24 Jul 2022 22:34:53 +0900 Subject: [PATCH 0009/2442] fix: consider assignee expressions in record fields exhaustiveness check --- crates/hir-ty/src/diagnostics/expr.rs | 5 ++- .../src/handlers/missing_fields.rs | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs index 1fcb4c2976eb..642e03edd230 100644 --- a/crates/hir-ty/src/diagnostics/expr.rs +++ b/crates/hir-ty/src/diagnostics/expr.rs @@ -305,7 +305,10 @@ pub fn record_literal_missing_fields( expr: &Expr, ) -> Option<(VariantId, Vec, /*exhaustive*/ bool)> { let (fields, exhaustive) = match expr { - Expr::RecordLit { fields, spread, .. } => (fields, spread.is_none()), + Expr::RecordLit { fields, spread, ellipsis, is_assignee_expr, .. } => { + let exhaustive = if *is_assignee_expr { !*ellipsis } else { spread.is_none() }; + (fields, exhaustive) + } _ => return None, }; diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index 30f903af50d5..edb1fc0919c2 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -292,6 +292,37 @@ fn x(a: S) { ) } + #[test] + fn missing_record_expr_in_assignee_expr() { + check_diagnostics( + r" +struct S { s: usize, t: usize } +struct S2 { s: S, t: () } +struct T(S); +fn regular(a: S) { + let s; + S { s, .. } = a; +} +fn nested(a: S2) { + let s; + S2 { s: S { s, .. }, .. } = a; +} +fn in_tuple(a: (S,)) { + let s; + (S { s, .. },) = a; +} +fn in_array(a: [S;1]) { + let s; + [S { s, .. },] = a; +} +fn in_tuple_struct(a: T) { + let s; + T(S { s, .. }) = a; +} + ", + ); + } + #[test] fn range_mapping_out_of_macros() { check_fix( From 77acb5c162957d9748d1f35261982591d9a85e22 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Sun, 24 Jul 2022 00:29:07 -0500 Subject: [PATCH 0010/2442] fix: Autocomplete for struct fields includes receiver fixes #12857 --- crates/ide-completion/src/render.rs | 40 ++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 3f25b294e018..9b25964a6086 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -121,7 +121,7 @@ pub(crate) fn render_field( let mut item = CompletionItem::new( SymbolKind::Field, ctx.source_range(), - receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name).into()), + field_with_receiver(receiver.as_ref(), &name), ); item.set_relevance(CompletionRelevance { type_match: compute_type_match(ctx.completion, ty), @@ -132,7 +132,7 @@ pub(crate) fn render_field( .set_documentation(field.docs(ctx.db())) .set_deprecated(is_deprecated) .lookup_by(name.clone()); - item.insert_text(escaped_name); + item.insert_text(field_with_receiver(receiver.as_ref(), &escaped_name)); if let Some(receiver) = &dot_access.receiver { if let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) { if let Some(ref_match) = compute_ref_match(ctx.completion, ty) { @@ -143,6 +143,11 @@ pub(crate) fn render_field( item.build() } +fn field_with_receiver(receiver: Option<&hir::Name>, field_name: &str) -> SmolStr { + receiver + .map_or_else(|| field_name.into(), |receiver| format!("{}.{}", receiver, field_name).into()) +} + pub(crate) fn render_tuple_field( ctx: RenderContext<'_>, receiver: Option, @@ -152,7 +157,7 @@ pub(crate) fn render_tuple_field( let mut item = CompletionItem::new( SymbolKind::Field, ctx.source_range(), - receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), + field_with_receiver(receiver.as_ref(), &field.to_string()), ); item.detail(ty.display(ctx.db()).to_string()).lookup_by(field.to_string()); item.build() @@ -1873,6 +1878,35 @@ impl r#trait for r#struct { type t$0 } struct r#struct {} trait r#trait { type r#type; } impl r#trait for r#struct { type r#type = $0; } +"#, + ) + } + + #[test] + fn field_access_includes_self() { + check_edit( + "length", + r#" +struct S { + length: i32 +} + +impl S { + fn some_fn(&self) { + let l = len$0 + } +} +"#, + r#" +struct S { + length: i32 +} + +impl S { + fn some_fn(&self) { + let l = self.length + } +} "#, ) } From 71225c35bf86e639e3a3cfaf229a9c29f6815751 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Mon, 25 Jul 2022 18:40:35 +0900 Subject: [PATCH 0011/2442] Replace `debug_assert!` with `stdx::always!` --- crates/ide-assists/src/utils/gen_trait_fn_body.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/crates/ide-assists/src/utils/gen_trait_fn_body.rs index 43aaad3150ce..7a0c912959a1 100644 --- a/crates/ide-assists/src/utils/gen_trait_fn_body.rs +++ b/crates/ide-assists/src/utils/gen_trait_fn_body.rs @@ -28,7 +28,7 @@ pub(crate) fn gen_trait_fn_body( /// Generate a `Clone` impl based on the fields and members of the target type. fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - debug_assert!(func.name().map_or(false, |name| name.text() == "clone")); + stdx::always!(func.name().map_or(false, |name| name.text() == "clone")); fn gen_clone_call(target: ast::Expr) -> ast::Expr { let method = make::name_ref("clone"); make::expr_method_call(target, method, make::arg_list(None)) @@ -340,7 +340,7 @@ fn gen_default_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { /// Generate a `Hash` impl based on the fields and members of the target type. fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - debug_assert!(func.name().map_or(false, |name| name.text() == "hash")); + stdx::always!(func.name().map_or(false, |name| name.text() == "hash")); fn gen_hash_call(target: ast::Expr) -> ast::Stmt { let method = make::name_ref("hash"); let arg = make::expr_path(make::ext::ident_path("state")); @@ -396,7 +396,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { /// Generate a `PartialEq` impl based on the fields and members of the target type. fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - debug_assert!(func.name().map_or(false, |name| name.text() == "eq")); + stdx::always!(func.name().map_or(false, |name| name.text() == "eq")); fn gen_eq_chain(expr: Option, cmp: ast::Expr) -> Option { match expr { Some(expr) => Some(make::expr_bin_op(expr, BinaryOp::LogicOp(LogicOp::And), cmp)), @@ -573,7 +573,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { } fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - debug_assert!(func.name().map_or(false, |name| name.text() == "partial_cmp")); + stdx::always!(func.name().map_or(false, |name| name.text() == "partial_cmp")); fn gen_partial_eq_match(match_target: ast::Expr) -> Option { let mut arms = vec![]; From dc9405081531d0f3e68d984290b4d752bee3b9bd Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Mon, 25 Jul 2022 14:18:28 +0200 Subject: [PATCH 0012/2442] revert nightly rustfmt formatting that accidentally slipped in cf. https://github.com/rust-lang/rust/pull/99603 cf. https://github.com/rust-lang/rust-analyzer/pull/12871#discussion_r928816339 --- crates/hir-def/src/import_map.rs | 6 +++++- crates/hir-def/src/nameres.rs | 6 +++++- crates/proc-macro-test/build.rs | 3 +-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs index 688055e430bd..05e0ceb05a9a 100644 --- a/crates/hir-def/src/import_map.rs +++ b/crates/hir-def/src/import_map.rs @@ -167,7 +167,11 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMap { let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| { let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public); - if per_ns.is_none() { None } else { Some((name, per_ns)) } + if per_ns.is_none() { + None + } else { + Some((name, per_ns)) + } }); for (name, per_ns) in visible_items { diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 756fd583af4d..3949fbb6e7b0 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -334,7 +334,11 @@ impl DefMap { pub(crate) fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId { self.with_ancestor_maps(db, self.root, &mut |def_map, _module| { - if def_map.block.is_none() { Some(def_map.module_id(def_map.root)) } else { None } + if def_map.block.is_none() { + Some(def_map.module_id(def_map.root)) + } else { + None + } }) .expect("DefMap chain without root") } diff --git a/crates/proc-macro-test/build.rs b/crates/proc-macro-test/build.rs index c90144509dec..a80c962617bb 100644 --- a/crates/proc-macro-test/build.rs +++ b/crates/proc-macro-test/build.rs @@ -62,8 +62,7 @@ fn main() { Command::new(toolchain::cargo()) }; - cmd - .current_dir(&staging_dir) + cmd.current_dir(&staging_dir) .args(&["build", "-p", "proc-macro-test-impl", "--message-format", "json"]) // Explicit override the target directory to avoid using the same one which the parent // cargo is using, or we'll deadlock. From 5f54ec0e859a020b125519d56ad2a08defd3ddf3 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Sat, 23 Jul 2022 22:47:34 +0200 Subject: [PATCH 0013/2442] Add a proc-macro-srv-cli crate --- Cargo.lock | 7 +++++++ crates/proc-macro-srv-cli/Cargo.toml | 13 +++++++++++++ crates/proc-macro-srv-cli/src/main.rs | 5 +++++ 3 files changed, 25 insertions(+) create mode 100644 crates/proc-macro-srv-cli/Cargo.toml create mode 100644 crates/proc-macro-srv-cli/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 4c830006832c..703f0e5b8af9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1198,6 +1198,13 @@ dependencies = [ "tt", ] +[[package]] +name = "proc-macro-srv-cli" +version = "0.0.0" +dependencies = [ + "proc-macro-srv", +] + [[package]] name = "proc-macro-test" version = "0.0.0" diff --git a/crates/proc-macro-srv-cli/Cargo.toml b/crates/proc-macro-srv-cli/Cargo.toml new file mode 100644 index 000000000000..959002f664a6 --- /dev/null +++ b/crates/proc-macro-srv-cli/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "proc-macro-srv-cli" +version = "0.0.0" +description = "TBD" +license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.57" + +[dependencies] +proc-macro-srv = { version = "0.0.0", path = "../proc-macro-srv" } + +[features] +sysroot-abi = ["proc-macro-srv/sysroot-abi"] diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs new file mode 100644 index 000000000000..ea16cfff4b99 --- /dev/null +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -0,0 +1,5 @@ +use proc_macro_srv::cli; + +fn main() { + cli::run().unwrap(); +} From fba6adfae48d55984934872a81d533dc405b7cd3 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Sun, 24 Jul 2022 00:48:20 +0200 Subject: [PATCH 0014/2442] Add doc comment to pass tidy check --- crates/proc-macro-srv-cli/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index ea16cfff4b99..0f23a7daafa2 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -1,3 +1,5 @@ +//! A standalone binary for `proc-macro-srv`. + use proc_macro_srv::cli; fn main() { From fd1b64ec718d8483a98872bd91ee8f11b6893e7f Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Sun, 24 Jul 2022 14:50:30 +0200 Subject: [PATCH 0015/2442] Return result directly Co-authored-by: Lukas Wirth --- crates/proc-macro-srv-cli/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index 0f23a7daafa2..8398f2ba6cb7 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -2,6 +2,6 @@ use proc_macro_srv::cli; -fn main() { - cli::run().unwrap(); +fn main() -> std::io::Result<()> { + cli::run() } From 4364531c2f3db41d9ba3a72f3e77ab26d16db8b0 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Sun, 24 Jul 2022 14:53:20 +0200 Subject: [PATCH 0016/2442] Name the binary 'proc-macro-srv' --- crates/proc-macro-srv-cli/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/proc-macro-srv-cli/Cargo.toml b/crates/proc-macro-srv-cli/Cargo.toml index 959002f664a6..badb594f0629 100644 --- a/crates/proc-macro-srv-cli/Cargo.toml +++ b/crates/proc-macro-srv-cli/Cargo.toml @@ -11,3 +11,7 @@ proc-macro-srv = { version = "0.0.0", path = "../proc-macro-srv" } [features] sysroot-abi = ["proc-macro-srv/sysroot-abi"] + +[[bin]] +name = "proc-macro-srv" +path = "src/main.rs" From dadb83282d7dc7bfb408d93d4953019a328e8e2b Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Mon, 25 Jul 2022 16:07:41 +0200 Subject: [PATCH 0017/2442] Remember the difference between 'sysroot root' and 'sysroot src root', start looking in there for a rust-analyzer-proc-macro-srv binary --- crates/project-model/src/project_json.rs | 5 ++++ crates/project-model/src/sysroot.rs | 21 +++++++++++++---- crates/project-model/src/tests.rs | 7 ++++-- crates/project-model/src/workspace.rs | 12 +++++++--- crates/rust-analyzer/src/reload.rs | 30 ++++++++++++++++++++++-- 5 files changed, 63 insertions(+), 12 deletions(-) diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs index a3c5ac167406..63d1d0ace96b 100644 --- a/crates/project-model/src/project_json.rs +++ b/crates/project-model/src/project_json.rs @@ -17,6 +17,9 @@ use crate::cfg_flag::CfgFlag; /// Roots and crates that compose this Rust project. #[derive(Clone, Debug, Eq, PartialEq)] pub struct ProjectJson { + /// e.g. `path/to/sysroot` + pub(crate) sysroot: Option, + /// e.g. `path/to/sysroot/lib/rustlib/src/rust` pub(crate) sysroot_src: Option, project_root: AbsPathBuf, crates: Vec, @@ -52,6 +55,7 @@ impl ProjectJson { /// configuration. pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { ProjectJson { + sysroot: data.sysroot.map(|it| base.join(it)), sysroot_src: data.sysroot_src.map(|it| base.join(it)), project_root: base.to_path_buf(), crates: data @@ -122,6 +126,7 @@ impl ProjectJson { #[derive(Deserialize, Debug, Clone)] pub struct ProjectJsonData { + sysroot: Option, sysroot_src: Option, crates: Vec, } diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index 52750f48969f..b17a59b10bb5 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -15,6 +15,7 @@ use crate::{utf8_stdout, ManifestPath}; #[derive(Debug, Clone, Eq, PartialEq)] pub struct Sysroot { root: AbsPathBuf, + src_root: AbsPathBuf, crates: Arena, } @@ -35,6 +36,15 @@ impl ops::Index for Sysroot { } impl Sysroot { + /// Returns sysroot directory, where `bin/`, `etc/`, `lib/`, `libexec/` + /// subfolder live, like: + /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library` + pub fn src_root(&self) -> &AbsPath { + &self.src_root + } + + /// Returns sysroot "src" directory, where stdlib sources are located, like: + /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu` pub fn root(&self) -> &AbsPath { &self.root } @@ -61,7 +71,7 @@ impl Sysroot { tracing::debug!("Discovering sysroot for {}", dir.display()); let sysroot_dir = discover_sysroot_dir(dir)?; let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir)?; - let res = Sysroot::load(sysroot_src_dir)?; + let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?; Ok(res) } @@ -71,14 +81,15 @@ impl Sysroot { discover_sysroot_dir(current_dir).ok().and_then(|sysroot_dir| get_rustc_src(&sysroot_dir)) } - pub fn load(sysroot_src_dir: AbsPathBuf) -> Result { - let mut sysroot = Sysroot { root: sysroot_src_dir, crates: Arena::default() }; + pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result { + let mut sysroot = + Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() }; for path in SYSROOT_CRATES.trim().lines() { let name = path.split('/').last().unwrap(); let root = [format!("{}/src/lib.rs", path), format!("lib{}/lib.rs", path)] .into_iter() - .map(|it| sysroot.root.join(it)) + .map(|it| sysroot.src_root.join(it)) .filter_map(|it| ManifestPath::try_from(it).ok()) .find(|it| fs::metadata(it).is_ok()); @@ -119,7 +130,7 @@ impl Sysroot { }; anyhow::bail!( "could not find libcore in sysroot path `{}`{}", - sysroot.root.as_path().display(), + sysroot.src_root.as_path().display(), var_note, ); } diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index ddfea0ce4c4f..e304a59c0180 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -75,8 +75,11 @@ fn get_test_path(file: &str) -> PathBuf { fn get_fake_sysroot() -> Sysroot { let sysroot_path = get_test_path("fake-sysroot"); - let sysroot_src_dir = AbsPathBuf::assert(sysroot_path); - Sysroot::load(sysroot_src_dir).unwrap() + // there's no `libexec/` directory with a `proc-macro-srv` binary in that + // fake sysroot, so we give them both the same path: + let sysroot_dir = AbsPathBuf::assert(sysroot_path); + let sysroot_src_dir = sysroot_dir.clone(); + Sysroot::load(sysroot_dir, sysroot_src_dir).unwrap() } fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index de4245835456..63882466fa41 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -230,8 +230,14 @@ impl ProjectWorkspace { project_json: ProjectJson, target: Option<&str>, ) -> Result { - let sysroot = match &project_json.sysroot_src { - Some(path) => Some(Sysroot::load(path.clone())?), + let sysroot = match project_json.sysroot_src.clone() { + Some(sysroot_src) => { + // if `sysroot` isn't specified (only `sysroot_src`), we won't have + // a real sysroot path, that's fine. it's just used to discover + // the standalone `proc-macro-srv` binary. + let sysroot = project_json.sysroot.clone().unwrap_or_else(|| sysroot_src.clone()); + Some(Sysroot::load(sysroot, sysroot_src)?) + } None => None, }; let rustc_cfg = rustc_cfg::get(None, target); @@ -345,7 +351,7 @@ impl ProjectWorkspace { }) .chain(sysroot.iter().map(|sysroot| PackageRoot { is_local: false, - include: vec![sysroot.root().to_path_buf()], + include: vec![sysroot.src_root().to_path_buf()], exclude: Vec::new(), })) .chain(rustc.iter().flat_map(|rustc| { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index e5802773e747..4256c2a764a3 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -305,8 +305,34 @@ impl GlobalState { if self.proc_macro_clients.is_empty() { if let Some((path, args)) = self.config.proc_macro_srv() { - self.proc_macro_clients = (0..self.workspaces.len()) - .map(|_| { + self.proc_macro_clients = self + .workspaces + .iter() + .map(|ws| { + let mut path = path.clone(); + if let ProjectWorkspace::Cargo { sysroot, .. } = ws { + tracing::info!("Found a cargo workspace..."); + if let Some(sysroot) = sysroot.as_ref() { + tracing::info!("Found a cargo workspace with a sysroot..."); + let server_path = sysroot + .root() + .join("libexec") + .join("rust-analyzer-proc-macro-srv"); + if std::fs::metadata(&server_path).is_ok() { + tracing::info!( + "And the server exists at {}", + server_path.display() + ); + path = server_path; + } else { + tracing::info!( + "And the server does not exist at {}", + server_path.display() + ); + } + } + } + ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| { let error = format!( "Failed to run proc_macro_srv from path {}, error: {:?}", From 74a2fad5e6b6193842fe52b50ee174736efb266d Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Mon, 25 Jul 2022 16:22:39 +0200 Subject: [PATCH 0018/2442] Gate and rename binary, use it if it's in the sysroot --- crates/proc-macro-api/src/process.rs | 1 + crates/proc-macro-srv-cli/Cargo.toml | 2 +- crates/proc-macro-srv-cli/src/main.rs | 12 ++++++++++++ crates/rust-analyzer/src/reload.rs | 8 ++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index ff4c59447d87..c4018d3b39e7 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -86,6 +86,7 @@ fn mk_child( ) -> io::Result { Command::new(path.as_os_str()) .args(args) + .env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::inherit()) diff --git a/crates/proc-macro-srv-cli/Cargo.toml b/crates/proc-macro-srv-cli/Cargo.toml index badb594f0629..9d0da5dee9c1 100644 --- a/crates/proc-macro-srv-cli/Cargo.toml +++ b/crates/proc-macro-srv-cli/Cargo.toml @@ -13,5 +13,5 @@ proc-macro-srv = { version = "0.0.0", path = "../proc-macro-srv" } sysroot-abi = ["proc-macro-srv/sysroot-abi"] [[bin]] -name = "proc-macro-srv" +name = "rust-analyzer-proc-macro-srv" path = "src/main.rs" diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index 8398f2ba6cb7..ac9fa9f5a4ce 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -3,5 +3,17 @@ use proc_macro_srv::cli; fn main() -> std::io::Result<()> { + let v = std::env::var("RUST_ANALYZER_INTERNALS_DO_NOT_USE"); + match v.as_deref() { + Ok("this is unstable") => { + // very well, if you must + } + _ => { + eprintln!("If you're rust-analyzer, you can use this tool by exporting RUST_ANALYZER_INTERNALS_DO_NOT_USE='this is unstable'."); + eprintln!("If not, you probably shouldn't use this tool. But do what you want: I'm an error message, not a cop."); + std::process::exit(122); + } + } + cli::run() } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 4256c2a764a3..9ae361b034e2 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -309,7 +309,9 @@ impl GlobalState { .workspaces .iter() .map(|ws| { + let mut args = args.clone(); let mut path = path.clone(); + if let ProjectWorkspace::Cargo { sysroot, .. } = ws { tracing::info!("Found a cargo workspace..."); if let Some(sysroot) = sysroot.as_ref() { @@ -324,6 +326,7 @@ impl GlobalState { server_path.display() ); path = server_path; + args = vec![]; } else { tracing::info!( "And the server does not exist at {}", @@ -333,6 +336,11 @@ impl GlobalState { } } + tracing::info!( + "Using proc-macro server at {} with args {:?}", + path.display(), + args + ); ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| { let error = format!( "Failed to run proc_macro_srv from path {}, error: {:?}", From 696775153dffaa701bcabe67b5fe601db862c4f4 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Mon, 25 Jul 2022 16:59:10 +0200 Subject: [PATCH 0019/2442] Fix mix up in comments --- crates/project-model/src/sysroot.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index b17a59b10bb5..362bb0f5e79c 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -36,19 +36,19 @@ impl ops::Index for Sysroot { } impl Sysroot { - /// Returns sysroot directory, where `bin/`, `etc/`, `lib/`, `libexec/` + /// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/` /// subfolder live, like: - /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library` - pub fn src_root(&self) -> &AbsPath { - &self.src_root - } - - /// Returns sysroot "src" directory, where stdlib sources are located, like: /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu` pub fn root(&self) -> &AbsPath { &self.root } + /// Returns the sysroot "source" directory, where stdlib sources are located, like: + /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library` + pub fn src_root(&self) -> &AbsPath { + &self.src_root + } + pub fn public_deps(&self) -> impl Iterator + '_ { // core is added as a dependency before std in order to // mimic rustcs dependency order From 2c2520fbb48b977a805b46af79e4016a4394e719 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Mon, 25 Jul 2022 17:52:38 +0200 Subject: [PATCH 0020/2442] Allow specifying sysroot OR sysroot_src --- crates/project-model/src/workspace.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 63882466fa41..b144006b44e0 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -230,16 +230,26 @@ impl ProjectWorkspace { project_json: ProjectJson, target: Option<&str>, ) -> Result { - let sysroot = match project_json.sysroot_src.clone() { - Some(sysroot_src) => { - // if `sysroot` isn't specified (only `sysroot_src`), we won't have - // a real sysroot path, that's fine. it's just used to discover - // the standalone `proc-macro-srv` binary. - let sysroot = project_json.sysroot.clone().unwrap_or_else(|| sysroot_src.clone()); + let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) { + (Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?), + (Some(sysroot), None) => { + // assume sysroot is structured like rustup's and guess `sysroot_src` + let sysroot_src = + sysroot.join("lib").join("rustlib").join("src").join("rust").join("library"); + Some(Sysroot::load(sysroot, sysroot_src)?) } - None => None, + (None, Some(sysroot_src)) => { + // assume sysroot is structured like rustup's and guess `sysroot` + let mut sysroot = sysroot_src.clone(); + for _ in 0..5 { + sysroot.pop(); + } + Some(Sysroot::load(sysroot, sysroot_src)?) + } + (None, None) => None, }; + let rustc_cfg = rustc_cfg::get(None, target); Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) } From e45a250f8c26e94a2a3ff8b50305530f75718239 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Mon, 25 Jul 2022 15:43:25 -0500 Subject: [PATCH 0021/2442] fix: Insert spaces when inlining a function defined in a macro. --- .../ide-assists/src/handlers/inline_call.rs | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs index 658a1aadf53e..8b2f6ac75a28 100644 --- a/crates/ide-assists/src/handlers/inline_call.rs +++ b/crates/ide-assists/src/handlers/inline_call.rs @@ -7,7 +7,7 @@ use ide_db::{ imports::insert_use::remove_path_if_in_use_stmt, path_transform::PathTransform, search::{FileReference, SearchScope}, - syntax_helpers::node_ext::expr_as_name_ref, + syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref}, RootDatabase, }; use itertools::{izip, Itertools}; @@ -301,7 +301,18 @@ fn inline( params: &[(ast::Pat, Option, hir::Param)], CallInfo { node, arguments, generic_arg_list }: &CallInfo, ) -> ast::Expr { - let body = fn_body.clone_for_update(); + let body = if sema.hir_file_for(fn_body.syntax()).is_macro() { + cov_mark::hit!(inline_call_defined_in_macro); + if let Some(body) = ast::BlockExpr::cast(insert_ws_into(fn_body.syntax().clone())) { + body + } else { + // FIXME(zachs18): I believe this should be unreachable, + // since insert_ws_into shouldn't change the kind of the SyntaxNode. + fn_body.clone_for_update() + } + } else { + fn_body.clone_for_update() + }; let usages_for_locals = |local| { Definition::Local(local) .usages(sema) @@ -1144,6 +1155,41 @@ fn bar() -> u32 { x }) + foo() } +"#, + ) + } + + #[test] + fn inline_call_defined_in_macro() { + cov_mark::check!(inline_call_defined_in_macro); + check_assist( + inline_call, + r#" +macro_rules! define_foo { + () => { fn foo() -> u32 { + let x = 0; + x + } }; +} +define_foo!(); +fn bar() -> u32 { + foo$0() +} +"#, + r#" +macro_rules! define_foo { + () => { fn foo() -> u32 { + let x = 0; + x + } }; +} +define_foo!(); +fn bar() -> u32 { + { + let x = 0; + x + } +} "#, ) } From 4e60db2d07b848d92a52d3fd9fa74e6a4f7f097f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 24 Jul 2022 12:04:15 +0200 Subject: [PATCH 0022/2442] feat: Downmap tokens inside derive helpers --- crates/hir-def/src/item_scope.rs | 35 ++++-- crates/hir-def/src/nameres.rs | 18 ++- crates/hir-def/src/nameres/collector.rs | 14 +-- crates/hir-def/src/resolver.rs | 6 +- crates/hir/src/semantics.rs | 132 ++++++++++++++-------- crates/hir/src/semantics/source_to_def.rs | 2 + crates/ide-db/src/rename.rs | 10 +- crates/ide-db/src/search.rs | 2 + crates/ide/src/hover.rs | 7 +- 9 files changed, 151 insertions(+), 75 deletions(-) diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index b98b2855cb08..579f803ea193 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -66,10 +66,14 @@ pub struct ItemScope { attr_macros: FxHashMap, MacroCallId>, /// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes /// paired with the derive macro invocations for the specific attribute. - derive_macros: FxHashMap< - AstId, - SmallVec<[(AttrId, MacroCallId, SmallVec<[Option; 1]>); 1]>, - >, + derive_macros: FxHashMap, SmallVec<[DeriveMacroInvocation; 1]>>, +} + +#[derive(Debug, PartialEq, Eq)] +struct DeriveMacroInvocation { + attr_id: AttrId, + attr_call_id: MacroCallId, + derive_call_ids: SmallVec<[Option; 1]>, } pub(crate) static BUILTIN_SCOPE: Lazy> = Lazy::new(|| { @@ -210,12 +214,14 @@ impl ItemScope { &mut self, adt: AstId, call: MacroCallId, - attr_id: AttrId, + id: AttrId, idx: usize, ) { if let Some(derives) = self.derive_macros.get_mut(&adt) { - if let Some((.., invocs)) = derives.iter_mut().find(|&&mut (id, ..)| id == attr_id) { - invocs[idx] = Some(call); + if let Some(DeriveMacroInvocation { derive_call_ids, .. }) = + derives.iter_mut().find(|&&mut DeriveMacroInvocation { attr_id, .. }| id == attr_id) + { + derive_call_ids[idx] = Some(call); } } } @@ -227,10 +233,14 @@ impl ItemScope { &mut self, adt: AstId, attr_id: AttrId, - call_id: MacroCallId, + attr_call_id: MacroCallId, len: usize, ) { - self.derive_macros.entry(adt).or_default().push((attr_id, call_id, smallvec![None; len])); + self.derive_macros.entry(adt).or_default().push(DeriveMacroInvocation { + attr_id, + attr_call_id, + derive_call_ids: smallvec![None; len], + }); } pub(crate) fn derive_macro_invocs( @@ -242,7 +252,12 @@ impl ItemScope { ), > + '_ { self.derive_macros.iter().map(|(k, v)| { - (*k, v.iter().map(|&(attr_id, call_id, ref invocs)| (attr_id, call_id, &**invocs))) + ( + *k, + v.iter().map(|DeriveMacroInvocation { attr_id, attr_call_id, derive_call_ids }| { + (*attr_id, *attr_call_id, &**derive_call_ids) + }), + ) }) } diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 3949fbb6e7b0..8165055e0924 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -57,10 +57,10 @@ mod proc_macro; #[cfg(test)] mod tests; -use std::{cmp::Ord, sync::Arc}; +use std::{ops::Deref, sync::Arc}; use base_db::{CrateId, Edition, FileId}; -use hir_expand::{name::Name, InFile, MacroDefId}; +use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId}; use itertools::Itertools; use la_arena::Arena; use profile::Count; @@ -106,6 +106,9 @@ pub struct DefMap { fn_proc_macro_mapping: FxHashMap, /// The error that occurred when failing to load the proc-macro dll. proc_macro_loading_error: Option>, + /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper + /// attributes. + derive_helpers_in_scope: FxHashMap, Vec<(Name, MacroCallId)>>, /// Custom attributes registered with `#![register_attr]`. registered_attrs: Vec, @@ -275,6 +278,7 @@ impl DefMap { exported_derives: FxHashMap::default(), fn_proc_macro_mapping: FxHashMap::default(), proc_macro_loading_error: None, + derive_helpers_in_scope: FxHashMap::default(), prelude: None, root, modules, @@ -294,12 +298,19 @@ impl DefMap { pub fn modules(&self) -> impl Iterator + '_ { self.modules.iter() } + + pub fn derive_helpers_in_scope(&self, id: AstId) -> Option<&[(Name, MacroCallId)]> { + self.derive_helpers_in_scope.get(&id.map(|it| it.upcast())).map(Deref::deref) + } + pub fn registered_tools(&self) -> &[SmolStr] { &self.registered_tools } + pub fn registered_attrs(&self) -> &[SmolStr] { &self.registered_attrs } + pub fn root(&self) -> LocalModuleId { self.root } @@ -307,6 +318,7 @@ impl DefMap { pub fn fn_as_proc_macro(&self, id: FunctionId) -> Option { self.fn_proc_macro_mapping.get(&id).copied() } + pub fn proc_macro_loading_error(&self) -> Option<&str> { self.proc_macro_loading_error.as_deref() } @@ -467,6 +479,7 @@ impl DefMap { registered_attrs, registered_tools, fn_proc_macro_mapping, + derive_helpers_in_scope, proc_macro_loading_error: _, block: _, edition: _, @@ -483,6 +496,7 @@ impl DefMap { registered_attrs.shrink_to_fit(); registered_tools.shrink_to_fit(); fn_proc_macro_mapping.shrink_to_fit(); + derive_helpers_in_scope.shrink_to_fit(); for (_, module) in modules.iter_mut() { module.children.shrink_to_fit(); module.scope.shrink_to_fit(); diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 67651e06413c..e14d29952dd7 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -110,7 +110,6 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T proc_macros, from_glob_import: Default::default(), skip_attrs: Default::default(), - derive_helpers_in_scope: Default::default(), is_proc_macro, }; if tree_id.is_block() { @@ -258,9 +257,6 @@ struct DefCollector<'a> { /// This also stores the attributes to skip when we resolve derive helpers and non-macro /// non-builtin attributes in general. skip_attrs: FxHashMap, AttrId>, - /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper - /// attributes. - derive_helpers_in_scope: FxHashMap, Vec>, } impl DefCollector<'_> { @@ -1132,8 +1128,8 @@ impl DefCollector<'_> { }; if let Some(ident) = path.as_ident() { - if let Some(helpers) = self.derive_helpers_in_scope.get(&ast_id) { - if helpers.contains(ident) { + if let Some(helpers) = self.def_map.derive_helpers_in_scope.get(&ast_id) { + if helpers.iter().any(|(it, _)| it == ident) { cov_mark::hit!(resolved_derive_helper); // Resolved to derive helper. Collect the item's attributes again, // starting after the derive helper. @@ -1322,10 +1318,11 @@ impl DefCollector<'_> { if loc.def.krate != self.def_map.krate { let def_map = self.db.crate_def_map(loc.def.krate); if let Some(helpers) = def_map.exported_derives.get(&loc.def) { - self.derive_helpers_in_scope + self.def_map + .derive_helpers_in_scope .entry(ast_id.map(|it| it.upcast())) .or_default() - .extend(helpers.iter().cloned()); + .extend(helpers.iter().cloned().zip(std::iter::repeat(macro_call_id))); } } } @@ -2140,7 +2137,6 @@ mod tests { proc_macros: Default::default(), from_glob_import: Default::default(), skip_attrs: Default::default(), - derive_helpers_in_scope: Default::default(), is_proc_macro: false, }; collector.seed_with_top_level(); diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index c8d3052102f4..0c1ae8a064a3 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -448,10 +448,14 @@ impl Resolver { } pub fn krate(&self) -> CrateId { + self.def_map().krate() + } + + pub fn def_map(&self) -> &DefMap { self.scopes .get(0) .and_then(|scope| match scope { - Scope::ModuleScope(m) => Some(m.def_map.krate()), + Scope::ModuleScope(m) => Some(&m.def_map), _ => None, }) .expect("module scope invariant violated") diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 043f2b7c24dc..218e15989ad3 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -733,6 +733,8 @@ impl<'db> SemanticsImpl<'db> { Some(it) => it, None => return, }; + let def_map = sa.resolver.def_map(); + let mut stack: SmallVec<[_; 4]> = smallvec![InFile::new(sa.file_id, token)]; let mut cache = self.expansion_info_cache.borrow_mut(); let mut mcache = self.macro_call_cache.borrow_mut(); @@ -764,7 +766,7 @@ impl<'db> SemanticsImpl<'db> { while let Some(token) = stack.pop() { self.db.unwind_if_cancelled(); let was_not_remapped = (|| { - // are we inside an attribute macro call + // First expand into attribute invocations let containing_attribute_macro_call = self.with_ctx(|ctx| { token.value.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| { if item.attrs().next().is_none() { @@ -784,53 +786,19 @@ impl<'db> SemanticsImpl<'db> { ); } - // or are we inside a function-like macro call - if let Some(tt) = - // FIXME replace map.while_some with take_while once stable - token - .value - .parent_ancestors() - .map(ast::TokenTree::cast) - .while_some() - .last() - { - let parent = tt.syntax().parent()?; - // check for derive attribute here - let macro_call = match_ast! { - match parent { - ast::MacroCall(mcall) => mcall, - // attribute we failed expansion for earlier, this might be a derive invocation - // so try downmapping the token into the pseudo derive expansion - // see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works - ast::Meta(meta) => { - let attr = meta.parent_attr()?; - let adt = attr.syntax().parent().and_then(ast::Adt::cast)?; - let call_id = self.with_ctx(|ctx| { - let (_, call_id, _) = ctx.attr_to_derive_macro_call( - token.with_value(&adt), - token.with_value(attr), - )?; - Some(call_id) - })?; - let file_id = call_id.as_file(); - return process_expansion_for_token( - &mut stack, - file_id, - Some(adt.into()), - token.as_ref(), - ); - }, - _ => return None, - } - }; + // Then check for token trees, that means we are either in a function-like macro or + // secondary attribute inputs + let tt = token.value.parent_ancestors().map_while(ast::TokenTree::cast).last()?; + let parent = tt.syntax().parent()?; - if tt.left_delimiter_token().map_or(false, |it| it == token.value) { - return None; - } - if tt.right_delimiter_token().map_or(false, |it| it == token.value) { - return None; - } + if tt.left_delimiter_token().map_or(false, |it| it == token.value) { + return None; + } + if tt.right_delimiter_token().map_or(false, |it| it == token.value) { + return None; + } + if let Some(macro_call) = ast::MacroCall::cast(parent.clone()) { let mcall = token.with_value(macro_call); let file_id = match mcache.get(&mcall) { Some(&it) => it, @@ -840,11 +808,75 @@ impl<'db> SemanticsImpl<'db> { it } }; - return process_expansion_for_token(&mut stack, file_id, None, token.as_ref()); - } + process_expansion_for_token(&mut stack, file_id, None, token.as_ref()) + } else if let Some(meta) = ast::Meta::cast(parent.clone()) { + // attribute we failed expansion for earlier, this might be a derive invocation + // or derive helper attribute + let attr = meta.parent_attr()?; - // outside of a macro invocation so this is a "final" token - None + let adt = if let Some(adt) = attr.syntax().parent().and_then(ast::Adt::cast) { + // this might be a derive, or a derive helper on an ADT + let derive_call = self.with_ctx(|ctx| { + // so try downmapping the token into the pseudo derive expansion + // see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works + ctx.attr_to_derive_macro_call( + token.with_value(&adt), + token.with_value(attr.clone()), + ) + .map(|(_, call_id, _)| call_id) + }); + + match derive_call { + Some(call_id) => { + // resolved to a derive + let file_id = call_id.as_file(); + return process_expansion_for_token( + &mut stack, + file_id, + Some(adt.into()), + token.as_ref(), + ); + } + None => Some(adt), + } + } else { + // Otherwise this could be a derive helper on a variant or field + if let Some(field) = attr.syntax().parent().and_then(ast::RecordField::cast) + { + field.syntax().ancestors().take(4).find_map(ast::Adt::cast) + } else if let Some(field) = + attr.syntax().parent().and_then(ast::TupleField::cast) + { + field.syntax().ancestors().take(4).find_map(ast::Adt::cast) + } else if let Some(variant) = + attr.syntax().parent().and_then(ast::Variant::cast) + { + variant.syntax().ancestors().nth(2).and_then(ast::Adt::cast) + } else { + None + } + }?; + + // Not an attribute, nor a derive, so it's either a builtin or a derive helper + // Try to resolve to a derive helper and downmap + let attr_name = attr.path().and_then(|it| it.as_single_name_ref())?.as_name(); + let id = self.db.ast_id_map(token.file_id).ast_id(&adt); + let helpers = + def_map.derive_helpers_in_scope(InFile::new(token.file_id, id))?; + let item = Some(adt.into()); + let mut res = None; + for (_, derive) in helpers.iter().filter(|(helper, _)| *helper == attr_name) { + res = res.or(process_expansion_for_token( + &mut stack, + derive.as_file(), + item.clone(), + token.as_ref(), + )); + } + res + } else { + None + } })() .is_none(); diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 5c4cfa7b45a5..ba9a1cfb6b51 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -247,6 +247,7 @@ impl SourceToDefCtx<'_, '_> { map[keys::ATTR_MACRO_CALL].get(&src.value).copied() } + /// (AttrId, derive attribute call id, derive call ids) pub(super) fn attr_to_derive_macro_call( &mut self, item: InFile<&ast::Adt>, @@ -257,6 +258,7 @@ impl SourceToDefCtx<'_, '_> { .get(&src.value) .map(|&(attr_id, call_id, ref ids)| (attr_id, call_id, &**ids)) } + pub(super) fn has_derives(&mut self, adt: InFile<&ast::Adt>) -> bool { self.dyn_map(adt).as_ref().map_or(false, |map| !map[keys::DERIVE_MACRO_CALL].is_empty()) } diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index bb466e43e752..dc1626f43967 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -316,14 +316,20 @@ pub fn source_edit_from_references( // macros can cause multiple refs to occur for the same text range, so keep track of what we have edited so far let mut edited_ranges = Vec::new(); for &FileReference { range, ref name, .. } in references { + let name_range = name.syntax().text_range(); + if name_range.len() != range.len() { + // This usage comes from a different token kind that was downmapped to a NameLike in a macro + // Renaming this will most likely break things syntax-wise + continue; + } let has_emitted_edit = match name { // if the ranges differ then the node is inside a macro call, we can't really attempt // to make special rewrites like shorthand syntax and such, so just rename the node in // the macro input - ast::NameLike::NameRef(name_ref) if name_ref.syntax().text_range() == range => { + ast::NameLike::NameRef(name_ref) if name_range == range => { source_edit_from_name_ref(&mut edit, name_ref, new_name, def) } - ast::NameLike::Name(name) if name.syntax().text_range() == range => { + ast::NameLike::Name(name) if name_range == range => { source_edit_from_name(&mut edit, name, new_name) } _ => false, diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index c75364084e36..eb4fc3643812 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -54,7 +54,9 @@ impl IntoIterator for UsageSearchResult { #[derive(Debug, Clone)] pub struct FileReference { + /// The range of the reference in the original file pub range: TextRange, + /// The node of the reference in the (macro-)file pub name: ast::NameLike, pub category: Option, } diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index d8867cf783ad..59c97f2dcf96 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -115,7 +115,12 @@ pub(crate) fn hover( }); } - let descended = sema.descend_into_macros_with_same_text(original_token.clone()); + let in_attr = matches!(original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind()))); + let descended = if in_attr { + [sema.descend_into_macros_with_kind_preference(original_token.clone())].into() + } else { + sema.descend_into_macros_with_same_text(original_token.clone()) + }; // FIXME: Definition should include known lints and the like instead of having this special case here let hovered_lint = descended.iter().find_map(|token| { From aa1491ecde22732329069773fed3e23f6b42e14d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 24 Jul 2022 14:05:37 +0200 Subject: [PATCH 0023/2442] Record derive helper attributes, resolve them in IDE layer --- crates/hir-def/src/lib.rs | 10 +-- crates/hir-def/src/nameres.rs | 9 ++- crates/hir-def/src/nameres/collector.rs | 50 ++++++++------- crates/hir-def/src/resolver.rs | 1 + crates/hir/src/lib.rs | 11 ++++ crates/hir/src/semantics.rs | 14 ++-- crates/hir/src/source_analyzer.rs | 64 +++++++++++++++---- crates/ide-completion/src/item.rs | 1 + crates/ide-db/src/defs.rs | 13 ++-- crates/ide-db/src/lib.rs | 1 + crates/ide-db/src/path_transform.rs | 3 +- crates/ide-db/src/rename.rs | 2 + crates/ide/src/doc_links.rs | 6 +- crates/ide/src/hover/render.rs | 2 + crates/ide/src/navigation_target.rs | 2 + crates/ide/src/signature_help.rs | 3 +- crates/ide/src/syntax_highlighting.rs | 1 + .../ide/src/syntax_highlighting/highlight.rs | 1 + crates/ide/src/syntax_highlighting/inject.rs | 1 + crates/ide/src/syntax_highlighting/tags.rs | 1 + crates/rust-analyzer/src/semantic_tokens.rs | 1 + crates/rust-analyzer/src/to_proto.rs | 5 +- 22 files changed, 144 insertions(+), 58 deletions(-) diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 0dd0a5861ef3..56603f4b1545 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -934,11 +934,11 @@ fn derive_macro_as_call_id( derive_attr: AttrId, derive_pos: u32, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option, -) -> Result { - let def: MacroDefId = resolver(item_attr.path.clone()) + resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>, +) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> { + let (macro_id, def_id) = resolver(item_attr.path.clone()) .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?; - let res = def.as_lazy_macro( + let call_id = def_id.as_lazy_macro( db.upcast(), krate, MacroCallKind::Derive { @@ -947,7 +947,7 @@ fn derive_macro_as_call_id( derive_attr_index: derive_attr.ast_index, }, ); - Ok(res) + Ok((macro_id, def_id, call_id)) } fn attr_macro_as_call_id( diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 8165055e0924..25fb302e8758 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -76,7 +76,7 @@ use crate::{ path::ModPath, per_ns::PerNs, visibility::Visibility, - AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, ModuleId, ProcMacroId, + AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, MacroId, ModuleId, ProcMacroId, }; /// Contains the results of (early) name resolution. @@ -108,7 +108,7 @@ pub struct DefMap { proc_macro_loading_error: Option>, /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper /// attributes. - derive_helpers_in_scope: FxHashMap, Vec<(Name, MacroCallId)>>, + derive_helpers_in_scope: FxHashMap, Vec<(Name, MacroId, MacroCallId)>>, /// Custom attributes registered with `#![register_attr]`. registered_attrs: Vec, @@ -299,7 +299,10 @@ impl DefMap { self.modules.iter() } - pub fn derive_helpers_in_scope(&self, id: AstId) -> Option<&[(Name, MacroCallId)]> { + pub fn derive_helpers_in_scope( + &self, + id: AstId, + ) -> Option<&[(Name, MacroId, MacroCallId)]> { self.derive_helpers_in_scope.get(&id.map(|it| it.upcast())).map(Deref::deref) } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index e14d29952dd7..f394c541719f 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -18,7 +18,7 @@ use hir_expand::{ ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, }; -use itertools::Itertools; +use itertools::{izip, Itertools}; use la_arena::Idx; use limit::Limit; use rustc_hash::{FxHashMap, FxHashSet}; @@ -1055,7 +1055,7 @@ impl DefCollector<'_> { }; let mut res = ReachedFixedPoint::Yes; macros.retain(|directive| { - let resolver = |path| { + let resolver2 = |path| { let resolved_res = self.def_map.resolve_path_fp_with_macro( self.db, ResolveMode::Other, @@ -1063,8 +1063,12 @@ impl DefCollector<'_> { &path, BuiltinShadowMode::Module, ); - resolved_res.resolved_def.take_macros().map(|it| macro_id_to_def_id(self.db, it)) + resolved_res + .resolved_def + .take_macros() + .map(|it| (it, macro_id_to_def_id(self.db, it))) }; + let resolver = |path| resolver2(path).map(|(_, it)| it); match &directive.kind { MacroDirectiveKind::FnLike { ast_id, expand_to } => { @@ -1083,21 +1087,37 @@ impl DefCollector<'_> { } } MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => { - let call_id = derive_macro_as_call_id( + let id = derive_macro_as_call_id( self.db, ast_id, *derive_attr, *derive_pos as u32, self.def_map.krate, - &resolver, + &resolver2, ); - if let Ok(call_id) = call_id { + + if let Ok((macro_id, def_id, call_id)) = id { self.def_map.modules[directive.module_id].scope.set_derive_macro_invoc( ast_id.ast_id, call_id, *derive_attr, *derive_pos, ); + // Record its helper attributes. + if def_id.krate != self.def_map.krate { + let def_map = self.db.crate_def_map(def_id.krate); + if let Some(helpers) = def_map.exported_derives.get(&def_id) { + self.def_map + .derive_helpers_in_scope + .entry(ast_id.ast_id.map(|it| it.upcast())) + .or_default() + .extend(izip!( + helpers.iter().cloned(), + iter::repeat(macro_id), + iter::repeat(call_id), + )); + } + } push_resolved(directive, call_id); res = ReachedFixedPoint::No; @@ -1129,7 +1149,7 @@ impl DefCollector<'_> { if let Some(ident) = path.as_ident() { if let Some(helpers) = self.def_map.derive_helpers_in_scope.get(&ast_id) { - if helpers.iter().any(|(it, _)| it == ident) { + if helpers.iter().any(|(it, ..)| it == ident) { cov_mark::hit!(resolved_derive_helper); // Resolved to derive helper. Collect the item's attributes again, // starting after the derive helper. @@ -1144,7 +1164,7 @@ impl DefCollector<'_> { }; if matches!( def, - MacroDefId { kind:MacroDefKind::BuiltInAttr(expander, _),.. } + MacroDefId { kind:MacroDefKind::BuiltInAttr(expander, _),.. } if expander.is_derive() ) { // Resolved to `#[derive]` @@ -1313,20 +1333,6 @@ impl DefCollector<'_> { self.def_map.diagnostics.push(diag); } - // If we've just resolved a derive, record its helper attributes. - if let MacroCallKind::Derive { ast_id, .. } = &loc.kind { - if loc.def.krate != self.def_map.krate { - let def_map = self.db.crate_def_map(loc.def.krate); - if let Some(helpers) = def_map.exported_derives.get(&loc.def) { - self.def_map - .derive_helpers_in_scope - .entry(ast_id.map(|it| it.upcast())) - .or_default() - .extend(helpers.iter().cloned().zip(std::iter::repeat(macro_call_id))); - } - } - } - // Then, fetch and process the item tree. This will reuse the expansion result from above. let item_tree = self.db.file_item_tree(file_id); let mod_dir = self.mod_dirs[&module_id].clone(); diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 0c1ae8a064a3..3163fa0f93fa 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -149,6 +149,7 @@ impl Resolver { self.resolve_module_path(db, path, BuiltinShadowMode::Module) } + // FIXME: This shouldn't exist pub fn resolve_module_path_in_trait_assoc_items( &self, db: &dyn DefDatabase, diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 9ffbb3964cf1..86b5bd3c2c81 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2252,6 +2252,17 @@ impl Local { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct DeriveHelper { + pub(crate) derive: MacroId, +} + +impl DeriveHelper { + pub fn derive(&self) -> Macro { + Macro { id: self.derive.into() } + } +} + // FIXME: Wrong name? This is could also be a registered attribute #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct BuiltinAttr { diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 218e15989ad3..fc8f23f19ab9 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -29,9 +29,9 @@ use crate::{ db::HirDatabase, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{resolve_hir_path, SourceAnalyzer}, - Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource, - HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, Path, - ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef, + Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, DeriveHelper, Field, Function, + HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, + Name, Path, ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -47,6 +47,7 @@ pub enum PathResolution { SelfType(Impl), BuiltinAttr(BuiltinAttr), ToolModule(ToolModule), + DeriveHelper(DeriveHelper), } impl PathResolution { @@ -71,6 +72,7 @@ impl PathResolution { PathResolution::BuiltinAttr(_) | PathResolution::ToolModule(_) | PathResolution::Local(_) + | PathResolution::DeriveHelper(_) | PathResolution::ConstParam(_) => None, PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), @@ -856,7 +858,9 @@ impl<'db> SemanticsImpl<'db> { None } }?; - + if !self.with_ctx(|ctx| ctx.has_derives(InFile::new(token.file_id, &adt))) { + return None; + } // Not an attribute, nor a derive, so it's either a builtin or a derive helper // Try to resolve to a derive helper and downmap let attr_name = attr.path().and_then(|it| it.as_single_name_ref())?.as_name(); @@ -865,7 +869,7 @@ impl<'db> SemanticsImpl<'db> { def_map.derive_helpers_in_scope(InFile::new(token.file_id, id))?; let item = Some(adt.into()); let mut res = None; - for (_, derive) in helpers.iter().filter(|(helper, _)| *helper == attr_name) { + for (.., derive) in helpers.iter().filter(|(helper, ..)| *helper == attr_name) { res = res.or(process_expansion_for_token( &mut stack, derive.as_file(), diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index e89f8a542981..d57a73ade3a6 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -43,8 +43,8 @@ use syntax::{ use crate::{ db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr, - BuiltinType, Callable, Const, Field, Function, Local, Macro, ModuleDef, Static, Struct, - ToolModule, Trait, Type, TypeAlias, Variant, + BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static, + Struct, ToolModule, Trait, Type, TypeAlias, Variant, }; /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of @@ -429,19 +429,21 @@ impl SourceAnalyzer { } } - let is_path_of_attr = path + let meta_path = path .syntax() .ancestors() - .map(|it| it.kind()) - .take_while(|&kind| ast::Path::can_cast(kind) || ast::Meta::can_cast(kind)) + .take_while(|it| { + let kind = it.kind(); + ast::Path::can_cast(kind) || ast::Meta::can_cast(kind) + }) .last() - .map_or(false, ast::Meta::can_cast); + .and_then(ast::Meta::cast); // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are // trying to resolve foo::bar. if path.parent_path().is_some() { return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) { - None if is_path_of_attr => { + None if meta_path.is_some() => { path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| { ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text()) .map(PathResolution::ToolModule) @@ -449,16 +451,50 @@ impl SourceAnalyzer { } res => res, }; - } else if is_path_of_attr { + } else if let Some(meta_path) = meta_path { // Case where we are resolving the final path segment of a path in an attribute // in this case we have to check for inert/builtin attributes and tools and prioritize // resolution of attributes over other namespaces - let name_ref = path.as_single_name_ref(); - let builtin = name_ref.as_ref().and_then(|name_ref| { - BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text()) - }); - if let Some(_) = builtin { - return builtin.map(PathResolution::BuiltinAttr); + if let Some(name_ref) = path.as_single_name_ref() { + let builtin = + BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text()); + if let Some(_) = builtin { + return builtin.map(PathResolution::BuiltinAttr); + } + + if let Some(attr) = meta_path.parent_attr() { + let adt = if let Some(field) = + attr.syntax().parent().and_then(ast::RecordField::cast) + { + field.syntax().ancestors().take(4).find_map(ast::Adt::cast) + } else if let Some(field) = + attr.syntax().parent().and_then(ast::TupleField::cast) + { + field.syntax().ancestors().take(4).find_map(ast::Adt::cast) + } else if let Some(variant) = + attr.syntax().parent().and_then(ast::Variant::cast) + { + variant.syntax().ancestors().nth(2).and_then(ast::Adt::cast) + } else { + None + }; + if let Some(adt) = adt { + let ast_id = db.ast_id_map(self.file_id).ast_id(&adt); + if let Some(helpers) = self + .resolver + .def_map() + .derive_helpers_in_scope(InFile::new(self.file_id, ast_id)) + { + // FIXME: Multiple derives can have the same helper + let name_ref = name_ref.as_name(); + if let Some(&(_, derive, _)) = + helpers.iter().find(|(name, ..)| *name == name_ref) + { + return Some(PathResolution::DeriveHelper(DeriveHelper { derive })); + } + } + } + } } return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) { Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))), diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index 27482ea489be..27c3ccb35a1e 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -292,6 +292,7 @@ impl CompletionItemKind { SymbolKind::Const => "ct", SymbolKind::ConstParam => "cp", SymbolKind::Derive => "de", + SymbolKind::DeriveHelper => "dh", SymbolKind::Enum => "en", SymbolKind::Field => "fd", SymbolKind::Function => "fn", diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index 692a31572030..a9a78e672904 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -7,9 +7,9 @@ use arrayvec::ArrayVec; use hir::{ - Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, Field, Function, - GenericParam, HasVisibility, Impl, ItemInNs, Label, Local, Macro, Module, ModuleDef, Name, - PathResolution, Semantics, Static, ToolModule, Trait, TypeAlias, Variant, Visibility, + Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, Field, + Function, GenericParam, HasVisibility, Impl, ItemInNs, Label, Local, Macro, Module, ModuleDef, + Name, PathResolution, Semantics, Static, ToolModule, Trait, TypeAlias, Variant, Visibility, }; use stdx::impl_from; use syntax::{ @@ -37,6 +37,7 @@ pub enum Definition { Local(Local), GenericParam(GenericParam), Label(Label), + DeriveHelper(DeriveHelper), BuiltinAttr(BuiltinAttr), ToolModule(ToolModule), } @@ -69,6 +70,7 @@ impl Definition { Definition::Local(it) => it.module(db), Definition::GenericParam(it) => it.module(db), Definition::Label(it) => it.module(db), + Definition::DeriveHelper(it) => it.derive().module(db), Definition::BuiltinAttr(_) | Definition::BuiltinType(_) | Definition::ToolModule(_) => { return None } @@ -94,7 +96,8 @@ impl Definition { | Definition::SelfType(_) | Definition::Local(_) | Definition::GenericParam(_) - | Definition::Label(_) => return None, + | Definition::Label(_) + | Definition::DeriveHelper(_) => return None, }; Some(vis) } @@ -118,6 +121,7 @@ impl Definition { Definition::Label(it) => it.name(db), Definition::BuiltinAttr(_) => return None, // FIXME Definition::ToolModule(_) => return None, // FIXME + Definition::DeriveHelper(_) => return None, // FIXME }; Some(name) } @@ -500,6 +504,7 @@ impl From for Definition { PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), PathResolution::BuiltinAttr(attr) => Definition::BuiltinAttr(attr), PathResolution::ToolModule(tool) => Definition::ToolModule(tool), + PathResolution::DeriveHelper(helper) => Definition::DeriveHelper(helper), } } } diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs index 26648b4d7638..966bba616f62 100644 --- a/crates/ide-db/src/lib.rs +++ b/crates/ide-db/src/lib.rs @@ -173,6 +173,7 @@ pub enum SymbolKind { Const, ConstParam, Derive, + DeriveHelper, Enum, Field, Function, diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index d78b8758d651..40af9e6fe2ad 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -224,7 +224,8 @@ impl<'a> Ctx<'a> { | hir::PathResolution::SelfType(_) | hir::PathResolution::Def(_) | hir::PathResolution::BuiltinAttr(_) - | hir::PathResolution::ToolModule(_) => (), + | hir::PathResolution::ToolModule(_) + | hir::PathResolution::DeriveHelper(_) => (), } Some(()) } diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index dc1626f43967..517fe3f246d0 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -156,6 +156,8 @@ impl Definition { Definition::SelfType(_) => return None, Definition::BuiltinAttr(_) => return None, Definition::ToolModule(_) => return None, + // FIXME: This should be doable in theory + Definition::DeriveHelper(_) => return None, }; return res; diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index fed327f52be5..582e9fe7e808 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -190,7 +190,8 @@ pub(crate) fn resolve_doc_path_for_def( | Definition::SelfType(_) | Definition::Local(_) | Definition::GenericParam(_) - | Definition::Label(_) => None, + | Definition::Label(_) + | Definition::DeriveHelper(_) => None, } .map(Definition::from) } @@ -515,7 +516,8 @@ fn filename_and_frag_for_def( | Definition::GenericParam(_) | Definition::Label(_) | Definition::BuiltinAttr(_) - | Definition::ToolModule(_) => return None, + | Definition::ToolModule(_) + | Definition::DeriveHelper(_) => return None, }; Some((def, res, None)) diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 925aaa61cdd0..fcdb23fa18aa 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -370,6 +370,8 @@ pub(super) fn definition( // FIXME: We should be able to show more info about these Definition::BuiltinAttr(it) => return render_builtin_attr(db, it), Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))), + // FIXME: it.name(db) + Definition::DeriveHelper(_it) => ("derive-helper".to_owned(), None), }; let docs = match config.documentation { diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index 1fb3b5ec3f38..9f049e298ad1 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -196,6 +196,8 @@ impl TryToNav for Definition { Definition::BuiltinType(_) => None, Definition::ToolModule(_) => None, Definition::BuiltinAttr(_) => None, + // FIXME: The focus range should be set to the helper declaration + Definition::DeriveHelper(it) => it.derive().try_to_nav(db), } } } diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index ba287d13aec1..fedc1a435827 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -237,7 +237,8 @@ fn signature_help_for_generics( | hir::PathResolution::Local(_) | hir::PathResolution::TypeParam(_) | hir::PathResolution::ConstParam(_) - | hir::PathResolution::SelfType(_) => return None, + | hir::PathResolution::SelfType(_) + | hir::PathResolution::DeriveHelper(_) => return None, }; generic_def diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index d7ad6a757995..eef717c16f2e 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -107,6 +107,7 @@ pub struct HlRange { // builtinType:: Emitted for builtin types like `u32`, `str` and `f32`. // comment:: Emitted for comments. // constParameter:: Emitted for const parameters. +// deriveHelper:: Emitted for derive helper attributes. // enumMember:: Emitted for enum variants. // generic:: Emitted for generic tokens that have no mapping. // keyword:: Emitted for keywords. diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index fd3723ed4548..9395e914c43a 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs @@ -472,6 +472,7 @@ fn highlight_def( Definition::Label(_) => Highlight::new(HlTag::Symbol(SymbolKind::Label)), Definition::BuiltinAttr(_) => Highlight::new(HlTag::Symbol(SymbolKind::BuiltinAttr)), Definition::ToolModule(_) => Highlight::new(HlTag::Symbol(SymbolKind::ToolModule)), + Definition::DeriveHelper(_) => Highlight::new(HlTag::Symbol(SymbolKind::DeriveHelper)), }; let def_crate = def.krate(db); diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 94d573a30b04..f779a985a99a 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs @@ -270,6 +270,7 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag { Definition::Label(_) => SymbolKind::Label, Definition::BuiltinAttr(_) => SymbolKind::BuiltinAttr, Definition::ToolModule(_) => SymbolKind::ToolModule, + Definition::DeriveHelper(_) => SymbolKind::DeriveHelper, }; HlTag::Symbol(symbol) } diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index b900dadcfa3c..5262770f3031 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs @@ -134,6 +134,7 @@ impl HlTag { SymbolKind::Const => "constant", SymbolKind::ConstParam => "const_param", SymbolKind::Derive => "derive", + SymbolKind::DeriveHelper => "derive_helper", SymbolKind::Enum => "enum", SymbolKind::Field => "field", SymbolKind::Function => "function", diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index 5fb945ea9872..6c78b5df1a70 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs @@ -54,6 +54,7 @@ define_semantic_token_types![ (COMPARISON, "comparison"), (CONST_PARAMETER, "constParameter"), (DERIVE, "derive"), + (DERIVE_HELPER, "deriveHelper"), (DOT, "dot"), (ESCAPE_SEQUENCE, "escapeSequence"), (FORMAT_SPECIFIER, "formatSpecifier"), diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 9c8e618b6ed0..7f4fa57fa1e0 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -53,7 +53,8 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind { SymbolKind::Macro | SymbolKind::BuiltinAttr | SymbolKind::Attribute - | SymbolKind::Derive => lsp_types::SymbolKind::FUNCTION, + | SymbolKind::Derive + | SymbolKind::DeriveHelper => lsp_types::SymbolKind::FUNCTION, SymbolKind::Module | SymbolKind::ToolModule => lsp_types::SymbolKind::MODULE, SymbolKind::TypeAlias | SymbolKind::TypeParam | SymbolKind::SelfType => { lsp_types::SymbolKind::TYPE_PARAMETER @@ -117,6 +118,7 @@ pub(crate) fn completion_item_kind( SymbolKind::Const => lsp_types::CompletionItemKind::CONSTANT, SymbolKind::ConstParam => lsp_types::CompletionItemKind::TYPE_PARAMETER, SymbolKind::Derive => lsp_types::CompletionItemKind::FUNCTION, + SymbolKind::DeriveHelper => lsp_types::CompletionItemKind::FUNCTION, SymbolKind::Enum => lsp_types::CompletionItemKind::ENUM, SymbolKind::Field => lsp_types::CompletionItemKind::FIELD, SymbolKind::Function => lsp_types::CompletionItemKind::FUNCTION, @@ -561,6 +563,7 @@ fn semantic_token_type_and_modifiers( HlTag::Symbol(symbol) => match symbol { SymbolKind::Attribute => semantic_tokens::ATTRIBUTE, SymbolKind::Derive => semantic_tokens::DERIVE, + SymbolKind::DeriveHelper => semantic_tokens::DERIVE_HELPER, SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE, SymbolKind::Impl => semantic_tokens::TYPE_ALIAS, SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, From ddad2847ab9a59d4b2fc7afb976a261c8c914686 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 24 Jul 2022 14:32:39 +0200 Subject: [PATCH 0024/2442] Allow name querying for derive helpers --- crates/hir-def/src/data.rs | 19 +++++++++++++------ crates/hir-def/src/nameres.rs | 4 ++-- crates/hir/src/lib.rs | 15 +++++++++++++++ crates/hir/src/source_analyzer.rs | 13 ++++++++++--- crates/ide-db/src/defs.rs | 2 +- crates/ide-db/src/search.rs | 8 ++++---- crates/ide/src/hover/render.rs | 3 +-- crates/ide/src/syntax_highlighting.rs | 7 +++++++ 8 files changed, 53 insertions(+), 18 deletions(-) diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 430941141933..35c8708955a7 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -12,7 +12,7 @@ use crate::{ db::DefDatabase, intern::Interned, item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId}, - nameres::{attr_resolution::ResolvedAttr, DefMap}, + nameres::{attr_resolution::ResolvedAttr, proc_macro::ProcMacroKind, DefMap}, type_ref::{TraitRef, TypeBound, TypeRef}, visibility::RawVisibility, AssocItemId, AstIdWithPath, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, @@ -348,7 +348,8 @@ impl MacroRulesData { #[derive(Debug, Clone, PartialEq, Eq)] pub struct ProcMacroData { pub name: Name, - // FIXME: Record deriver helper here? + /// Derive helpers, if this is a derive + pub helpers: Option>, } impl ProcMacroData { @@ -360,17 +361,23 @@ impl ProcMacroData { let item_tree = loc.id.item_tree(db); let makro = &item_tree[loc.id.value]; - let name = if let Some(def) = item_tree + let (name, helpers) = if let Some(def) = item_tree .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into()) .parse_proc_macro_decl(&makro.name) { - def.name + ( + def.name, + match def.kind { + ProcMacroKind::CustomDerive { helpers } => Some(helpers), + ProcMacroKind::FnLike | ProcMacroKind::Attr => None, + }, + ) } else { // eeeh... stdx::never!("proc macro declaration is not a proc macro"); - makro.name.clone() + (makro.name.clone(), None) }; - Arc::new(ProcMacroData { name }) + Arc::new(ProcMacroData { name, helpers }) } } diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 25fb302e8758..45f631936d2a 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -48,11 +48,11 @@ //! the result pub mod attr_resolution; -mod collector; +pub mod proc_macro; pub mod diagnostics; +mod collector; mod mod_resolution; mod path_resolution; -mod proc_macro; #[cfg(test)] mod tests; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 86b5bd3c2c81..d4925455d7bd 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2255,12 +2255,27 @@ impl Local { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct DeriveHelper { pub(crate) derive: MacroId, + pub(crate) idx: usize, } impl DeriveHelper { pub fn derive(&self) -> Macro { Macro { id: self.derive.into() } } + + pub fn name(&self, db: &dyn HirDatabase) -> Name { + match self.derive { + MacroId::Macro2Id(_) => None, + MacroId::MacroRulesId(_) => None, + MacroId::ProcMacroId(proc_macro) => db + .proc_macro_data(proc_macro) + .helpers + .as_ref() + .and_then(|it| it.get(self.idx)) + .cloned(), + } + .unwrap_or_else(|| Name::missing()) + } } // FIXME: Wrong name? This is could also be a registered attribute diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index d57a73ade3a6..1eb51b20c356 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -35,6 +35,7 @@ use hir_ty::{ method_resolution, Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt, TyKind, TyLoweringContext, }; +use itertools::Itertools; use smallvec::SmallVec; use syntax::{ ast::{self, AstNode}, @@ -487,10 +488,16 @@ impl SourceAnalyzer { { // FIXME: Multiple derives can have the same helper let name_ref = name_ref.as_name(); - if let Some(&(_, derive, _)) = - helpers.iter().find(|(name, ..)| *name == name_ref) + for (macro_id, mut helpers) in + helpers.iter().group_by(|(_, macro_id, ..)| macro_id).into_iter() { - return Some(PathResolution::DeriveHelper(DeriveHelper { derive })); + if let Some(idx) = helpers.position(|(name, ..)| *name == name_ref) + { + return Some(PathResolution::DeriveHelper(DeriveHelper { + derive: *macro_id, + idx, + })); + } } } } diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index a9a78e672904..aeaca00ec65c 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -121,7 +121,7 @@ impl Definition { Definition::Label(it) => it.name(db), Definition::BuiltinAttr(_) => return None, // FIXME Definition::ToolModule(_) => return None, // FIXME - Definition::DeriveHelper(_) => return None, // FIXME + Definition::DeriveHelper(it) => it.name(db), }; Some(name) } diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index eb4fc3643812..bd038cdaa068 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -278,16 +278,16 @@ impl Definition { } } hir::MacroKind::BuiltIn => SearchScope::crate_graph(db), - // FIXME: We don't actually see derives in derive attributes as these do not - // expand to something that references the derive macro in the output. - // We could get around this by doing pseudo expansions for proc_macro_derive like we - // do for the derive attribute hir::MacroKind::Derive | hir::MacroKind::Attr | hir::MacroKind::ProcMacro => { SearchScope::reverse_dependencies(db, module.krate()) } }; } + if let Definition::DeriveHelper(_) = self { + return SearchScope::reverse_dependencies(db, module.krate()); + } + let vis = self.visibility(db); if let Some(Visibility::Public) = vis { return SearchScope::reverse_dependencies(db, module.krate()); diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index fcdb23fa18aa..6c50a4e6adc0 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -370,8 +370,7 @@ pub(super) fn definition( // FIXME: We should be able to show more info about these Definition::BuiltinAttr(it) => return render_builtin_attr(db, it), Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))), - // FIXME: it.name(db) - Definition::DeriveHelper(_it) => ("derive-helper".to_owned(), None), + Definition::DeriveHelper(it) => (format!("derive_helper {}", it.name(db)), None), }; let docs = match config.documentation { diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index eef717c16f2e..d013d6f4b19f 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -432,6 +432,13 @@ fn traverse( // let the editor do its highlighting for these tokens instead continue; } + if highlight.tag == HlTag::UnresolvedReference + && matches!(attr_or_derive_item, Some(AttrOrDerive::Derive(_)) if inside_attribute) + { + // do not emit unresolved references in derive helpers if the token mapping maps to + // something unresolvable. FIXME: There should be a way to prevent that + continue; + } if inside_attribute { highlight |= HlMod::Attribute } From b1e3daf14b14404945a14346d7b478feee7c5508 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Tue, 26 Jul 2022 11:30:41 +0200 Subject: [PATCH 0025/2442] Find standalone proc-macro-srv on windows too --- crates/rust-analyzer/src/reload.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 9ae361b034e2..b9aa13ec5b33 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -303,6 +303,9 @@ impl GlobalState { let files_config = self.config.files(); let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude); + let standalone_server_name = + format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX); + if self.proc_macro_clients.is_empty() { if let Some((path, args)) = self.config.proc_macro_srv() { self.proc_macro_clients = self @@ -316,10 +319,8 @@ impl GlobalState { tracing::info!("Found a cargo workspace..."); if let Some(sysroot) = sysroot.as_ref() { tracing::info!("Found a cargo workspace with a sysroot..."); - let server_path = sysroot - .root() - .join("libexec") - .join("rust-analyzer-proc-macro-srv"); + let server_path = + sysroot.root().join("libexec").join(&standalone_server_name); if std::fs::metadata(&server_path).is_ok() { tracing::info!( "And the server exists at {}", From c8ff70e924efe3adba39ac5dc2a93dbd94bde5a4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 26 Jul 2022 16:30:45 +0200 Subject: [PATCH 0026/2442] fix: Fix server panicking on project loading when proc-macros are disabled --- crates/rust-analyzer/src/cli/load_cargo.rs | 4 +++- crates/rust-analyzer/src/reload.rs | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 0ada4b73e842..5d1c013c3275 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -66,7 +66,9 @@ pub fn load_workspace( }; let crate_graph = ws.to_crate_graph( - &mut |_, path: &AbsPath| load_proc_macro(proc_macro_client.as_ref(), path, &[]), + &mut |_, path: &AbsPath| { + load_proc_macro(proc_macro_client.as_ref().map_err(|e| &**e), path, &[]) + }, &mut |path: &AbsPath| { let contents = loader.load_sync(path); let path = vfs::VfsPath::from(path.to_path_buf()); diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index b9aa13ec5b33..eaab275bc68a 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -390,7 +390,10 @@ impl GlobalState { let mut crate_graph = CrateGraph::default(); for (idx, ws) in self.workspaces.iter().enumerate() { - let proc_macro_client = self.proc_macro_clients[idx].as_ref(); + let proc_macro_client = match self.proc_macro_clients.get(idx) { + Some(res) => res.as_ref().map_err(|e| &**e), + None => Err("Proc macros are disabled"), + }; let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| { load_proc_macro( proc_macro_client, @@ -574,7 +577,7 @@ impl SourceRootConfig { /// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace` /// with an identity dummy expander. pub(crate) fn load_proc_macro( - server: Result<&ProcMacroServer, &String>, + server: Result<&ProcMacroServer, &str>, path: &AbsPath, dummy_replace: &[Box], ) -> ProcMacroLoadResult { From add33b65dda4b59b46b5192f3a88a83b771af844 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 26 Jul 2022 10:59:19 -0500 Subject: [PATCH 0027/2442] Remove FIXME comment for unreachable fallback. --- crates/ide-assists/src/handlers/inline_call.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs index 8b2f6ac75a28..80d3b9255936 100644 --- a/crates/ide-assists/src/handlers/inline_call.rs +++ b/crates/ide-assists/src/handlers/inline_call.rs @@ -306,8 +306,6 @@ fn inline( if let Some(body) = ast::BlockExpr::cast(insert_ws_into(fn_body.syntax().clone())) { body } else { - // FIXME(zachs18): I believe this should be unreachable, - // since insert_ws_into shouldn't change the kind of the SyntaxNode. fn_body.clone_for_update() } } else { From 6c379b9f4bb9774758e018944a33db5eb29622fb Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 27 Jul 2022 12:45:29 +0200 Subject: [PATCH 0028/2442] fix: Fix Semantics::original_ast_node not caching the resulting file --- crates/hir/src/semantics.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index fc8f23f19ab9..a75e5cafd0bd 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -924,7 +924,12 @@ impl<'db> SemanticsImpl<'db> { } fn original_ast_node(&self, node: N) -> Option { - self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(|it| it.value) + self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map( + |InFile { file_id, value }| { + self.cache(find_root(value.syntax()), file_id); + value + }, + ) } fn diagnostics_display_range(&self, src: InFile) -> FileRange { From 1f8daa180fdfb847f5f82b8ac9870aebb17c9494 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 27 Jul 2022 13:48:26 +0200 Subject: [PATCH 0029/2442] fix: Honor ref expressions for compute_ref_match completions --- crates/hir-ty/src/chalk_ext.rs | 5 ++ crates/hir/src/lib.rs | 4 ++ crates/ide-completion/src/context/analysis.rs | 69 ++++++++++++------- crates/ide-completion/src/context/tests.rs | 20 ++++++ 4 files changed, 75 insertions(+), 23 deletions(-) diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index b0885ab003f7..a9c124b42dc2 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -34,6 +34,7 @@ pub trait TyExt { fn callable_sig(&self, db: &dyn HirDatabase) -> Option; fn strip_references(&self) -> &Ty; + fn strip_reference(&self) -> &Ty; /// If this is a `dyn Trait`, returns that trait. fn dyn_trait(&self) -> Option; @@ -182,6 +183,10 @@ impl TyExt for Ty { t } + fn strip_reference(&self) -> &Ty { + self.as_reference().map_or(self, |(ty, _, _)| ty) + } + fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option> { match self.kind(Interner) { TyKind::OpaqueType(opaque_ty_id, subst) => { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index d4925455d7bd..8f984210e117 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2769,6 +2769,10 @@ impl Type { self.derived(self.ty.strip_references().clone()) } + pub fn strip_reference(&self) -> Type { + self.derived(self.ty.strip_reference().clone()) + } + pub fn is_unknown(&self) -> bool { self.ty.is_unknown() } diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index c71ffa0ed86f..09a1a99eb64c 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -162,11 +162,52 @@ impl<'a> CompletionContext<'a> { } /// Calculate the expected type and name of the cursor position. - fn expected_type_and_name(&self) -> (Option, Option) { + fn expected_type_and_name( + &self, + name_like: &ast::NameLike, + ) -> (Option, Option) { let mut node = match self.token.parent() { Some(it) => it, None => return (None, None), }; + + let strip_refs = |mut ty: Type| match name_like { + ast::NameLike::NameRef(n) => { + let p = match n.syntax().parent() { + Some(it) => it, + None => return ty, + }; + let top_syn = match_ast! { + match p { + ast::FieldExpr(e) => e + .syntax() + .ancestors() + .map_while(ast::FieldExpr::cast) + .last() + .map(|it| it.syntax().clone()), + ast::PathSegment(e) => e + .syntax() + .ancestors() + .skip(1) + .take_while(|it| ast::Path::can_cast(it.kind()) || ast::PathExpr::can_cast(it.kind())) + .find_map(ast::PathExpr::cast) + .map(|it| it.syntax().clone()), + _ => None + } + }; + let top_syn = match top_syn { + Some(it) => it, + None => return ty, + }; + for _ in top_syn.ancestors().skip(1).map_while(ast::RefExpr::cast) { + cov_mark::hit!(expected_type_fn_param_ref); + ty = ty.strip_reference(); + } + ty + } + _ => ty, + }; + loop { break match_ast! { match node { @@ -199,13 +240,9 @@ impl<'a> CompletionContext<'a> { self.token.clone(), ).map(|ap| { let name = ap.ident().map(NameOrNameRef::Name); - let ty = if has_ref(&self.token) { - cov_mark::hit!(expected_type_fn_param_ref); - ap.ty.remove_ref() - } else { - Some(ap.ty) - }; - (ty, name) + + let ty = strip_refs(ap.ty); + (Some(ty), name) }) .unwrap_or((None, None)) }, @@ -330,8 +367,6 @@ impl<'a> CompletionContext<'a> { return None; } - (self.expected_type, self.expected_name) = self.expected_type_and_name(); - // Overwrite the path kind for derives if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx { if let Some(ast::NameLike::NameRef(name_ref)) = @@ -389,6 +424,7 @@ impl<'a> CompletionContext<'a> { return Some(analysis); } }; + (self.expected_type, self.expected_name) = self.expected_type_and_name(&name_like); let analysis = match name_like { ast::NameLike::Lifetime(lifetime) => CompletionAnalysis::Lifetime( Self::classify_lifetime(&self.sema, original_file, lifetime)?, @@ -1141,19 +1177,6 @@ fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> { Some((use_tree.path()?, true)) } -fn has_ref(token: &SyntaxToken) -> bool { - let mut token = token.clone(); - for skip in [SyntaxKind::IDENT, SyntaxKind::WHITESPACE, T![mut]] { - if token.kind() == skip { - token = match token.prev_token() { - Some(it) => it, - None => return false, - } - } - } - token.kind() == T![&] -} - pub(crate) fn is_in_token_of_for_loop(element: SyntaxElement) -> bool { // oh my ... (|| { diff --git a/crates/ide-completion/src/context/tests.rs b/crates/ide-completion/src/context/tests.rs index c5557bdafb33..50845b3881f4 100644 --- a/crates/ide-completion/src/context/tests.rs +++ b/crates/ide-completion/src/context/tests.rs @@ -391,3 +391,23 @@ fn foo($0: Foo) {} expect![[r#"ty: ?, name: ?"#]], ); } + +#[test] +fn expected_type_ref_prefix_on_field() { + check_expected_type_and_name( + r#" +fn foo(_: &mut i32) {} +struct S { + field: i32, +} + +fn main() { + let s = S { + field: 100, + }; + foo(&mut s.f$0); +} +"#, + expect!["ty: i32, name: ?"], + ); +} From 349dfc7e95c7b384a3e520db3cc26645918857d2 Mon Sep 17 00:00:00 2001 From: hi-rustin Date: Wed, 27 Jul 2022 20:18:00 +0800 Subject: [PATCH 0030/2442] Find original ast node before compute ref match in fn render Signed-off-by: hi-rustin --- crates/ide-completion/src/render/function.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs index 241de0a1834a..4b5535718c5d 100644 --- a/crates/ide-completion/src/render/function.rs +++ b/crates/ide-completion/src/render/function.rs @@ -85,7 +85,9 @@ fn render( item.ref_match(ref_match, path_ctx.path.syntax().text_range().start()); } FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => { - item.ref_match(ref_match, receiver.syntax().text_range().start()); + if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) { + item.ref_match(ref_match, original_expr.syntax().text_range().start()); + } } _ => (), } From bf893d59b54eb3b0dd3bcf34a66f9f0703753ffb Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 27 Jul 2022 17:14:50 +0200 Subject: [PATCH 0031/2442] internal: Assume condition/iterable is missing if there is only a BlockExpr --- crates/syntax/src/ast/generated/nodes.rs | 4 --- crates/syntax/src/ast/node_ext.rs | 38 ++++++++++++++++++++++++ crates/syntax/src/tests/sourcegen_ast.rs | 2 ++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index cf90ba64cff1..63309a155219 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -880,7 +880,6 @@ impl ForExpr { pub fn for_token(&self) -> Option { support::token(&self.syntax, T![for]) } pub fn pat(&self) -> Option { support::child(&self.syntax) } pub fn in_token(&self) -> Option { support::token(&self.syntax, T![in]) } - pub fn iterable(&self) -> Option { support::child(&self.syntax) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -890,7 +889,6 @@ pub struct IfExpr { impl ast::HasAttrs for IfExpr {} impl IfExpr { pub fn if_token(&self) -> Option { support::token(&self.syntax, T![if]) } - pub fn condition(&self) -> Option { support::child(&self.syntax) } pub fn else_token(&self) -> Option { support::token(&self.syntax, T![else]) } } @@ -1051,7 +1049,6 @@ pub struct WhileExpr { impl ast::HasAttrs for WhileExpr {} impl WhileExpr { pub fn while_token(&self) -> Option { support::token(&self.syntax, T![while]) } - pub fn condition(&self) -> Option { support::child(&self.syntax) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -1170,7 +1167,6 @@ pub struct MatchGuard { } impl MatchGuard { pub fn if_token(&self) -> Option { support::token(&self.syntax, T![if]) } - pub fn condition(&self) -> Option { support::child(&self.syntax) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index b143df1f83f2..bb92c51e9a90 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -806,6 +806,19 @@ impl ast::GenericParamList { } } +impl ast::ForExpr { + pub fn iterable(&self) -> Option { + // If the iterable is a BlockExpr, check if the body is missing. + // If it is assume the iterable is the expression that is missing instead. + let mut exprs = support::children(self.syntax()); + let first = exprs.next(); + match first { + Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first), + first => first, + } + } +} + impl ast::HasLoopBody for ast::ForExpr { fn loop_body(&self) -> Option { let mut exprs = support::children(self.syntax()); @@ -815,6 +828,19 @@ impl ast::HasLoopBody for ast::ForExpr { } } +impl ast::WhileExpr { + pub fn condition(&self) -> Option { + // If the condition is a BlockExpr, check if the body is missing. + // If it is assume the condition is the expression that is missing instead. + let mut exprs = support::children(self.syntax()); + let first = exprs.next(); + match first { + Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first), + first => first, + } + } +} + impl ast::HasLoopBody for ast::WhileExpr { fn loop_body(&self) -> Option { let mut exprs = support::children(self.syntax()); @@ -835,3 +861,15 @@ impl From for ast::Item { } } } + +impl ast::IfExpr { + pub fn condition(&self) -> Option { + support::child(&self.syntax) + } +} + +impl ast::MatchGuard { + pub fn condition(&self) -> Option { + support::child(&self.syntax) + } +} diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs index 4cfb8075cb15..6d2766225103 100644 --- a/crates/syntax/src/tests/sourcegen_ast.rs +++ b/crates/syntax/src/tests/sourcegen_ast.rs @@ -682,6 +682,8 @@ fn lower_rule(acc: &mut Vec, grammar: &Grammar, label: Option<&String>, r | "value" | "trait" | "self_ty" + | "iterable" + | "condition" ); if manually_implemented { return; From a96948195227f98dd18eecea8cd85c58406b6388 Mon Sep 17 00:00:00 2001 From: Paul Lange Date: Tue, 26 Jul 2022 16:10:26 +0200 Subject: [PATCH 0032/2442] Add syntax fixup for while loops --- crates/hir-expand/src/fixup.rs | 76 +++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index 9999790fae72..6d0766020bd9 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -5,7 +5,7 @@ use std::mem; use mbe::{SyntheticToken, SyntheticTokenId, TokenMap}; use rustc_hash::FxHashMap; use syntax::{ - ast::{self, AstNode}, + ast::{self, AstNode, HasLoopBody}, match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, }; use tt::Subtree; @@ -142,6 +142,39 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { ]); } }, + ast::WhileExpr(it) => { + if it.condition().is_none() { + // insert placeholder token after the while token + let while_token = match it.while_token() { + Some(t) => t, + None => continue, + }; + append.insert(while_token.into(), vec![ + SyntheticToken { + kind: SyntaxKind::IDENT, + text: "__ra_fixup".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + if it.loop_body().is_none() { + append.insert(node.clone().into(), vec![ + SyntheticToken { + kind: SyntaxKind::L_CURLY, + text: "{".into(), + range: end_range, + id: EMPTY_ID, + }, + SyntheticToken { + kind: SyntaxKind::R_CURLY, + text: "}".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + }, // FIXME: foo:: // FIXME: for, loop, match etc. _ => (), @@ -376,6 +409,47 @@ fn foo() { // the {} gets parsed as the condition, I think? expect![[r#" fn foo () {if {} {}} +"#]], + ) + } + + #[test] + fn fixup_while_1() { + check( + r#" +fn foo() { + while +} +"#, + expect![[r#" +fn foo () {while __ra_fixup {}} +"#]], + ) + } + + #[test] + fn fixup_while_2() { + check( + r#" +fn foo() { + while foo +} +"#, + expect![[r#" +fn foo () {while foo {}} +"#]], + ) + } + #[test] + fn fixup_while_3() { + check( + r#" +fn foo() { + while {} +} +"#, + expect![[r#" +fn foo () {while __ra_fixup {}} "#]], ) } From c16e4f260fb6b915767d18a59ab395cb46d82449 Mon Sep 17 00:00:00 2001 From: Paul Lange Date: Wed, 27 Jul 2022 18:18:51 +0200 Subject: [PATCH 0033/2442] Add syntax fixup for `loop` --- crates/hir-expand/src/fixup.rs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index 6d0766020bd9..e46f43a878fe 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -175,8 +175,26 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { ]); } }, + ast::LoopExpr(it) => { + if it.loop_body().is_none() { + append.insert(node.clone().into(), vec![ + SyntheticToken { + kind: SyntaxKind::L_CURLY, + text: "{".into(), + range: end_range, + id: EMPTY_ID, + }, + SyntheticToken { + kind: SyntaxKind::R_CURLY, + text: "}".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + }, // FIXME: foo:: - // FIXME: for, loop, match etc. + // FIXME: for, match etc. _ => (), } } @@ -450,6 +468,20 @@ fn foo() { "#, expect![[r#" fn foo () {while __ra_fixup {}} +"#]], + ) + } + + #[test] + fn fixup_loop() { + check( + r#" +fn foo() { + loop +} +"#, + expect![[r#" +fn foo () {loop {}} "#]], ) } From f83738e1d993d84c1607fcabdf9f41ab00f83d55 Mon Sep 17 00:00:00 2001 From: Brennan Vincent Date: Wed, 27 Jul 2022 14:34:46 -0400 Subject: [PATCH 0034/2442] Use large stack on expander thread --- crates/proc-macro-srv/src/lib.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index 4b1858b8ed89..4c205b9cadac 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -39,6 +39,8 @@ pub(crate) struct ProcMacroSrv { expanders: HashMap<(PathBuf, SystemTime), dylib::Expander>, } +const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; + impl ProcMacroSrv { pub fn expand(&mut self, task: ExpandMacro) -> Result { let expander = self.expander(task.lib.as_ref()).map_err(|err| { @@ -66,13 +68,18 @@ impl ProcMacroSrv { // FIXME: replace this with std's scoped threads once they stabilize // (then remove dependency on crossbeam) let result = crossbeam::scope(|s| { - let res = s + let res = match s + .builder() + .stack_size(EXPANDER_STACK_SIZE) + .name(task.macro_name.clone()) .spawn(|_| { expander .expand(&task.macro_name, ¯o_body, attributes.as_ref()) .map(|it| FlatTree::new(&it)) - }) - .join(); + }) { + Ok(handle) => handle.join(), + Err(e) => std::panic::resume_unwind(Box::new(e)), + }; match res { Ok(res) => res, From e782e59d3de3d4a58cbc8005fd9521502b8d9a61 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 28 Jul 2022 10:05:21 +0200 Subject: [PATCH 0035/2442] fix: Calculate completions after type anchors --- crates/hir/src/semantics.rs | 18 ++++++ .../src/completions/attribute.rs | 2 +- .../src/completions/attribute/derive.rs | 2 +- crates/ide-completion/src/completions/expr.rs | 23 +++++++- .../src/completions/item_list.rs | 2 +- .../ide-completion/src/completions/pattern.rs | 2 +- crates/ide-completion/src/completions/type.rs | 18 +++++- crates/ide-completion/src/completions/use_.rs | 2 +- crates/ide-completion/src/completions/vis.rs | 2 +- crates/ide-completion/src/context.rs | 5 +- crates/ide-completion/src/context/analysis.rs | 56 ++++++++++--------- crates/ide-completion/src/tests/special.rs | 55 +++++++++++++++++- 12 files changed, 151 insertions(+), 36 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index a75e5cafd0bd..c84318b2fb87 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -324,6 +324,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_type(ty) } + pub fn resolve_trait(&self, trait_: &ast::Path) -> Option { + self.imp.resolve_trait(trait_) + } + // FIXME: Figure out a nice interface to inspect adjustments pub fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option { self.imp.is_implicit_reborrow(expr) @@ -1014,6 +1018,20 @@ impl<'db> SemanticsImpl<'db> { Some(Type::new_with_resolver(self.db, &analyze.resolver, ty)) } + fn resolve_trait(&self, path: &ast::Path) -> Option { + let analyze = self.analyze(path.syntax())?; + let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id); + let ctx = body::LowerCtx::with_hygiene(self.db.upcast(), &hygiene); + let hir_path = Path::from_src(path.clone(), &ctx)?; + match analyze + .resolver + .resolve_path_in_type_ns_fully(self.db.upcast(), hir_path.mod_path())? + { + TypeNs::TraitId(id) => Some(Trait { id }), + _ => None, + } + } + fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option { self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr) } diff --git a/crates/ide-completion/src/completions/attribute.rs b/crates/ide-completion/src/completions/attribute.rs index 1d8a8c5f20db..d9fe94cb44ee 100644 --- a/crates/ide-completion/src/completions/attribute.rs +++ b/crates/ide-completion/src/completions/attribute.rs @@ -115,7 +115,7 @@ pub(crate) fn complete_attribute_path( }); acc.add_nameref_keywords_with_colon(ctx); } - Qualified::Infer | Qualified::With { .. } => {} + Qualified::TypeAnchor { .. } | Qualified::With { .. } => {} } let attributes = annotated_item_kind.and_then(|kind| { diff --git a/crates/ide-completion/src/completions/attribute/derive.rs b/crates/ide-completion/src/completions/attribute/derive.rs index 14538fef6072..793c22630bf8 100644 --- a/crates/ide-completion/src/completions/attribute/derive.rs +++ b/crates/ide-completion/src/completions/attribute/derive.rs @@ -97,7 +97,7 @@ pub(crate) fn complete_derive_path( }); acc.add_nameref_keywords_with_colon(ctx); } - Qualified::Infer | Qualified::With { .. } => {} + Qualified::TypeAnchor { .. } | Qualified::With { .. } => {} } } diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index bdf6e64f0969..d4f2766602fb 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -46,11 +46,32 @@ pub(crate) fn complete_expr_path( }; match qualified { - Qualified::Infer => ctx + Qualified::TypeAnchor { ty: None, trait_: None } => ctx .traits_in_scope() .iter() .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db)) .for_each(|item| add_assoc_item(acc, item)), + Qualified::TypeAnchor { trait_: Some(trait_), .. } => { + trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item)) + } + Qualified::TypeAnchor { ty: Some(ty), trait_: None } => { + if let Some(hir::Adt::Enum(e)) = ty.as_adt() { + cov_mark::hit!(completes_variant_through_alias); + acc.add_enum_variants(ctx, path_ctx, e); + } + + ctx.iterate_path_candidates(&ty, |item| { + add_assoc_item(acc, item); + }); + + // Iterate assoc types separately + ty.iterate_assoc_items(ctx.db, ctx.krate, |item| { + if let hir::AssocItem::TypeAlias(ty) = item { + acc.add_type_alias(ctx, ty) + } + None::<()> + }); + } Qualified::With { resolution: None, .. } => {} Qualified::With { resolution: Some(resolution), .. } => { // Add associated types on type parameters and `Self`. diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs index 4e4c9fba6cc5..60d05ae46b91 100644 --- a/crates/ide-completion/src/completions/item_list.rs +++ b/crates/ide-completion/src/completions/item_list.rs @@ -66,7 +66,7 @@ pub(crate) fn complete_item_list( }); acc.add_nameref_keywords_with_colon(ctx); } - Qualified::Infer | Qualified::No | Qualified::With { .. } => {} + Qualified::TypeAnchor { .. } | Qualified::No | Qualified::With { .. } => {} } } diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs index 17dfe432b352..af8a0853313b 100644 --- a/crates/ide-completion/src/completions/pattern.rs +++ b/crates/ide-completion/src/completions/pattern.rs @@ -180,6 +180,6 @@ pub(crate) fn complete_pattern_path( acc.add_nameref_keywords_with_colon(ctx); } - Qualified::Infer | Qualified::With { .. } => {} + Qualified::TypeAnchor { .. } | Qualified::With { .. } => {} } } diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs index 87a998dfcce6..8f9db2f94c20 100644 --- a/crates/ide-completion/src/completions/type.rs +++ b/crates/ide-completion/src/completions/type.rs @@ -49,11 +49,27 @@ pub(crate) fn complete_type_path( }; match qualified { - Qualified::Infer => ctx + Qualified::TypeAnchor { ty: None, trait_: None } => ctx .traits_in_scope() .iter() .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db)) .for_each(|item| add_assoc_item(acc, item)), + Qualified::TypeAnchor { trait_: Some(trait_), .. } => { + trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item)) + } + Qualified::TypeAnchor { ty: Some(ty), trait_: None } => { + ctx.iterate_path_candidates(&ty, |item| { + add_assoc_item(acc, item); + }); + + // Iterate assoc types separately + ty.iterate_assoc_items(ctx.db, ctx.krate, |item| { + if let hir::AssocItem::TypeAlias(ty) = item { + acc.add_type_alias(ctx, ty) + } + None::<()> + }); + } Qualified::With { resolution: None, .. } => {} Qualified::With { resolution: Some(resolution), .. } => { // Add associated types on type parameters and `Self`. diff --git a/crates/ide-completion/src/completions/use_.rs b/crates/ide-completion/src/completions/use_.rs index bb2ecc9fdde7..2555c34aa747 100644 --- a/crates/ide-completion/src/completions/use_.rs +++ b/crates/ide-completion/src/completions/use_.rs @@ -115,6 +115,6 @@ pub(crate) fn complete_use_path( }); acc.add_nameref_keywords_with_colon(ctx); } - Qualified::Infer | Qualified::With { resolution: None, .. } => {} + Qualified::TypeAnchor { .. } | Qualified::With { resolution: None, .. } => {} } } diff --git a/crates/ide-completion/src/completions/vis.rs b/crates/ide-completion/src/completions/vis.rs index ca8303906a80..5e6cf4bf9a52 100644 --- a/crates/ide-completion/src/completions/vis.rs +++ b/crates/ide-completion/src/completions/vis.rs @@ -29,7 +29,7 @@ pub(crate) fn complete_vis_path( acc.add_super_keyword(ctx, *super_chain_len); } - Qualified::Absolute | Qualified::Infer | Qualified::With { .. } => {} + Qualified::Absolute | Qualified::TypeAnchor { .. } | Qualified::With { .. } => {} Qualified::No => { if !has_in_token { cov_mark::hit!(kw_completion_in); diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 93b6ad5d145d..e35f79d2b695 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -193,7 +193,10 @@ pub(super) enum Qualified { super_chain_len: Option, }, /// <_>:: - Infer, + TypeAnchor { + ty: Option, + trait_: Option, + }, /// Whether the path is an absolute path Absolute, } diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 09a1a99eb64c..3e7e637dd9ed 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -920,49 +920,53 @@ impl<'a> CompletionContext<'a> { path_ctx.has_type_args = segment.generic_arg_list().is_some(); // calculate the qualifier context - if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) { + if let Some((qualifier, use_tree_parent)) = path_or_use_tree_qualifier(&path) { path_ctx.use_tree_parent = use_tree_parent; if !use_tree_parent && segment.coloncolon_token().is_some() { path_ctx.qualified = Qualified::Absolute; } else { - let path = path + let qualifier = qualifier .segment() .and_then(|it| find_node_in_file(original_file, &it)) .map(|it| it.parent_path()); - if let Some(path) = path { - // `<_>::$0` - let is_infer_qualifier = path.qualifier().is_none() - && matches!( - path.segment().and_then(|it| it.kind()), - Some(ast::PathSegmentKind::Type { - type_ref: Some(ast::Type::InferType(_)), - trait_ref: None, - }) - ); + if let Some(qualifier) = qualifier { + let type_anchor = match qualifier.segment().and_then(|it| it.kind()) { + Some(ast::PathSegmentKind::Type { + type_ref: Some(type_ref), + trait_ref, + }) if qualifier.qualifier().is_none() => Some((type_ref, trait_ref)), + _ => None, + }; - path_ctx.qualified = if is_infer_qualifier { - Qualified::Infer + path_ctx.qualified = if let Some((ty, trait_ref)) = type_anchor { + let ty = match ty { + ast::Type::InferType(_) => None, + ty => sema.resolve_type(&ty), + }; + let trait_ = trait_ref.and_then(|it| sema.resolve_trait(&it.path()?)); + Qualified::TypeAnchor { ty, trait_ } } else { - let res = sema.resolve_path(&path); + let res = sema.resolve_path(&qualifier); // For understanding how and why super_chain_len is calculated the way it // is check the documentation at it's definition let mut segment_count = 0; - let super_count = iter::successors(Some(path.clone()), |p| p.qualifier()) - .take_while(|p| { - p.segment() - .and_then(|s| { - segment_count += 1; - s.super_token() - }) - .is_some() - }) - .count(); + let super_count = + iter::successors(Some(qualifier.clone()), |p| p.qualifier()) + .take_while(|p| { + p.segment() + .and_then(|s| { + segment_count += 1; + s.super_token() + }) + .is_some() + }) + .count(); let super_chain_len = if segment_count > super_count { None } else { Some(super_count) }; - Qualified::With { path, resolution: res, super_chain_len } + Qualified::With { path: qualifier, resolution: res, super_chain_len } } }; } diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index ca779c2fc713..033dc99c26cf 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -674,7 +674,60 @@ fn bar() -> Bar { expect![[r#" fn foo() (as Foo) fn() -> Self "#]], - ) + ); +} + +#[test] +fn type_anchor_type() { + check( + r#" +trait Foo { + fn foo() -> Self; +} +struct Bar; +impl Bar { + fn bar() {} +} +impl Foo for Bar { + fn foo() -> { + Bar + } +} +fn bar() -> Bar { + ::$0 +} +"#, + expect![[r#" + fn bar() fn() + fn foo() (as Foo) fn() -> Self + "#]], + ); +} + +#[test] +fn type_anchor_type_trait() { + check( + r#" +trait Foo { + fn foo() -> Self; +} +struct Bar; +impl Bar { + fn bar() {} +} +impl Foo for Bar { + fn foo() -> { + Bar + } +} +fn bar() -> Bar { + ::$0 +} +"#, + expect![[r#" + fn foo() (as Foo) fn() -> Self + "#]], + ); } #[test] From 7c59d7c75c1aed160bf1aa67047ba6063ae21ba0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 28 Jul 2022 15:47:46 +0200 Subject: [PATCH 0036/2442] fix: Fix pattern completions adding unnecessary braces --- crates/ide-completion/src/completions.rs | 13 +++++++++-- .../ide-completion/src/completions/pattern.rs | 2 +- crates/ide-completion/src/render/pattern.rs | 23 +++++++++++++++---- crates/ide-completion/src/tests/pattern.rs | 4 ++-- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index 149afcac9d47..72579e6026ae 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -400,7 +400,7 @@ impl Completions { ) { if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx { cov_mark::hit!(enum_variant_pattern_path); - self.add_variant_pat(ctx, pat_ctx, variant, local_name); + self.add_variant_pat(ctx, pat_ctx, Some(path_ctx), variant, local_name); return; } @@ -484,12 +484,14 @@ impl Completions { &mut self, ctx: &CompletionContext<'_>, pattern_ctx: &PatternContext, + path_ctx: Option<&PathCompletionCtx>, variant: hir::Variant, local_name: Option, ) { self.add_opt(render_variant_pat( RenderContext::new(ctx), pattern_ctx, + path_ctx, variant, local_name.clone(), None, @@ -504,7 +506,14 @@ impl Completions { path: hir::ModPath, ) { let path = Some(&path); - self.add_opt(render_variant_pat(RenderContext::new(ctx), pattern_ctx, variant, None, path)); + self.add_opt(render_variant_pat( + RenderContext::new(ctx), + pattern_ctx, + None, + variant, + None, + path, + )); } pub(crate) fn add_struct_pat( diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs index af8a0853313b..71d2d9d434b4 100644 --- a/crates/ide-completion/src/completions/pattern.rs +++ b/crates/ide-completion/src/completions/pattern.rs @@ -74,7 +74,7 @@ pub(crate) fn complete_pattern( hir::ModuleDef::Variant(variant) if refutable || single_variant_enum(variant.parent_enum(ctx.db)) => { - acc.add_variant_pat(ctx, pattern_ctx, variant, Some(name.clone())); + acc.add_variant_pat(ctx, pattern_ctx, None, variant, Some(name.clone())); true } hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e), diff --git a/crates/ide-completion/src/render/pattern.rs b/crates/ide-completion/src/render/pattern.rs index 03db08a911e9..34a384f2f7ae 100644 --- a/crates/ide-completion/src/render/pattern.rs +++ b/crates/ide-completion/src/render/pattern.rs @@ -6,7 +6,7 @@ use itertools::Itertools; use syntax::SmolStr; use crate::{ - context::{ParamContext, ParamKind, PatternContext}, + context::{ParamContext, ParamKind, PathCompletionCtx, PatternContext}, render::{ variant::{format_literal_label, visible_fields}, RenderContext, @@ -42,6 +42,7 @@ pub(crate) fn render_struct_pat( pub(crate) fn render_variant_pat( ctx: RenderContext<'_>, pattern_ctx: &PatternContext, + path_ctx: Option<&PathCompletionCtx>, variant: hir::Variant, local_name: Option, path: Option<&hir::ModPath>, @@ -58,9 +59,23 @@ pub(crate) fn render_variant_pat( (name.to_smol_str(), name.escaped().to_smol_str()) } }; - let kind = variant.kind(ctx.db()); - let label = format_literal_label(name.as_str(), kind); - let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?; + + let (label, pat) = match path_ctx { + Some(PathCompletionCtx { has_call_parens: true, .. }) => (name, escaped_name.to_string()), + _ => { + let kind = variant.kind(ctx.db()); + let label = format_literal_label(name.as_str(), kind); + let pat = render_pat( + &ctx, + pattern_ctx, + &escaped_name, + kind, + &visible_fields, + fields_omitted, + )?; + (label, pat) + } + }; Some(build_completion(ctx, label, pat, variant)) } diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs index 877b5f216433..30ddbe2dc6f6 100644 --- a/crates/ide-completion/src/tests/pattern.rs +++ b/crates/ide-completion/src/tests/pattern.rs @@ -443,7 +443,7 @@ fn foo() { } "#, expect![[r#" - bn TupleVariant(…) TupleVariant($1)$0 + bn TupleVariant TupleVariant "#]], ); check_empty( @@ -458,7 +458,7 @@ fn foo() { } "#, expect![[r#" - bn RecordVariant {…} RecordVariant { field$1 }$0 + bn RecordVariant RecordVariant "#]], ); } From 74abd44a265d6daded813ccb48ed599d835ea532 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 28 Jul 2022 17:09:31 +0200 Subject: [PATCH 0037/2442] fix: Do completions in path qualifier position --- crates/ide-completion/src/completions/expr.rs | 16 +- crates/ide-completion/src/context/analysis.rs | 189 ++++++++++-------- 2 files changed, 119 insertions(+), 86 deletions(-) diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index d4f2766602fb..bafaeb502ad7 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -11,7 +11,14 @@ pub(crate) fn complete_expr_path( acc: &mut Completions, ctx: &CompletionContext<'_>, path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, - &ExprCtx { + expr_ctx: &ExprCtx, +) { + let _p = profile::span("complete_expr_path"); + if !ctx.qualifier_ctx.none() { + return; + } + + let &ExprCtx { in_block_expr, in_loop_body, after_if_expr, @@ -23,12 +30,7 @@ pub(crate) fn complete_expr_path( ref impl_, in_match_guard, .. - }: &ExprCtx, -) { - let _p = profile::span("complete_expr_path"); - if !ctx.qualifier_ctx.none() { - return; - } + } = expr_ctx; let wants_mut_token = ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false); diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 3e7e637dd9ed..76fc74c01d22 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -592,7 +592,7 @@ impl<'a> CompletionContext<'a> { has_call_parens: false, has_macro_bang: false, qualified: Qualified::No, - parent: path.parent_path(), + parent: None, path: path.clone(), kind: PathKind::Item { kind: ItemListKind::SourceFile }, has_type_args: false, @@ -827,92 +827,123 @@ impl<'a> CompletionContext<'a> { PathKind::Type { location: location.unwrap_or(TypeLocation::Other) } }; + let mut kind_macro_call = |it: ast::MacroCall| { + path_ctx.has_macro_bang = it.excl_token().is_some(); + let parent = it.syntax().parent()?; + // Any path in an item list will be treated as a macro call by the parser + let kind = match_ast! { + match parent { + ast::MacroExpr(expr) => make_path_kind_expr(expr.into()), + ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}, + ast::MacroType(ty) => make_path_kind_type(ty.into()), + ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module }, + ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() { + Some(it) => match_ast! { + match it { + ast::Trait(_) => ItemListKind::Trait, + ast::Impl(it) => if it.trait_().is_some() { + ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it)) + } else { + ItemListKind::Impl + }, + _ => return None + } + }, + None => return None, + } }, + ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock }, + ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile }, + _ => return None, + } + }; + Some(kind) + }; + let make_path_kind_attr = |meta: ast::Meta| { + let attr = meta.parent_attr()?; + let kind = attr.kind(); + let attached = attr.syntax().parent()?; + let is_trailing_outer_attr = kind != AttrKind::Inner + && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next) + .is_none(); + let annotated_item_kind = + if is_trailing_outer_attr { None } else { Some(attached.kind()) }; + Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } }) + }; + // Infer the path kind let parent = path.syntax().parent()?; let kind = match_ast! { - match parent { - ast::PathType(it) => make_path_kind_type(it.into()), - ast::PathExpr(it) => { - if let Some(p) = it.syntax().parent() { - if ast::ExprStmt::can_cast(p.kind()) { - if let Some(kind) = inbetween_body_and_decl_check(p) { - return Some(make_res(NameRefKind::Keyword(kind))); - } + match parent { + ast::PathType(it) => make_path_kind_type(it.into()), + ast::PathExpr(it) => { + if let Some(p) = it.syntax().parent() { + if ast::ExprStmt::can_cast(p.kind()) { + if let Some(kind) = inbetween_body_and_decl_check(p) { + return Some(make_res(NameRefKind::Keyword(kind))); } } + } - path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind())); + path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind())); - make_path_kind_expr(it.into()) - }, - ast::TupleStructPat(it) => { - path_ctx.has_call_parens = true; - PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())} - }, - ast::RecordPat(it) => { - path_ctx.has_call_parens = true; - PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())} - }, - ast::PathPat(it) => { - PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())} - }, - ast::MacroCall(it) => { - // A macro call in this position is usually a result of parsing recovery, so check that - if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) { - return Some(make_res(NameRefKind::Keyword(kind))); + make_path_kind_expr(it.into()) + }, + ast::TupleStructPat(it) => { + path_ctx.has_call_parens = true; + PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) } + }, + ast::RecordPat(it) => { + path_ctx.has_call_parens = true; + PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) } + }, + ast::PathPat(it) => { + PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())} + }, + ast::MacroCall(it) => { + // A macro call in this position is usually a result of parsing recovery, so check that + if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) { + return Some(make_res(NameRefKind::Keyword(kind))); + } + + kind_macro_call(it)? + }, + ast::Meta(meta) => make_path_kind_attr(meta)?, + ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() }, + ast::UseTree(_) => PathKind::Use, + // completing inside a qualifier + ast::Path(parent) => { + path_ctx.parent = Some(parent.clone()); + let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?; + match_ast! { + match parent { + ast::PathType(it) => make_path_kind_type(it.into()), + ast::PathExpr(it) => { + path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind())); + + make_path_kind_expr(it.into()) + }, + ast::TupleStructPat(it) => { + path_ctx.has_call_parens = true; + PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) } + }, + ast::RecordPat(it) => { + path_ctx.has_call_parens = true; + PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) } + }, + ast::PathPat(it) => { + PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())} + }, + ast::MacroCall(it) => { + kind_macro_call(it)? + }, + ast::Meta(meta) => make_path_kind_attr(meta)?, + ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() }, + ast::UseTree(_) => PathKind::Use, + _ => return None, } - - path_ctx.has_macro_bang = it.excl_token().is_some(); - let parent = it.syntax().parent()?; - // Any path in an item list will be treated as a macro call by the parser - match_ast! { - match parent { - ast::MacroExpr(expr) => make_path_kind_expr(expr.into()), - ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}, - ast::MacroType(ty) => make_path_kind_type(ty.into()), - ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module }, - ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() { - Some(it) => match_ast! { - match it { - ast::Trait(_) => ItemListKind::Trait, - ast::Impl(it) => if it.trait_().is_some() { - ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it)) - } else { - ItemListKind::Impl - }, - _ => return None - } - }, - None => return None, - } }, - ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock }, - ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile }, - _ => return None, - } - } - }, - ast::Meta(meta) => { - let attr = meta.parent_attr()?; - let kind = attr.kind(); - let attached = attr.syntax().parent()?; - let is_trailing_outer_attr = kind != AttrKind::Inner - && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none(); - let annotated_item_kind = if is_trailing_outer_attr { - None - } else { - Some(attached.kind()) - }; - PathKind::Attr { - attr_ctx: AttrCtx { - kind, - annotated_item_kind, - } - } - }, - ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() }, - ast::UseTree(_) => PathKind::Use, - _ => return None, - + } + }, + _ => return None, } }; From 8658425a672e5e56ac5e02db8423ca56c81c2c31 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Thu, 28 Jul 2022 16:21:14 +0100 Subject: [PATCH 0038/2442] publish: Use cargo ws rename to rename crates --- .github/workflows/publish.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 927996c1bef2..a4497f49e3c2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -34,8 +34,21 @@ jobs: git config --global user.email "runner@gha.local" git config --global user.name "Github Action" rm Cargo.lock + # Fix names for crates that were published before switch to kebab-case. + cargo workspaces rename --from base-db base_db + cargo workspaces rename --from hir-def hir_def + cargo workspaces rename --from hir-expand hir_expand + cargo workspaces rename --from hir-ty hir_ty + cargo workspaces rename --from ide-assists ide_assists + cargo workspaces rename --from ide-completion ide_completion + cargo workspaces rename --from ide-db ide_db + cargo workspaces rename --from ide-diagnostics ide_diagnostics + cargo workspaces rename --from ide-ssr ide_ssr + cargo workspaces rename --from proc-macro-api proc_macro_api + cargo workspaces rename --from proc-macro-srv proc_macro_srv + cargo workspaces rename --from project-model project_model + cargo workspaces rename --from test-utils test_utils + cargo workspaces rename --from text-edit text_edit cargo workspaces rename ra_ap_%n find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} + - # Fix names for crates that were published before switch to kebab-case. - find crates -name 'Cargo.toml' -exec sed -i "s/ra_ap_base-db/ra_ap_base_db/g; s/ra_ap_hir-def/ra_ap_hir_def/g; s/ra_ap_hir-expand/ra_ap_hir_expand/g; s/ra_ap_hir-ty/ra_ap_hir_ty/g; s/ra_ap_ide-assists/ra_ap_ide_assists/g; s/ra_ap_ide-completion/ra_ap_ide_completion/g; s/ra_ap_ide-db/ra_ap_ide_db/g; s/ra_ap_ide-diagnostics/ra_ap_ide_diagnostics/g; s/ra_ap_ide-ssr/ra_ap_ide_ssr/g; s/ra_ap_proc-macro-api/ra_ap_proc_macro_api/g; s/ra_ap_proc-macro-srv/ra_ap_proc_macro_srv/g; s/ra_ap_project-model/ra_ap_project_model/g; s/ra_ap_test-utils/ra_ap_test_utils/g; s/ra_ap_text-edit/ra_ap_text_edit/g" {} + cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH From ce7541260d6a5c76633b4c0e2e1639730018773d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 28 Jul 2022 17:49:23 +0200 Subject: [PATCH 0039/2442] fix: Don't complete marker traits in expression position --- crates/ide-completion/src/completions/expr.rs | 17 ++++++++++++++--- crates/ide-completion/src/render.rs | 3 --- crates/ide-completion/src/tests/expression.rs | 2 -- crates/ide-completion/src/tests/record.rs | 1 - 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index bafaeb502ad7..5d0ddaaf2a22 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -202,10 +202,21 @@ pub(crate) fn complete_expr_path( } } } - ctx.process_all_names(&mut |name, def| { - if scope_def_applicable(def) { - acc.add_path_resolution(ctx, path_ctx, name, def); + ctx.process_all_names(&mut |name, def| match def { + ScopeDef::ModuleDef(hir::ModuleDef::Trait(t)) => { + let assocs = t.items_with_supertraits(ctx.db); + match &*assocs { + // traits with no assoc items are unusable as expressions since + // there is no associated item path that can be constructed with them + [] => (), + // FIXME: Render the assoc item with the trait qualified + &[_item] => acc.add_path_resolution(ctx, path_ctx, name, def), + // FIXME: Append `::` to the thing here, since a trait on its own won't work + [..] => acc.add_path_resolution(ctx, path_ctx, name, def), + } } + _ if scope_def_applicable(def) => acc.add_path_resolution(ctx, path_ctx, name, def), + _ => (), }); if is_func_update.is_none() { diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 9b25964a6086..39cf95713793 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -1347,7 +1347,6 @@ fn main() { fn main() [] fn foo(…) [] md core [] - tt Sized [] "#]], ) } @@ -1394,7 +1393,6 @@ fn main() { fn main() [] fn foo(…) [] md core [] - tt Sized [] "#]], ) } @@ -1492,7 +1490,6 @@ fn main() { fn &bar() [type] fn foo(…) [] md core [] - tt Sized [] "#]], ) } diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index ce9d01d337ba..ce7a543d9f30 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -44,7 +44,6 @@ fn baz() { st Record st Tuple st Unit - tt Trait un Union ev TupleV(…) TupleV(u32) bt u32 @@ -137,7 +136,6 @@ impl Unit { st Record st Tuple st Unit - tt Trait tp TypeParam un Union ev TupleV(…) TupleV(u32) diff --git a/crates/ide-completion/src/tests/record.rs b/crates/ide-completion/src/tests/record.rs index ec32602fa3c2..f6accc68e5e8 100644 --- a/crates/ide-completion/src/tests/record.rs +++ b/crates/ide-completion/src/tests/record.rs @@ -167,7 +167,6 @@ fn main() { st Foo st Foo {…} Foo { foo1: u32, foo2: u32 } tt Default - tt Sized bt u32 kw crate:: kw self:: From f867ddc6217438ad514980fcbd5f59e2d99c3d55 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 28 Jul 2022 18:49:31 +0200 Subject: [PATCH 0040/2442] fix: Order ItemScope::entries results --- crates/hir-def/src/item_scope.rs | 10 ++++----- .../src/handlers/expand_glob_import.rs | 10 ++++----- crates/ide-assists/src/tests/generated.rs | 2 +- crates/ide-completion/src/render.rs | 22 +++++++++---------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 579f803ea193..a11a92204c15 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -5,6 +5,7 @@ use std::collections::hash_map::Entry; use base_db::CrateId; use hir_expand::{name::Name, AstId, MacroCallId}; +use itertools::Itertools; use once_cell::sync::Lazy; use profile::Count; use rustc_hash::{FxHashMap, FxHashSet}; @@ -97,15 +98,14 @@ pub(crate) enum BuiltinShadowMode { impl ItemScope { pub fn entries<'a>(&'a self) -> impl Iterator + 'a { // FIXME: shadowing - let keys: FxHashSet<_> = self - .types + self.types .keys() .chain(self.values.keys()) .chain(self.macros.keys()) .chain(self.unresolved.iter()) - .collect(); - - keys.into_iter().map(move |name| (name, self.get(name))) + .sorted() + .unique() + .map(move |name| (name, self.get(name))) } pub fn declarations(&self) -> impl Iterator + '_ { diff --git a/crates/ide-assists/src/handlers/expand_glob_import.rs b/crates/ide-assists/src/handlers/expand_glob_import.rs index 943c1d90e636..87f5018fb695 100644 --- a/crates/ide-assists/src/handlers/expand_glob_import.rs +++ b/crates/ide-assists/src/handlers/expand_glob_import.rs @@ -36,7 +36,7 @@ use crate::{ // pub struct Baz; // } // -// use foo::{Baz, Bar}; +// use foo::{Bar, Baz}; // // fn qux(bar: Bar, baz: Baz) {} // ``` @@ -281,7 +281,7 @@ mod foo { pub fn f() {} } -use foo::{Baz, Bar, f}; +use foo::{Bar, Baz, f}; fn qux(bar: Bar, baz: Baz) { f(); @@ -351,7 +351,7 @@ mod foo { pub fn f() {} } -use foo::{Baz, Bar, f}; +use foo::{Bar, Baz, f}; fn qux(bar: Bar, baz: Baz) { f(); @@ -440,7 +440,7 @@ mod foo { } } -use foo::{bar::{Baz, Bar, f}, baz::*}; +use foo::{bar::{Bar, Baz, f}, baz::*}; fn qux(bar: Bar, baz: Baz) { f(); @@ -561,7 +561,7 @@ mod foo { use foo::{ bar::{*, f}, - baz::{g, qux::{q, h}} + baz::{g, qux::{h, q}} }; fn qux(bar: Bar, baz: Baz) { diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index e8d48607be0e..6eaab48a32ba 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -535,7 +535,7 @@ mod foo { pub struct Baz; } -use foo::{Baz, Bar}; +use foo::{Bar, Baz}; fn qux(bar: Bar, baz: Baz) {} "#####, diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 39cf95713793..946134b0ff95 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -1271,8 +1271,8 @@ fn main() { st S [] st &mut S [type] st S [] - fn main() [] fn foo(…) [] + fn main() [] "#]], ); check_relevance( @@ -1288,8 +1288,8 @@ fn main() { lc s [type+name+local] st S [type] st S [] - fn main() [] fn foo(…) [] + fn main() [] "#]], ); check_relevance( @@ -1305,8 +1305,8 @@ fn main() { lc ssss [type+local] st S [type] st S [] - fn main() [] fn foo(…) [] + fn main() [] "#]], ); } @@ -1342,10 +1342,10 @@ fn main() { lc &t [type+local] st S [] st &S [type] - st T [] st S [] - fn main() [] + st T [] fn foo(…) [] + fn main() [] md core [] "#]], ) @@ -1388,10 +1388,10 @@ fn main() { lc &mut t [type+local] st S [] st &mut S [type] - st T [] st S [] - fn main() [] + st T [] fn foo(…) [] + fn main() [] md core [] "#]], ) @@ -1483,12 +1483,12 @@ fn main() { expect![[r#" st S [] st &S [type] - st T [] st S [] - fn main() [] + st T [] fn bar() [] fn &bar() [type] fn foo(…) [] + fn main() [] md core [] "#]], ) @@ -1633,8 +1633,8 @@ fn foo() { ev Foo::B [type_could_unify] fn foo() [] en Foo [] - fn baz() [] fn bar() [] + fn baz() [] "#]], ); } @@ -1724,9 +1724,9 @@ fn f() { } "#, expect![[r#" - md std [] st Buffer [] fn f() [] + md std [] tt BufRead (use std::io::BufRead) [requires_import] st BufReader (use std::io::BufReader) [requires_import] st BufWriter (use std::io::BufWriter) [requires_import] From 948c9afc73786d5b4895fa4ea9041992601a59c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 28 Jul 2022 21:02:36 +0300 Subject: [PATCH 0041/2442] Only run rainbow highlighting test on 64-bit Unix --- crates/ide/src/syntax_highlighting/tests.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 6ba6153178da..d21bfc938514 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -915,6 +915,10 @@ fn main() { } #[test] +#[cfg_attr( + all(unix, not(target_pointer_width = "64")), + ignore = "depends on `DefaultHasher` outputs" +)] fn test_rainbow_highlighting() { check_highlighting( r#" From 61d1c3e1385be65abc197115817c28fbeb3294d6 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Thu, 28 Jul 2022 22:38:20 +0430 Subject: [PATCH 0042/2442] add debug impl for AnyDiagnostic --- crates/hir/src/diagnostics.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 6c6c11ea4ebd..50374f4b3fe4 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -14,6 +14,7 @@ use crate::{MacroKind, Type}; macro_rules! diagnostics { ($($diag:ident,)*) => { + #[derive(Debug)] pub enum AnyDiagnostic {$( $diag(Box<$diag>), )*} From 11ef494b3764811b8ea5178d6c9bd67b287f104a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 28 Jul 2022 21:45:47 +0300 Subject: [PATCH 0043/2442] Be more explicit when filtering built-in completions --- crates/ide-completion/src/tests.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs index 4be6acbe8461..cf826648dcf7 100644 --- a/crates/ide-completion/src/tests.rs +++ b/crates/ide-completion/src/tests.rs @@ -23,8 +23,6 @@ mod type_pos; mod use_tree; mod visibility; -use std::mem; - use hir::{db::DefDatabase, PrefixKind, Semantics}; use ide_db::{ base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, @@ -107,12 +105,9 @@ fn completion_list_with_config( ) -> String { // filter out all but one builtintype completion for smaller test outputs let items = get_all_items(config, ra_fixture, trigger_character); - let mut bt_seen = false; let items = items .into_iter() - .filter(|it| { - it.kind() != CompletionItemKind::BuiltinType || !mem::replace(&mut bt_seen, true) - }) + .filter(|it| it.kind() != CompletionItemKind::BuiltinType || it.label() == "u32") .filter(|it| include_keywords || it.kind() != CompletionItemKind::Keyword) .filter(|it| include_keywords || it.kind() != CompletionItemKind::Snippet) .sorted_by_key(|it| (it.kind(), it.label().to_owned(), it.detail().map(ToOwned::to_owned))) From 902fd6ddcdd4e3ad03c7a9099f0b3b1d7e6a95e8 Mon Sep 17 00:00:00 2001 From: cynecx Date: Fri, 29 Jul 2022 02:27:16 +0200 Subject: [PATCH 0044/2442] fix: complete path of existing record expr --- crates/ide-completion/src/context/analysis.rs | 2 ++ crates/ide-completion/src/tests/expression.rs | 19 +++++++++++++++++++ crates/parser/src/grammar/paths.rs | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 76fc74c01d22..22ec7cead498 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -939,10 +939,12 @@ impl<'a> CompletionContext<'a> { ast::Meta(meta) => make_path_kind_attr(meta)?, ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() }, ast::UseTree(_) => PathKind::Use, + ast::RecordExpr(it) => make_path_kind_expr(it.into()), _ => return None, } } }, + ast::RecordExpr(it) => make_path_kind_expr(it.into()), _ => return None, } }; diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index ce7a543d9f30..925081ebf660 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -651,3 +651,22 @@ fn main() { "]], ); } + +#[test] +fn complete_record_expr_path() { + check( + r#" +struct Zulu; +impl Zulu { + fn test() -> Self { } +} +fn boi(val: Zulu) { } +fn main() { + boi(Zulu:: $0 {}); +} +"#, + expect![[r#" + fn test() fn() -> Zulu + "#]], + ); +} diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs index f9efcef92a61..8de5d33a1936 100644 --- a/crates/parser/src/grammar/paths.rs +++ b/crates/parser/src/grammar/paths.rs @@ -54,7 +54,7 @@ fn path_for_qualifier( mut qual: CompletedMarker, ) -> CompletedMarker { loop { - let use_tree = matches!(p.nth(2), T![*] | T!['{']); + let use_tree = mode == Mode::Use && matches!(p.nth(2), T![*] | T!['{']); if p.at(T![::]) && !use_tree { let path = qual.precede(p); p.bump(T![::]); From c1a175f61e3584eb7c4ecf59a589a57447621461 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Thu, 28 Jul 2022 22:38:44 +0430 Subject: [PATCH 0045/2442] Generate rust type from json --- Cargo.lock | 1 + crates/ide-diagnostics/Cargo.toml | 1 + .../src/handlers/json_is_not_rust.rs | 201 ++++++++++++++++++ crates/ide-diagnostics/src/lib.rs | 2 + 4 files changed, 205 insertions(+) create mode 100644 crates/ide-diagnostics/src/handlers/json_is_not_rust.rs diff --git a/Cargo.lock b/Cargo.lock index 4c830006832c..6c01b8a0dfd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -710,6 +710,7 @@ dependencies = [ "ide-db", "itertools", "profile", + "serde_json", "sourcegen", "stdx", "syntax", diff --git a/crates/ide-diagnostics/Cargo.toml b/crates/ide-diagnostics/Cargo.toml index e221425edd5b..9b9e21a4ddb5 100644 --- a/crates/ide-diagnostics/Cargo.toml +++ b/crates/ide-diagnostics/Cargo.toml @@ -15,6 +15,7 @@ itertools = "0.10.3" either = "1.7.0" +serde_json = "1.0.82" profile = { path = "../profile", version = "0.0.0" } stdx = { path = "../stdx", version = "0.0.0" } diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs new file mode 100644 index 000000000000..aa7fcffb48ac --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -0,0 +1,201 @@ +//! This diagnostic provides an assist for creating a struct definition from a JSON +//! example. + +use ide_db::{base_db::FileId, source_change::SourceChange}; +use itertools::Itertools; +use stdx::format_to; +use syntax::{ + ast::{self, make}, + SyntaxKind, SyntaxNode, +}; +use text_edit::TextEdit; + +use crate::{fix, Diagnostic, Severity}; + +#[derive(Default)] +struct State { + result: String, + struct_counts: usize, +} + +impl State { + fn generate_new_name(&mut self) -> ast::Name { + self.struct_counts += 1; + make::name(&format!("Struct{}", self.struct_counts)) + } + + fn build_struct(&mut self, value: &serde_json::Map) -> ast::Type { + let name = self.generate_new_name(); + let ty = make::ty(&name.to_string()); + let strukt = make::struct_( + None, + name, + None, + make::record_field_list(value.iter().sorted_unstable_by_key(|x| x.0).map( + |(name, value)| make::record_field(None, make::name(name), self.type_of(value)), + )) + .into(), + ); + format_to!(self.result, "#[derive(Serialize, Deserialize)]\n{}\n", strukt); + ty + } + + fn type_of(&mut self, value: &serde_json::Value) -> ast::Type { + match value { + serde_json::Value::Null => make::ty_unit(), + serde_json::Value::Bool(_) => make::ty("bool"), + serde_json::Value::Number(x) => make::ty(if x.is_i64() { "i64" } else { "f64" }), + serde_json::Value::String(_) => make::ty("String"), + serde_json::Value::Array(x) => { + let ty = match x.iter().next() { + Some(x) => self.type_of(x), + None => make::ty_placeholder(), + }; + make::ty(&format!("Vec<{ty}>")) + } + serde_json::Value::Object(x) => self.build_struct(x), + } + } +} + +pub(crate) fn json_in_items(acc: &mut Vec, file_id: FileId, node: &SyntaxNode) { + if node.kind() == SyntaxKind::ERROR + && node.first_token().map(|x| x.kind()) == Some(SyntaxKind::L_CURLY) + && node.last_token().map(|x| x.kind()) == Some(SyntaxKind::R_CURLY) + { + let node_string = node.to_string(); + if let Ok(x) = serde_json::from_str(&node_string) { + if let serde_json::Value::Object(x) = x { + let range = node.text_range(); + let mut edit = TextEdit::builder(); + edit.delete(range); + let mut state = State::default(); + state.build_struct(&x); + edit.insert(range.start(), state.result); + acc.push( + Diagnostic::new( + "json-is-not-rust", + "JSON syntax is not valid as a Rust item", + range, + ) + .severity(Severity::WeakWarning) + .with_fixes(Some(vec![fix( + "convert_json_to_struct", + "Convert JSON to struct", + SourceChange::from_text_edit(file_id, edit.finish()), + range, + )])), + ); + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::{ + tests::{check_diagnostics_with_config, check_fix, check_no_fix}, + DiagnosticsConfig, + }; + + #[test] + fn diagnostic_for_simple_case() { + let mut config = DiagnosticsConfig::default(); + config.disabled.insert("syntax-error".to_string()); + check_diagnostics_with_config( + config, + r#" + { "foo": "bar" } + // ^^^^^^^^^^^^^^^^ 💡 weak: JSON syntax is not valid as a Rust item +"#, + ); + } + + #[test] + fn types_of_primitives() { + check_fix( + r#" + {$0 + "foo": "bar", + "bar": 2.3, + "baz": null, + "bay": 57, + "box": true + } + "#, + r#" + #[derive(Serialize, Deserialize)] + struct Struct1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String } + + "#, + ); + } + + #[test] + fn nested_structs() { + check_fix( + r#" + {$0 + "foo": "bar", + "bar": { + "kind": "Object", + "value": {} + } + } + "#, + r#" + #[derive(Serialize, Deserialize)] + struct Struct3{ } + #[derive(Serialize, Deserialize)] + struct Struct2{ kind: String, value: Struct3 } + #[derive(Serialize, Deserialize)] + struct Struct1{ bar: Struct2, foo: String } + + "#, + ); + } + + #[test] + fn arrays() { + check_fix( + r#" + { + "of_string": ["foo", "2", "x"], $0 + "of_object": [{ + "x": 10, + "y": 20 + }, { + "x": 10, + "y": 20 + }], + "nested": [[[2]]], + "empty": [] + } + "#, + r#" + #[derive(Serialize, Deserialize)] + struct Struct2{ x: i64, y: i64 } + #[derive(Serialize, Deserialize)] + struct Struct1{ empty: Vec<_>, nested: Vec>>, of_object: Vec, of_string: Vec } + + "#, + ); + } + + #[test] + fn no_emit_outside_of_item_position() { + check_no_fix( + r#" + fn foo() { + let json = {$0 + "foo": "bar", + "bar": { + "kind": "Object", + "value": {} + } + }; + } + "#, + ); + } +} diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 41abaa836f5f..7034f010e1b0 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -50,6 +50,7 @@ mod handlers { pub(crate) mod field_shorthand; pub(crate) mod useless_braces; pub(crate) mod unlinked_file; + pub(crate) mod json_is_not_rust; } #[cfg(test)] @@ -175,6 +176,7 @@ pub fn diagnostics( for node in parse.tree().syntax().descendants() { handlers::useless_braces::useless_braces(&mut res, file_id, &node); handlers::field_shorthand::field_shorthand(&mut res, file_id, &node); + handlers::json_is_not_rust::json_in_items(&mut res, file_id, &node); } let module = sema.to_module_def(file_id); From 618cfd792ca2b3da5cd027bad20a7769f5d9f973 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 30 Jul 2022 09:43:30 +0200 Subject: [PATCH 0046/2442] fix: Fix ast-id up when merging raw attributes --- crates/hir-def/src/attr.rs | 21 ++++++-- crates/ide/src/syntax_highlighting.rs | 4 +- crates/ide/src/syntax_highlighting/inject.rs | 9 ++-- .../highlight_module_docs_inline.html | 51 +++++++++++++++++++ .../highlight_module_docs_outline.html | 50 ++++++++++++++++++ crates/ide/src/syntax_highlighting/tests.rs | 42 +++++++++++++++ 6 files changed, 167 insertions(+), 10 deletions(-) create mode 100644 crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html create mode 100644 crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index 8a6b6f3effd2..2b39c6f8da86 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -124,13 +124,24 @@ impl RawAttrs { pub(crate) fn merge(&self, other: Self) -> Self { // FIXME: This needs to fixup `AttrId`s - match (&self.entries, &other.entries) { + match (&self.entries, other.entries) { (None, None) => Self::EMPTY, - (Some(entries), None) | (None, Some(entries)) => { - Self { entries: Some(entries.clone()) } - } + (None, entries @ Some(_)) => Self { entries }, + (Some(entries), None) => Self { entries: Some(entries.clone()) }, (Some(a), Some(b)) => { - Self { entries: Some(a.iter().chain(b.iter()).cloned().collect()) } + let last_ast_index = a.last().map_or(0, |it| it.id.ast_index + 1); + Self { + entries: Some( + a.iter() + .cloned() + .chain(b.iter().map(|it| { + let mut it = it.clone(); + it.id.ast_index += last_ast_index; + it + })) + .collect(), + ), + } } } } diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index d013d6f4b19f..3fb49b45d988 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -13,7 +13,7 @@ mod html; #[cfg(test)] mod tests; -use hir::{InFile, Name, Semantics}; +use hir::{Name, Semantics}; use ide_db::{FxHashMap, RootDatabase}; use syntax::{ ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T, @@ -325,7 +325,7 @@ fn traverse( Leave(NodeOrToken::Node(node)) => { // Doc comment highlighting injection, we do this when leaving the node // so that we overwrite the highlighting of the doc comment itself. - inject::doc_comment(hl, sema, InFile::new(file_id.into(), &node)); + inject::doc_comment(hl, sema, file_id, &node); continue; } }; diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index f779a985a99a..f376f9fda7a5 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs @@ -5,7 +5,8 @@ use std::mem; use either::Either; use hir::{InFile, Semantics}; use ide_db::{ - active_parameter::ActiveParameter, defs::Definition, rust_doc::is_rust_fence, SymbolKind, + active_parameter::ActiveParameter, base_db::FileId, defs::Definition, rust_doc::is_rust_fence, + SymbolKind, }; use syntax::{ ast::{self, AstNode, IsString, QuoteOffsets}, @@ -81,16 +82,18 @@ pub(super) fn ra_fixture( const RUSTDOC_FENCE_LENGTH: usize = 3; const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"]; -/// Injection of syntax highlighting of doctests. +/// Injection of syntax highlighting of doctests and intra doc links. pub(super) fn doc_comment( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, - InFile { file_id: src_file_id, value: node }: InFile<&SyntaxNode>, + src_file_id: FileId, + node: &SyntaxNode, ) { let (attributes, def) = match doc_attributes(sema, node) { Some(it) => it, None => return, }; + let src_file_id = src_file_id.into(); // Extract intra-doc links and emit highlights for them. if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) { diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html new file mode 100644 index 000000000000..8a1d69816e68 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html @@ -0,0 +1,51 @@ + + +
//! [Struct]
+//! This is an intra doc injection test for modules
+//! [Struct]
+//! This is an intra doc injection test for modules
+
+pub struct Struct;
+
\ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html new file mode 100644 index 000000000000..c4c3e3dc2606 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html @@ -0,0 +1,50 @@ + + +
/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+mod foo;
+
\ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index d21bfc938514..99be7c664868 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -914,6 +914,48 @@ fn main() { ); } +#[test] +fn test_mod_hl_injection() { + check_highlighting( + r##" +//- /foo.rs +//! [Struct] +//! This is an intra doc injection test for modules +//! [Struct] +//! This is an intra doc injection test for modules + +pub struct Struct; +//- /lib.rs crate:foo +/// [crate::foo::Struct] +/// This is an intra doc injection test for modules +/// [crate::foo::Struct] +/// This is an intra doc injection test for modules +mod foo; +"##, + expect_file!["./test_data/highlight_module_docs_inline.html"], + false, + ); + check_highlighting( + r##" +//- /lib.rs crate:foo +/// [crate::foo::Struct] +/// This is an intra doc injection test for modules +/// [crate::foo::Struct] +/// This is an intra doc injection test for modules +mod foo; +//- /foo.rs +//! [Struct] +//! This is an intra doc injection test for modules +//! [Struct] +//! This is an intra doc injection test for modules + +pub struct Struct; +"##, + expect_file!["./test_data/highlight_module_docs_outline.html"], + false, + ); +} + #[test] #[cfg_attr( all(unix, not(target_pointer_width = "64")), From 58c3a5634fec30705be19f21971e016c730f305c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sun, 31 Jul 2022 20:26:35 +0300 Subject: [PATCH 0047/2442] Update xtask promote and release instructions --- docs/dev/README.md | 7 ++++--- xtask/src/release.rs | 10 ++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/docs/dev/README.md b/docs/dev/README.md index 468f2b9e981f..76bbd1e91889 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -210,7 +210,8 @@ Release process is handled by `release`, `dist` and `promote` xtasks, `release` ./rust-rust-analyzer # Note the name! ``` -Additionally, it assumes that the remote for `rust-analyzer` is called `upstream` (I use `origin` to point to my fork). +The remote for `rust-analyzer` must be called `upstream` (I use `origin` to point to my fork). +In addition, for `xtask promote` (see below), `rust-rust-analyzer` must have a `rust-analyzer` remote pointing to this repository on GitHub. `release` calls the GitHub API calls to scrape pull request comments and categorize them in the changelog. This step uses the `curl` and `jq` applications, which need to be available in `PATH`. @@ -225,13 +226,13 @@ Release steps: * push it to `upstream`. This triggers GitHub Actions which: * runs `cargo xtask dist` to package binaries and VS Code extension * makes a GitHub release - * pushes VS Code extension to the marketplace + * publishes the VS Code extension to the marketplace * call the GitHub API for PR details * create a new changelog in `rust-analyzer.github.io` 3. While the release is in progress, fill in the changelog 4. Commit & push the changelog 5. Tweet -6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's submodule. +6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's subtree. Self-approve the PR. If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console. diff --git a/xtask/src/release.rs b/xtask/src/release.rs index 1c5fc64c2417..17ada5156407 100644 --- a/xtask/src/release.rs +++ b/xtask/src/release.rs @@ -77,18 +77,12 @@ impl flags::Promote { cmd!(sh, "git switch master").run()?; cmd!(sh, "git fetch upstream").run()?; cmd!(sh, "git reset --hard upstream/master").run()?; - cmd!(sh, "git submodule update --recursive").run()?; let date = date_iso(sh)?; let branch = format!("rust-analyzer-{date}"); cmd!(sh, "git switch -c {branch}").run()?; - { - let _dir = sh.push_dir("src/tools/rust-analyzer"); - cmd!(sh, "git fetch origin").run()?; - cmd!(sh, "git reset --hard origin/release").run()?; - } - cmd!(sh, "git add src/tools/rust-analyzer").run()?; - cmd!(sh, "git commit -m':arrow_up: rust-analyzer'").run()?; + cmd!(sh, "git subtree pull -P src/tools/rust-analyzer rust-analyzer master").run()?; + if !self.dry_run { cmd!(sh, "git push -u origin {branch}").run()?; cmd!( From d31f3605cea39530cb6b5b1c89934b174c886f49 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 31 Jul 2022 19:27:20 +0200 Subject: [PATCH 0048/2442] Properly cfg the `max` field of Limit --- crates/limit/src/lib.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/limit/src/lib.rs b/crates/limit/src/lib.rs index 3c1da80edb98..d6a706a7cd73 100644 --- a/crates/limit/src/lib.rs +++ b/crates/limit/src/lib.rs @@ -2,12 +2,13 @@ #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] +#[cfg(feature = "tracking")] use std::sync::atomic::AtomicUsize; /// Represents a struct used to enforce a numerical limit. pub struct Limit { upper_bound: usize, - #[allow(unused)] + #[cfg(feature = "tracking")] max: AtomicUsize, } @@ -15,14 +16,22 @@ impl Limit { /// Creates a new limit. #[inline] pub const fn new(upper_bound: usize) -> Self { - Self { upper_bound, max: AtomicUsize::new(0) } + Self { + upper_bound, + #[cfg(feature = "tracking")] + max: AtomicUsize::new(0), + } } /// Creates a new limit. #[inline] #[cfg(feature = "tracking")] pub const fn new_tracking(upper_bound: usize) -> Self { - Self { upper_bound, max: AtomicUsize::new(1) } + Self { + upper_bound, + #[cfg(feature = "tracking")] + max: AtomicUsize::new(1), + } } /// Gets the underlying numeric limit. From 3b2ecf44a0ee8437f8eb0e5b607312de6af7312a Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 31 Jul 2022 19:27:34 +0200 Subject: [PATCH 0049/2442] Give variables more descriptive names --- crates/hir-def/src/nameres/collector.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index f394c541719f..8a6bb929c3df 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -1055,7 +1055,7 @@ impl DefCollector<'_> { }; let mut res = ReachedFixedPoint::Yes; macros.retain(|directive| { - let resolver2 = |path| { + let resolver = |path| { let resolved_res = self.def_map.resolve_path_fp_with_macro( self.db, ResolveMode::Other, @@ -1068,7 +1068,7 @@ impl DefCollector<'_> { .take_macros() .map(|it| (it, macro_id_to_def_id(self.db, it))) }; - let resolver = |path| resolver2(path).map(|(_, it)| it); + let resolver_def_id = |path| resolver(path).map(|(_, it)| it); match &directive.kind { MacroDirectiveKind::FnLike { ast_id, expand_to } => { @@ -1077,7 +1077,7 @@ impl DefCollector<'_> { ast_id, *expand_to, self.def_map.krate, - &resolver, + &resolver_def_id, &mut |_err| (), ); if let Ok(Ok(call_id)) = call_id { @@ -1093,7 +1093,7 @@ impl DefCollector<'_> { *derive_attr, *derive_pos as u32, self.def_map.krate, - &resolver2, + &resolver, ); if let Ok((macro_id, def_id, call_id)) = id { @@ -1158,7 +1158,7 @@ impl DefCollector<'_> { } } - let def = match resolver(path.clone()) { + let def = match resolver_def_id(path.clone()) { Some(def) if def.is_attribute() => def, _ => return true, }; @@ -1292,7 +1292,8 @@ impl DefCollector<'_> { true }); // Attribute resolution can add unresolved macro invocations, so concatenate the lists. - self.unresolved_macros.extend(macros); + macros.extend(mem::take(&mut self.unresolved_macros)); + self.unresolved_macros = macros; for (module_id, depth, container, macro_call_id) in resolved { self.collect_macro_expansion(module_id, macro_call_id, depth, container); From d40ab66186fa477177a10d01eb16960a5f20c7ac Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Mon, 1 Aug 2022 16:48:33 +0900 Subject: [PATCH 0050/2442] fix: remove whitespaces from doctest names --- crates/ide/src/runnables.rs | 77 ++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index bec770ed99f1..3155f97f258d 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -373,11 +373,13 @@ pub(crate) fn runnable_impl( let adt_name = ty.as_adt()?.name(sema.db); let mut ty_args = ty.type_arguments().peekable(); let params = if ty_args.peek().is_some() { - format!("<{}>", ty_args.format_with(", ", |ty, cb| cb(&ty.display(sema.db)))) + format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty.display(sema.db)))) } else { String::new() }; - let test_id = TestId::Path(format!("{}{}", adt_name, params)); + let mut test_id = format!("{}{}", adt_name, params); + test_id.retain(|c| c != ' '); + let test_id = TestId::Path(test_id); Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::DocTest { test_id }, cfg }) } @@ -441,10 +443,11 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { format_to!( path, "<{}>", - ty_args.format_with(", ", |ty, cb| cb(&ty.display(db))) + ty_args.format_with(",", |ty, cb| cb(&ty.display(db))) ); } format_to!(path, "::{}", def_name); + path.retain(|c| c != ' '); return Some(path); } } @@ -2067,13 +2070,23 @@ mod tests { $0 struct Foo; +/// ``` +/// ``` impl Foo { /// ```rust /// ```` fn t() {} } + +/// ``` +/// ``` +impl Foo, ()> { + /// ``` + /// ``` + fn t() {} +} "#, - &[DocTest], + &[DocTest, DocTest, DocTest, DocTest], expect![[r#" [ Runnable { @@ -2082,12 +2095,64 @@ impl Foo { file_id: FileId( 0, ), - full_range: 47..85, + full_range: 20..103, + focus_range: 47..56, + name: "impl", + kind: Impl, + }, + kind: DocTest { + test_id: Path( + "Foo", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 63..101, name: "t", }, kind: DocTest { test_id: Path( - "Foo::t", + "Foo::t", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 105..188, + focus_range: 126..146, + name: "impl", + kind: Impl, + }, + kind: DocTest { + test_id: Path( + "Foo,()>", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 153..186, + name: "t", + }, + kind: DocTest { + test_id: Path( + "Foo,()>::t", ), }, cfg: None, From bd7dfac5ebbd8ba3bd63384000759fb4bb49b329 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 1 Aug 2022 13:47:09 +0200 Subject: [PATCH 0051/2442] Fix r-a spelling in some places --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- README.md | 2 +- crates/hir-def/src/item_tree.rs | 2 +- crates/ide-db/src/apply_change.rs | 2 +- crates/ide-ssr/src/lib.rs | 2 +- crates/ide/src/expand_macro.rs | 4 +- crates/ide/src/inlay_hints.rs | 2 +- crates/ide/src/join_lines.rs | 2 +- crates/ide/src/matching_brace.rs | 2 +- crates/ide/src/move_item.rs | 4 +- crates/ide/src/parent_module.rs | 2 +- crates/ide/src/runnables.rs | 4 +- crates/ide/src/shuffle_crate_graph.rs | 2 +- crates/ide/src/status.rs | 2 +- crates/ide/src/syntax_tree.rs | 2 +- crates/ide/src/view_crate_graph.rs | 2 +- crates/ide/src/view_hir.rs | 2 +- crates/ide/src/view_item_tree.rs | 2 +- crates/proc-macro-api/src/lib.rs | 2 +- crates/proc-macro-srv/src/abis/mod.rs | 2 +- crates/project-model/src/cargo_workspace.rs | 2 +- .../src/integrated_benchmarks.rs | 4 +- crates/syntax/src/lib.rs | 2 +- docs/dev/README.md | 8 +-- docs/dev/architecture.md | 2 +- docs/dev/guide.md | 2 +- docs/user/manual.adoc | 4 +- editors/code/package.json | 58 +++++++++---------- 28 files changed, 64 insertions(+), 64 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7ba06356a37c..1f246ed79b69 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -19,7 +19,7 @@ Before submitting, please make sure that you're not running into one of these kn Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3. --> -**rust-analyzer version**: (eg. output of "Rust Analyzer: Show RA Version" command) +**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command) **rustc version**: (eg. output of `rustc -V`) diff --git a/README.md b/README.md index 8bb0517ed5ab..8c3f6f8468bf 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer ## License -Rust analyzer is primarily distributed under the terms of both the MIT +rust-analyzer is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0). See LICENSE-APACHE and LICENSE-MIT for details. diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 375587ee935b..3342d4db4aa6 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -14,7 +14,7 @@ //! unaffected, so we don't have to recompute name resolution results or item data (see `data.rs`). //! //! The `ItemTree` for the currently open file can be displayed by using the VS Code command -//! "Rust Analyzer: Debug ItemTree". +//! "rust-analyzer: Debug ItemTree". //! //! Compared to rustc's architecture, `ItemTree` has properties from both rustc's AST and HIR: many //! syntax-level Rust features are already desugared to simpler forms in the `ItemTree`, but name diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs index 98b0e9c947a7..f8134c552f75 100644 --- a/crates/ide-db/src/apply_change.rs +++ b/crates/ide-db/src/apply_change.rs @@ -45,7 +45,7 @@ impl RootDatabase { // |=== // | Editor | Action Name // - // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)** + // | VS Code | **rust-analyzer: Memory Usage (Clears Database)** // |=== // image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[] pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { diff --git a/crates/ide-ssr/src/lib.rs b/crates/ide-ssr/src/lib.rs index a5e24daa9fa0..739e0ccb436d 100644 --- a/crates/ide-ssr/src/lib.rs +++ b/crates/ide-ssr/src/lib.rs @@ -57,7 +57,7 @@ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Structural Search Replace** +// | VS Code | **rust-analyzer: Structural Search Replace** // |=== // // Also available as an assist, by writing a comment containing the structural diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index efa8551a00d5..93252339cd4a 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs @@ -19,7 +19,7 @@ pub struct ExpandedMacro { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Expand macro recursively** +// | VS Code | **rust-analyzer: Expand macro recursively** // |=== // // image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[] @@ -32,7 +32,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< _ => 0, })?; - // due to how Rust Analyzer works internally, we need to special case derive attributes, + // due to how rust-analyzer works internally, we need to special case derive attributes, // otherwise they might not get found, e.g. here with the cursor at $0 `#[attr]` would expand: // ``` // #[attr] diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 5aae669aa4d6..ed19784d1fa4 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -100,7 +100,7 @@ pub enum InlayTooltip { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Toggle inlay hints* +// | VS Code | **rust-analyzer: Toggle inlay hints* // |=== // // image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[] diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 08621addeef4..edc48e84d725 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs @@ -28,7 +28,7 @@ pub struct JoinLinesConfig { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Join lines** +// | VS Code | **rust-analyzer: Join lines** // |=== // // image::https://user-images.githubusercontent.com/48062697/113020661-b6922200-917a-11eb-87c4-b75acc028f11.gif[] diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs index da70cecdd8e1..6e8a6d020cc7 100644 --- a/crates/ide/src/matching_brace.rs +++ b/crates/ide/src/matching_brace.rs @@ -12,7 +12,7 @@ use syntax::{ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Find matching brace** +// | VS Code | **rust-analyzer: Find matching brace** // |=== // // image::https://user-images.githubusercontent.com/48062697/113065573-04298180-91b1-11eb-8dec-d4e2a202f304.gif[] diff --git a/crates/ide/src/move_item.rs b/crates/ide/src/move_item.rs index 02e9fb8b5e28..ffc4bdd7da33 100644 --- a/crates/ide/src/move_item.rs +++ b/crates/ide/src/move_item.rs @@ -19,8 +19,8 @@ pub enum Direction { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Move item up** -// | VS Code | **Rust Analyzer: Move item down** +// | VS Code | **rust-analyzer: Move item up** +// | VS Code | **rust-analyzer: Move item down** // |=== // // image::https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif[] diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs index 9b1f480446aa..8f3cc86873f5 100644 --- a/crates/ide/src/parent_module.rs +++ b/crates/ide/src/parent_module.rs @@ -18,7 +18,7 @@ use crate::NavigationTarget; // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Locate parent module** +// | VS Code | **rust-analyzer: Locate parent module** // |=== // // image::https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif[] diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 3155f97f258d..b0853b10fde2 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -116,7 +116,7 @@ impl Runnable { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Run** +// | VS Code | **rust-analyzer: Run** // |=== // image::https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif[] pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { @@ -202,7 +202,7 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Peek related tests** +// | VS Code | **rust-analyzer: Peek related tests** // |=== pub(crate) fn related_tests( db: &RootDatabase, diff --git a/crates/ide/src/shuffle_crate_graph.rs b/crates/ide/src/shuffle_crate_graph.rs index 15cb89dcce95..2d86627643d7 100644 --- a/crates/ide/src/shuffle_crate_graph.rs +++ b/crates/ide/src/shuffle_crate_graph.rs @@ -12,7 +12,7 @@ use ide_db::{ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Shuffle Crate Graph** +// | VS Code | **rust-analyzer: Shuffle Crate Graph** // |=== pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { let crate_graph = db.crate_graph(); diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index 3191870eb5e8..32e39f82a0e9 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs @@ -29,7 +29,7 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Status** +// | VS Code | **rust-analyzer: Status** // |=== // image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[] pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs index 9003e7cd34d0..4256fea0f81e 100644 --- a/crates/ide/src/syntax_tree.rs +++ b/crates/ide/src/syntax_tree.rs @@ -12,7 +12,7 @@ use syntax::{ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Show Syntax Tree** +// | VS Code | **rust-analyzer: Show Syntax Tree** // |=== // image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[] pub(crate) fn syntax_tree( diff --git a/crates/ide/src/view_crate_graph.rs b/crates/ide/src/view_crate_graph.rs index 51291a64532f..bf7b7efe2822 100644 --- a/crates/ide/src/view_crate_graph.rs +++ b/crates/ide/src/view_crate_graph.rs @@ -16,7 +16,7 @@ use ide_db::{ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: View Crate Graph** +// | VS Code | **rust-analyzer: View Crate Graph** // |=== pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result { let crate_graph = db.crate_graph(); diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs index 7312afe5310b..bf0835ed7e0d 100644 --- a/crates/ide/src/view_hir.rs +++ b/crates/ide/src/view_hir.rs @@ -8,7 +8,7 @@ use syntax::{algo::find_node_at_offset, ast, AstNode}; // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: View Hir** +// | VS Code | **rust-analyzer: View Hir** // |=== // image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[] pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { diff --git a/crates/ide/src/view_item_tree.rs b/crates/ide/src/view_item_tree.rs index 3dc03085d651..9c1f93356ee2 100644 --- a/crates/ide/src/view_item_tree.rs +++ b/crates/ide/src/view_item_tree.rs @@ -9,7 +9,7 @@ use ide_db::RootDatabase; // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Debug ItemTree** +// | VS Code | **rust-analyzer: Debug ItemTree** // |=== pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String { db.file_item_tree(file_id.into()).pretty_print() diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index d7010e825aa9..a3ea05f4aff8 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -60,7 +60,7 @@ impl MacroDylib { let info = version::read_dylib_info(&path)?; if info.version.0 < 1 || info.version.1 < 47 { - let msg = format!("proc-macro {} built by {:#?} is not supported by Rust Analyzer, please update your rust version.", path.display(), info); + let msg = format!("proc-macro {} built by {:#?} is not supported by rust-analyzer, please update your Rust version.", path.display(), info); return Err(io::Error::new(io::ErrorKind::InvalidData, msg)); } diff --git a/crates/proc-macro-srv/src/abis/mod.rs b/crates/proc-macro-srv/src/abis/mod.rs index bcf3f1184cf6..705d09ea9458 100644 --- a/crates/proc-macro-srv/src/abis/mod.rs +++ b/crates/proc-macro-srv/src/abis/mod.rs @@ -5,7 +5,7 @@ //! compiler into submodules of this module (e.g proc_macro_srv::abis::abi_1_47). //! //! All of these ABIs are subsumed in the `Abi` enum, which exposes a simple -//! interface the rest of rust analyzer can use to talk to the macro +//! interface the rest of rust-analyzer can use to talk to the macro //! provider. //! //! # Adding a new ABI diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index 597880c2ca21..eed955b42daa 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -19,7 +19,7 @@ use crate::{utf8_stdout, ManifestPath}; /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo /// workspace. It pretty closely mirrors `cargo metadata` output. /// -/// Note that internally, rust analyzer uses a different structure: +/// Note that internally, rust-analyzer uses a different structure: /// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, /// while this knows about `Packages` & `Targets`: purely cargo-related /// concepts. diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index 47cdd8dfc75d..e49a98685a7f 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -6,8 +6,8 @@ //! code here exercise this specific completion, and thus have a fast //! edit/compile/test cycle. //! -//! Note that "Rust Analyzer: Run" action does not allow running a single test -//! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line" +//! Note that "rust-analyzer: Run" action does not allow running a single test +//! in release mode in VS Code. There's however "rust-analyzer: Copy Run Command Line" //! which you can use to paste the command in terminal and add `--release` manually. use std::sync::Arc; diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 7fa354c0c465..4f5e273a520a 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -1,4 +1,4 @@ -//! Syntax Tree library used throughout the rust analyzer. +//! Syntax Tree library used throughout the rust-analyzer. //! //! Properties: //! - easy and fast incremental re-parsing diff --git a/docs/dev/README.md b/docs/dev/README.md index 76bbd1e91889..c7f152acc266 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -82,7 +82,7 @@ There's **"Run Extension (Debug Build)"** launch configuration for this in VS Co In general, I use one of the following workflows for fixing bugs and implementing features: If the problem concerns only internal parts of rust-analyzer (i.e. I don't need to touch the `rust-analyzer` crate or TypeScript code), there is a unit-test for it. -So, I use **Rust Analyzer: Run** action in VS Code to run this single test, and then just do printf-driven development/debugging. +So, I use **rust-analyzer: Run** action in VS Code to run this single test, and then just do printf-driven development/debugging. As a sanity check after I'm done, I use `cargo xtask install --server` and **Reload Window** action in VS Code to verify that the thing works as I expect. If the problem concerns only the VS Code extension, I use **Run Installed Extension** launch configuration from `launch.json`. @@ -152,11 +152,11 @@ To log all communication between the server and the client, there are two choice There are also several VS Code commands which might be of interest: -* `Rust Analyzer: Status` shows some memory-usage statistics. +* `rust-analyzer: Status` shows some memory-usage statistics. -* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection. +* `rust-analyzer: Syntax Tree` shows syntax tree of the current file/selection. -* `Rust Analyzer: View Hir` shows the HIR expressions within the function containing the cursor. +* `rust-analyzer: View Hir` shows the HIR expressions within the function containing the cursor. You can hover over syntax nodes in the opened text file to see the appropriate rust code that it refers to and the rust editor will also highlight the proper diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index ea4035baf114..51e26c58a917 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md @@ -371,7 +371,7 @@ That is, rust-analyzer requires unwinding. ### Testing -Rust Analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on. +rust-analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on. The outermost boundary is the `rust-analyzer` crate, which defines an LSP interface in terms of stdio. We do integration testing of this component, by feeding it with a stream of LSP requests and checking responses. diff --git a/docs/dev/guide.md b/docs/dev/guide.md index 47ae3f3e6a90..808eb5d10bf4 100644 --- a/docs/dev/guide.md +++ b/docs/dev/guide.md @@ -63,7 +63,7 @@ Next, let's talk about what the inputs to the `Analysis` are, precisely. ## Inputs -Rust Analyzer never does any I/O itself, all inputs get passed explicitly via +rust-analyzer never does any I/O itself, all inputs get passed explicitly via the `AnalysisHost::apply_change` method, which accepts a single argument, a `Change`. [`Change`] is a builder for a single change "transaction", so it suffices to study its methods to understand all of the diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 999a6437ab9e..c482fcbed0e0 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -479,7 +479,7 @@ You can follow instructions for installing < Date: Mon, 1 Aug 2022 14:26:20 +0200 Subject: [PATCH 0052/2442] Publish extension for 32-bit ARM systems --- .github/workflows/release.yaml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4e62f2cde279..abc0a34c5eec 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -5,6 +5,8 @@ on: workflow_dispatch: + pull_request: + push: branches: - release @@ -36,6 +38,9 @@ jobs: - os: ubuntu-18.04 target: aarch64-unknown-linux-gnu code-target: linux-arm64 + - os: ubuntu-18.04 + target: arm-unknown-linux-gnueabihf + code-target: linux-armhf - os: macos-11 target: x86_64-apple-darwin code-target: darwin-x64 @@ -67,13 +72,17 @@ jobs: node-version: 14.x - name: Update apt repositories - if: matrix.target == 'aarch64-unknown-linux-gnu' + if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'gcc-arm-linux-gnueabihf' run: sudo apt-get update - - name: Install target toolchain + - name: Install AArch64 target toolchain if: matrix.target == 'aarch64-unknown-linux-gnu' run: sudo apt-get install gcc-aarch64-linux-gnu + - name: Install ARM target toolchain + if: matrix.target == 'gcc-arm-linux-gnueabihf' + run: sudo apt-get install gcc-arm-linux-gnueabihf + - name: Dist run: cargo xtask dist --client-patch-version ${{ github.run_number }} From caf8a6454a0ee4a045537cfdbe5ab859b3dc6b6d Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 1 Aug 2022 15:09:45 +0200 Subject: [PATCH 0053/2442] Set linker --- .github/workflows/release.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index abc0a34c5eec..56ee876cf1f9 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -20,6 +20,7 @@ env: FETCH_DEPTH: 0 # pull in the tags for the version string MACOSX_DEPLOYMENT_TARGET: 10.15 CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHD_LINKER: arm-linux-gnueabihf-gcc jobs: dist: From 64090ee27cc630778fabd25a4d2ffd70329d62db Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 1 Aug 2022 15:22:02 +0200 Subject: [PATCH 0054/2442] Fix target check --- .github/workflows/release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 56ee876cf1f9..4845168282ee 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -73,7 +73,7 @@ jobs: node-version: 14.x - name: Update apt repositories - if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'gcc-arm-linux-gnueabihf' + if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf' run: sudo apt-get update - name: Install AArch64 target toolchain @@ -81,7 +81,7 @@ jobs: run: sudo apt-get install gcc-aarch64-linux-gnu - name: Install ARM target toolchain - if: matrix.target == 'gcc-arm-linux-gnueabihf' + if: matrix.target == 'arm-unknown-linux-gnueabihf' run: sudo apt-get install gcc-arm-linux-gnueabihf - name: Dist From b72ff95901bcd65931b600f36e3a79b92b6cab3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 1 Aug 2022 16:46:18 +0300 Subject: [PATCH 0055/2442] Fix linker env var name --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4845168282ee..7ffe2748b76b 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -20,7 +20,7 @@ env: FETCH_DEPTH: 0 # pull in the tags for the version string MACOSX_DEPLOYMENT_TARGET: 10.15 CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHD_LINKER: arm-linux-gnueabihf-gcc + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc jobs: dist: From cfbada4e0fbdb0fbde515df21be934d12cad63bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 1 Aug 2022 16:54:54 +0300 Subject: [PATCH 0056/2442] Upload arm-unknown-linux-gnueabihf build artifact --- .github/workflows/release.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7ffe2748b76b..015614c8b4d0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -214,6 +214,10 @@ jobs: with: name: dist-aarch64-unknown-linux-gnu path: dist + - uses: actions/download-artifact@v1 + with: + name: dist-arm-unknown-linux-gnueabihf + path: dist - uses: actions/download-artifact@v1 with: name: dist-x86_64-pc-windows-msvc From c71f1e70a87bfbaab7095a297628ff78acfc14df Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 1 Aug 2022 16:16:22 +0200 Subject: [PATCH 0057/2442] Don't run on PRs --- .github/workflows/release.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 015614c8b4d0..ca8eb1309de3 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -5,8 +5,6 @@ on: workflow_dispatch: - pull_request: - push: branches: - release From 405dd77d30382f417f033e4feba2b2bd02ebe00e Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Wed, 20 Jul 2022 12:03:18 -0500 Subject: [PATCH 0058/2442] Support adding variants via structural editing --- crates/syntax/src/ast/edit_in_place.rs | 171 +++++++++++++++++++++---- crates/syntax/src/ast/make.rs | 5 +- 2 files changed, 148 insertions(+), 28 deletions(-) diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index e3e928aecd4a..8efd58e2c39a 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -11,7 +11,7 @@ use crate::{ ted::{self, Position}, AstNode, AstToken, Direction, SyntaxKind::{ATTR, COMMENT, WHITESPACE}, - SyntaxNode, + SyntaxNode, SyntaxToken, }; use super::HasName; @@ -506,19 +506,7 @@ impl ast::RecordExprFieldList { let position = match self.fields().last() { Some(last_field) => { - let comma = match last_field - .syntax() - .siblings_with_tokens(Direction::Next) - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T![,]) - { - Some(it) => it, - None => { - let comma = ast::make::token(T![,]); - ted::insert(Position::after(last_field.syntax()), &comma); - comma - } - }; + let comma = get_or_insert_comma_after(last_field.syntax()); Position::after(comma) } None => match self.l_curly_token() { @@ -579,19 +567,8 @@ impl ast::RecordPatFieldList { let position = match self.fields().last() { Some(last_field) => { - let comma = match last_field - .syntax() - .siblings_with_tokens(Direction::Next) - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T![,]) - { - Some(it) => it, - None => { - let comma = ast::make::token(T![,]); - ted::insert(Position::after(last_field.syntax()), &comma); - comma - } - }; + let syntax = last_field.syntax(); + let comma = get_or_insert_comma_after(syntax); Position::after(comma) } None => match self.l_curly_token() { @@ -606,12 +583,53 @@ impl ast::RecordPatFieldList { } } } + +fn get_or_insert_comma_after(syntax: &SyntaxNode) -> SyntaxToken { + let comma = match syntax + .siblings_with_tokens(Direction::Next) + .filter_map(|it| it.into_token()) + .find(|it| it.kind() == T![,]) + { + Some(it) => it, + None => { + let comma = ast::make::token(T![,]); + ted::insert(Position::after(syntax), &comma); + comma + } + }; + comma +} + impl ast::StmtList { pub fn push_front(&self, statement: ast::Stmt) { ted::insert(Position::after(self.l_curly_token().unwrap()), statement.syntax()); } } +impl ast::VariantList { + pub fn add_variant(&self, variant: ast::Variant) { + let (indent, position) = match self.variants().last() { + Some(last_item) => ( + IndentLevel::from_node(last_item.syntax()), + Position::after(get_or_insert_comma_after(last_item.syntax())), + ), + None => match self.l_curly_token() { + Some(l_curly) => { + normalize_ws_between_braces(self.syntax()); + (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly)) + } + None => (IndentLevel::single(), Position::last_child_of(self.syntax())), + }, + }; + let elements: Vec> = vec![ + make::tokens::whitespace(&format!("{}{}", "\n", indent)).into(), + variant.syntax().clone().into(), + ast::make::token(T![,]).into(), + ]; + ted::insert_all(position, elements); + } +} + fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> { let l = node .children_with_tokens() @@ -661,6 +679,9 @@ impl Indent for N {} mod tests { use std::fmt; + use stdx::trim_indent; + use test_utils::assert_eq_text; + use crate::SourceFile; use super::*; @@ -714,4 +735,100 @@ mod tests { }", ); } + + #[test] + fn add_variant_to_empty_enum() { + let variant = make::variant(make::name("Bar"), None).clone_for_update(); + + check_add_variant( + r#" +enum Foo {} +"#, + r#" +enum Foo { + Bar, +} +"#, + variant, + ); + } + + #[test] + fn add_variant_to_non_empty_enum() { + let variant = make::variant(make::name("Baz"), None).clone_for_update(); + + check_add_variant( + r#" +enum Foo { + Bar, +} +"#, + r#" +enum Foo { + Bar, + Baz, +} +"#, + variant, + ); + } + + #[test] + fn add_variant_with_tuple_field_list() { + let variant = make::variant( + make::name("Baz"), + Some(ast::FieldList::TupleFieldList(make::tuple_field_list(std::iter::once( + make::tuple_field(None, make::ty("bool")), + )))), + ) + .clone_for_update(); + + check_add_variant( + r#" +enum Foo { + Bar, +} +"#, + r#" +enum Foo { + Bar, + Baz(bool), +} +"#, + variant, + ); + } + + #[test] + fn add_variant_with_record_field_list() { + let variant = make::variant( + make::name("Baz"), + Some(ast::FieldList::RecordFieldList(make::record_field_list(std::iter::once( + make::record_field(None, make::name("x"), make::ty("bool")), + )))), + ) + .clone_for_update(); + + check_add_variant( + r#" +enum Foo { + Bar, +} +"#, + r#" +enum Foo { + Bar, + Baz { x: bool }, +} +"#, + variant, + ); + } + + fn check_add_variant(before: &str, expected: &str, variant: ast::Variant) { + let enum_ = ast_mut_from_text::(before); + enum_.variant_list().map(|it| it.add_variant(variant)); + let after = enum_.to_string(); + assert_eq_text!(&trim_indent(expected.trim()), &trim_indent(&after.trim())); + } } diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 5908dda8e638..037de876d45c 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -745,7 +745,10 @@ pub fn tuple_field(visibility: Option, ty: ast::Type) -> ast::T pub fn variant(name: ast::Name, field_list: Option) -> ast::Variant { let field_list = match field_list { None => String::new(), - Some(it) => format!("{}", it), + Some(it) => match it { + ast::FieldList::RecordFieldList(record) => format!(" {}", record), + ast::FieldList::TupleFieldList(tuple) => format!("{}", tuple), + }, }; ast_from_text(&format!("enum f {{ {}{} }}", name, field_list)) } From bea1fec7a2c949d6470f2182d34c5b349605f7a1 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Wed, 20 Jul 2022 12:11:00 -0500 Subject: [PATCH 0059/2442] convert generate_enum_variant to use add_variant --- .../src/handlers/generate_enum_variant.rs | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index 4461fbd5ac82..04620645e6d3 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -1,8 +1,8 @@ use hir::{HasSource, InFile}; use ide_db::assists::{AssistId, AssistKind}; use syntax::{ - ast::{self, edit::IndentLevel}, - AstNode, TextSize, + ast::{self, make}, + AstNode, }; use crate::assist_context::{AssistContext, Assists}; @@ -65,26 +65,16 @@ fn add_variant_to_accumulator( ) -> Option<()> { let db = ctx.db(); let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?; - let enum_indent = IndentLevel::from_node(&enum_node.syntax()); - - let variant_list = enum_node.variant_list()?; - let offset = variant_list.syntax().text_range().end() - TextSize::of('}'); - let empty_enum = variant_list.variants().next().is_none(); + let variant = make::variant(make::name(&name_ref.text()), None); acc.add( AssistId("generate_enum_variant", AssistKind::Generate), "Generate variant", target, |builder| { builder.edit_file(file_id.original_file(db)); - let text = format!( - "{maybe_newline}{indent_1}{name},\n{enum_indent}", - maybe_newline = if empty_enum { "\n" } else { "" }, - indent_1 = IndentLevel(1), - name = name_ref, - enum_indent = enum_indent - ); - builder.insert(offset, text) + let node = builder.make_mut(enum_node); + node.variant_list().map(|it| it.add_variant(variant.clone_for_update())); }, ) } From 15d8049fa9a9cd3ecbd19401336c4c150606522c Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Wed, 20 Jul 2022 12:26:27 -0500 Subject: [PATCH 0060/2442] Support tuple fields in generate_enum_variant --- .../src/handlers/generate_enum_variant.rs | 115 +++++++++++++++++- 1 file changed, 111 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index 04620645e6d3..f671877e5217 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -1,7 +1,7 @@ -use hir::{HasSource, InFile}; +use hir::{HasSource, HirDisplay, InFile}; use ide_db::assists::{AssistId, AssistKind}; use syntax::{ - ast::{self, make}, + ast::{self, make, HasArgList}, AstNode, }; @@ -50,7 +50,7 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) ctx.sema.resolve_path(&path.qualifier()?) { let target = path.syntax().text_range(); - return add_variant_to_accumulator(acc, ctx, target, e, &name_ref); + return add_variant_to_accumulator(acc, ctx, target, e, &name_ref, &path); } None @@ -62,11 +62,11 @@ fn add_variant_to_accumulator( target: syntax::TextRange, adt: hir::Enum, name_ref: &ast::NameRef, + path: &ast::Path, ) -> Option<()> { let db = ctx.db(); let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?; - let variant = make::variant(make::name(&name_ref.text()), None); acc.add( AssistId("generate_enum_variant", AssistKind::Generate), "Generate variant", @@ -74,11 +74,53 @@ fn add_variant_to_accumulator( |builder| { builder.edit_file(file_id.original_file(db)); let node = builder.make_mut(enum_node); + let variant = make_variant(ctx, name_ref, &path); node.variant_list().map(|it| it.add_variant(variant.clone_for_update())); }, ) } +fn make_variant( + ctx: &AssistContext<'_>, + name_ref: &ast::NameRef, + path: &ast::Path, +) -> ast::Variant { + let field_list = make_field_list(ctx, path); + make::variant(make::name(&name_ref.text()), field_list) +} + +fn make_field_list(ctx: &AssistContext<'_>, path: &ast::Path) -> Option { + let scope = ctx.sema.scope(&path.syntax())?; + if let Some(call_expr) = + path.syntax().parent().and_then(|it| it.parent()).and_then(ast::CallExpr::cast) + { + make_tuple_field_list(call_expr, ctx, &scope) + } else { + None + } +} + +fn make_tuple_field_list( + call_expr: ast::CallExpr, + ctx: &AssistContext<'_>, + scope: &hir::SemanticsScope<'_>, +) -> Option { + let args = call_expr.arg_list()?.args(); + let tuple_fields = args.map(|arg| { + let ty = expr_ty(ctx, arg, &scope); + make::tuple_field(None, ty) + }); + Some(make::tuple_field_list(tuple_fields).into()) +} + +fn expr_ty(ctx: &AssistContext<'_>, arg: ast::Expr, scope: &hir::SemanticsScope<'_>) -> ast::Type { + let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted()); + let text = ty + .and_then(|it| it.display_source_code(ctx.db(), scope.module().into()).ok()) + .unwrap_or_else(|| "_".to_string()); + make::ty(&text) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -211,6 +253,71 @@ mod m { fn main() { m::Foo::Baz } +", + ) + } + + #[test] + fn associated_single_element_tuple() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::Bar$0(true) +} +", + r" +enum Foo { + Bar(bool), +} +fn main() { + Foo::Bar(true) +} +", + ) + } + + #[test] + fn associated_single_element_tuple_unknown_type() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::Bar$0(x) +} +", + r" +enum Foo { + Bar(_), +} +fn main() { + Foo::Bar(x) +} +", + ) + } + + #[test] + fn associated_multi_element_tuple() { + check_assist( + generate_enum_variant, + r" +struct Struct {} +enum Foo {} +fn main() { + Foo::Bar$0(true, x, Struct {}) +} +", + r" +struct Struct {} +enum Foo { + Bar(bool, _, Struct), +} +fn main() { + Foo::Bar(true, x, Struct {}) +} ", ) } From e4638def7aedd8d69ec2670abf6a08b876ad75d9 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Wed, 20 Jul 2022 13:02:21 -0500 Subject: [PATCH 0061/2442] Support record fields in generate_enum_variant --- .../src/handlers/generate_enum_variant.rs | 165 +++++++++++++++++- 1 file changed, 156 insertions(+), 9 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index f671877e5217..afbfc74b72a2 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -32,8 +32,7 @@ use crate::assist_context::{AssistContext, Assists}; // } // ``` pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let path_expr: ast::PathExpr = ctx.find_node_at_offset()?; - let path = path_expr.path()?; + let path: ast::Path = ctx.find_node_at_offset()?; if ctx.sema.resolve_path(&path).is_some() { // No need to generate anything if the path resolves @@ -95,11 +94,48 @@ fn make_field_list(ctx: &AssistContext<'_>, path: &ast::Path) -> Option, + scope: &hir::SemanticsScope<'_>, +) -> Option { + let fields = record.record_expr_field_list()?.fields(); + let record_fields = fields.map(|field| { + let name = name_from_field(&field); + + let ty = field + .expr() + .and_then(|it| expr_ty(ctx, it, scope)) + .unwrap_or_else(make::ty_placeholder); + + make::record_field(None, name, ty) + }); + Some(make::record_field_list(record_fields).into()) +} + +fn name_from_field(field: &ast::RecordExprField) -> ast::Name { + let text = match field.name_ref() { + Some(it) => it.to_string(), + None => name_from_field_shorthand(field).unwrap_or("unknown".to_string()), + }; + make::name(&text) +} + +fn name_from_field_shorthand(field: &ast::RecordExprField) -> Option { + let path = match field.expr()? { + ast::Expr::PathExpr(path_expr) => path_expr.path(), + _ => None, + }?; + Some(path.as_single_name_ref()?.to_string()) +} + fn make_tuple_field_list( call_expr: ast::CallExpr, ctx: &AssistContext<'_>, @@ -107,18 +143,20 @@ fn make_tuple_field_list( ) -> Option { let args = call_expr.arg_list()?.args(); let tuple_fields = args.map(|arg| { - let ty = expr_ty(ctx, arg, &scope); + let ty = expr_ty(ctx, arg, &scope).unwrap_or_else(make::ty_placeholder); make::tuple_field(None, ty) }); Some(make::tuple_field_list(tuple_fields).into()) } -fn expr_ty(ctx: &AssistContext<'_>, arg: ast::Expr, scope: &hir::SemanticsScope<'_>) -> ast::Type { - let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted()); - let text = ty - .and_then(|it| it.display_source_code(ctx.db(), scope.module().into()).ok()) - .unwrap_or_else(|| "_".to_string()); - make::ty(&text) +fn expr_ty( + ctx: &AssistContext<'_>, + arg: ast::Expr, + scope: &hir::SemanticsScope<'_>, +) -> Option { + let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted())?; + let text = ty.display_source_code(ctx.db(), scope.module().into()).ok()?; + Some(make::ty(&text)) } #[cfg(test)] @@ -318,6 +356,115 @@ enum Foo { fn main() { Foo::Bar(true, x, Struct {}) } +", + ) + } + + #[test] + fn associated_record() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::$0Bar { x: true } +} +", + r" +enum Foo { + Bar { x: bool }, +} +fn main() { + Foo::Bar { x: true } +} +", + ) + } + + #[test] + fn associated_record_unknown_type() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::$0Bar { x: y } +} +", + r" +enum Foo { + Bar { x: _ }, +} +fn main() { + Foo::Bar { x: y } +} +", + ) + } + + #[test] + fn associated_record_field_shorthand() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + let x = true; + Foo::$0Bar { x } +} +", + r" +enum Foo { + Bar { x: bool }, +} +fn main() { + let x = true; + Foo::Bar { x } +} +", + ) + } + + #[test] + fn associated_record_field_shorthand_unknown_type() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::$0Bar { x } +} +", + r" +enum Foo { + Bar { x: _ }, +} +fn main() { + Foo::Bar { x } +} +", + ) + } + + #[test] + fn associated_record_field_multiple_fields() { + check_assist( + generate_enum_variant, + r" +struct Struct {} +enum Foo {} +fn main() { + Foo::$0Bar { x, y: x, s: Struct {} } +} +", + r" +struct Struct {} +enum Foo { + Bar { x: _, y: _, s: Struct }, +} +fn main() { + Foo::Bar { x, y: x, s: Struct {} } +} ", ) } From 111694d85bc64e3604599668c5b2db574e07abf0 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Tue, 2 Aug 2022 11:54:00 -0400 Subject: [PATCH 0062/2442] Be more strict about supported Paths in generate_enum_variant PathType path parents don't support this assist --- .../src/handlers/generate_enum_variant.rs | 105 ++++++++++++++---- 1 file changed, 85 insertions(+), 20 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index afbfc74b72a2..b3dd29b77108 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -2,7 +2,7 @@ use hir::{HasSource, HirDisplay, InFile}; use ide_db::assists::{AssistId, AssistKind}; use syntax::{ ast::{self, make, HasArgList}, - AstNode, + match_ast, AstNode, SyntaxNode, }; use crate::assist_context::{AssistContext, Assists}; @@ -33,6 +33,7 @@ use crate::assist_context::{AssistContext, Assists}; // ``` pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let path: ast::Path = ctx.find_node_at_offset()?; + let parent = path_parent(&path)?; if ctx.sema.resolve_path(&path).is_some() { // No need to generate anything if the path resolves @@ -49,19 +50,65 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) ctx.sema.resolve_path(&path.qualifier()?) { let target = path.syntax().text_range(); - return add_variant_to_accumulator(acc, ctx, target, e, &name_ref, &path); + return add_variant_to_accumulator(acc, ctx, target, e, &name_ref, parent); } None } +#[derive(Debug)] +enum PathParent { + PathExpr(ast::PathExpr), + RecordExpr(ast::RecordExpr), + UseTree(ast::UseTree), +} + +impl PathParent { + fn syntax(&self) -> &SyntaxNode { + match self { + PathParent::PathExpr(it) => it.syntax(), + PathParent::RecordExpr(it) => it.syntax(), + PathParent::UseTree(it) => it.syntax(), + } + } + + fn make_field_list(&self, ctx: &AssistContext<'_>) -> Option { + let scope = ctx.sema.scope(self.syntax())?; + + match self { + PathParent::PathExpr(it) => { + if let Some(call_expr) = it.syntax().parent().and_then(ast::CallExpr::cast) { + make_tuple_field_list(call_expr, ctx, &scope) + } else { + None + } + } + PathParent::RecordExpr(it) => make_record_field_list(it, ctx, &scope), + PathParent::UseTree(_) => None, + } + } +} + +fn path_parent(path: &ast::Path) -> Option { + let parent = path.syntax().parent()?; + + match_ast! { + match parent { + ast::PathExpr(it) => Some(PathParent::PathExpr(it)), + ast::RecordExpr(it) => Some(PathParent::RecordExpr(it)), + ast::UseTree(it) => Some(PathParent::UseTree(it)), + _ => None + } + } +} + fn add_variant_to_accumulator( acc: &mut Assists, ctx: &AssistContext<'_>, target: syntax::TextRange, adt: hir::Enum, name_ref: &ast::NameRef, - path: &ast::Path, + parent: PathParent, ) -> Option<()> { let db = ctx.db(); let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?; @@ -73,7 +120,7 @@ fn add_variant_to_accumulator( |builder| { builder.edit_file(file_id.original_file(db)); let node = builder.make_mut(enum_node); - let variant = make_variant(ctx, name_ref, &path); + let variant = make_variant(ctx, name_ref, parent); node.variant_list().map(|it| it.add_variant(variant.clone_for_update())); }, ) @@ -82,27 +129,14 @@ fn add_variant_to_accumulator( fn make_variant( ctx: &AssistContext<'_>, name_ref: &ast::NameRef, - path: &ast::Path, + parent: PathParent, ) -> ast::Variant { - let field_list = make_field_list(ctx, path); + let field_list = parent.make_field_list(ctx); make::variant(make::name(&name_ref.text()), field_list) } -fn make_field_list(ctx: &AssistContext<'_>, path: &ast::Path) -> Option { - let scope = ctx.sema.scope(&path.syntax())?; - if let Some(call_expr) = - path.syntax().parent().and_then(|it| it.parent()).and_then(ast::CallExpr::cast) - { - make_tuple_field_list(call_expr, ctx, &scope) - } else if let Some(record_expr) = path.syntax().parent().and_then(ast::RecordExpr::cast) { - make_record_field_list(record_expr, ctx, &scope) - } else { - None - } -} - fn make_record_field_list( - record: ast::RecordExpr, + record: &ast::RecordExpr, ctx: &AssistContext<'_>, scope: &hir::SemanticsScope<'_>, ) -> Option { @@ -465,6 +499,37 @@ enum Foo { fn main() { Foo::Bar { x, y: x, s: Struct {} } } +", + ) + } + + #[test] + fn use_tree() { + check_assist( + generate_enum_variant, + r" +//- /main.rs +mod foo; +use foo::Foo::Bar$0; + +//- /foo.rs +enum Foo {} +", + r" +enum Foo { + Bar, +} +", + ) + } + + #[test] + fn not_applicable_for_path_type() { + check_assist_not_applicable( + generate_enum_variant, + r" +enum Foo {} +impl Foo::Bar$0 {} ", ) } From 1980c1192c7bcfb10e1ed380ee90bcaa7153d58d Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Tue, 2 Aug 2022 12:11:32 -0400 Subject: [PATCH 0063/2442] Support PathPat paths in generate_enum_variant --- .../src/handlers/generate_enum_variant.rs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index b3dd29b77108..35cd42908af2 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -60,6 +60,7 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) enum PathParent { PathExpr(ast::PathExpr), RecordExpr(ast::RecordExpr), + PathPat(ast::PathPat), UseTree(ast::UseTree), } @@ -68,6 +69,7 @@ impl PathParent { match self { PathParent::PathExpr(it) => it.syntax(), PathParent::RecordExpr(it) => it.syntax(), + PathParent::PathPat(it) => it.syntax(), PathParent::UseTree(it) => it.syntax(), } } @@ -84,7 +86,7 @@ impl PathParent { } } PathParent::RecordExpr(it) => make_record_field_list(it, ctx, &scope), - PathParent::UseTree(_) => None, + PathParent::UseTree(_) | PathParent::PathPat(_) => None, } } } @@ -96,6 +98,7 @@ fn path_parent(path: &ast::Path) -> Option { match parent { ast::PathExpr(it) => Some(PathParent::PathExpr(it)), ast::RecordExpr(it) => Some(PathParent::RecordExpr(it)), + ast::PathPat(it) => Some(PathParent::PathPat(it)), ast::UseTree(it) => Some(PathParent::UseTree(it)), _ => None } @@ -530,6 +533,31 @@ enum Foo { r" enum Foo {} impl Foo::Bar$0 {} +", + ) + } + + #[test] + fn path_pat() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn foo(x: Foo) { + match x { + Foo::Bar$0 => + } +} +", + r" +enum Foo { + Bar, +} +fn foo(x: Foo) { + match x { + Foo::Bar => + } +} ", ) } From 9a447c04f6c07ec6b835b3577610cfaf3f7667cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 3 Aug 2022 09:48:44 +0300 Subject: [PATCH 0064/2442] Use the release branch in xtask promote --- xtask/src/release.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xtask/src/release.rs b/xtask/src/release.rs index 17ada5156407..eda8fceef05b 100644 --- a/xtask/src/release.rs +++ b/xtask/src/release.rs @@ -81,7 +81,7 @@ impl flags::Promote { let date = date_iso(sh)?; let branch = format!("rust-analyzer-{date}"); cmd!(sh, "git switch -c {branch}").run()?; - cmd!(sh, "git subtree pull -P src/tools/rust-analyzer rust-analyzer master").run()?; + cmd!(sh, "git subtree pull -m ':arrow_up: rust-analyzer' -P src/tools/rust-analyzer rust-analyzer release").run()?; if !self.dry_run { cmd!(sh, "git push -u origin {branch}").run()?; From c203ac2cf5aaf7b7ed759e0f84426debc063d3e8 Mon Sep 17 00:00:00 2001 From: oxalica Date: Wed, 3 Aug 2022 17:35:31 +0800 Subject: [PATCH 0065/2442] Add more constructors for la-arena --- lib/la-arena/src/lib.rs | 10 ++++++++++ lib/la-arena/src/map.rs | 12 +++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/la-arena/src/lib.rs b/lib/la-arena/src/lib.rs index dadee43b1085..a6766edd4190 100644 --- a/lib/la-arena/src/lib.rs +++ b/lib/la-arena/src/lib.rs @@ -208,6 +208,16 @@ impl Arena { Arena { data: Vec::new() } } + /// Create a new empty arena with specific capacity. + /// + /// ``` + /// let arena: la_arena::Arena = la_arena::Arena::with_capacity(42); + /// assert!(arena.is_empty()); + /// ``` + pub fn with_capacity(capacity: usize) -> Arena { + Arena { data: Vec::with_capacity(capacity) } + } + /// Empties the arena, removing all contained values. /// /// ``` diff --git a/lib/la-arena/src/map.rs b/lib/la-arena/src/map.rs index d27f086d37bf..b5c49b3435d0 100644 --- a/lib/la-arena/src/map.rs +++ b/lib/la-arena/src/map.rs @@ -11,6 +11,16 @@ pub struct ArenaMap { } impl ArenaMap, V> { + /// Creates a new empty map. + pub const fn new() -> Self { + Self { v: Vec::new(), _ty: PhantomData } + } + + /// Create a new empty map with specific capacity. + pub fn with_capacity(capacity: usize) -> Self { + Self { v: Vec::with_capacity(capacity), _ty: PhantomData } + } + /// Inserts a value associated with a given arena index into the map. pub fn insert(&mut self, idx: Idx, t: V) { let idx = Self::to_idx(idx); @@ -70,6 +80,6 @@ impl std::ops::IndexMut> for ArenaMap, T> { impl Default for ArenaMap, T> { fn default() -> Self { - ArenaMap { v: Vec::new(), _ty: PhantomData } + Self::new() } } From 10f870eff44f07e3e8dc241e5cc11e0fa4d50ae3 Mon Sep 17 00:00:00 2001 From: oxalica Date: Wed, 3 Aug 2022 18:16:05 +0800 Subject: [PATCH 0066/2442] Impl entry-API for la_arena::ArenaMap We enforce integral and `Copy` key, so some key-related functions are not necessary since user can just reuse the index for the `entry` call. --- lib/la-arena/src/lib.rs | 2 +- lib/la-arena/src/map.rs | 107 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/lib/la-arena/src/lib.rs b/lib/la-arena/src/lib.rs index a6766edd4190..a3fe59e946ee 100644 --- a/lib/la-arena/src/lib.rs +++ b/lib/la-arena/src/lib.rs @@ -12,7 +12,7 @@ use std::{ }; mod map; -pub use map::ArenaMap; +pub use map::{ArenaMap, Entry, OccupiedEntry, VacantEntry}; /// The raw index of a value in an arena. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/lib/la-arena/src/map.rs b/lib/la-arena/src/map.rs index b5c49b3435d0..f74ec5d97cb9 100644 --- a/lib/la-arena/src/map.rs +++ b/lib/la-arena/src/map.rs @@ -56,6 +56,16 @@ impl ArenaMap, V> { self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?))) } + /// Gets the given key's corresponding entry in the map for in-place manipulation. + pub fn entry(&mut self, idx: Idx) -> Entry<'_, Idx, V> { + let idx = Self::to_idx(idx); + self.v.resize_with((idx + 1).max(self.v.len()), || None); + match &mut self.v[idx] { + slot @ Some(_) => Entry::Occupied(OccupiedEntry { slot, _ty: PhantomData }), + slot @ None => Entry::Vacant(VacantEntry { slot, _ty: PhantomData }), + } + } + fn to_idx(idx: Idx) -> usize { u32::from(idx.into_raw()) as usize } @@ -83,3 +93,100 @@ impl Default for ArenaMap, T> { Self::new() } } + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`ArenaMap`]. +/// +/// [`entry`]: ArenaMap::entry +pub enum Entry<'a, IDX, V> { + /// A vacant entry. + Vacant(VacantEntry<'a, IDX, V>), + /// An occupied entry. + Occupied(OccupiedEntry<'a, IDX, V>), +} + +impl<'a, IDX, V> Entry<'a, IDX, V> { + /// Ensures a value is in the entry by inserting the default if empty, and returns a mutable reference to + /// the value in the entry. + pub fn or_insert(self, default: V) -> &'a mut V { + match self { + Self::Vacant(ent) => ent.insert(default), + Self::Occupied(ent) => ent.into_mut(), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, and returns + /// a mutable reference to the value in the entry. + pub fn or_insert_with V>(self, default: F) -> &'a mut V { + match self { + Self::Vacant(ent) => ent.insert(default()), + Self::Occupied(ent) => ent.into_mut(), + } + } + + /// Provides in-place mutable access to an occupied entry before any potential inserts into the map. + pub fn and_modify(mut self, f: F) -> Self { + if let Self::Occupied(ent) = &mut self { + f(ent.get_mut()); + } + self + } +} + +impl<'a, IDX, V> Entry<'a, IDX, V> +where + V: Default, +{ + /// Ensures a value is in the entry by inserting the default value if empty, and returns a mutable reference + /// to the value in the entry. + pub fn or_default(self) -> &'a mut V { + self.or_insert_with(Default::default) + } +} + +/// A view into an vacant entry in a [`ArenaMap`]. It is part of the [`Entry`] enum. +pub struct VacantEntry<'a, IDX, V> { + slot: &'a mut Option, + _ty: PhantomData, +} + +impl<'a, IDX, V> VacantEntry<'a, IDX, V> { + /// Sets the value of the entry with the `VacantEntry`’s key, and returns a mutable reference to it. + pub fn insert(self, value: V) -> &'a mut V { + self.slot.insert(value) + } +} + +/// A view into an occupied entry in a [`ArenaMap`]. It is part of the [`Entry`] enum. +pub struct OccupiedEntry<'a, IDX, V> { + slot: &'a mut Option, + _ty: PhantomData, +} + +impl<'a, IDX, V> OccupiedEntry<'a, IDX, V> { + /// Gets a reference to the value in the entry. + pub fn get(&self) -> &V { + self.slot.as_ref().expect("Occupied") + } + + /// Gets a mutable reference to the value in the entry. + pub fn get_mut(&mut self) -> &mut V { + self.slot.as_mut().expect("Occupied") + } + + /// Converts the entry into a mutable reference to its value. + pub fn into_mut(self) -> &'a mut V { + self.slot.as_mut().expect("Occupied") + } + + /// Sets the value of the entry with the `OccupiedEntry`’s key, and returns the entry’s old value. + pub fn insert(&mut self, value: V) -> V { + self.slot.replace(value).expect("Occupied") + } + + /// Takes the value of the entry out of the map, and returns it. + pub fn remove(self) -> V { + self.slot.take().expect("Occupied") + } +} From a8a6c160be157ee7fe130d2c99521a2f76d3b4be Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 3 Aug 2022 18:10:15 +0200 Subject: [PATCH 0067/2442] Use an empty expander for ignored non-attribute proc-macros --- crates/rust-analyzer/src/reload.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index eaab275bc68a..9a9a9dd4d84c 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -621,7 +621,10 @@ pub(crate) fn load_proc_macro( }; let expander: Arc = if dummy_replace.iter().any(|replace| &**replace == name) { - Arc::new(DummyExpander) + match kind { + ProcMacroKind::Attr => Arc::new(IdentityExpander), + _ => Arc::new(EmptyExpander), + } } else { Arc::new(Expander(expander)) }; @@ -647,11 +650,11 @@ pub(crate) fn load_proc_macro( } } - /// Dummy identity expander, used for proc-macros that are deliberately ignored by the user. + /// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user. #[derive(Debug)] - struct DummyExpander; + struct IdentityExpander; - impl ProcMacroExpander for DummyExpander { + impl ProcMacroExpander for IdentityExpander { fn expand( &self, subtree: &tt::Subtree, @@ -661,6 +664,21 @@ pub(crate) fn load_proc_macro( Ok(subtree.clone()) } } + + /// Empty expander, used for proc-macros that are deliberately ignored by the user. + #[derive(Debug)] + struct EmptyExpander; + + impl ProcMacroExpander for EmptyExpander { + fn expand( + &self, + _: &tt::Subtree, + _: Option<&tt::Subtree>, + _: &Env, + ) -> Result { + Ok(tt::Subtree::default()) + } + } } pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool { From 46d6357994eb8ced835a69390dfbf01abed40ee1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 3 Aug 2022 18:22:45 +0200 Subject: [PATCH 0068/2442] Add a setting to disable comment continuation in VSCode --- editors/code/package.json | 5 +++++ editors/code/src/config.ts | 14 +++++++++++--- editors/code/src/main.ts | 4 +++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/editors/code/package.json b/editors/code/package.json index a13798d8b36c..39ff3eb0855c 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -380,6 +380,11 @@ "default": false, "type": "boolean" }, + "rust-analyzer.typing.continueCommentsOnNewline": { + "markdownDescription": "Whether to prefix newlines after comments with the corresponding comment prefix.", + "default": true, + "type": "boolean" + }, "$generated-start": {}, "rust-analyzer.assist.expressionFillDefault": { "markdownDescription": "Placeholder expression to use for missing expressions in assists.", diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index b04f18890b98..1c58040d58c2 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -16,9 +16,13 @@ export class Config { readonly extensionId = "rust-lang.rust-analyzer"; readonly rootSection = "rust-analyzer"; - private readonly requiresWorkspaceReloadOpts = ["serverPath", "server"].map( - (opt) => `${this.rootSection}.${opt}` - ); + private readonly requiresWorkspaceReloadOpts = [ + "serverPath", + "server", + // FIXME: This shouldn't be here, changing this setting should reload + // `continueCommentsOnNewline` behavior without restart + "typing", + ].map((opt) => `${this.rootSection}.${opt}`); private readonly requiresReloadOpts = [ "cargo", "procMacro", @@ -140,6 +144,10 @@ export class Config { return this.get("restartServerOnConfigChange"); } + get typingContinueCommentsOnNewline() { + return this.get("typing.continueCommentsOnNewline"); + } + get debug() { let sourceFileMap = this.get | "auto">("debug.sourceFileMap"); if (sourceFileMap !== "auto") { diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 9ae20ddc4ac4..d78b711a47a8 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -84,7 +84,9 @@ async function tryActivate(context: vscode.ExtensionContext): Promise From 5cb3e7a41b89b5612cefe9c688f0ffdff18d4df4 Mon Sep 17 00:00:00 2001 From: fprasx Date: Wed, 3 Aug 2022 14:44:21 -0400 Subject: [PATCH 0069/2442] Added fixup for match statements w/ missing parts Passes tests --- crates/hir-expand/src/fixup.rs | 111 ++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index e46f43a878fe..c875b23b2dcd 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -67,7 +67,6 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { preorder.skip_subtree(); continue; } - // In some other situations, we can fix things by just appending some tokens. let end_range = TextRange::empty(node.text_range().end()); match_ast! { @@ -195,6 +194,69 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { }, // FIXME: foo:: // FIXME: for, match etc. + ast::MatchExpr(it) => { + if it.expr().is_none() { + let match_token = match it.match_token() { + Some(t) => t, + None => continue + }; + append.insert(match_token.into(), vec![ + SyntheticToken { + kind: SyntaxKind::IDENT, + text: "__ra_fixup".into(), + range: end_range, + id: EMPTY_ID + }, + ]); + } + if it.match_arm_list().is_none() { + // No match arms + append.insert(node.clone().into(), vec![ + SyntheticToken { + kind: SyntaxKind::L_CURLY, + text: "{".into(), + range: end_range, + id: EMPTY_ID, + }, + SyntheticToken { + kind: SyntaxKind::UNDERSCORE, + text: "_".into(), + range: end_range, + id: EMPTY_ID + }, + SyntheticToken { + kind: SyntaxKind::EQ, + text: "=".into(), + range: end_range, + id: EMPTY_ID + }, + SyntheticToken { + kind: SyntaxKind::R_ANGLE, + text: ">".into(), + range: end_range, + id: EMPTY_ID + }, + SyntheticToken { + kind: SyntaxKind::L_CURLY, + text: "{".into(), + range: end_range, + id: EMPTY_ID, + }, + SyntheticToken { + kind: SyntaxKind::R_CURLY, + text: "}".into(), + range: end_range, + id: EMPTY_ID, + }, + SyntheticToken { + kind: SyntaxKind::R_CURLY, + text: "}".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + }, _ => (), } } @@ -287,6 +349,53 @@ mod tests { assert_eq!(tt.to_string(), original_as_tt.to_string()); } + + #[test] + fn match_no_expr_no_arms() { + check( + r#" +fn foo() { + match +} +"#, + expect![[r#" +fn foo () {match __ra_fixup {_ => {}}} +"#]], + ) + } + + #[test] + fn match_expr_no_arms() { + check( + r#" +fn foo() { + match x { + + } +} +"#, + expect![[r#" +fn foo () {match x {}} +"#]], + ) + } + + #[test] + fn match_no_expr() { + check( + r#" +fn foo() { + match { + _ => {} + } +} +"#, + expect![[r#" +fn foo () {match __ra_fixup {_ => {}}} +"#]], + ) + } + #[test] fn incomplete_field_expr_1() { check( From d513b4c8baaf2c71e5f13ce790bd0083ccb81a64 Mon Sep 17 00:00:00 2001 From: fprasx Date: Wed, 3 Aug 2022 15:51:30 -0400 Subject: [PATCH 0070/2442] Added fixup for for loops w/ missing parts --- crates/hir-expand/src/fixup.rs | 78 +++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index c875b23b2dcd..ade28f27bf1c 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -193,7 +193,6 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { } }, // FIXME: foo:: - // FIXME: for, match etc. ast::MatchExpr(it) => { if it.expr().is_none() { let match_token = match it.match_token() { @@ -257,6 +256,42 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { ]); } }, + ast::ForExpr(it) => { + let for_token = match it.for_token() { + Some(token) => token, + None => continue + }; + + let [pat, in_token, iter] = [ + (SyntaxKind::UNDERSCORE, "_"), + (SyntaxKind::IN_KW, "in"), + (SyntaxKind::IDENT, "__ra_fixup") + ].map(|(kind, text)| SyntheticToken { kind, text: text.into(), range: end_range, id: EMPTY_ID}); + + if it.pat().is_none() && it.in_token().is_none() && it.iterable().is_none() { + append.insert(for_token.into(), vec![pat, in_token, iter]); + } + + // Tricky: add logic to add in just a pattern or iterable if not all + // the pieces are missing + + if it.loop_body().is_none() { + append.insert(node.clone().into(), vec![ + SyntheticToken { + kind: SyntaxKind::L_CURLY, + text: "{".into(), + range: end_range, + id: EMPTY_ID, + }, + SyntheticToken { + kind: SyntaxKind::R_CURLY, + text: "}".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + }, _ => (), } } @@ -349,6 +384,47 @@ mod tests { assert_eq!(tt.to_string(), original_as_tt.to_string()); } + #[test] + fn for_no_iter_no_body() { + check( + r#" +fn foo() { + for +} +"#, + expect![[r#" +fn foo () {for _ in __ra_fixup {}} +"#]], + ) + } + + #[test] + fn for_no_iter() { + check( + r#" +fn foo() { + for {} +} +"#, + expect![[r#" +fn foo () {for _ in __ra_fixup {}} +"#]], + ) + } + + #[test] + fn for_no_body() { + check( + r#" +fn foo() { + for bar in qux +} +"#, + expect![[r#" +fn foo () {for bar in qux {}} +"#]], + ) + } #[test] fn match_no_expr_no_arms() { From ef2eabbfa84fb11deda705df724b28ef3431256c Mon Sep 17 00:00:00 2001 From: fprasx Date: Wed, 3 Aug 2022 16:27:43 -0400 Subject: [PATCH 0071/2442] Tidy formatted --- crates/hir-expand/src/fixup.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index ade28f27bf1c..cd02c802e50e 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -263,14 +263,14 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { }; let [pat, in_token, iter] = [ - (SyntaxKind::UNDERSCORE, "_"), - (SyntaxKind::IN_KW, "in"), + (SyntaxKind::UNDERSCORE, "_"), + (SyntaxKind::IN_KW, "in"), (SyntaxKind::IDENT, "__ra_fixup") ].map(|(kind, text)| SyntheticToken { kind, text: text.into(), range: end_range, id: EMPTY_ID}); if it.pat().is_none() && it.in_token().is_none() && it.iterable().is_none() { append.insert(for_token.into(), vec![pat, in_token, iter]); - } + } // Tricky: add logic to add in just a pattern or iterable if not all // the pieces are missing From 49dac4070cf731ad53bfe12e784975b38262d6ab Mon Sep 17 00:00:00 2001 From: Jean santos Date: Wed, 3 Aug 2022 17:37:11 -0300 Subject: [PATCH 0072/2442] on hover fallback error, adds ast::type as possible node --- crates/ide/src/hover.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 59c97f2dcf96..f74b981a28bb 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -235,7 +235,11 @@ fn hover_type_fallback( let node = token .parent_ancestors() .take_while(|it| !ast::Item::can_cast(it.kind())) - .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?; + .find(|n| { + ast::Expr::can_cast(n.kind()) + || ast::Pat::can_cast(n.kind()) + || ast::Type::can_cast(n.kind()) + })?; let expr_or_pat = match_ast! { match node { From df9d3db82f1d0dce5f74faf8ae0501a534953f84 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 4 Aug 2022 13:22:15 +0200 Subject: [PATCH 0073/2442] Trigger flycheck on all transitive dependencies as well --- crates/rust-analyzer/src/main_loop.rs | 32 ++++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 561c2d7aef77..5c93874ca2af 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -9,7 +9,8 @@ use std::{ use always_assert::always; use crossbeam_channel::{select, Receiver}; -use ide_db::base_db::{SourceDatabaseExt, VfsPath}; +use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath}; +use itertools::Itertools; use lsp_server::{Connection, Notification, Request}; use lsp_types::notification::Notification as _; use vfs::{ChangeKind, FileId}; @@ -727,9 +728,21 @@ impl GlobalState { let (vfs, _) = &*this.vfs.read(); if let Some(file_id) = vfs.file_id(&vfs_path) { let analysis = this.analysis_host.analysis(); - let crate_ids = analysis.crate_for(file_id)?; + // Crates containing or depending on the saved file + let crate_ids: Vec<_> = analysis + .crate_for(file_id)? + .into_iter() + .flat_map(|id| { + this.analysis_host + .raw_database() + .crate_graph() + .transitive_rev_deps(id) + }) + .sorted() + .unique() + .collect(); - let paths: Vec<_> = crate_ids + let crate_root_paths: Vec<_> = crate_ids .iter() .filter_map(|&crate_id| { analysis @@ -740,16 +753,17 @@ impl GlobalState { .transpose() }) .collect::>()?; - let paths: Vec<_> = paths.iter().map(Deref::deref).collect(); + let crate_root_paths: Vec<_> = + crate_root_paths.iter().map(Deref::deref).collect(); + // Find all workspaces that have at least one target containing the saved file let workspace_ids = this.workspaces.iter().enumerate().filter(|(_, ws)| match ws { project_model::ProjectWorkspace::Cargo { cargo, .. } => { cargo.packages().any(|pkg| { - cargo[pkg] - .targets - .iter() - .any(|&it| paths.contains(&cargo[it].root.as_path())) + cargo[pkg].targets.iter().any(|&it| { + crate_root_paths.contains(&cargo[it].root.as_path()) + }) }) } project_model::ProjectWorkspace::Json { project, .. } => project @@ -757,6 +771,8 @@ impl GlobalState { .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)), project_model::ProjectWorkspace::DetachedFiles { .. } => false, }); + + // Find and trigger corresponding flychecks for flycheck in &this.flycheck { for (id, _) in workspace_ids.clone() { if id == flycheck.id() { From 5698e51027a8f60e0fd7b8ae5f7c077b051197c6 Mon Sep 17 00:00:00 2001 From: Jean santos Date: Thu, 4 Aug 2022 09:28:34 -0300 Subject: [PATCH 0074/2442] tidy formatting --- crates/ide/src/hover.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index f74b981a28bb..784f85dbbefb 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -232,10 +232,8 @@ fn hover_type_fallback( token: &SyntaxToken, original_token: &SyntaxToken, ) -> Option> { - let node = token - .parent_ancestors() - .take_while(|it| !ast::Item::can_cast(it.kind())) - .find(|n| { + let node = + token.parent_ancestors().take_while(|it| !ast::Item::can_cast(it.kind())).find(|n| { ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()) || ast::Type::can_cast(n.kind()) From df7f755e3b08e58a30bdbb39685bea76be7762ba Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 4 Aug 2022 14:01:33 +0200 Subject: [PATCH 0075/2442] Don't flycheck while the workspace is being loaded --- crates/rust-analyzer/src/diagnostics.rs | 1 - crates/rust-analyzer/src/global_state.rs | 1 + crates/rust-analyzer/src/main_loop.rs | 5 ++++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs index 7917ced666a8..09150c77d7dd 100644 --- a/crates/rust-analyzer/src/diagnostics.rs +++ b/crates/rust-analyzer/src/diagnostics.rs @@ -72,7 +72,6 @@ impl DiagnosticCollection { let check_fixes = Arc::make_mut(&mut self.check_fixes); check_fixes.entry(flycheck_id).or_default().entry(file_id).or_default().extend(fix); diagnostics.push(diagnostic); - tracing::warn!(?flycheck_id, ?file_id, "add_check_diagnostic changes pushed"); self.changes.insert(file_id); } diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 2cd2044aeff0..55c4cfcf8608 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -192,6 +192,7 @@ impl GlobalState { if let Some(path) = vfs.file_path(file.file_id).as_path() { let path = path.to_path_buf(); if reload::should_refresh_for_change(&path, file.change_kind) { + tracing::warn!("fetch-fiel_change"); self.fetch_workspaces_queue .request_op(format!("vfs file change: {}", path.display())); } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 5c93874ca2af..4ed34df01ca9 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -447,7 +447,10 @@ impl GlobalState { let memdocs_added_or_removed = self.mem_docs.take_changes(); if self.is_quiescent() { - if !was_quiescent { + if !was_quiescent + && !self.fetch_workspaces_queue.op_requested() + && !self.fetch_build_data_queue.op_requested() + { for flycheck in &self.flycheck { flycheck.update(); } From d6d8a1c18f29ad6402f9594e3908cbb6d80aa31c Mon Sep 17 00:00:00 2001 From: fprasx Date: Thu, 4 Aug 2022 09:28:25 -0400 Subject: [PATCH 0076/2442] Shortened fixup for match, added cases for for Previously added a blank _ => {} for match statements --- crates/hir-expand/src/fixup.rs | 53 ++++++++++++---------------------- 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index cd02c802e50e..58d73f2d6c01 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -217,36 +217,6 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { range: end_range, id: EMPTY_ID, }, - SyntheticToken { - kind: SyntaxKind::UNDERSCORE, - text: "_".into(), - range: end_range, - id: EMPTY_ID - }, - SyntheticToken { - kind: SyntaxKind::EQ, - text: "=".into(), - range: end_range, - id: EMPTY_ID - }, - SyntheticToken { - kind: SyntaxKind::R_ANGLE, - text: ">".into(), - range: end_range, - id: EMPTY_ID - }, - SyntheticToken { - kind: SyntaxKind::L_CURLY, - text: "{".into(), - range: end_range, - id: EMPTY_ID, - }, - SyntheticToken { - kind: SyntaxKind::R_CURLY, - text: "}".into(), - range: end_range, - id: EMPTY_ID, - }, SyntheticToken { kind: SyntaxKind::R_CURLY, text: "}".into(), @@ -270,11 +240,12 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { if it.pat().is_none() && it.in_token().is_none() && it.iterable().is_none() { append.insert(for_token.into(), vec![pat, in_token, iter]); + } else if it.pat().is_none() { + append.insert(for_token.into(), vec![pat]); + } else if it.pat().is_none() && it.in_token().is_none() { + append.insert(for_token.into(), vec![pat, in_token]); } - // Tricky: add logic to add in just a pattern or iterable if not all - // the pieces are missing - if it.loop_body().is_none() { append.insert(node.clone().into(), vec![ SyntheticToken { @@ -398,6 +369,18 @@ fn foo () {for _ in __ra_fixup {}} ) } + fn for_no_iter_no_in() { + check( + r#" +fn foo() { + for _ {} +} +"#, + expect![[r#" +fn foo () {for _ in __ra_fixup {}} +"#]], + ) + } #[test] fn for_no_iter() { check( @@ -435,7 +418,7 @@ fn foo() { } "#, expect![[r#" -fn foo () {match __ra_fixup {_ => {}}} +fn foo () {match __ra_fixup {}} "#]], ) } @@ -467,7 +450,7 @@ fn foo() { } "#, expect![[r#" -fn foo () {match __ra_fixup {_ => {}}} +fn foo () {match __ra_fixup {}} "#]], ) } From ab44a811501c12c4e3c471387f02ad451034639f Mon Sep 17 00:00:00 2001 From: fprasx Date: Thu, 4 Aug 2022 10:43:09 -0400 Subject: [PATCH 0077/2442] Fixed up for loops, added fixme with problem https://github.com/rust-lang/rust-analyzer/pull/12937#discussion_r937633695 --- crates/hir-expand/src/fixup.rs | 36 +++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index 58d73f2d6c01..46257b6bc4dc 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -240,10 +240,9 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { if it.pat().is_none() && it.in_token().is_none() && it.iterable().is_none() { append.insert(for_token.into(), vec![pat, in_token, iter]); + // does something funky -- see test case for_no_pat } else if it.pat().is_none() { append.insert(for_token.into(), vec![pat]); - } else if it.pat().is_none() && it.in_token().is_none() { - append.insert(for_token.into(), vec![pat, in_token]); } if it.loop_body().is_none() { @@ -356,7 +355,7 @@ mod tests { } #[test] - fn for_no_iter_no_body() { + fn just_for_token() { check( r#" fn foo() { @@ -369,20 +368,8 @@ fn foo () {for _ in __ra_fixup {}} ) } - fn for_no_iter_no_in() { - check( - r#" -fn foo() { - for _ {} -} -"#, - expect![[r#" -fn foo () {for _ in __ra_fixup {}} -"#]], - ) - } #[test] - fn for_no_iter() { + fn for_no_iter_pattern() { check( r#" fn foo() { @@ -409,6 +396,23 @@ fn foo () {for bar in qux {}} ) } + // FIXME: https://github.com/rust-lang/rust-analyzer/pull/12937#discussion_r937633695 + #[test] + fn for_no_pat() { + check( + r#" +fn foo() { + for in qux { + + } +} +"#, + expect![[r#" +fn foo () {__ra_fixup} +"#]], + ) + } + #[test] fn match_no_expr_no_arms() { check( From 859d467276bf45e621858069192d7a68c42d2a32 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 5 Aug 2022 02:51:38 +0900 Subject: [PATCH 0078/2442] fix: make `concat!` work with char --- .../src/macro_expansion_tests/builtin_fn_macro.rs | 4 ++-- crates/hir-expand/src/builtin_fn_macro.rs | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 92dffa7f372e..32006c4b43e1 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -295,13 +295,13 @@ fn test_concat_expand() { #[rustc_builtin_macro] macro_rules! concat {} -fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false); } +fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false, '\n'); } "##, expect![[r##" #[rustc_builtin_macro] macro_rules! concat {} -fn main() { "foor0bar\nfalse"; } +fn main() { "foor0bar\nfalse\n"; } "##]], ); } diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index 76da7c9f1ee8..c21b35cdc091 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -357,6 +357,12 @@ fn unquote_str(lit: &tt::Literal) -> Option { token.value().map(|it| it.into_owned()) } +fn unquote_char(lit: &tt::Literal) -> Option { + let lit = ast::make::tokens::literal(&lit.to_string()); + let token = ast::Char::cast(lit)?; + token.value() +} + fn unquote_byte_string(lit: &tt::Literal) -> Option> { let lit = ast::make::tokens::literal(&lit.to_string()); let token = ast::ByteString::cast(lit)?; @@ -408,8 +414,12 @@ fn concat_expand( // concat works with string and char literals, so remove any quotes. // It also works with integer, float and boolean literals, so just use the rest // as-is. - let component = unquote_str(it).unwrap_or_else(|| it.text.to_string()); - text.push_str(&component); + if let Some(c) = unquote_char(it) { + text.push(c); + } else { + let component = unquote_str(it).unwrap_or_else(|| it.text.to_string()); + text.push_str(&component); + } } // handle boolean literals tt::TokenTree::Leaf(tt::Leaf::Ident(id)) From 30c4f9fa7d31cd60f1fcc5998af6c17f69178fae Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 08:42:13 +0200 Subject: [PATCH 0079/2442] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1f246ed79b69..5566b3d1f8d0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -19,7 +19,7 @@ Before submitting, please make sure that you're not running into one of these kn Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3. --> -**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command) +**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command, accessible in VSCode via Ctrl+Shift+P) **rustc version**: (eg. output of `rustc -V`) From d94a42d652f4c402891bd2b1004364d32bc41253 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 09:04:27 +0200 Subject: [PATCH 0080/2442] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5566b3d1f8d0..a038dce3248a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -19,7 +19,7 @@ Before submitting, please make sure that you're not running into one of these kn Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3. --> -**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command, accessible in VSCode via Ctrl+Shift+P) +**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command, accessible in VSCode via Ctrl/⌘+Shift+P) **rustc version**: (eg. output of `rustc -V`) From 6a1737242b75ae96bae03885c3d3e75b61a3f8ed Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 12:06:31 +0200 Subject: [PATCH 0081/2442] Don't switch workspace on vfs file changes from libraries When r-a starts up, it starts switching the workspace before all vfs events have been processed which causes us to switch workspace multiple times until all vfs changes have been processed. This scales with the size of the project and its dependencies. If workspace files from dependencies as well as the sysroot get loaded, we shouldn't switch the workspace as those have no impact on the project workspace. --- crates/rust-analyzer/src/global_state.rs | 34 +++++++++++-------- crates/rust-analyzer/src/reload.rs | 42 +++++++++++------------- crates/vfs-notify/src/lib.rs | 7 +++- 3 files changed, 47 insertions(+), 36 deletions(-) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 932a31e08f6f..b5f6aef2e1a8 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -8,7 +8,7 @@ use std::{sync::Arc, time::Instant}; use crossbeam_channel::{unbounded, Receiver, Sender}; use flycheck::FlycheckHandle; use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId}; -use ide_db::base_db::{CrateId, FileLoader, SourceDatabase}; +use ide_db::base_db::{CrateId, FileLoader, SourceDatabase, SourceDatabaseExt}; use lsp_types::{SemanticTokens, Url}; use parking_lot::{Mutex, RwLock}; use proc_macro_api::ProcMacroServer; @@ -176,7 +176,7 @@ impl GlobalState { pub(crate) fn process_changes(&mut self) -> bool { let _p = profile::span("GlobalState::process_changes"); - let mut fs_changes = Vec::new(); + let mut fs_refresh_changes = Vec::new(); // A file was added or deleted let mut has_structure_changes = false; @@ -192,11 +192,8 @@ impl GlobalState { if let Some(path) = vfs.file_path(file.file_id).as_path() { let path = path.to_path_buf(); if reload::should_refresh_for_change(&path, file.change_kind) { - tracing::warn!("fetch-fiel_change"); - self.fetch_workspaces_queue - .request_op(format!("vfs file change: {}", path.display())); + fs_refresh_changes.push((path, file.file_id)); } - fs_changes.push((path, file.change_kind)); if file.is_created_or_deleted() { has_structure_changes = true; } @@ -228,14 +225,25 @@ impl GlobalState { self.analysis_host.apply_change(change); - let raw_database = &self.analysis_host.raw_database(); - self.proc_macro_changed = - changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| { - let crates = raw_database.relevant_crates(file.file_id); - let crate_graph = raw_database.crate_graph(); + { + let raw_database = self.analysis_host.raw_database(); + let workspace_structure_change = + fs_refresh_changes.into_iter().find(|&(_, file_id)| { + !raw_database.source_root(raw_database.file_source_root(file_id)).is_library + }); + if let Some((path, _)) = workspace_structure_change { + self.fetch_workspaces_queue + .request_op(format!("workspace vfs file change: {}", path.display())); + } + self.proc_macro_changed = + changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| { + let crates = raw_database.relevant_crates(file.file_id); + let crate_graph = raw_database.crate_graph(); + + crates.iter().any(|&krate| crate_graph[krate].is_proc_macro) + }); + } - crates.iter().any(|&krate| crate_graph[krate].is_proc_macro) - }); true } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index c90291eb5e29..49ccad71a10e 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -196,10 +196,7 @@ impl GlobalState { } if let Err(error) = self.fetch_build_data_error() { - self.show_and_log_error( - "rust-analyzer failed to run build scripts".to_string(), - Some(error), - ); + self.show_and_log_error("failed to run build scripts".to_string(), Some(error)); } let workspaces = self @@ -308,6 +305,7 @@ impl GlobalState { if self.proc_macro_clients.is_empty() { if let Some((path, args)) = self.config.proc_macro_srv() { + tracing::info!("Spawning proc-macro servers"); self.proc_macro_clients = self .workspaces .iter() @@ -316,20 +314,20 @@ impl GlobalState { let mut path = path.clone(); if let ProjectWorkspace::Cargo { sysroot, .. } = ws { - tracing::info!("Found a cargo workspace..."); + tracing::debug!("Found a cargo workspace..."); if let Some(sysroot) = sysroot.as_ref() { - tracing::info!("Found a cargo workspace with a sysroot..."); + tracing::debug!("Found a cargo workspace with a sysroot..."); let server_path = sysroot.root().join("libexec").join(&standalone_server_name); if std::fs::metadata(&server_path).is_ok() { - tracing::info!( + tracing::debug!( "And the server exists at {}", server_path.display() ); path = server_path; args = vec![]; } else { - tracing::info!( + tracing::debug!( "And the server does not exist at {}", server_path.display() ); @@ -337,14 +335,10 @@ impl GlobalState { } } - tracing::info!( - "Using proc-macro server at {} with args {:?}", - path.display(), - args - ); + tracing::info!(?args, "Using proc-macro server at {}", path.display(),); ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| { let error = format!( - "Failed to run proc_macro_srv from path {}, error: {:?}", + "Failed to run proc-macro server from path {}, error: {:?}", path.display(), err ); @@ -684,22 +678,26 @@ pub(crate) fn load_proc_macro( pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool { const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"]; const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"]; - let file_name = path.file_name().unwrap_or_default(); - if file_name == "Cargo.toml" || file_name == "Cargo.lock" { + let file_name = match path.file_name().unwrap_or_default().to_str() { + Some(it) => it, + None => return false, + }; + + if let "Cargo.toml" | "Cargo.lock" = file_name { return true; } if change_kind == ChangeKind::Modify { return false; } + + // .cargo/config{.toml} if path.extension().unwrap_or_default() != "rs" { - if (file_name == "config.toml" || file_name == "config") - && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")) == Some(true) - { - return true; - } - return false; + let is_cargo_config = matches!(file_name, "config.toml" | "config") + && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")).unwrap_or(false); + return is_cargo_config; } + if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_ref().ends_with(it)) { return true; } diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs index 4d33a9afb963..d6d9c66159fe 100644 --- a/crates/vfs-notify/src/lib.rs +++ b/crates/vfs-notify/src/lib.rs @@ -40,12 +40,15 @@ impl loader::Handle for NotifyHandle { .expect("failed to spawn thread"); NotifyHandle { sender, _thread: thread } } + fn set_config(&mut self, config: loader::Config) { self.sender.send(Message::Config(config)).unwrap(); } + fn invalidate(&mut self, path: AbsPathBuf) { self.sender.send(Message::Invalidate(path)).unwrap(); } + fn load_sync(&mut self, path: &AbsPath) -> Option> { read(path) } @@ -70,6 +73,7 @@ impl NotifyActor { fn new(sender: loader::Sender) -> NotifyActor { NotifyActor { sender, watched_entries: Vec::new(), watcher: None } } + fn next_event(&self, receiver: &Receiver) -> Option { let watcher_receiver = self.watcher.as_ref().map(|(_, receiver)| receiver); select! { @@ -77,9 +81,10 @@ impl NotifyActor { recv(watcher_receiver.unwrap_or(&never())) -> it => Some(Event::NotifyEvent(it.unwrap())), } } + fn run(mut self, inbox: Receiver) { while let Some(event) = self.next_event(&inbox) { - tracing::debug!("vfs-notify event: {:?}", event); + tracing::debug!(?event, "vfs-notify event"); match event { Event::Message(msg) => match msg { Message::Config(config) => { From d6e78b04d00c9144b70b2477d21076b516d5fca7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 14:16:36 +0200 Subject: [PATCH 0082/2442] feat: Handle operators like their trait functions in the IDE --- crates/hir-expand/src/name.rs | 2 + crates/hir-ty/src/infer/expr.rs | 63 ++----------- crates/hir-ty/src/method_resolution.rs | 51 ++++++++++- crates/hir/src/semantics.rs | 40 ++++++++ crates/hir/src/source_analyzer.rs | 116 ++++++++++++++++++++++- crates/ide-db/src/defs.rs | 80 ++++++++++++++++ crates/ide/src/goto_definition.rs | 122 ++++++++++++++++++++++++- crates/ide/src/highlight_related.rs | 3 +- crates/ide/src/hover.rs | 12 ++- crates/ide/src/hover/tests.rs | 34 +++++++ crates/ide/src/moniker.rs | 2 +- crates/ide/src/static_index.rs | 2 +- 12 files changed, 459 insertions(+), 68 deletions(-) diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 85b0a7735fe9..47d191822d84 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -381,6 +381,7 @@ pub mod known { bitor, bitxor_assign, bitxor, + branch, deref_mut, deref, div_assign, @@ -396,6 +397,7 @@ pub mod known { not, owned_box, partial_ord, + poll, r#fn, rem_assign, rem, diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index d164e64a8be0..2a13106390d9 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -10,13 +10,13 @@ use chalk_ir::{ cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind, }; use hir_def::{ - expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp}, + expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Statement, UnaryOp}, generics::TypeOrConstParamData, path::{GenericArg, GenericArgs}, resolver::resolver_for_expr, - ConstParamId, FieldId, FunctionId, ItemContainerId, Lookup, + ConstParamId, FieldId, ItemContainerId, Lookup, }; -use hir_expand::name::{name, Name}; +use hir_expand::name::Name; use stdx::always; use syntax::ast::RangeOp; @@ -28,7 +28,7 @@ use crate::{ const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode, }, mapping::{from_chalk, ToChalk}, - method_resolution::{self, VisibleFromModule}, + method_resolution::{self, lang_names_for_bin_op, VisibleFromModule}, primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, utils::{generics, Generics}, @@ -947,7 +947,9 @@ impl<'a> InferenceContext<'a> { let lhs_ty = self.infer_expr(lhs, &lhs_expectation); let rhs_ty = self.table.new_type_var(); - let func = self.resolve_binop_method(op); + let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| { + self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name) + }); let func = match func { Some(func) => func, None => { @@ -1473,55 +1475,4 @@ impl<'a> InferenceContext<'a> { }, }) } - - fn resolve_binop_method(&self, op: BinaryOp) -> Option { - let (name, lang_item) = match op { - BinaryOp::LogicOp(_) => return None, - BinaryOp::ArithOp(aop) => match aop { - ArithOp::Add => (name!(add), name!(add)), - ArithOp::Mul => (name!(mul), name!(mul)), - ArithOp::Sub => (name!(sub), name!(sub)), - ArithOp::Div => (name!(div), name!(div)), - ArithOp::Rem => (name!(rem), name!(rem)), - ArithOp::Shl => (name!(shl), name!(shl)), - ArithOp::Shr => (name!(shr), name!(shr)), - ArithOp::BitXor => (name!(bitxor), name!(bitxor)), - ArithOp::BitOr => (name!(bitor), name!(bitor)), - ArithOp::BitAnd => (name!(bitand), name!(bitand)), - }, - BinaryOp::Assignment { op: Some(aop) } => match aop { - ArithOp::Add => (name!(add_assign), name!(add_assign)), - ArithOp::Mul => (name!(mul_assign), name!(mul_assign)), - ArithOp::Sub => (name!(sub_assign), name!(sub_assign)), - ArithOp::Div => (name!(div_assign), name!(div_assign)), - ArithOp::Rem => (name!(rem_assign), name!(rem_assign)), - ArithOp::Shl => (name!(shl_assign), name!(shl_assign)), - ArithOp::Shr => (name!(shr_assign), name!(shr_assign)), - ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)), - ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)), - ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)), - }, - BinaryOp::CmpOp(cop) => match cop { - CmpOp::Eq { negated: false } => (name!(eq), name!(eq)), - CmpOp::Eq { negated: true } => (name!(ne), name!(eq)), - CmpOp::Ord { ordering: Ordering::Less, strict: false } => { - (name!(le), name!(partial_ord)) - } - CmpOp::Ord { ordering: Ordering::Less, strict: true } => { - (name!(lt), name!(partial_ord)) - } - CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { - (name!(ge), name!(partial_ord)) - } - CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { - (name!(gt), name!(partial_ord)) - } - }, - BinaryOp::Assignment { op: None } => return None, - }; - - let trait_ = self.resolve_lang_item(lang_item)?.as_trait()?; - - self.db.trait_data(trait_).method_by_name(&name) - } } diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 15df7b3dd2b9..64622545f840 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -336,7 +336,7 @@ impl InherentImpls { } } -pub fn inherent_impl_crates_query( +pub(crate) fn inherent_impl_crates_query( db: &dyn HirDatabase, krate: CrateId, fp: TyFingerprint, @@ -419,6 +419,55 @@ pub fn def_crates( } } +pub fn lang_names_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, Name)> { + use hir_expand::name; + use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering}; + Some(match op { + BinaryOp::LogicOp(_) => return None, + BinaryOp::ArithOp(aop) => match aop { + ArithOp::Add => (name!(add), name!(add)), + ArithOp::Mul => (name!(mul), name!(mul)), + ArithOp::Sub => (name!(sub), name!(sub)), + ArithOp::Div => (name!(div), name!(div)), + ArithOp::Rem => (name!(rem), name!(rem)), + ArithOp::Shl => (name!(shl), name!(shl)), + ArithOp::Shr => (name!(shr), name!(shr)), + ArithOp::BitXor => (name!(bitxor), name!(bitxor)), + ArithOp::BitOr => (name!(bitor), name!(bitor)), + ArithOp::BitAnd => (name!(bitand), name!(bitand)), + }, + BinaryOp::Assignment { op: Some(aop) } => match aop { + ArithOp::Add => (name!(add_assign), name!(add_assign)), + ArithOp::Mul => (name!(mul_assign), name!(mul_assign)), + ArithOp::Sub => (name!(sub_assign), name!(sub_assign)), + ArithOp::Div => (name!(div_assign), name!(div_assign)), + ArithOp::Rem => (name!(rem_assign), name!(rem_assign)), + ArithOp::Shl => (name!(shl_assign), name!(shl_assign)), + ArithOp::Shr => (name!(shr_assign), name!(shr_assign)), + ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)), + ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)), + ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)), + }, + BinaryOp::CmpOp(cop) => match cop { + CmpOp::Eq { negated: false } => (name!(eq), name!(eq)), + CmpOp::Eq { negated: true } => (name!(ne), name!(eq)), + CmpOp::Ord { ordering: Ordering::Less, strict: false } => { + (name!(le), name!(partial_ord)) + } + CmpOp::Ord { ordering: Ordering::Less, strict: true } => { + (name!(lt), name!(partial_ord)) + } + CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { + (name!(ge), name!(partial_ord)) + } + CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { + (name!(gt), name!(partial_ord)) + } + }, + BinaryOp::Assignment { op: None } => return None, + }) +} + /// Look up the method with the given name. pub(crate) fn lookup_method( ty: &Canonical, diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index c84318b2fb87..36756866f997 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -357,6 +357,26 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_method_call(call).map(Function::from) } + pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { + self.imp.resolve_await_to_poll(await_expr).map(Function::from) + } + + pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { + self.imp.resolve_prefix_expr(prefix_expr).map(Function::from) + } + + pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { + self.imp.resolve_index_expr(index_expr).map(Function::from) + } + + pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { + self.imp.resolve_bin_expr(bin_expr).map(Function::from) + } + + pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { + self.imp.resolve_try_expr(try_expr).map(Function::from) + } + pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option { self.imp.resolve_method_call_as_callable(call) } @@ -1066,6 +1086,26 @@ impl<'db> SemanticsImpl<'db> { self.analyze(call.syntax())?.resolve_method_call(self.db, call) } + pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { + self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr) + } + + pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { + self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr) + } + + pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { + self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr) + } + + pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { + self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr) + } + + pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { + self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr) + } + fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option { self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call) } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 1eb51b20c356..45879ff9c6ad 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -25,15 +25,17 @@ use hir_def::{ Lookup, ModuleDefId, VariantId, }; use hir_expand::{ - builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, name::AsName, HirFileId, InFile, + builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, name, name::AsName, HirFileId, + InFile, }; use hir_ty::{ diagnostics::{ record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions, UnsafeExpr, }, - method_resolution, Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, - TyExt, TyKind, TyLoweringContext, + method_resolution::{self, lang_names_for_bin_op}, + Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt, TyKind, + TyLoweringContext, }; use itertools::Itertools; use smallvec::SmallVec; @@ -255,8 +257,103 @@ impl SourceAnalyzer { ) -> Option { let expr_id = self.expr_id(db, &call.clone().into())?; let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?; - let f_in_impl = self.resolve_impl_method(db, f_in_trait, &substs); - f_in_impl.or(Some(f_in_trait)) + + Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs)) + } + + pub fn resolve_await_to_poll( + &self, + db: &dyn HirDatabase, + await_expr: &ast::AwaitExpr, + ) -> Option { + let expr_id = self.expr_id(db, &await_expr.expr()?.into())?; + let ty = self.infer.as_ref()?.type_of_expr.get(expr_id)?; + + let op_fn = db + .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())? + .as_function()?; + let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build(); + + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + } + + pub fn resolve_prefix_expr( + &self, + db: &dyn HirDatabase, + prefix_expr: &ast::PrefixExpr, + ) -> Option { + let lang_item_name = match prefix_expr.op_kind()? { + ast::UnaryOp::Deref => name![deref], + ast::UnaryOp::Not => name![not], + ast::UnaryOp::Neg => name![neg], + }; + let expr_id = self.expr_id(db, &prefix_expr.expr()?.into())?; + let ty = self.infer.as_ref()?.type_of_expr.get(expr_id)?; + + let trait_ = + db.lang_item(self.resolver.krate(), lang_item_name.to_smol_str())?.as_trait()?; + let op_fn = db.trait_data(trait_).method_by_name(&lang_item_name)?; + let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build(); + + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + } + + pub fn resolve_index_expr( + &self, + db: &dyn HirDatabase, + index_expr: &ast::IndexExpr, + ) -> Option { + let base_expr_id = self.expr_id(db, &index_expr.base()?.into())?; + let index_expr_id = self.expr_id(db, &index_expr.index()?.into())?; + let base_ty = self.infer.as_ref()?.type_of_expr.get(base_expr_id)?; + let index_ty = self.infer.as_ref()?.type_of_expr.get(index_expr_id)?; + + let lang_item_name = name![index]; + + let trait_ = + db.lang_item(self.resolver.krate(), lang_item_name.to_smol_str())?.as_trait()?; + let op_fn = db.trait_data(trait_).method_by_name(&lang_item_name)?; + let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn) + .push(base_ty.clone()) + .push(index_ty.clone()) + .build(); + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + } + + pub fn resolve_bin_expr( + &self, + db: &dyn HirDatabase, + binop_expr: &ast::BinExpr, + ) -> Option { + let op = binop_expr.op_kind()?; + let lhs_expr_id = self.expr_id(db, &binop_expr.lhs()?.into())?; + let rhs_expr_id = self.expr_id(db, &binop_expr.rhs()?.into())?; + let lhs = self.infer.as_ref()?.type_of_expr.get(lhs_expr_id)?; + let rhs = self.infer.as_ref()?.type_of_expr.get(rhs_expr_id)?; + + let op_fn = lang_names_for_bin_op(op).and_then(|(name, lang_item)| { + db.trait_data(db.lang_item(self.resolver.krate(), lang_item.to_smol_str())?.as_trait()?) + .method_by_name(&name) + })?; + let substs = + hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build(); + + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + } + + pub fn resolve_try_expr( + &self, + db: &dyn HirDatabase, + try_expr: &ast::TryExpr, + ) -> Option { + let expr_id = self.expr_id(db, &try_expr.expr()?.into())?; + let ty = self.infer.as_ref()?.type_of_expr.get(expr_id)?; + + let op_fn = + db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?; + let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build(); + + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) } pub(crate) fn resolve_field( @@ -666,6 +763,15 @@ impl SourceAnalyzer { let fun_data = db.function_data(func); method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name) } + + fn resolve_impl_method_or_trait_def( + &self, + db: &dyn HirDatabase, + func: FunctionId, + substs: &Substitution, + ) -> FunctionId { + self.resolve_impl_method(db, func, substs).unwrap_or(func) + } } fn scope_for( diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index aeaca00ec65c..6c13c039723b 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -127,10 +127,12 @@ impl Definition { } } +// FIXME: IdentClass as a name no longer fits #[derive(Debug)] pub enum IdentClass { NameClass(NameClass), NameRefClass(NameRefClass), + Operator(OperatorClass), } impl IdentClass { @@ -147,6 +149,11 @@ impl IdentClass { .map(IdentClass::NameClass) .or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass)) }, + ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator), + ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator), + ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator), + ast::PrefixExpr(prefix_expr) => OperatorClass::classify_prefix(sema,&prefix_expr).map(IdentClass::Operator), + ast::TryExpr(try_expr) => OperatorClass::classify_try(sema,&try_expr).map(IdentClass::Operator), _ => None, } } @@ -184,6 +191,33 @@ impl IdentClass { res.push(Definition::Local(local_ref)); res.push(Definition::Field(field_ref)); } + IdentClass::Operator( + OperatorClass::Await(func) + | OperatorClass::Prefix(func) + | OperatorClass::Bin(func) + | OperatorClass::Index(func) + | OperatorClass::Try(func), + ) => res.push(Definition::Function(func)), + } + res + } + + pub fn definitions_no_ops(self) -> ArrayVec { + let mut res = ArrayVec::new(); + match self { + IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => { + res.push(it) + } + IdentClass::NameClass(NameClass::PatFieldShorthand { local_def, field_ref }) => { + res.push(Definition::Local(local_def)); + res.push(Definition::Field(field_ref)); + } + IdentClass::NameRefClass(NameRefClass::Definition(it)) => res.push(it), + IdentClass::NameRefClass(NameRefClass::FieldShorthand { local_ref, field_ref }) => { + res.push(Definition::Local(local_ref)); + res.push(Definition::Field(field_ref)); + } + IdentClass::Operator(_) => (), } res } @@ -332,6 +366,52 @@ impl NameClass { } } +#[derive(Debug)] +pub enum OperatorClass { + Await(Function), + Prefix(Function), + Index(Function), + Try(Function), + Bin(Function), +} + +impl OperatorClass { + pub fn classify_await( + sema: &Semantics<'_, RootDatabase>, + await_expr: &ast::AwaitExpr, + ) -> Option { + sema.resolve_await_to_poll(await_expr).map(OperatorClass::Await) + } + + pub fn classify_prefix( + sema: &Semantics<'_, RootDatabase>, + prefix_expr: &ast::PrefixExpr, + ) -> Option { + sema.resolve_prefix_expr(prefix_expr).map(OperatorClass::Prefix) + } + + pub fn classify_try( + sema: &Semantics<'_, RootDatabase>, + try_expr: &ast::TryExpr, + ) -> Option { + sema.resolve_try_expr(try_expr).map(OperatorClass::Try) + } + + pub fn classify_index( + sema: &Semantics<'_, RootDatabase>, + index_expr: &ast::IndexExpr, + ) -> Option { + sema.resolve_index_expr(index_expr).map(OperatorClass::Index) + } + + pub fn classify_bin( + sema: &Semantics<'_, RootDatabase>, + bin_expr: &ast::BinExpr, + ) -> Option { + sema.resolve_bin_expr(bin_expr).map(OperatorClass::Bin) + } +} + /// This is similar to [`NameClass`], but works for [`ast::NameRef`] rather than /// for [`ast::Name`]. Similarly, what looks like a reference in syntax is a /// reference most of the time, but there are a couple of annoying exceptions. diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index d9c97751c95c..b2123b9a8793 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -39,7 +39,11 @@ pub(crate) fn goto_definition( | T![super] | T![crate] | T![Self] - | COMMENT => 2, + | COMMENT => 4, + // index and prefix ops + T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3, + kind if kind.is_keyword() => 2, + T!['('] | T![')'] => 2, kind if kind.is_trivia() => 0, _ => 1, })?; @@ -1628,6 +1632,122 @@ macro_rules! foo { } foo!(bar$0); +"#, + ); + } + + #[test] + fn goto_await_poll() { + check( + r#" +//- minicore: future + +struct MyFut; + +impl core::future::Future for MyFut { + type Output = (); + + fn poll( + //^^^^ + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_> + ) -> std::task::Poll + { + () + } +} + +fn f() { + MyFut.await$0; +} +"#, + ); + } + + #[test] + fn goto_try_op() { + check( + r#" +//- minicore: try + +struct Struct; + +impl core::ops::Try for Struct { + fn branch( + //^^^^^^ + self + ) {} +} + +fn f() { + Struct?$0; +} +"#, + ); + } + + #[test] + fn goto_index_op() { + check( + r#" +//- minicore: index + +struct Struct; + +impl core::ops::Index for Struct { + fn index( + //^^^^^ + self + ) {} +} + +fn f() { + Struct[0]$0; +} +"#, + ); + } + + #[test] + fn goto_prefix_op() { + check( + r#" +//- minicore: deref + +struct Struct; + +impl core::ops::Deref for Struct { + fn deref( + //^^^^^ + self + ) {} +} + +fn f() { + $0*Struct; +} +"#, + ); + } + + #[test] + fn goto_bin_op() { + check( + r#" +//- minicore: add + +struct Struct; + +impl core::ops::Add for Struct { + fn add( + //^^^ + self + ) {} +} + +fn f() { + Struct +$0 Struct; +} "#, ); } diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs index f2d7029eab19..f190da326e45 100644 --- a/crates/ide/src/highlight_related.rs +++ b/crates/ide/src/highlight_related.rs @@ -333,7 +333,8 @@ fn cover_range(r0: Option, r1: Option) -> Option, token: SyntaxToken) -> FxHashSet { sema.descend_into_macros(token) .into_iter() - .filter_map(|token| IdentClass::classify_token(sema, &token).map(IdentClass::definitions)) + .filter_map(|token| IdentClass::classify_token(sema, &token)) + .map(IdentClass::definitions_no_ops) .flatten() .collect() } diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 784f85dbbefb..3ada181f1ed2 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -9,7 +9,7 @@ use either::Either; use hir::{HasSource, Semantics}; use ide_db::{ base_db::FileRange, - defs::{Definition, IdentClass}, + defs::{Definition, IdentClass, OperatorClass}, famous_defs::FamousDefs, helpers::pick_best_token, FxIndexSet, RootDatabase, @@ -101,7 +101,10 @@ pub(crate) fn hover( let offset = range.start(); let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { - IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 3, + IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 4, + // index and prefix ops + T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3, + kind if kind.is_keyword() => 2, T!['('] | T![')'] => 2, kind if kind.is_trivia() => 0, _ => 1, @@ -136,6 +139,11 @@ pub(crate) fn hover( .filter_map(|token| { let node = token.parent()?; let class = IdentClass::classify_token(sema, token)?; + if let IdentClass::Operator(OperatorClass::Await(_)) = class { + // It's better for us to fall back to the keyword hover here, + // rendering poll is very confusing + return None; + } Some(class.definitions().into_iter().zip(iter::once(node).cycle())) }) .flatten() diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 867d1f54d4fe..c6274264b8f1 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -5051,3 +5051,37 @@ fn f() { ```"#]], ); } + +#[test] +fn hover_deref() { + check( + r#" +//- minicore: deref + +struct Struct(usize); + +impl core::ops::Deref for Struct { + type Target = usize; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn f() { + $0*Struct(0); +} +"#, + expect![[r#" + *** + + ```rust + test::Struct + ``` + + ```rust + fn deref(&self) -> &Self::Target + ``` + "#]], + ); +} diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 6bab9fa1ebbb..4f758967b461 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -90,7 +90,7 @@ pub(crate) fn moniker( .descend_into_macros(original_token.clone()) .into_iter() .filter_map(|token| { - IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| { + IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops).map(|it| { it.into_iter().flat_map(|def| def_to_moniker(sema.db, def, current_crate)) }) }) diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index d74b640415c7..cc79ee55b7da 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -204,7 +204,7 @@ impl StaticIndex<'_> { fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { for token in sema.descend_into_macros(token) { - let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions); + let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); if let Some(&[x]) = def.as_deref() { return Some(x); } else { From 352d3c6e50f4c64cded06b51ef81d4ac83b4e34c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 14:28:36 +0200 Subject: [PATCH 0083/2442] Fix visibilities --- crates/hir/src/semantics.rs | 10 +++++----- crates/hir/src/source_analyzer.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 36756866f997..416b6f58061d 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1086,23 +1086,23 @@ impl<'db> SemanticsImpl<'db> { self.analyze(call.syntax())?.resolve_method_call(self.db, call) } - pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { + fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr) } - pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { + fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr) } - pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { + fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr) } - pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { + fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr) } - pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { + fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr) } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 45879ff9c6ad..5e0bf7c5fb9f 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -261,7 +261,7 @@ impl SourceAnalyzer { Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs)) } - pub fn resolve_await_to_poll( + pub(crate) fn resolve_await_to_poll( &self, db: &dyn HirDatabase, await_expr: &ast::AwaitExpr, @@ -277,7 +277,7 @@ impl SourceAnalyzer { Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) } - pub fn resolve_prefix_expr( + pub(crate) fn resolve_prefix_expr( &self, db: &dyn HirDatabase, prefix_expr: &ast::PrefixExpr, @@ -298,7 +298,7 @@ impl SourceAnalyzer { Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) } - pub fn resolve_index_expr( + pub(crate) fn resolve_index_expr( &self, db: &dyn HirDatabase, index_expr: &ast::IndexExpr, @@ -320,7 +320,7 @@ impl SourceAnalyzer { Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) } - pub fn resolve_bin_expr( + pub(crate) fn resolve_bin_expr( &self, db: &dyn HirDatabase, binop_expr: &ast::BinExpr, @@ -341,7 +341,7 @@ impl SourceAnalyzer { Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) } - pub fn resolve_try_expr( + pub(crate) fn resolve_try_expr( &self, db: &dyn HirDatabase, try_expr: &ast::TryExpr, From 8aa50e08af4bd2ecc6b2132d2db48edabe51f352 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 14:54:14 +0200 Subject: [PATCH 0084/2442] Simplify --- crates/hir/src/source_analyzer.rs | 58 +++++++++++++++++-------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 5e0bf7c5fb9f..f5e2e4430709 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -25,8 +25,11 @@ use hir_def::{ Lookup, ModuleDefId, VariantId, }; use hir_expand::{ - builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, name, name::AsName, HirFileId, - InFile, + builtin_fn_macro::BuiltinFnLikeExpander, + hygiene::Hygiene, + name, + name::{AsName, Name}, + HirFileId, InFile, }; use hir_ty::{ diagnostics::{ @@ -34,7 +37,7 @@ use hir_ty::{ UnsafeExpr, }, method_resolution::{self, lang_names_for_bin_op}, - Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt, TyKind, + Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext, }; use itertools::Itertools; @@ -266,8 +269,7 @@ impl SourceAnalyzer { db: &dyn HirDatabase, await_expr: &ast::AwaitExpr, ) -> Option { - let expr_id = self.expr_id(db, &await_expr.expr()?.into())?; - let ty = self.infer.as_ref()?.type_of_expr.get(expr_id)?; + let ty = self.ty_of_expr(db, &await_expr.expr()?.into())?; let op_fn = db .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())? @@ -287,12 +289,9 @@ impl SourceAnalyzer { ast::UnaryOp::Not => name![not], ast::UnaryOp::Neg => name![neg], }; - let expr_id = self.expr_id(db, &prefix_expr.expr()?.into())?; - let ty = self.infer.as_ref()?.type_of_expr.get(expr_id)?; + let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?; - let trait_ = - db.lang_item(self.resolver.krate(), lang_item_name.to_smol_str())?.as_trait()?; - let op_fn = db.trait_data(trait_).method_by_name(&lang_item_name)?; + let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?; let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build(); Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) @@ -303,16 +302,12 @@ impl SourceAnalyzer { db: &dyn HirDatabase, index_expr: &ast::IndexExpr, ) -> Option { - let base_expr_id = self.expr_id(db, &index_expr.base()?.into())?; - let index_expr_id = self.expr_id(db, &index_expr.index()?.into())?; - let base_ty = self.infer.as_ref()?.type_of_expr.get(base_expr_id)?; - let index_ty = self.infer.as_ref()?.type_of_expr.get(index_expr_id)?; + let base_ty = self.ty_of_expr(db, &index_expr.base()?.into())?; + let index_ty = self.ty_of_expr(db, &index_expr.index()?.into())?; let lang_item_name = name![index]; - let trait_ = - db.lang_item(self.resolver.krate(), lang_item_name.to_smol_str())?.as_trait()?; - let op_fn = db.trait_data(trait_).method_by_name(&lang_item_name)?; + let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?; let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn) .push(base_ty.clone()) .push(index_ty.clone()) @@ -326,15 +321,11 @@ impl SourceAnalyzer { binop_expr: &ast::BinExpr, ) -> Option { let op = binop_expr.op_kind()?; - let lhs_expr_id = self.expr_id(db, &binop_expr.lhs()?.into())?; - let rhs_expr_id = self.expr_id(db, &binop_expr.rhs()?.into())?; - let lhs = self.infer.as_ref()?.type_of_expr.get(lhs_expr_id)?; - let rhs = self.infer.as_ref()?.type_of_expr.get(rhs_expr_id)?; + let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?; + let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?; - let op_fn = lang_names_for_bin_op(op).and_then(|(name, lang_item)| { - db.trait_data(db.lang_item(self.resolver.krate(), lang_item.to_smol_str())?.as_trait()?) - .method_by_name(&name) - })?; + let op_fn = lang_names_for_bin_op(op) + .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?; let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build(); @@ -346,8 +337,7 @@ impl SourceAnalyzer { db: &dyn HirDatabase, try_expr: &ast::TryExpr, ) -> Option { - let expr_id = self.expr_id(db, &try_expr.expr()?.into())?; - let ty = self.infer.as_ref()?.type_of_expr.get(expr_id)?; + let ty = self.ty_of_expr(db, &try_expr.expr()?.into())?; let op_fn = db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?; @@ -772,6 +762,20 @@ impl SourceAnalyzer { ) -> FunctionId { self.resolve_impl_method(db, func, substs).unwrap_or(func) } + + fn lang_trait_fn( + &self, + db: &dyn HirDatabase, + lang_trait: &Name, + method_name: &Name, + ) -> Option { + db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?) + .method_by_name(method_name) + } + + fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> { + self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, &expr)?) + } } fn scope_for( From 6bf674c8e4ddcccb4fc7eaa8754bdc431c6cad33 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 14:59:26 +0200 Subject: [PATCH 0085/2442] fix: Fix incorrect token pick rankings --- crates/ide/src/call_hierarchy.rs | 4 ++-- crates/ide/src/goto_implementation.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs index a18a6bea9798..5a8cda8fb3dd 100644 --- a/crates/ide/src/call_hierarchy.rs +++ b/crates/ide/src/call_hierarchy.rs @@ -7,7 +7,7 @@ use ide_db::{ search::FileReference, FxIndexMap, RootDatabase, }; -use syntax::{ast, AstNode, SyntaxKind::NAME, TextRange}; +use syntax::{ast, AstNode, SyntaxKind::IDENT, TextRange}; use crate::{goto_definition, FilePosition, NavigationTarget, RangeInfo, TryToNav}; @@ -79,7 +79,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio let file = sema.parse(file_id); let file = file.syntax(); let token = pick_best_token(file.token_at_offset(position.offset), |kind| match kind { - NAME => 1, + IDENT => 1, _ => 0, })?; let mut calls = CallLocations::default(); diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 04b51c839407..b3f711b6b88c 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs @@ -30,7 +30,7 @@ pub(crate) fn goto_implementation( let original_token = pick_best_token(syntax.token_at_offset(position.offset), |kind| match kind { - IDENT | T![self] => 1, + IDENT | T![self] | INT_NUMBER => 1, _ => 0, })?; let range = original_token.text_range(); From 4d5873e92f50f3f08f98f04ade4768f9d9ab380f Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 5 Aug 2022 22:01:09 +0900 Subject: [PATCH 0086/2442] minor: align with rustc on escaping characters in macro expansion --- crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs | 4 ++-- crates/hir-expand/src/quote.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 32006c4b43e1..4f626105a53d 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -295,13 +295,13 @@ fn test_concat_expand() { #[rustc_builtin_macro] macro_rules! concat {} -fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false, '\n'); } +fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false, '"', '\0'); } "##, expect![[r##" #[rustc_builtin_macro] macro_rules! concat {} -fn main() { "foor0bar\nfalse\n"; } +fn main() { "foor0bar\nfalse\"\u{0}"; } "##]], ); } diff --git a/crates/hir-expand/src/quote.rs b/crates/hir-expand/src/quote.rs index 82f410ecda91..e839e97bf02d 100644 --- a/crates/hir-expand/src/quote.rs +++ b/crates/hir-expand/src/quote.rs @@ -196,8 +196,8 @@ impl_to_to_tokentrees! { tt::Literal => self { self }; tt::Ident => self { self }; tt::Punct => self { self }; - &str => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}}; - String => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}} + &str => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}}; + String => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}} } #[cfg(test)] From fd00bd4d3b96109dcd1b9fb2ebfeb3b747776ad1 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 5 Aug 2022 15:28:53 +0200 Subject: [PATCH 0087/2442] Document CLI flag stability --- crates/rust-analyzer/src/cli/flags.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs index 19907ebddb6a..080e2fb44388 100644 --- a/crates/rust-analyzer/src/cli/flags.rs +++ b/crates/rust-analyzer/src/cli/flags.rs @@ -10,6 +10,10 @@ xflags::xflags! { src "./src/cli/flags.rs" /// LSP server for the Rust programming language. + /// + /// Subcommands and their flags do not provide any stability guarantees and may be removed or + /// changed without notice. Top-level flags that are not are marked as [Unstable] provide + /// backwards-compatibility and may be relied on. cmd rust-analyzer { /// Verbosity level, can be repeated multiple times. repeated -v, --verbose @@ -21,7 +25,7 @@ xflags::xflags! { /// Flush log records to the file immediately. optional --no-log-buffering - /// Wait until a debugger is attached to (requires debug build). + /// [Unstable] Wait until a debugger is attached to (requires debug build). optional --wait-dbg default cmd lsp-server { From e8a9bc09a3f0ddf4d5f5706a6b101eceb0d90960 Mon Sep 17 00:00:00 2001 From: Adrian Stanciu Date: Sat, 6 Aug 2022 17:12:13 +0300 Subject: [PATCH 0088/2442] run stable fmt through rustup --- crates/rust-analyzer/tests/slow-tests/tidy.rs | 7 +++---- crates/sourcegen/src/lib.rs | 14 ++++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs index 18f95925d9a4..58099a58de05 100644 --- a/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs @@ -13,9 +13,8 @@ use xshell::cmd; fn check_code_formatting() { let sh = &Shell::new().unwrap(); sh.change_dir(sourcegen::project_root()); - sh.set_var("RUSTUP_TOOLCHAIN", "stable"); - let out = cmd!(sh, "rustfmt --version").read().unwrap(); + let out = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap(); if !out.contains("stable") { panic!( "Failed to run rustfmt from toolchain 'stable'. \ @@ -23,9 +22,9 @@ fn check_code_formatting() { ) } - let res = cmd!(sh, "cargo fmt -- --check").run(); + let res = cmd!(sh, "rustup run stable cargo fmt -- --check").run(); if res.is_err() { - let _ = cmd!(sh, "cargo fmt").run(); + let _ = cmd!(sh, "rustup run stable cargo fmt").run(); } res.unwrap() } diff --git a/crates/sourcegen/src/lib.rs b/crates/sourcegen/src/lib.rs index ce0224ec744d..4e0ee63f32f2 100644 --- a/crates/sourcegen/src/lib.rs +++ b/crates/sourcegen/src/lib.rs @@ -136,7 +136,7 @@ impl fmt::Display for Location { } fn ensure_rustfmt(sh: &Shell) { - let version = cmd!(sh, "rustfmt --version").read().unwrap_or_default(); + let version = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap_or_default(); if !version.contains("stable") { panic!( "Failed to run rustfmt from toolchain 'stable'. \ @@ -147,13 +147,15 @@ fn ensure_rustfmt(sh: &Shell) { pub fn reformat(text: String) -> String { let sh = Shell::new().unwrap(); - sh.set_var("RUSTUP_TOOLCHAIN", "stable"); ensure_rustfmt(&sh); let rustfmt_toml = project_root().join("rustfmt.toml"); - let mut stdout = cmd!(sh, "rustfmt --config-path {rustfmt_toml} --config fn_single_line=true") - .stdin(text) - .read() - .unwrap(); + let mut stdout = cmd!( + sh, + "rustup run stable rustfmt --config-path {rustfmt_toml} --config fn_single_line=true" + ) + .stdin(text) + .read() + .unwrap(); if !stdout.ends_with('\n') { stdout.push('\n'); } From 851f6db7f704587e4b5f0fb429a843d5f26f73c7 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sat, 6 Aug 2022 19:21:51 +0430 Subject: [PATCH 0089/2442] Import serde derives on converting json to struct --- crates/ide-assists/src/assist_context.rs | 157 +------------- .../convert_tuple_struct_to_named_struct.rs | 10 +- .../src/handlers/destructure_tuple_binding.rs | 10 +- .../extract_struct_from_enum_variant.rs | 4 +- .../src/handlers/generate_deref.rs | 4 +- .../src/handlers/introduce_named_lifetime.rs | 4 +- .../src/handlers/remove_unused_param.rs | 5 +- .../replace_derive_with_manual_impl.rs | 4 +- crates/ide-assists/src/utils.rs | 4 +- crates/ide-db/src/source_change.rs | 136 ++++++++++++- .../src/handlers/inactive_code.rs | 2 +- .../src/handlers/json_is_not_rust.rs | 191 ++++++++++++++---- .../src/handlers/macro_error.rs | 2 +- crates/ide-diagnostics/src/lib.rs | 33 ++- crates/ide-diagnostics/src/tests.rs | 12 +- crates/rust-analyzer/src/cli/diagnostics.rs | 2 +- crates/rust-analyzer/src/config.rs | 1 + 17 files changed, 357 insertions(+), 224 deletions(-) diff --git a/crates/ide-assists/src/assist_context.rs b/crates/ide-assists/src/assist_context.rs index f9b426614257..8c7670e0cb71 100644 --- a/crates/ide-assists/src/assist_context.rs +++ b/crates/ide-assists/src/assist_context.rs @@ -1,28 +1,20 @@ //! See [`AssistContext`]. -use std::mem; - use hir::Semantics; -use ide_db::{ - base_db::{AnchoredPathBuf, FileId, FileRange}, - SnippetCap, -}; -use ide_db::{ - label::Label, - source_change::{FileSystemEdit, SourceChange}, - RootDatabase, -}; +use ide_db::base_db::{FileId, FileRange}; +use ide_db::{label::Label, RootDatabase}; use syntax::{ algo::{self, find_node_at_offset, find_node_at_range}, - AstNode, AstToken, Direction, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr, - SyntaxToken, TextRange, TextSize, TokenAtOffset, + AstNode, AstToken, Direction, SourceFile, SyntaxElement, SyntaxKind, SyntaxToken, TextRange, + TextSize, TokenAtOffset, }; -use text_edit::{TextEdit, TextEditBuilder}; use crate::{ assist_config::AssistConfig, Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel, }; +pub(crate) use ide_db::source_change::{SourceChangeBuilder, TreeMutator}; + /// `AssistContext` allows to apply an assist or check if it could be applied. /// /// Assists use a somewhat over-engineered approach, given the current needs. @@ -163,7 +155,7 @@ impl Assists { id: AssistId, label: impl Into, target: TextRange, - f: impl FnOnce(&mut AssistBuilder), + f: impl FnOnce(&mut SourceChangeBuilder), ) -> Option<()> { let mut f = Some(f); self.add_impl(None, id, label.into(), target, &mut |it| f.take().unwrap()(it)) @@ -175,7 +167,7 @@ impl Assists { id: AssistId, label: impl Into, target: TextRange, - f: impl FnOnce(&mut AssistBuilder), + f: impl FnOnce(&mut SourceChangeBuilder), ) -> Option<()> { let mut f = Some(f); self.add_impl(Some(group), id, label.into(), target, &mut |it| f.take().unwrap()(it)) @@ -187,7 +179,7 @@ impl Assists { id: AssistId, label: String, target: TextRange, - f: &mut dyn FnMut(&mut AssistBuilder), + f: &mut dyn FnMut(&mut SourceChangeBuilder), ) -> Option<()> { if !self.is_allowed(&id) { return None; @@ -195,7 +187,7 @@ impl Assists { let mut trigger_signature_help = false; let source_change = if self.resolve.should_resolve(&id) { - let mut builder = AssistBuilder::new(self.file); + let mut builder = SourceChangeBuilder::new(self.file); f(&mut builder); trigger_signature_help = builder.trigger_signature_help; Some(builder.finish()) @@ -216,132 +208,3 @@ impl Assists { } } } - -pub(crate) struct AssistBuilder { - edit: TextEditBuilder, - file_id: FileId, - source_change: SourceChange, - trigger_signature_help: bool, - - /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin. - mutated_tree: Option, -} - -pub(crate) struct TreeMutator { - immutable: SyntaxNode, - mutable_clone: SyntaxNode, -} - -impl TreeMutator { - pub(crate) fn new(immutable: &SyntaxNode) -> TreeMutator { - let immutable = immutable.ancestors().last().unwrap(); - let mutable_clone = immutable.clone_for_update(); - TreeMutator { immutable, mutable_clone } - } - - pub(crate) fn make_mut(&self, node: &N) -> N { - N::cast(self.make_syntax_mut(node.syntax())).unwrap() - } - - pub(crate) fn make_syntax_mut(&self, node: &SyntaxNode) -> SyntaxNode { - let ptr = SyntaxNodePtr::new(node); - ptr.to_node(&self.mutable_clone) - } -} - -impl AssistBuilder { - pub(crate) fn new(file_id: FileId) -> AssistBuilder { - AssistBuilder { - edit: TextEdit::builder(), - file_id, - source_change: SourceChange::default(), - trigger_signature_help: false, - mutated_tree: None, - } - } - - pub(crate) fn edit_file(&mut self, file_id: FileId) { - self.commit(); - self.file_id = file_id; - } - - fn commit(&mut self) { - if let Some(tm) = self.mutated_tree.take() { - algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit) - } - - let edit = mem::take(&mut self.edit).finish(); - if !edit.is_empty() { - self.source_change.insert_source_edit(self.file_id, edit); - } - } - - pub(crate) fn make_mut(&mut self, node: N) -> N { - self.mutated_tree.get_or_insert_with(|| TreeMutator::new(node.syntax())).make_mut(&node) - } - /// Returns a copy of the `node`, suitable for mutation. - /// - /// Syntax trees in rust-analyzer are typically immutable, and mutating - /// operations panic at runtime. However, it is possible to make a copy of - /// the tree and mutate the copy freely. Mutation is based on interior - /// mutability, and different nodes in the same tree see the same mutations. - /// - /// The typical pattern for an assist is to find specific nodes in the read - /// phase, and then get their mutable couterparts using `make_mut` in the - /// mutable state. - pub(crate) fn make_syntax_mut(&mut self, node: SyntaxNode) -> SyntaxNode { - self.mutated_tree.get_or_insert_with(|| TreeMutator::new(&node)).make_syntax_mut(&node) - } - - /// Remove specified `range` of text. - pub(crate) fn delete(&mut self, range: TextRange) { - self.edit.delete(range) - } - /// Append specified `text` at the given `offset` - pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into) { - self.edit.insert(offset, text.into()) - } - /// Append specified `snippet` at the given `offset` - pub(crate) fn insert_snippet( - &mut self, - _cap: SnippetCap, - offset: TextSize, - snippet: impl Into, - ) { - self.source_change.is_snippet = true; - self.insert(offset, snippet); - } - /// Replaces specified `range` of text with a given string. - pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into) { - self.edit.replace(range, replace_with.into()) - } - /// Replaces specified `range` of text with a given `snippet`. - pub(crate) fn replace_snippet( - &mut self, - _cap: SnippetCap, - range: TextRange, - snippet: impl Into, - ) { - self.source_change.is_snippet = true; - self.replace(range, snippet); - } - pub(crate) fn replace_ast(&mut self, old: N, new: N) { - algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) - } - pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into) { - let file_system_edit = FileSystemEdit::CreateFile { dst, initial_contents: content.into() }; - self.source_change.push_file_system_edit(file_system_edit); - } - pub(crate) fn move_file(&mut self, src: FileId, dst: AnchoredPathBuf) { - let file_system_edit = FileSystemEdit::MoveFile { src, dst }; - self.source_change.push_file_system_edit(file_system_edit); - } - pub(crate) fn trigger_signature_help(&mut self) { - self.trigger_signature_help = true; - } - - fn finish(mut self) -> SourceChange { - self.commit(); - mem::take(&mut self.source_change) - } -} diff --git a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index 4ab8e93a2909..d8f522708460 100644 --- a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -5,7 +5,7 @@ use syntax::{ match_ast, SyntaxNode, }; -use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; +use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists}; // Assist: convert_tuple_struct_to_named_struct // @@ -80,7 +80,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct( fn edit_struct_def( ctx: &AssistContext<'_>, - edit: &mut AssistBuilder, + edit: &mut SourceChangeBuilder, strukt: &Either, tuple_fields: ast::TupleFieldList, names: Vec, @@ -122,7 +122,7 @@ fn edit_struct_def( fn edit_struct_references( ctx: &AssistContext<'_>, - edit: &mut AssistBuilder, + edit: &mut SourceChangeBuilder, strukt: Either, names: &[ast::Name], ) { @@ -132,7 +132,7 @@ fn edit_struct_references( }; let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); - let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> { + let edit_node = |edit: &mut SourceChangeBuilder, node: SyntaxNode| -> Option<()> { match_ast! { match node { ast::TupleStructPat(tuple_struct_pat) => { @@ -203,7 +203,7 @@ fn edit_struct_references( fn edit_field_references( ctx: &AssistContext<'_>, - edit: &mut AssistBuilder, + edit: &mut SourceChangeBuilder, fields: impl Iterator, names: &[ast::Name], ) { diff --git a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index c1f57532bb29..dc581ff3bd2c 100644 --- a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -8,7 +8,7 @@ use syntax::{ TextRange, }; -use crate::assist_context::{AssistBuilder, AssistContext, Assists}; +use crate::assist_context::{AssistContext, Assists, SourceChangeBuilder}; // Assist: destructure_tuple_binding // @@ -151,7 +151,7 @@ struct TupleData { } fn edit_tuple_assignment( ctx: &AssistContext<'_>, - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, data: &TupleData, in_sub_pattern: bool, ) { @@ -195,7 +195,7 @@ fn edit_tuple_assignment( fn edit_tuple_usages( data: &TupleData, - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, ctx: &AssistContext<'_>, in_sub_pattern: bool, ) { @@ -211,7 +211,7 @@ fn edit_tuple_usages( } fn edit_tuple_usage( ctx: &AssistContext<'_>, - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, usage: &FileReference, data: &TupleData, in_sub_pattern: bool, @@ -239,7 +239,7 @@ fn edit_tuple_usage( fn edit_tuple_field_usage( ctx: &AssistContext<'_>, - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, data: &TupleData, index: TupleIndex, ) { diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index a93648f2d315..dfb565212646 100644 --- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -20,7 +20,7 @@ use syntax::{ SyntaxNode, T, }; -use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; +use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists}; // Assist: extract_struct_from_enum_variant // @@ -374,7 +374,7 @@ fn apply_references( fn process_references( ctx: &AssistContext<'_>, - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, visited_modules: &mut FxHashSet, enum_module_def: &ModuleDef, variant_hir_name: &Name, diff --git a/crates/ide-assists/src/handlers/generate_deref.rs b/crates/ide-assists/src/handlers/generate_deref.rs index b9637ee8d7c6..b484635121eb 100644 --- a/crates/ide-assists/src/handlers/generate_deref.rs +++ b/crates/ide-assists/src/handlers/generate_deref.rs @@ -8,7 +8,7 @@ use syntax::{ }; use crate::{ - assist_context::{AssistBuilder, AssistContext, Assists}, + assist_context::{AssistContext, Assists, SourceChangeBuilder}, utils::generate_trait_impl_text, AssistId, AssistKind, }; @@ -120,7 +120,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() } fn generate_edit( - edit: &mut AssistBuilder, + edit: &mut SourceChangeBuilder, strukt: ast::Struct, field_type_syntax: &SyntaxNode, field_name: impl Display, diff --git a/crates/ide-assists/src/handlers/introduce_named_lifetime.rs b/crates/ide-assists/src/handlers/introduce_named_lifetime.rs index ce91dd23703b..2fc754e3e50d 100644 --- a/crates/ide-assists/src/handlers/introduce_named_lifetime.rs +++ b/crates/ide-assists/src/handlers/introduce_named_lifetime.rs @@ -5,7 +5,7 @@ use syntax::{ AstNode, TextRange, }; -use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; +use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists}; static ASSIST_NAME: &str = "introduce_named_lifetime"; static ASSIST_LABEL: &str = "Introduce named lifetime"; @@ -140,7 +140,7 @@ enum NeedsLifetime { } impl NeedsLifetime { - fn make_mut(self, builder: &mut AssistBuilder) -> Self { + fn make_mut(self, builder: &mut SourceChangeBuilder) -> Self { match self { Self::SelfParam(it) => Self::SelfParam(builder.make_mut(it)), Self::RefType(it) => Self::RefType(builder.make_mut(it)), diff --git a/crates/ide-assists/src/handlers/remove_unused_param.rs b/crates/ide-assists/src/handlers/remove_unused_param.rs index 59ea94ea1ff6..bd2e8fbe3896 100644 --- a/crates/ide-assists/src/handlers/remove_unused_param.rs +++ b/crates/ide-assists/src/handlers/remove_unused_param.rs @@ -8,7 +8,8 @@ use syntax::{ use SyntaxKind::WHITESPACE; use crate::{ - assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists, + assist_context::SourceChangeBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, + Assists, }; // Assist: remove_unused_param @@ -88,7 +89,7 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> fn process_usages( ctx: &AssistContext<'_>, - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, file_id: FileId, references: Vec, arg_to_remove: usize, diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index bd50208da5ff..d139f78a6f36 100644 --- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -10,7 +10,7 @@ use syntax::{ }; use crate::{ - assist_context::{AssistBuilder, AssistContext, Assists}, + assist_context::{AssistContext, Assists, SourceChangeBuilder}, utils::{ add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, generate_trait_impl_text, render_snippet, Cursor, DefaultMethods, @@ -224,7 +224,7 @@ fn impl_def_from_trait( } fn update_attribute( - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, old_derives: &[ast::Path], old_tree: &ast::TokenTree, old_trait_path: &ast::Path, diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index 3e61d0741d3f..103e3259fa2e 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -20,7 +20,7 @@ use syntax::{ SyntaxNode, TextRange, TextSize, T, }; -use crate::assist_context::{AssistBuilder, AssistContext}; +use crate::assist_context::{AssistContext, SourceChangeBuilder}; pub(crate) mod suggest_name; mod gen_trait_fn_body; @@ -484,7 +484,7 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str } pub(crate) fn add_method_to_adt( - builder: &mut AssistBuilder, + builder: &mut SourceChangeBuilder, adt: &ast::Adt, impl_def: Option, method: &str, diff --git a/crates/ide-db/src/source_change.rs b/crates/ide-db/src/source_change.rs index 8132c73ef26b..21314ad74ef9 100644 --- a/crates/ide-db/src/source_change.rs +++ b/crates/ide-db/src/source_change.rs @@ -3,12 +3,15 @@ //! //! It can be viewed as a dual for `Change`. -use std::{collections::hash_map::Entry, iter}; +use std::{collections::hash_map::Entry, iter, mem}; use base_db::{AnchoredPathBuf, FileId}; use rustc_hash::FxHashMap; use stdx::never; -use text_edit::TextEdit; +use syntax::{algo, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize}; +use text_edit::{TextEdit, TextEditBuilder}; + +use crate::SnippetCap; #[derive(Default, Debug, Clone)] pub struct SourceChange { @@ -81,6 +84,135 @@ impl From> for SourceChange { } } +pub struct SourceChangeBuilder { + pub edit: TextEditBuilder, + pub file_id: FileId, + pub source_change: SourceChange, + pub trigger_signature_help: bool, + + /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin. + pub mutated_tree: Option, +} + +pub struct TreeMutator { + immutable: SyntaxNode, + mutable_clone: SyntaxNode, +} + +impl TreeMutator { + pub fn new(immutable: &SyntaxNode) -> TreeMutator { + let immutable = immutable.ancestors().last().unwrap(); + let mutable_clone = immutable.clone_for_update(); + TreeMutator { immutable, mutable_clone } + } + + pub fn make_mut(&self, node: &N) -> N { + N::cast(self.make_syntax_mut(node.syntax())).unwrap() + } + + pub fn make_syntax_mut(&self, node: &SyntaxNode) -> SyntaxNode { + let ptr = SyntaxNodePtr::new(node); + ptr.to_node(&self.mutable_clone) + } +} + +impl SourceChangeBuilder { + pub fn new(file_id: FileId) -> SourceChangeBuilder { + SourceChangeBuilder { + edit: TextEdit::builder(), + file_id, + source_change: SourceChange::default(), + trigger_signature_help: false, + mutated_tree: None, + } + } + + pub fn edit_file(&mut self, file_id: FileId) { + self.commit(); + self.file_id = file_id; + } + + fn commit(&mut self) { + if let Some(tm) = self.mutated_tree.take() { + algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit) + } + + let edit = mem::take(&mut self.edit).finish(); + if !edit.is_empty() { + self.source_change.insert_source_edit(self.file_id, edit); + } + } + + pub fn make_mut(&mut self, node: N) -> N { + self.mutated_tree.get_or_insert_with(|| TreeMutator::new(node.syntax())).make_mut(&node) + } + /// Returns a copy of the `node`, suitable for mutation. + /// + /// Syntax trees in rust-analyzer are typically immutable, and mutating + /// operations panic at runtime. However, it is possible to make a copy of + /// the tree and mutate the copy freely. Mutation is based on interior + /// mutability, and different nodes in the same tree see the same mutations. + /// + /// The typical pattern for an assist is to find specific nodes in the read + /// phase, and then get their mutable couterparts using `make_mut` in the + /// mutable state. + pub fn make_syntax_mut(&mut self, node: SyntaxNode) -> SyntaxNode { + self.mutated_tree.get_or_insert_with(|| TreeMutator::new(&node)).make_syntax_mut(&node) + } + + /// Remove specified `range` of text. + pub fn delete(&mut self, range: TextRange) { + self.edit.delete(range) + } + /// Append specified `text` at the given `offset` + pub fn insert(&mut self, offset: TextSize, text: impl Into) { + self.edit.insert(offset, text.into()) + } + /// Append specified `snippet` at the given `offset` + pub fn insert_snippet( + &mut self, + _cap: SnippetCap, + offset: TextSize, + snippet: impl Into, + ) { + self.source_change.is_snippet = true; + self.insert(offset, snippet); + } + /// Replaces specified `range` of text with a given string. + pub fn replace(&mut self, range: TextRange, replace_with: impl Into) { + self.edit.replace(range, replace_with.into()) + } + /// Replaces specified `range` of text with a given `snippet`. + pub fn replace_snippet( + &mut self, + _cap: SnippetCap, + range: TextRange, + snippet: impl Into, + ) { + self.source_change.is_snippet = true; + self.replace(range, snippet); + } + pub fn replace_ast(&mut self, old: N, new: N) { + algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) + } + pub fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into) { + let file_system_edit = FileSystemEdit::CreateFile { dst, initial_contents: content.into() }; + self.source_change.push_file_system_edit(file_system_edit); + } + pub fn move_file(&mut self, src: FileId, dst: AnchoredPathBuf) { + let file_system_edit = FileSystemEdit::MoveFile { src, dst }; + self.source_change.push_file_system_edit(file_system_edit); + } + pub fn trigger_signature_help(&mut self) { + self.trigger_signature_help = true; + } + + pub fn finish(mut self) -> SourceChange { + self.commit(); + mem::take(&mut self.source_change) + } +} + #[derive(Debug, Clone)] pub enum FileSystemEdit { CreateFile { dst: AnchoredPathBuf, initial_contents: String }, diff --git a/crates/ide-diagnostics/src/handlers/inactive_code.rs b/crates/ide-diagnostics/src/handlers/inactive_code.rs index 97ea5c456a63..5694f33525e0 100644 --- a/crates/ide-diagnostics/src/handlers/inactive_code.rs +++ b/crates/ide-diagnostics/src/handlers/inactive_code.rs @@ -43,7 +43,7 @@ mod tests { use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig}; pub(crate) fn check(ra_fixture: &str) { - let config = DiagnosticsConfig::default(); + let config = DiagnosticsConfig::test_sample(); check_diagnostics_with_config(config, ra_fixture) } diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index aa7fcffb48ac..a21db5b2cec9 100644 --- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -1,21 +1,30 @@ //! This diagnostic provides an assist for creating a struct definition from a JSON //! example. -use ide_db::{base_db::FileId, source_change::SourceChange}; +use hir::{PathResolution, Semantics}; +use ide_db::{ + base_db::FileId, + helpers::mod_path_to_ast, + imports::insert_use::{insert_use, ImportScope}, + source_change::SourceChangeBuilder, + RootDatabase, +}; use itertools::Itertools; -use stdx::format_to; +use stdx::{format_to, never}; use syntax::{ ast::{self, make}, SyntaxKind, SyntaxNode, }; use text_edit::TextEdit; -use crate::{fix, Diagnostic, Severity}; +use crate::{fix, Diagnostic, DiagnosticsConfig, Severity}; #[derive(Default)] struct State { result: String, struct_counts: usize, + has_serialize: bool, + has_deserialize: bool, } impl State { @@ -24,6 +33,25 @@ impl State { make::name(&format!("Struct{}", self.struct_counts)) } + fn serde_derive(&self) -> String { + let mut v = vec![]; + if self.has_serialize { + v.push("Serialize"); + } + if self.has_deserialize { + v.push("Deserialize"); + } + match v.as_slice() { + [] => "".to_string(), + [x] => format!("#[derive({x})]\n"), + [x, y] => format!("#[derive({x}, {y})]\n"), + _ => { + never!(); + "".to_string() + } + } + } + fn build_struct(&mut self, value: &serde_json::Map) -> ast::Type { let name = self.generate_new_name(); let ty = make::ty(&name.to_string()); @@ -36,7 +64,7 @@ impl State { )) .into(), ); - format_to!(self.result, "#[derive(Serialize, Deserialize)]\n{}\n", strukt); + format_to!(self.result, "{}{}\n", self.serde_derive(), strukt); ty } @@ -44,10 +72,10 @@ impl State { match value { serde_json::Value::Null => make::ty_unit(), serde_json::Value::Bool(_) => make::ty("bool"), - serde_json::Value::Number(x) => make::ty(if x.is_i64() { "i64" } else { "f64" }), + serde_json::Value::Number(it) => make::ty(if it.is_i64() { "i64" } else { "f64" }), serde_json::Value::String(_) => make::ty("String"), - serde_json::Value::Array(x) => { - let ty = match x.iter().next() { + serde_json::Value::Array(it) => { + let ty = match it.iter().next() { Some(x) => self.type_of(x), None => make::ty_placeholder(), }; @@ -58,37 +86,91 @@ impl State { } } -pub(crate) fn json_in_items(acc: &mut Vec, file_id: FileId, node: &SyntaxNode) { - if node.kind() == SyntaxKind::ERROR - && node.first_token().map(|x| x.kind()) == Some(SyntaxKind::L_CURLY) - && node.last_token().map(|x| x.kind()) == Some(SyntaxKind::R_CURLY) - { - let node_string = node.to_string(); - if let Ok(x) = serde_json::from_str(&node_string) { - if let serde_json::Value::Object(x) = x { - let range = node.text_range(); - let mut edit = TextEdit::builder(); - edit.delete(range); - let mut state = State::default(); - state.build_struct(&x); - edit.insert(range.start(), state.result); - acc.push( - Diagnostic::new( - "json-is-not-rust", - "JSON syntax is not valid as a Rust item", - range, - ) - .severity(Severity::WeakWarning) - .with_fixes(Some(vec![fix( - "convert_json_to_struct", - "Convert JSON to struct", - SourceChange::from_text_edit(file_id, edit.finish()), - range, - )])), - ); +pub(crate) fn json_in_items( + sema: &Semantics<'_, RootDatabase>, + acc: &mut Vec, + file_id: FileId, + node: &SyntaxNode, + config: &DiagnosticsConfig, +) { + (|| { + if node.kind() == SyntaxKind::ERROR + && node.first_token().map(|x| x.kind()) == Some(SyntaxKind::L_CURLY) + && node.last_token().map(|x| x.kind()) == Some(SyntaxKind::R_CURLY) + { + let node_string = node.to_string(); + if let Ok(it) = serde_json::from_str(&node_string) { + if let serde_json::Value::Object(it) = it { + let import_scope = ImportScope::find_insert_use_container(node, sema)?; + let range = node.text_range(); + let mut edit = TextEdit::builder(); + edit.delete(range); + let mut state = State::default(); + let semantics_scope = sema.scope(node)?; + let scope_resolve = + |it| semantics_scope.speculative_resolve(&make::path_from_text(it)); + let scope_has = |it| scope_resolve(it).is_some(); + let deserialize_resolved = scope_resolve("::serde::Deserialize"); + let serialize_resolved = scope_resolve("::serde::Serialize"); + state.has_deserialize = deserialize_resolved.is_some(); + state.has_serialize = serialize_resolved.is_some(); + state.build_struct(&it); + edit.insert(range.start(), state.result); + acc.push( + Diagnostic::new( + "json-is-not-rust", + "JSON syntax is not valid as a Rust item", + range, + ) + .severity(Severity::WeakWarning) + .with_fixes(Some(vec![{ + let mut scb = SourceChangeBuilder::new(file_id); + let scope = match import_scope.clone() { + ImportScope::File(it) => ImportScope::File(scb.make_mut(it)), + ImportScope::Module(it) => ImportScope::Module(scb.make_mut(it)), + ImportScope::Block(it) => ImportScope::Block(scb.make_mut(it)), + }; + let current_module = semantics_scope.module(); + if !scope_has("Serialize") { + if let Some(PathResolution::Def(it)) = serialize_resolved { + if let Some(it) = current_module.find_use_path_prefixed( + sema.db, + it, + config.insert_use.prefix_kind, + ) { + insert_use( + &scope, + mod_path_to_ast(&it), + &config.insert_use, + ); + } + } + } + if !scope_has("Deserialize") { + if let Some(PathResolution::Def(it)) = deserialize_resolved { + if let Some(it) = current_module.find_use_path_prefixed( + sema.db, + it, + config.insert_use.prefix_kind, + ) { + insert_use( + &scope, + mod_path_to_ast(&it), + &config.insert_use, + ); + } + } + } + let mut sc = scb.finish(); + sc.insert_source_edit(file_id, edit.finish()); + fix("convert_json_to_struct", "Convert JSON to struct", sc, range) + }])), + ); + } } } - } + Some(()) + })(); } #[cfg(test)] @@ -100,7 +182,7 @@ mod tests { #[test] fn diagnostic_for_simple_case() { - let mut config = DiagnosticsConfig::default(); + let mut config = DiagnosticsConfig::test_sample(); config.disabled.insert("syntax-error".to_string()); check_diagnostics_with_config( config, @@ -115,6 +197,13 @@ mod tests { fn types_of_primitives() { check_fix( r#" + //- /lib.rs crate:lib deps:serde + use serde::Serialize; + + fn some_garbage() { + + } + {$0 "foo": "bar", "bar": 2.3, @@ -122,9 +211,20 @@ mod tests { "bay": 57, "box": true } + //- /serde.rs crate:serde + + pub trait Serialize { + fn serialize() -> u8; + } "#, r#" - #[derive(Serialize, Deserialize)] + use serde::Serialize; + + fn some_garbage() { + + } + + #[derive(Serialize)] struct Struct1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String } "#, @@ -144,11 +244,8 @@ mod tests { } "#, r#" - #[derive(Serialize, Deserialize)] struct Struct3{ } - #[derive(Serialize, Deserialize)] struct Struct2{ kind: String, value: Struct3 } - #[derive(Serialize, Deserialize)] struct Struct1{ bar: Struct2, foo: String } "#, @@ -159,6 +256,7 @@ mod tests { fn arrays() { check_fix( r#" + //- /lib.rs crate:lib deps:serde { "of_string": ["foo", "2", "x"], $0 "of_object": [{ @@ -171,8 +269,19 @@ mod tests { "nested": [[[2]]], "empty": [] } + //- /serde.rs crate:serde + + pub trait Serialize { + fn serialize() -> u8; + } + pub trait Deserialize { + fn deserialize() -> u8; + } "#, r#" + use serde::Serialize; + use serde::Deserialize; + #[derive(Serialize, Deserialize)] struct Struct2{ x: i64, y: i64 } #[derive(Serialize, Deserialize)] diff --git a/crates/ide-diagnostics/src/handlers/macro_error.rs b/crates/ide-diagnostics/src/handlers/macro_error.rs index d6a66dc15091..43ff4ed5a6c8 100644 --- a/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -79,7 +79,7 @@ pub macro panic { #[test] fn include_macro_should_allow_empty_content() { - let mut config = DiagnosticsConfig::default(); + let mut config = DiagnosticsConfig::test_sample(); // FIXME: This is a false-positive, the file is actually linked in via // `include!` macro diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 7034f010e1b0..61e63ea7a93c 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -60,6 +60,7 @@ use hir::{diagnostics::AnyDiagnostic, InFile, Semantics}; use ide_db::{ assists::{Assist, AssistId, AssistKind, AssistResolveStrategy}, base_db::{FileId, FileRange, SourceDatabase}, + imports::insert_use::InsertUseConfig, label::Label, source_change::SourceChange, FxHashSet, RootDatabase, @@ -140,13 +141,37 @@ impl Default for ExprFillDefaultMode { } } -#[derive(Default, Debug, Clone)] +#[derive(Debug, Clone)] pub struct DiagnosticsConfig { pub proc_macros_enabled: bool, pub proc_attr_macros_enabled: bool, pub disable_experimental: bool, pub disabled: FxHashSet, pub expr_fill_default: ExprFillDefaultMode, + // FIXME: We may want to include a whole `AssistConfig` here + pub insert_use: InsertUseConfig, +} + +impl DiagnosticsConfig { + pub fn test_sample() -> Self { + use hir::PrefixKind; + use ide_db::imports::insert_use::ImportGranularity; + + Self { + proc_macros_enabled: Default::default(), + proc_attr_macros_enabled: Default::default(), + disable_experimental: Default::default(), + disabled: Default::default(), + expr_fill_default: Default::default(), + insert_use: InsertUseConfig { + granularity: ImportGranularity::Preserve, + enforce_granularity: false, + prefix_kind: PrefixKind::Plain, + group: false, + skip_glob_imports: false, + }, + } + } } struct DiagnosticsContext<'a> { @@ -173,10 +198,12 @@ pub fn diagnostics( }), ); - for node in parse.tree().syntax().descendants() { + let parse = sema.parse(file_id); + + for node in parse.syntax().descendants() { handlers::useless_braces::useless_braces(&mut res, file_id, &node); handlers::field_shorthand::field_shorthand(&mut res, file_id, &node); - handlers::json_is_not_rust::json_in_items(&mut res, file_id, &node); + handlers::json_is_not_rust::json_in_items(&sema, &mut res, file_id, &node, &config); } let module = sema.to_module_def(file_id); diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs index 7312bca32fed..729619cfde03 100644 --- a/crates/ide-diagnostics/src/tests.rs +++ b/crates/ide-diagnostics/src/tests.rs @@ -37,7 +37,7 @@ fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { let after = trim_indent(ra_fixture_after); let (db, file_position) = RootDatabase::with_position(ra_fixture_before); - let mut conf = DiagnosticsConfig::default(); + let mut conf = DiagnosticsConfig::test_sample(); conf.expr_fill_default = ExprFillDefaultMode::Default; let diagnostic = super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id) @@ -69,7 +69,7 @@ pub(crate) fn check_no_fix(ra_fixture: &str) { let (db, file_position) = RootDatabase::with_position(ra_fixture); let diagnostic = super::diagnostics( &db, - &DiagnosticsConfig::default(), + &DiagnosticsConfig::test_sample(), &AssistResolveStrategy::All, file_position.file_id, ) @@ -82,7 +82,7 @@ pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) { let (db, file_id) = RootDatabase::with_single_file(ra_fixture); let diagnostics = super::diagnostics( &db, - &DiagnosticsConfig::default(), + &DiagnosticsConfig::test_sample(), &AssistResolveStrategy::All, file_id, ); @@ -91,7 +91,7 @@ pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) { #[track_caller] pub(crate) fn check_diagnostics(ra_fixture: &str) { - let mut config = DiagnosticsConfig::default(); + let mut config = DiagnosticsConfig::test_sample(); config.disabled.insert("inactive-code".to_string()); check_diagnostics_with_config(config, ra_fixture) } @@ -127,7 +127,7 @@ pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixtur #[test] fn test_disabled_diagnostics() { - let mut config = DiagnosticsConfig::default(); + let mut config = DiagnosticsConfig::test_sample(); config.disabled.insert("unresolved-module".into()); let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#); @@ -137,7 +137,7 @@ fn test_disabled_diagnostics() { let diagnostics = super::diagnostics( &db, - &DiagnosticsConfig::default(), + &DiagnosticsConfig::test_sample(), &AssistResolveStrategy::All, file_id, ); diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs index 52511ceb5805..247007db0a78 100644 --- a/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/crates/rust-analyzer/src/cli/diagnostics.rs @@ -43,7 +43,7 @@ impl flags::Diagnostics { println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id)); for diagnostic in analysis .diagnostics( - &DiagnosticsConfig::default(), + &DiagnosticsConfig::test_sample(), AssistResolveStrategy::None, file_id, ) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index ac0fdf85a774..1629c1dd328a 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -881,6 +881,7 @@ impl Config { ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo, ExprFillDefaultDef::Default => ExprFillDefaultMode::Default, }, + insert_use: self.insert_use_config(), } } From 1a94193602e65c99344ba313c71d4298b0d4c0cc Mon Sep 17 00:00:00 2001 From: oxalica Date: Sun, 7 Aug 2022 04:17:04 +0800 Subject: [PATCH 0090/2442] Impl more methods and traits for la_arena::ArenaMap --- lib/la-arena/src/map.rs | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/lib/la-arena/src/map.rs b/lib/la-arena/src/map.rs index f74ec5d97cb9..3034e33a7885 100644 --- a/lib/la-arena/src/map.rs +++ b/lib/la-arena/src/map.rs @@ -21,6 +21,33 @@ impl ArenaMap, V> { Self { v: Vec::with_capacity(capacity), _ty: PhantomData } } + /// Reserves capacity for at least additional more elements to be inserted in the map. + pub fn reserve(&mut self, additional: usize) { + self.v.reserve(additional); + } + + /// Clears the map, removing all elements. + pub fn clear(&mut self) { + self.v.clear(); + } + + /// Shrinks the capacity of the map as much as possible. + pub fn shrink_to_fit(&mut self) { + let min_len = self.v.iter().rposition(|slot| slot.is_some()).map_or(0, |i| i + 1); + self.v.truncate(min_len); + self.v.shrink_to_fit(); + } + + /// Returns whether the map contains a value for the specified index. + pub fn contains_idx(&self, idx: Idx) -> bool { + matches!(self.v.get(Self::to_idx(idx)), Some(Some(_))) + } + + /// Removes an index from the map, returning the value at the index if the index was previously in the map. + pub fn remove(&mut self, idx: Idx) -> Option { + self.v.get_mut(Self::to_idx(idx))?.take() + } + /// Inserts a value associated with a given arena index into the map. pub fn insert(&mut self, idx: Idx, t: V) { let idx = Self::to_idx(idx); @@ -94,6 +121,22 @@ impl Default for ArenaMap, T> { } } +impl Extend<(Idx, T)> for ArenaMap, T> { + fn extend, T)>>(&mut self, iter: I) { + iter.into_iter().for_each(move |(k, v)| { + self.insert(k, v); + }); + } +} + +impl FromIterator<(Idx, T)> for ArenaMap, T> { + fn from_iter, T)>>(iter: I) -> Self { + let mut this = Self::new(); + this.extend(iter); + this + } +} + /// A view into a single entry in a map, which may either be vacant or occupied. /// /// This `enum` is constructed from the [`entry`] method on [`ArenaMap`]. From 326ffee5b71e0113be20fc3b3b2aefbd4cd3b6d9 Mon Sep 17 00:00:00 2001 From: oxalica Date: Sun, 7 Aug 2022 04:48:52 +0800 Subject: [PATCH 0091/2442] Returns the old value for la_arena::ArenaMap::insert --- crates/hir-def/src/generics.rs | 2 +- crates/hir-def/src/visibility.rs | 2 +- crates/hir-ty/src/lower.rs | 2 +- lib/la-arena/src/map.rs | 7 +++++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index 2397cf501584..469b28c2d9ed 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -451,7 +451,7 @@ impl HasChildSource for GenericDefId { if let GenericDefId::TraitId(id) = *self { let trait_ref = id.lookup(db).source(db).value; let idx = idx_iter.next().unwrap(); - params.insert(idx, Either::Right(trait_ref)) + params.insert(idx, Either::Right(trait_ref)); } if let Some(generic_params_list) = generic_params_list { diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index 6e22a877a9fa..087268a9ecee 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -224,7 +224,7 @@ pub(crate) fn field_visibilities_query( let resolver = variant_id.module(db).resolver(db); let mut res = ArenaMap::default(); for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, field_data.visibility.resolve(db, &resolver)) + res.insert(field_id, field_data.visibility.resolve(db, &resolver)); } Arc::new(res) } diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 3ed9c941f479..239f66bcb7e7 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -1126,7 +1126,7 @@ pub(crate) fn field_types_query( let ctx = TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))) + res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))); } Arc::new(res) } diff --git a/lib/la-arena/src/map.rs b/lib/la-arena/src/map.rs index 3034e33a7885..5f347e274500 100644 --- a/lib/la-arena/src/map.rs +++ b/lib/la-arena/src/map.rs @@ -49,11 +49,14 @@ impl ArenaMap, V> { } /// Inserts a value associated with a given arena index into the map. - pub fn insert(&mut self, idx: Idx, t: V) { + /// + /// If the map did not have this index present, None is returned. + /// Otherwise, the value is updated, and the old value is returned. + pub fn insert(&mut self, idx: Idx, t: V) -> Option { let idx = Self::to_idx(idx); self.v.resize_with((idx + 1).max(self.v.len()), || None); - self.v[idx] = Some(t); + self.v[idx].replace(t) } /// Returns a reference to the value associated with the provided index From eca6f2e897a0c09546fd8d8faba79ec2ce45be52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sun, 7 Aug 2022 09:29:26 +0300 Subject: [PATCH 0092/2442] Fix test_rainbow_highlighting gate --- crates/ide/src/syntax_highlighting/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 99be7c664868..382735cb368d 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -958,7 +958,7 @@ pub struct Struct; #[test] #[cfg_attr( - all(unix, not(target_pointer_width = "64")), + not(all(unix, target_pointer_width = "64")), ignore = "depends on `DefaultHasher` outputs" )] fn test_rainbow_highlighting() { From a81c7a2974841f335fd87bfd8c3c3b8a7c3d3612 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 5 Aug 2022 20:01:50 +0900 Subject: [PATCH 0093/2442] Parse range patterns in struct and slice without trailing comma --- crates/parser/src/grammar/patterns.rs | 27 +++- .../parser/inline/ok/0058_range_pat.rast | 116 ++++++++++++++++++ .../parser/inline/ok/0058_range_pat.rs | 10 ++ 3 files changed, 150 insertions(+), 3 deletions(-) diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs index 4cbf10306149..bfa41c686e5c 100644 --- a/crates/parser/src/grammar/patterns.rs +++ b/crates/parser/src/grammar/patterns.rs @@ -75,6 +75,16 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) { // Some(1..) => () // } // + // match () { + // S { a: 0 } => (), + // S { a: 1.. } => (), + // } + // + // match () { + // [0] => (), + // [1..] => (), + // } + // // match (10 as u8, 5 as u8) { // (0, _) => (), // (1.., _) => () @@ -88,9 +98,20 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) { let m = lhs.precede(p); p.bump(range_op); - // `0 .. =>` or `let 0 .. =` or `Some(0 .. )` - // ^ ^ ^ - if p.at(T![=]) | p.at(T![')']) | p.at(T![,]) { + // testing if we're at one of the following positions: + // `0 .. =>` + // ^ + // `let 0 .. =` + // ^ + // (1.., _) + // ^ + // `Some(0 .. )` + // ^ + // `S { t: 0.. }` + // ^ + // `[0..]` + // ^ + if p.at(T![=]) | p.at(T![')']) | p.at(T![,]) | p.at(T!['}']) | p.at(T![']']) { // test half_open_range_pat // fn f() { let 0 .. = 1u32; } } else { diff --git a/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast b/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast index 44c967e8dc59..cfef5d3f9538 100644 --- a/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast +++ b/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast @@ -172,6 +172,122 @@ SOURCE_FILE WHITESPACE "\n " R_CURLY "}" WHITESPACE "\n\n " + EXPR_STMT + MATCH_EXPR + MATCH_KW "match" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + MATCH_ARM_LIST + L_CURLY "{" + WHITESPACE "\n " + MATCH_ARM + RECORD_PAT + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_PAT_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_PAT_FIELD + NAME_REF + IDENT "a" + COLON ":" + WHITESPACE " " + LITERAL_PAT + LITERAL + INT_NUMBER "0" + WHITESPACE " " + R_CURLY "}" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + MATCH_ARM + RECORD_PAT + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_PAT_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_PAT_FIELD + NAME_REF + IDENT "a" + COLON ":" + WHITESPACE " " + RANGE_PAT + LITERAL_PAT + LITERAL + INT_NUMBER "1" + DOT2 ".." + WHITESPACE " " + R_CURLY "}" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + R_CURLY "}" + WHITESPACE "\n\n " + EXPR_STMT + MATCH_EXPR + MATCH_KW "match" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + MATCH_ARM_LIST + L_CURLY "{" + WHITESPACE "\n " + MATCH_ARM + SLICE_PAT + L_BRACK "[" + LITERAL_PAT + LITERAL + INT_NUMBER "0" + R_BRACK "]" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + MATCH_ARM + SLICE_PAT + L_BRACK "[" + RANGE_PAT + LITERAL_PAT + LITERAL + INT_NUMBER "1" + DOT2 ".." + R_BRACK "]" + WHITESPACE " " + FAT_ARROW "=>" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + R_CURLY "}" + WHITESPACE "\n\n " MATCH_EXPR MATCH_KW "match" WHITESPACE " " diff --git a/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs b/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs index 6c586a895609..2411d51096b3 100644 --- a/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs +++ b/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs @@ -11,6 +11,16 @@ fn main() { Some(1..) => () } + match () { + S { a: 0 } => (), + S { a: 1.. } => (), + } + + match () { + [0] => (), + [1..] => (), + } + match (10 as u8, 5 as u8) { (0, _) => (), (1.., _) => () From 70255029cf49928862c5b5603e731668ade5fa85 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sun, 7 Aug 2022 17:09:36 +0530 Subject: [PATCH 0094/2442] clippy: make generated code nice to read Feel free to close if this is too minor. --- crates/syntax/src/tests/sourcegen_ast.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs index 6d2766225103..daad939f82e0 100644 --- a/crates/syntax/src/tests/sourcegen_ast.rs +++ b/crates/syntax/src/tests/sourcegen_ast.rs @@ -410,24 +410,17 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String { impl SyntaxKind { pub fn is_keyword(self) -> bool { - match self { - #(#all_keywords)|* => true, - _ => false, - } + matches!(self, #(#all_keywords)|*) } pub fn is_punct(self) -> bool { - match self { - #(#punctuation)|* => true, - _ => false, - } + + matches!(self, #(#punctuation)|*) + } pub fn is_literal(self) -> bool { - match self { - #(#literals)|* => true, - _ => false, - } + matches!(self, #(#literals)|*) } pub fn from_keyword(ident: &str) -> Option { From a3fc4dbb04e9e9fd639ad5c0988af6c9c540b9a0 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sun, 7 Aug 2022 17:37:50 +0530 Subject: [PATCH 0095/2442] more matches! sites --- crates/syntax/src/tests/sourcegen_ast.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs index daad939f82e0..70b54843dbaa 100644 --- a/crates/syntax/src/tests/sourcegen_ast.rs +++ b/crates/syntax/src/tests/sourcegen_ast.rs @@ -169,10 +169,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { quote! { impl AstNode for #name { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - #(#kinds)|* => true, - _ => false, - } + matches!(kind, #(#kinds)|*) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -253,10 +250,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { } impl AstNode for #name { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - #(#kinds)|* => true, - _ => false, - } + matches!(kind, #(#kinds)|*) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| #name { syntax }) From bcab4be9383f5dc3d177ec585df85e2becf2512b Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sun, 7 Aug 2022 17:38:20 +0530 Subject: [PATCH 0096/2442] regenerate files with new syntax --- crates/parser/src/syntax_kind/generated.rs | 130 +++++-- crates/syntax/src/ast/generated/nodes.rs | 410 ++++++++++++--------- 2 files changed, 345 insertions(+), 195 deletions(-) diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs index 628fa745e752..c84f45f1f8e4 100644 --- a/crates/parser/src/syntax_kind/generated.rs +++ b/crates/parser/src/syntax_kind/generated.rs @@ -262,33 +262,117 @@ pub enum SyntaxKind { use self::SyntaxKind::*; impl SyntaxKind { pub fn is_keyword(self) -> bool { - match self { - AS_KW | ASYNC_KW | AWAIT_KW | BOX_KW | BREAK_KW | CONST_KW | CONTINUE_KW | CRATE_KW - | DYN_KW | ELSE_KW | ENUM_KW | EXTERN_KW | FALSE_KW | FN_KW | FOR_KW | IF_KW - | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW - | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | SELF_TYPE_KW | STATIC_KW - | STRUCT_KW | SUPER_KW | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW - | WHERE_KW | WHILE_KW | YIELD_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW - | RAW_KW | MACRO_RULES_KW => true, - _ => false, - } + matches!( + self, + AS_KW + | ASYNC_KW + | AWAIT_KW + | BOX_KW + | BREAK_KW + | CONST_KW + | CONTINUE_KW + | CRATE_KW + | DYN_KW + | ELSE_KW + | ENUM_KW + | EXTERN_KW + | FALSE_KW + | FN_KW + | FOR_KW + | IF_KW + | IMPL_KW + | IN_KW + | LET_KW + | LOOP_KW + | MACRO_KW + | MATCH_KW + | MOD_KW + | MOVE_KW + | MUT_KW + | PUB_KW + | REF_KW + | RETURN_KW + | SELF_KW + | SELF_TYPE_KW + | STATIC_KW + | STRUCT_KW + | SUPER_KW + | TRAIT_KW + | TRUE_KW + | TRY_KW + | TYPE_KW + | UNSAFE_KW + | USE_KW + | WHERE_KW + | WHILE_KW + | YIELD_KW + | AUTO_KW + | DEFAULT_KW + | EXISTENTIAL_KW + | UNION_KW + | RAW_KW + | MACRO_RULES_KW + ) } pub fn is_punct(self) -> bool { - match self { - SEMICOLON | COMMA | L_PAREN | R_PAREN | L_CURLY | R_CURLY | L_BRACK | R_BRACK - | L_ANGLE | R_ANGLE | AT | POUND | TILDE | QUESTION | DOLLAR | AMP | PIPE | PLUS - | STAR | SLASH | CARET | PERCENT | UNDERSCORE | DOT | DOT2 | DOT3 | DOT2EQ | COLON - | COLON2 | EQ | EQ2 | FAT_ARROW | BANG | NEQ | MINUS | THIN_ARROW | LTEQ | GTEQ - | PLUSEQ | MINUSEQ | PIPEEQ | AMPEQ | CARETEQ | SLASHEQ | STAREQ | PERCENTEQ | AMP2 - | PIPE2 | SHL | SHR | SHLEQ | SHREQ => true, - _ => false, - } + matches!( + self, + SEMICOLON + | COMMA + | L_PAREN + | R_PAREN + | L_CURLY + | R_CURLY + | L_BRACK + | R_BRACK + | L_ANGLE + | R_ANGLE + | AT + | POUND + | TILDE + | QUESTION + | DOLLAR + | AMP + | PIPE + | PLUS + | STAR + | SLASH + | CARET + | PERCENT + | UNDERSCORE + | DOT + | DOT2 + | DOT3 + | DOT2EQ + | COLON + | COLON2 + | EQ + | EQ2 + | FAT_ARROW + | BANG + | NEQ + | MINUS + | THIN_ARROW + | LTEQ + | GTEQ + | PLUSEQ + | MINUSEQ + | PIPEEQ + | AMPEQ + | CARETEQ + | SLASHEQ + | STAREQ + | PERCENTEQ + | AMP2 + | PIPE2 + | SHL + | SHR + | SHLEQ + | SHREQ + ) } pub fn is_literal(self) -> bool { - match self { - INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING => true, - _ => false, - } + matches!(self, INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING) } pub fn from_keyword(ident: &str) -> Option { let kw = match ident { diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 63309a155219..8c4825ad69eb 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -3169,10 +3169,7 @@ impl From for GenericArg { } impl AstNode for GenericArg { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG => true, - _ => false, - } + matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3237,12 +3234,23 @@ impl From for Type { } impl AstNode for Type { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ARRAY_TYPE | DYN_TRAIT_TYPE | FN_PTR_TYPE | FOR_TYPE | IMPL_TRAIT_TYPE | INFER_TYPE - | MACRO_TYPE | NEVER_TYPE | PAREN_TYPE | PATH_TYPE | PTR_TYPE | REF_TYPE - | SLICE_TYPE | TUPLE_TYPE => true, - _ => false, - } + matches!( + kind, + ARRAY_TYPE + | DYN_TRAIT_TYPE + | FN_PTR_TYPE + | FOR_TYPE + | IMPL_TRAIT_TYPE + | INFER_TYPE + | MACRO_TYPE + | NEVER_TYPE + | PAREN_TYPE + | PATH_TYPE + | PTR_TYPE + | REF_TYPE + | SLICE_TYPE + | TUPLE_TYPE + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3384,15 +3392,42 @@ impl From for Expr { } impl AstNode for Expr { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR - | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR - | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_EXPR | MACRO_STMTS | MATCH_EXPR - | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR - | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR - | YIELD_EXPR | LET_EXPR | UNDERSCORE_EXPR => true, - _ => false, - } + matches!( + kind, + ARRAY_EXPR + | AWAIT_EXPR + | BIN_EXPR + | BLOCK_EXPR + | BOX_EXPR + | BREAK_EXPR + | CALL_EXPR + | CAST_EXPR + | CLOSURE_EXPR + | CONTINUE_EXPR + | FIELD_EXPR + | FOR_EXPR + | IF_EXPR + | INDEX_EXPR + | LITERAL + | LOOP_EXPR + | MACRO_EXPR + | MACRO_STMTS + | MATCH_EXPR + | METHOD_CALL_EXPR + | PAREN_EXPR + | PATH_EXPR + | PREFIX_EXPR + | RANGE_EXPR + | RECORD_EXPR + | REF_EXPR + | RETURN_EXPR + | TRY_EXPR + | TUPLE_EXPR + | WHILE_EXPR + | YIELD_EXPR + | LET_EXPR + | UNDERSCORE_EXPR + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3521,11 +3556,25 @@ impl From for Item { } impl AstNode for Item { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MACRO_RULES - | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true, - _ => false, - } + matches!( + kind, + CONST + | ENUM + | EXTERN_BLOCK + | EXTERN_CRATE + | FN + | IMPL + | MACRO_CALL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3629,12 +3678,25 @@ impl From for Pat { } impl AstNode for Pat { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - IDENT_PAT | BOX_PAT | REST_PAT | LITERAL_PAT | MACRO_PAT | OR_PAT | PAREN_PAT - | PATH_PAT | WILDCARD_PAT | RANGE_PAT | RECORD_PAT | REF_PAT | SLICE_PAT - | TUPLE_PAT | TUPLE_STRUCT_PAT | CONST_BLOCK_PAT => true, - _ => false, - } + matches!( + kind, + IDENT_PAT + | BOX_PAT + | REST_PAT + | LITERAL_PAT + | MACRO_PAT + | OR_PAT + | PAREN_PAT + | PATH_PAT + | WILDCARD_PAT + | RANGE_PAT + | RECORD_PAT + | REF_PAT + | SLICE_PAT + | TUPLE_PAT + | TUPLE_STRUCT_PAT + | CONST_BLOCK_PAT + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3686,12 +3748,7 @@ impl From for FieldList { fn from(node: TupleFieldList) -> FieldList { FieldList::TupleFieldList(node) } } impl AstNode for FieldList { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - RECORD_FIELD_LIST | TUPLE_FIELD_LIST => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, RECORD_FIELD_LIST | TUPLE_FIELD_LIST) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { RECORD_FIELD_LIST => FieldList::RecordFieldList(RecordFieldList { syntax }), @@ -3717,12 +3774,7 @@ impl From for Adt { fn from(node: Union) -> Adt { Adt::Union(node) } } impl AstNode for Adt { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ENUM | STRUCT | UNION => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ENUM | STRUCT | UNION) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { ENUM => Adt::Enum(Enum { syntax }), @@ -3753,12 +3805,7 @@ impl From for AssocItem { fn from(node: TypeAlias) -> AssocItem { AssocItem::TypeAlias(node) } } impl AstNode for AssocItem { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST | FN | MACRO_CALL | TYPE_ALIAS => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CONST | FN | MACRO_CALL | TYPE_ALIAS) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { CONST => AssocItem::Const(Const { syntax }), @@ -3791,12 +3838,7 @@ impl From for ExternItem { fn from(node: TypeAlias) -> ExternItem { ExternItem::TypeAlias(node) } } impl AstNode for ExternItem { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - FN | MACRO_CALL | STATIC | TYPE_ALIAS => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FN | MACRO_CALL | STATIC | TYPE_ALIAS) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { FN => ExternItem::Fn(Fn { syntax }), @@ -3827,10 +3869,7 @@ impl From for GenericParam { } impl AstNode for GenericParam { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM => true, - _ => false, - } + matches!(kind, CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3856,12 +3895,7 @@ impl AnyHasArgList { } } impl AstNode for AnyHasArgList { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CALL_EXPR | METHOD_CALL_EXPR => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CALL_EXPR | METHOD_CALL_EXPR) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasArgList { syntax }) } @@ -3875,76 +3909,76 @@ impl AnyHasAttrs { } impl AstNode for AnyHasAttrs { fn can_cast(kind: SyntaxKind) -> bool { - match kind { + matches!( + kind, MACRO_CALL - | SOURCE_FILE - | CONST - | ENUM - | EXTERN_BLOCK - | EXTERN_CRATE - | FN - | IMPL - | MACRO_RULES - | MACRO_DEF - | MODULE - | STATIC - | STRUCT - | TRAIT - | TYPE_ALIAS - | UNION - | USE - | ITEM_LIST - | BLOCK_EXPR - | SELF_PARAM - | PARAM - | RECORD_FIELD - | TUPLE_FIELD - | VARIANT - | ASSOC_ITEM_LIST - | EXTERN_ITEM_LIST - | CONST_PARAM - | LIFETIME_PARAM - | TYPE_PARAM - | LET_STMT - | ARRAY_EXPR - | AWAIT_EXPR - | BIN_EXPR - | BOX_EXPR - | BREAK_EXPR - | CALL_EXPR - | CAST_EXPR - | CLOSURE_EXPR - | CONTINUE_EXPR - | FIELD_EXPR - | FOR_EXPR - | IF_EXPR - | INDEX_EXPR - | LITERAL - | LOOP_EXPR - | MATCH_EXPR - | METHOD_CALL_EXPR - | PAREN_EXPR - | PATH_EXPR - | PREFIX_EXPR - | RANGE_EXPR - | REF_EXPR - | RETURN_EXPR - | TRY_EXPR - | TUPLE_EXPR - | WHILE_EXPR - | YIELD_EXPR - | LET_EXPR - | UNDERSCORE_EXPR - | STMT_LIST - | RECORD_EXPR_FIELD_LIST - | RECORD_EXPR_FIELD - | MATCH_ARM_LIST - | MATCH_ARM - | IDENT_PAT - | REST_PAT - | RECORD_PAT_FIELD => true, - _ => false, - } + | SOURCE_FILE + | CONST + | ENUM + | EXTERN_BLOCK + | EXTERN_CRATE + | FN + | IMPL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + | ITEM_LIST + | BLOCK_EXPR + | SELF_PARAM + | PARAM + | RECORD_FIELD + | TUPLE_FIELD + | VARIANT + | ASSOC_ITEM_LIST + | EXTERN_ITEM_LIST + | CONST_PARAM + | LIFETIME_PARAM + | TYPE_PARAM + | LET_STMT + | ARRAY_EXPR + | AWAIT_EXPR + | BIN_EXPR + | BOX_EXPR + | BREAK_EXPR + | CALL_EXPR + | CAST_EXPR + | CLOSURE_EXPR + | CONTINUE_EXPR + | FIELD_EXPR + | FOR_EXPR + | IF_EXPR + | INDEX_EXPR + | LITERAL + | LOOP_EXPR + | MATCH_EXPR + | METHOD_CALL_EXPR + | PAREN_EXPR + | PATH_EXPR + | PREFIX_EXPR + | RANGE_EXPR + | REF_EXPR + | RETURN_EXPR + | TRY_EXPR + | TUPLE_EXPR + | WHILE_EXPR + | YIELD_EXPR + | LET_EXPR + | UNDERSCORE_EXPR + | STMT_LIST + | RECORD_EXPR_FIELD_LIST + | RECORD_EXPR_FIELD + | MATCH_ARM_LIST + | MATCH_ARM + | IDENT_PAT + | REST_PAT + | RECORD_PAT_FIELD + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasAttrs { syntax }) @@ -3959,12 +3993,29 @@ impl AnyHasDocComments { } impl AstNode for AnyHasDocComments { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - MACRO_CALL | SOURCE_FILE | CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL - | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION - | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => true, - _ => false, - } + matches!( + kind, + MACRO_CALL + | SOURCE_FILE + | CONST + | ENUM + | EXTERN_BLOCK + | EXTERN_CRATE + | FN + | IMPL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + | RECORD_FIELD + | TUPLE_FIELD + | VARIANT + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasDocComments { syntax }) @@ -3979,10 +4030,7 @@ impl AnyHasGenericParams { } impl AstNode for AnyHasGenericParams { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION => true, - _ => false, - } + matches!(kind, ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasGenericParams { syntax }) @@ -3996,12 +4044,7 @@ impl AnyHasLoopBody { } } impl AstNode for AnyHasLoopBody { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - FOR_EXPR | LOOP_EXPR | WHILE_EXPR => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FOR_EXPR | LOOP_EXPR | WHILE_EXPR) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasLoopBody { syntax }) } @@ -4014,12 +4057,7 @@ impl AnyHasModuleItem { } } impl AstNode for AnyHasModuleItem { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, MACRO_ITEMS | SOURCE_FILE | ITEM_LIST) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasModuleItem { syntax }) } @@ -4033,12 +4071,27 @@ impl AnyHasName { } impl AstNode for AnyHasName { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST | ENUM | FN | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT - | TYPE_ALIAS | UNION | RENAME | SELF_PARAM | RECORD_FIELD | VARIANT | CONST_PARAM - | TYPE_PARAM | IDENT_PAT => true, - _ => false, - } + matches!( + kind, + CONST + | ENUM + | FN + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | RENAME + | SELF_PARAM + | RECORD_FIELD + | VARIANT + | CONST_PARAM + | TYPE_PARAM + | IDENT_PAT + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasName { syntax }) @@ -4053,10 +4106,10 @@ impl AnyHasTypeBounds { } impl AstNode for AnyHasTypeBounds { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED => true, - _ => false, - } + matches!( + kind, + ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasTypeBounds { syntax }) @@ -4071,13 +4124,26 @@ impl AnyHasVisibility { } impl AstNode for AnyHasVisibility { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST | ENUM | EXTERN_CRATE | FN | IMPL | MACRO_RULES | MACRO_DEF | MODULE | STATIC - | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => { - true - } - _ => false, - } + matches!( + kind, + CONST + | ENUM + | EXTERN_CRATE + | FN + | IMPL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + | RECORD_FIELD + | TUPLE_FIELD + | VARIANT + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasVisibility { syntax }) From 1883d1f14146959cfa9cdf1ed43e5d1ad013e07e Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sun, 7 Aug 2022 20:39:11 +0530 Subject: [PATCH 0097/2442] activate assoc item test --- crates/ide-diagnostics/src/handlers/inactive_code.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ide-diagnostics/src/handlers/inactive_code.rs b/crates/ide-diagnostics/src/handlers/inactive_code.rs index 97ea5c456a63..6715823f1ffb 100644 --- a/crates/ide-diagnostics/src/handlers/inactive_code.rs +++ b/crates/ide-diagnostics/src/handlers/inactive_code.rs @@ -112,12 +112,12 @@ fn f() { struct Foo; impl Foo { #[cfg(any())] pub fn f() {} - //*************************** weak: code is inactive due to #[cfg] directives + //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives } trait Bar { #[cfg(any())] pub fn f() {} - //*************************** weak: code is inactive due to #[cfg] directives + //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives } "#, ); From 4b648d8f6cfb9f58490a70e4539aa36c89b9d35e Mon Sep 17 00:00:00 2001 From: Jake Heinz Date: Mon, 8 Aug 2022 00:20:17 +0000 Subject: [PATCH 0098/2442] [code] make toggleInlayHints understand {off,on}UntilPressed --- editors/code/src/commands.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index bf55329ca1f5..1b793bb0b15c 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -326,8 +326,22 @@ export function toggleInlayHints(_ctx: Ctx): Cmd { const config = vscode.workspace.getConfiguration("editor.inlayHints", { languageId: "rust", }); - const value = !config.get("enabled"); - await config.update("enabled", value, vscode.ConfigurationTarget.Global); + + const value = config.get("enabled"); + let stringValue; + if (typeof value === "string") { + stringValue = value; + } else { + stringValue = value ? "on" : "off"; + } + const nextValues: Record = { + on: "off", + off: "on", + onUnlessPressed: "offUnlessPressed", + offUnlessPressed: "onUnlessPressed", + }; + const nextValue = nextValues[stringValue] ?? "on"; + await config.update("enabled", nextValue, vscode.ConfigurationTarget.Global); }; } From 196f389a708d5e0002a1d3b4e1059d43dc4542fb Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Mon, 8 Aug 2022 16:40:29 +0530 Subject: [PATCH 0099/2442] try adding diagnostrics for AssocItems --- crates/hir-def/src/data.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 35c8708955a7..1b4f4ed04ac1 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -2,7 +2,7 @@ use std::sync::Arc; -use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, MacroCallId, MacroDefKind}; +use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, MacroCallId, MacroDefKind, InFile}; use smallvec::SmallVec; use syntax::ast; @@ -12,7 +12,7 @@ use crate::{ db::DefDatabase, intern::Interned, item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId}, - nameres::{attr_resolution::ResolvedAttr, proc_macro::ProcMacroKind, DefMap}, + nameres::{attr_resolution::ResolvedAttr, proc_macro::ProcMacroKind, DefMap, diagnostics::DefDiagnostic}, type_ref::{TraitRef, TypeBound, TypeRef}, visibility::RawVisibility, AssocItemId, AstIdWithPath, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, @@ -479,6 +479,13 @@ impl<'a> AssocItemCollector<'a> { 'items: for &item in assoc_items { let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into()); if !attrs.is_cfg_enabled(self.expander.cfg_options()) { + self.def_map.push_diagnostic(DefDiagnostic::unconfigured_code( + self.module_id.local_id, + InFile::new(tree_id.file_id(), item.ast_id(&item_tree).upcast()), + attrs.cfg().unwrap(), + self.expander.cfg_options().clone() + )); + dbg!("Ignoring assoc item!"); continue; } From c1eae3d0281e1e34f64332b02a7dc4bdd0ae6e5b Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Mon, 8 Aug 2022 16:45:27 +0530 Subject: [PATCH 0100/2442] make diagnostic function public --- crates/hir-def/src/nameres.rs | 8 ++++++++ crates/hir-def/src/nameres/diagnostics.rs | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 45f631936d2a..a2181a6bf41c 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -511,6 +511,14 @@ impl DefMap { self.diagnostics.as_slice() } + pub fn push_diagnostic(&mut self, d: DefDiagnostic) { + self.diagnostics.push(d) + } + + pub fn push_diagnostics(&mut self, i: impl Iterator) { + self.diagnostics.extend(i) + } + pub fn recursion_limit(&self) -> Option { self.recursion_limit } diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index 0d01f6d0aba3..ed7e920fd2b8 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -73,7 +73,7 @@ impl DefDiagnostic { Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } } } - pub(super) fn unconfigured_code( + pub fn unconfigured_code( container: LocalModuleId, ast: AstId, cfg: CfgExpr, From b14062aaecfe11978a5525824567e8011526aeb2 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Tue, 9 Aug 2022 00:00:22 +0900 Subject: [PATCH 0101/2442] Parse range patterns in let statement with type annotation --- crates/parser/src/grammar/patterns.rs | 9 ++++++-- .../inline/ok/0166_half_open_range_pat.rast | 23 +++++++++++++++++-- .../inline/ok/0166_half_open_range_pat.rs | 5 +++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs index bfa41c686e5c..7e21a808da0a 100644 --- a/crates/parser/src/grammar/patterns.rs +++ b/crates/parser/src/grammar/patterns.rs @@ -103,6 +103,8 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) { // ^ // `let 0 .. =` // ^ + // `let 0..: _ =` + // ^ // (1.., _) // ^ // `Some(0 .. )` @@ -111,9 +113,12 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) { // ^ // `[0..]` // ^ - if p.at(T![=]) | p.at(T![')']) | p.at(T![,]) | p.at(T!['}']) | p.at(T![']']) { + if matches!(p.current(), T![=] | T![,] | T![:] | T![')'] | T!['}'] | T![']']) { // test half_open_range_pat - // fn f() { let 0 .. = 1u32; } + // fn f() { + // let 0 .. = 1u32; + // let 0..: _ = 1u32; + // } } else { atom_pat(p, recovery_set); } diff --git a/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast b/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast index 3d3587a70633..4b401b60df0c 100644 --- a/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast +++ b/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast @@ -11,7 +11,7 @@ SOURCE_FILE BLOCK_EXPR STMT_LIST L_CURLY "{" - WHITESPACE " " + WHITESPACE "\n " LET_STMT LET_KW "let" WHITESPACE " " @@ -27,6 +27,25 @@ SOURCE_FILE LITERAL INT_NUMBER "1u32" SEMICOLON ";" - WHITESPACE " " + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + RANGE_PAT + LITERAL_PAT + LITERAL + INT_NUMBER "0" + DOT2 ".." + COLON ":" + WHITESPACE " " + INFER_TYPE + UNDERSCORE "_" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "1u32" + SEMICOLON ";" + WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs b/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs index 1360eda05658..c9386a221a95 100644 --- a/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs +++ b/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs @@ -1 +1,4 @@ -fn f() { let 0 .. = 1u32; } +fn f() { + let 0 .. = 1u32; + let 0..: _ = 1u32; +} From e39918f553d7dd5fb5afd6517f80d3e35290c4d2 Mon Sep 17 00:00:00 2001 From: fprasx Date: Mon, 8 Aug 2022 11:05:18 -0400 Subject: [PATCH 0102/2442] Corrected order of printing op and `=` --- crates/syntax/src/ast/operators.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/syntax/src/ast/operators.rs b/crates/syntax/src/ast/operators.rs index a687ba0b77a5..8f7b3fb60087 100644 --- a/crates/syntax/src/ast/operators.rs +++ b/crates/syntax/src/ast/operators.rs @@ -111,10 +111,10 @@ impl fmt::Display for BinaryOp { BinaryOp::ArithOp(op) => fmt::Display::fmt(op, f), BinaryOp::CmpOp(op) => fmt::Display::fmt(op, f), BinaryOp::Assignment { op } => { - f.write_str("=")?; if let Some(op) = op { fmt::Display::fmt(op, f)?; } + f.write_str("=")?; Ok(()) } } From 232176b46af3955e20997eb4ffb5e77fefde0ed5 Mon Sep 17 00:00:00 2001 From: KaDiWa Date: Tue, 9 Aug 2022 01:16:32 +0200 Subject: [PATCH 0103/2442] remove imports that are also in edition 2021's prelude --- crates/base-db/src/input.rs | 2 +- crates/hir-ty/src/consteval.rs | 1 - crates/ide-db/src/search.rs | 2 +- crates/ide/src/goto_definition.rs | 2 +- crates/ide/src/status.rs | 2 +- crates/proc-macro-api/src/msg/flat.rs | 5 +---- crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs | 4 ++-- crates/proc-macro-srv/src/abis/abi_1_58/ra_server.rs | 1 - crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs | 4 ++-- crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs | 1 - crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs | 4 ++-- crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs | 1 - crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs | 2 +- crates/proc-macro-srv/src/dylib.rs | 1 - crates/rust-analyzer/src/diagnostics/to_proto.rs | 2 +- crates/rust-analyzer/src/to_proto.rs | 2 +- crates/syntax/src/fuzz.rs | 5 +---- lib/la-arena/src/lib.rs | 1 - 18 files changed, 15 insertions(+), 27 deletions(-) diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 9b5a10acfbea..9580ce8007c7 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -6,7 +6,7 @@ //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how //! actual IO is done and lowered to input. -use std::{fmt, iter::FromIterator, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc}; +use std::{fmt, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc}; use cfg::CfgOptions; use rustc_hash::{FxHashMap, FxHashSet}; diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 0495a4e64cac..6ecb6e6fd173 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -2,7 +2,6 @@ use std::{ collections::HashMap, - convert::TryInto, fmt::{Display, Write}, }; diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index bd038cdaa068..9eaabeec7a4e 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -4,7 +4,7 @@ //! get a super-set of matches. Then, we we confirm each match using precise //! name resolution. -use std::{convert::TryInto, mem, sync::Arc}; +use std::{mem, sync::Arc}; use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility}; diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index b2123b9a8793..d6cd5783f05e 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -1,4 +1,4 @@ -use std::{convert::TryInto, mem::discriminant}; +use std::mem::discriminant; use crate::{doc_links::token_as_doc_comment, FilePosition, NavigationTarget, RangeInfo, TryToNav}; use hir::{AsAssocItem, AssocItem, Semantics}; diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index 32e39f82a0e9..f4d0387440d4 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs @@ -1,4 +1,4 @@ -use std::{fmt, iter::FromIterator, sync::Arc}; +use std::{fmt, sync::Arc}; use hir::{ExpandResult, MacroFile}; use ide_db::base_db::{ diff --git a/crates/proc-macro-api/src/msg/flat.rs b/crates/proc-macro-api/src/msg/flat.rs index 8437444e183a..268a03bb5359 100644 --- a/crates/proc-macro-api/src/msg/flat.rs +++ b/crates/proc-macro-api/src/msg/flat.rs @@ -35,10 +35,7 @@ //! as we don't have bincode in Cargo.toml yet, lets stick with serde_json for //! the time being. -use std::{ - collections::{HashMap, VecDeque}, - convert::TryInto, -}; +use std::collections::{HashMap, VecDeque}; use serde::{Deserialize, Serialize}; use tt::TokenId; diff --git a/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs b/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs index 4a07f22779e6..a405497f3c9b 100644 --- a/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs +++ b/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs @@ -157,7 +157,7 @@ impl From for TokenStream { } /// Collects a number of token trees into a single stream. -impl iter::FromIterator for TokenStream { +impl FromIterator for TokenStream { fn from_iter>(trees: I) -> Self { trees.into_iter().map(TokenStream::from).collect() } @@ -165,7 +165,7 @@ impl iter::FromIterator for TokenStream { /// A "flattening" operation on token streams, collects token trees /// from multiple token streams into a single stream. -impl iter::FromIterator for TokenStream { +impl FromIterator for TokenStream { fn from_iter>(streams: I) -> Self { let mut builder = bridge::client::TokenStreamBuilder::new(); streams.into_iter().for_each(|stream| builder.push(stream.0)); diff --git a/crates/proc-macro-srv/src/abis/abi_1_58/ra_server.rs b/crates/proc-macro-srv/src/abis/abi_1_58/ra_server.rs index ebdfca00d735..b1e982f4779f 100644 --- a/crates/proc-macro-srv/src/abis/abi_1_58/ra_server.rs +++ b/crates/proc-macro-srv/src/abis/abi_1_58/ra_server.rs @@ -12,7 +12,6 @@ use super::proc_macro::bridge::{self, server}; use std::collections::HashMap; use std::hash::Hash; -use std::iter::FromIterator; use std::ops::Bound; use std::{ascii, vec::IntoIter}; diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs index c50a16bf4d1d..7ab1f421daf8 100644 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs +++ b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs @@ -207,7 +207,7 @@ impl ConcatStreamsHelper { } /// Collects a number of token trees into a single stream. -impl iter::FromIterator for TokenStream { +impl FromIterator for TokenStream { fn from_iter>(trees: I) -> Self { trees.into_iter().map(TokenStream::from).collect() } @@ -215,7 +215,7 @@ impl iter::FromIterator for TokenStream { /// A "flattening" operation on token streams, collects token trees /// from multiple token streams into a single stream. -impl iter::FromIterator for TokenStream { +impl FromIterator for TokenStream { fn from_iter>(streams: I) -> Self { let iter = streams.into_iter(); let mut builder = ConcatStreamsHelper::new(iter.size_hint().0); diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs b/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs index 05a565fbf343..ed49cc759660 100644 --- a/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs +++ b/crates/proc-macro-srv/src/abis/abi_1_63/ra_server.rs @@ -12,7 +12,6 @@ use super::proc_macro::bridge::{self, server}; use std::collections::HashMap; use std::hash::Hash; -use std::iter::FromIterator; use std::ops::Bound; use std::{ascii, vec::IntoIter}; diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs index be62c73ef32b..86a59b645590 100644 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs +++ b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs @@ -207,7 +207,7 @@ impl ConcatStreamsHelper { } /// Collects a number of token trees into a single stream. -impl iter::FromIterator for TokenStream { +impl FromIterator for TokenStream { fn from_iter>(trees: I) -> Self { trees.into_iter().map(TokenStream::from).collect() } @@ -215,7 +215,7 @@ impl iter::FromIterator for TokenStream { /// A "flattening" operation on token streams, collects token trees /// from multiple token streams into a single stream. -impl iter::FromIterator for TokenStream { +impl FromIterator for TokenStream { fn from_iter>(streams: I) -> Self { let iter = streams.into_iter(); let mut builder = ConcatStreamsHelper::new(iter.size_hint().0); diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs b/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs index 7e8e67856e9f..d8aa1ec429a7 100644 --- a/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs +++ b/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs @@ -12,7 +12,6 @@ use super::proc_macro::bridge::{self, server}; use std::collections::HashMap; use std::hash::Hash; -use std::iter::FromIterator; use std::ops::Bound; use std::{ascii, vec::IntoIter}; diff --git a/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs b/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs index 46882845a807..52eb7ce17d6a 100644 --- a/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs +++ b/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs @@ -20,7 +20,7 @@ use token_stream::TokenStreamBuilder; mod symbol; pub use symbol::*; -use std::{iter::FromIterator, ops::Bound}; +use std::ops::Bound; type Group = tt::Subtree; type TokenTree = tt::TokenTree; diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs index 2b6c070fece3..7aba74e5396d 100644 --- a/crates/proc-macro-srv/src/dylib.rs +++ b/crates/proc-macro-srv/src/dylib.rs @@ -1,7 +1,6 @@ //! Handles dynamic library loading for proc macro use std::{ - convert::TryInto, fmt, fs::File, io, diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index cff4bd7f66ac..74689fd8757f 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -512,7 +512,7 @@ fn clippy_code_description(code: Option<&str>) -> Option Date: Mon, 8 Aug 2022 20:20:45 -0400 Subject: [PATCH 0104/2442] Implement IntoFuture type inference --- crates/hir-expand/src/mod_path.rs | 1 + crates/hir-expand/src/name.rs | 2 + crates/hir-ty/src/infer.rs | 5 ++- crates/hir-ty/src/tests/traits.rs | 25 +++++++++++ crates/hir/src/lib.rs | 2 + crates/hir/src/source_analyzer.rs | 2 + crates/ide-assists/src/utils/suggest_name.rs | 1 + .../ide-completion/src/completions/keyword.rs | 44 ++++++++++--------- crates/test-utils/src/minicore.rs | 15 +++++++ 9 files changed, 75 insertions(+), 22 deletions(-) diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs index fea09521e87c..9ddafe018107 100644 --- a/crates/hir-expand/src/mod_path.rs +++ b/crates/hir-expand/src/mod_path.rs @@ -257,6 +257,7 @@ macro_rules! __known_path { (core::ops::RangeToInclusive) => {}; (core::ops::RangeInclusive) => {}; (core::future::Future) => {}; + (core::future::IntoFuture) => {}; (core::ops::Try) => {}; ($path:path) => { compile_error!("Please register your known path in the path module") diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 47d191822d84..757db79db4db 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -258,6 +258,7 @@ pub mod known { Try, Ok, Future, + IntoFuture, Result, Option, Output, @@ -391,6 +392,7 @@ pub mod known { future_trait, index, index_mut, + into_future, mul_assign, mul, neg, diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 46eeea0e6fc4..95a7229e8795 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -875,7 +875,10 @@ impl<'a> InferenceContext<'a> { } fn resolve_future_future_output(&self) -> Option { - let trait_ = self.resolve_lang_item(name![future_trait])?.as_trait()?; + let trait_ = self + .resolver + .resolve_known_trait(self.db.upcast(), &path![core::future::IntoFuture]) + .or_else(|| self.resolve_lang_item(name![future_trait])?.as_trait())?; self.db.trait_data(trait_).associated_type_by_name(&name![Output]) } diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 75802a5eb4db..730ebe2357d1 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -137,6 +137,31 @@ fn not_send() -> Box + 'static> { ); } +#[test] +fn into_future_trait() { + check_types( + r#" +//- minicore: future +struct Futurable; +impl core::future::IntoFuture for Futurable { + type Output = u64; + type IntoFuture = IntFuture; +} + +struct IntFuture; +impl core::future::Future for IntFuture { + type Output = u64; +} + +fn test() { + let r = Futurable; + let v = r.await; + v; +} //^ u64 +"#, + ); +} + #[test] fn infer_try() { check_types( diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8f984210e117..800ea58ba292 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2780,6 +2780,8 @@ impl Type { /// Checks that particular type `ty` implements `std::future::Future`. /// This function is used in `.await` syntax completion. pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { + // FIXME: This should be checking for IntoFuture trait, but I don't know how to find the + // right TraitId in this crate. let std_future_trait = db .lang_item(self.env.krate, SmolStr::new_inline("future_trait")) .and_then(|it| it.as_trait()); diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index f5e2e4430709..756772cf84e5 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -269,6 +269,8 @@ impl SourceAnalyzer { db: &dyn HirDatabase, await_expr: &ast::AwaitExpr, ) -> Option { + // FIXME This should be pointing to the poll of IntoFuture::Output's Future impl, but I + // don't know how to resolve the Output type so that we can query for its poll method. let ty = self.ty_of_expr(db, &await_expr.expr()?.into())?; let op_fn = db diff --git a/crates/ide-assists/src/utils/suggest_name.rs b/crates/ide-assists/src/utils/suggest_name.rs index 779cdbc93c54..68d59daef485 100644 --- a/crates/ide-assists/src/utils/suggest_name.rs +++ b/crates/ide-assists/src/utils/suggest_name.rs @@ -55,6 +55,7 @@ const USELESS_METHODS: &[&str] = &[ "iter", "into_iter", "iter_mut", + "into_future", ]; pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr { diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs index 3989a451bde4..032b23725f82 100644 --- a/crates/ide-completion/src/completions/keyword.rs +++ b/crates/ide-completion/src/completions/keyword.rs @@ -75,16 +75,17 @@ impl Future for A {} fn foo(a: A) { a.$0 } "#, expect![[r#" - kw await expr.await - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr + kw await expr.await + me into_future() (as IntoFuture) fn(self) -> ::IntoFuture + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr "#]], ); @@ -98,18 +99,19 @@ fn foo() { } "#, expect![[r#" - kw await expr.await - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr + kw await expr.await + me into_future() (use core::future::IntoFuture) fn(self) -> ::IntoFuture + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr "#]], - ) + ); } #[test] diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index f48d1ec66aae..6df29db4745d 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -471,6 +471,21 @@ pub mod future { #[lang = "poll"] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } + + pub trait IntoFuture { + type Output; + type IntoFuture: Future; + #[lang = "into_future"] + fn into_future(self) -> Self::IntoFuture; + } + + impl IntoFuture for F { + type Output = F::Output; + type IntoFuture = F; + fn into_future(self) -> F { + self + } + } } pub mod task { pub enum Poll { From 950de7c3c355398a9c15812b74376e252cb176db Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 9 Aug 2022 14:31:17 +0200 Subject: [PATCH 0105/2442] Use `--keep-going` cargo flag when building build scripts --- crates/project-model/src/build_scripts.rs | 15 +++++++++++++-- crates/project-model/src/tests.rs | 1 + crates/project-model/src/workspace.rs | 18 ++++++++++++++---- crates/rust-analyzer/src/reload.rs | 1 + 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index ee7f8339a76a..4b00479a4c9c 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -12,6 +12,7 @@ use cargo_metadata::{camino::Utf8Path, Message}; use la_arena::ArenaMap; use paths::AbsPathBuf; use rustc_hash::FxHashMap; +use semver::Version; use serde::Deserialize; use crate::{cfg_flag::CfgFlag, CargoConfig, CargoWorkspace, Package}; @@ -38,7 +39,7 @@ pub(crate) struct BuildScriptOutput { } impl WorkspaceBuildScripts { - fn build_command(config: &CargoConfig) -> Command { + fn build_command(config: &CargoConfig, toolchain: &Option) -> Command { if let Some([program, args @ ..]) = config.run_build_script_command.as_deref() { let mut cmd = Command::new(program); cmd.args(args); @@ -70,6 +71,15 @@ impl WorkspaceBuildScripts { } } + const RUST_1_62: Version = Version::new(1, 62, 0); + + match toolchain { + Some(v) if v >= &RUST_1_62 => { + cmd.args(&["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1"); + } + _ => (), + } + cmd } @@ -77,8 +87,9 @@ impl WorkspaceBuildScripts { config: &CargoConfig, workspace: &CargoWorkspace, progress: &dyn Fn(String), + toolchain: &Option, ) -> io::Result { - let mut cmd = Self::build_command(config); + let mut cmd = Self::build_command(config, toolchain); if config.wrap_rustc_in_build_scripts { // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index e304a59c0180..8d0fa757c2e1 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -28,6 +28,7 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGr rustc: None, rustc_cfg: Vec::new(), cfg_overrides, + toolchain: None, }; to_crate_graph(project_workspace) } diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index b144006b44e0..daabb299f76c 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -12,6 +12,7 @@ use base_db::{ use cfg::{CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; +use semver::Version; use stdx::always; use crate::{ @@ -77,6 +78,7 @@ pub enum ProjectWorkspace { /// different target. rustc_cfg: Vec, cfg_overrides: CfgOverrides, + toolchain: Option, }, /// Project workspace was manually specified using a `rust-project.json` file. Json { project: ProjectJson, sysroot: Option, rustc_cfg: Vec }, @@ -105,6 +107,7 @@ impl fmt::Debug for ProjectWorkspace { rustc, rustc_cfg, cfg_overrides, + toolchain, } => f .debug_struct("Cargo") .field("root", &cargo.workspace_root().file_name()) @@ -116,6 +119,7 @@ impl fmt::Debug for ProjectWorkspace { ) .field("n_rustc_cfg", &rustc_cfg.len()) .field("n_cfg_overrides", &cfg_overrides.len()) + .field("toolchain", &toolchain) .finish(), ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { let mut debug_struct = f.debug_struct("Json"); @@ -160,6 +164,9 @@ impl ProjectWorkspace { cmd.arg("--version"); cmd })?; + let toolchain = cargo_version + .get("cargo ".len()..) + .and_then(|it| Version::parse(it.split_whitespace().next()?).ok()); let meta = CargoWorkspace::fetch_metadata( &cargo_toml, @@ -169,9 +176,9 @@ impl ProjectWorkspace { ) .with_context(|| { format!( - "Failed to read Cargo metadata from Cargo.toml file {}, {}", + "Failed to read Cargo metadata from Cargo.toml file {}, {:?}", cargo_toml.display(), - cargo_version + toolchain ) })?; let cargo = CargoWorkspace::new(meta); @@ -219,6 +226,7 @@ impl ProjectWorkspace { rustc, rustc_cfg, cfg_overrides, + toolchain, } } }; @@ -271,8 +279,8 @@ impl ProjectWorkspace { progress: &dyn Fn(String), ) -> Result { match self { - ProjectWorkspace::Cargo { cargo, .. } => { - WorkspaceBuildScripts::run(config, cargo, progress).with_context(|| { + ProjectWorkspace::Cargo { cargo, toolchain, .. } => { + WorkspaceBuildScripts::run(config, cargo, progress, toolchain).with_context(|| { format!("Failed to run build scripts for {}", &cargo.workspace_root().display()) }) } @@ -320,6 +328,7 @@ impl ProjectWorkspace { rustc_cfg: _, cfg_overrides: _, build_scripts, + toolchain: _, } => { cargo .packages() @@ -425,6 +434,7 @@ impl ProjectWorkspace { rustc_cfg, cfg_overrides, build_scripts, + toolchain: _, } => cargo_to_crate_graph( rustc_cfg.clone(), cfg_overrides, diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 49ccad71a10e..ceb2a6d703d9 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -219,6 +219,7 @@ impl GlobalState { cfg_overrides, build_scripts: _, + toolchain: _, } => Some((cargo, sysroot, rustc, rustc_cfg, cfg_overrides)), _ => None, }; From 8c9359b072098403eb0b37a1b0822bb7b4f3b8ba Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 9 Aug 2022 17:53:16 +0200 Subject: [PATCH 0106/2442] Fix pattern field completions not working for unions --- crates/ide-completion/src/completions.rs | 1 - crates/ide-completion/src/completions/expr.rs | 116 ++++++++++-------- .../ide-completion/src/completions/record.rs | 47 ++++--- crates/ide-completion/src/context.rs | 1 + crates/ide-completion/src/tests/record.rs | 91 ++++++++------ 5 files changed, 140 insertions(+), 116 deletions(-) diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index 72579e6026ae..55c3e28392a4 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -617,7 +617,6 @@ pub(super) fn complete_name_ref( dot::complete_undotted_self(acc, ctx, path_ctx, expr_ctx); item_list::complete_item_list_in_expr(acc, ctx, path_ctx, expr_ctx); - record::complete_record_expr_func_update(acc, ctx, path_ctx, expr_ctx); snippet::complete_expr_snippet(acc, ctx, path_ctx, expr_ctx); } PathKind::Type { location } => { diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index 5d0ddaaf2a22..e6c4bdf5206c 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -1,8 +1,10 @@ //! Completion of names from the current scope in expression position. use hir::ScopeDef; +use syntax::ast; use crate::{ + completions::record::add_default_update, context::{ExprCtx, PathCompletionCtx, Qualified}, CompletionContext, Completions, }; @@ -219,60 +221,76 @@ pub(crate) fn complete_expr_path( _ => (), }); - if is_func_update.is_none() { - let mut add_keyword = - |kw, snippet| acc.add_keyword_snippet_expr(ctx, incomplete_let, kw, snippet); + match is_func_update { + Some(record_expr) => { + let ty = ctx.sema.type_of_expr(&ast::Expr::RecordExpr(record_expr.clone())); - if !in_block_expr { - add_keyword("unsafe", "unsafe {\n $0\n}"); + match ty.as_ref().and_then(|t| t.original.as_adt()) { + Some(hir::Adt::Union(_)) => (), + _ => { + cov_mark::hit!(functional_update); + let missing_fields = + ctx.sema.record_literal_missing_fields(record_expr); + add_default_update(acc, ctx, ty, &missing_fields); + } + }; } - add_keyword("match", "match $1 {\n $0\n}"); - add_keyword("while", "while $1 {\n $0\n}"); - add_keyword("while let", "while let $1 = $2 {\n $0\n}"); - add_keyword("loop", "loop {\n $0\n}"); - if in_match_guard { - add_keyword("if", "if $0"); - } else { - add_keyword("if", "if $1 {\n $0\n}"); - } - add_keyword("if let", "if let $1 = $2 {\n $0\n}"); - add_keyword("for", "for $1 in $2 {\n $0\n}"); - add_keyword("true", "true"); - add_keyword("false", "false"); + None => { + let mut add_keyword = |kw, snippet| { + acc.add_keyword_snippet_expr(ctx, incomplete_let, kw, snippet) + }; - if in_condition || in_block_expr { - add_keyword("let", "let"); - } - - if after_if_expr { - add_keyword("else", "else {\n $0\n}"); - add_keyword("else if", "else if $1 {\n $0\n}"); - } - - if wants_mut_token { - add_keyword("mut", "mut "); - } - - if in_loop_body { - if in_block_expr { - add_keyword("continue", "continue;"); - add_keyword("break", "break;"); - } else { - add_keyword("continue", "continue"); - add_keyword("break", "break"); + if !in_block_expr { + add_keyword("unsafe", "unsafe {\n $0\n}"); } - } + add_keyword("match", "match $1 {\n $0\n}"); + add_keyword("while", "while $1 {\n $0\n}"); + add_keyword("while let", "while let $1 = $2 {\n $0\n}"); + add_keyword("loop", "loop {\n $0\n}"); + if in_match_guard { + add_keyword("if", "if $0"); + } else { + add_keyword("if", "if $1 {\n $0\n}"); + } + add_keyword("if let", "if let $1 = $2 {\n $0\n}"); + add_keyword("for", "for $1 in $2 {\n $0\n}"); + add_keyword("true", "true"); + add_keyword("false", "false"); - if let Some(ty) = innermost_ret_ty { - add_keyword( - "return", - match (in_block_expr, ty.is_unit()) { - (true, true) => "return ;", - (true, false) => "return;", - (false, true) => "return $0", - (false, false) => "return", - }, - ); + if in_condition || in_block_expr { + add_keyword("let", "let"); + } + + if after_if_expr { + add_keyword("else", "else {\n $0\n}"); + add_keyword("else if", "else if $1 {\n $0\n}"); + } + + if wants_mut_token { + add_keyword("mut", "mut "); + } + + if in_loop_body { + if in_block_expr { + add_keyword("continue", "continue;"); + add_keyword("break", "break;"); + } else { + add_keyword("continue", "continue"); + add_keyword("break", "break"); + } + } + + if let Some(ty) = innermost_ret_ty { + add_keyword( + "return", + match (in_block_expr, ty.is_unit()) { + (true, true) => "return ;", + (true, false) => "return;", + (false, true) => "return $0", + (false, false) => "return", + }, + ); + } } } } diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs index 1c9042390d3b..3f85b45a13cb 100644 --- a/crates/ide-completion/src/completions/record.rs +++ b/crates/ide-completion/src/completions/record.rs @@ -3,7 +3,7 @@ use ide_db::SymbolKind; use syntax::ast::{self, Expr}; use crate::{ - context::{DotAccess, DotAccessKind, ExprCtx, PathCompletionCtx, PatternContext, Qualified}, + context::{DotAccess, DotAccessKind, PatternContext}, CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch, Completions, }; @@ -14,7 +14,24 @@ pub(crate) fn complete_record_pattern_fields( pattern_ctx: &PatternContext, ) { if let PatternContext { record_pat: Some(record_pat), .. } = pattern_ctx { - complete_fields(acc, ctx, ctx.sema.record_pattern_missing_fields(record_pat)); + let ty = ctx.sema.type_of_pat(&ast::Pat::RecordPat(record_pat.clone())); + let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) { + Some(hir::Adt::Union(un)) => { + // ctx.sema.record_pat_missing_fields will always return + // an empty Vec on a union literal. This is normally + // reasonable, but here we'd like to present the full list + // of fields if the literal is empty. + let were_fields_specified = + record_pat.record_pat_field_list().and_then(|fl| fl.fields().next()).is_some(); + + match were_fields_specified { + false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(), + true => return, + } + } + _ => ctx.sema.record_pattern_missing_fields(record_pat), + }; + complete_fields(acc, ctx, missing_fields); } } @@ -44,6 +61,7 @@ pub(crate) fn complete_record_expr_fields( let missing_fields = ctx.sema.record_literal_missing_fields(record_expr); add_default_update(acc, ctx, ty, &missing_fields); if dot_prefix { + cov_mark::hit!(functional_update_one_dot); let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), ".."); item.insert_text("."); @@ -56,30 +74,7 @@ pub(crate) fn complete_record_expr_fields( complete_fields(acc, ctx, missing_fields); } -// FIXME: This should probably be part of complete_path_expr -pub(crate) fn complete_record_expr_func_update( - acc: &mut Completions, - ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - expr_ctx: &ExprCtx, -) { - if !matches!(path_ctx.qualified, Qualified::No) { - return; - } - if let ExprCtx { is_func_update: Some(record_expr), .. } = expr_ctx { - let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone())); - - match ty.as_ref().and_then(|t| t.original.as_adt()) { - Some(hir::Adt::Union(_)) => (), - _ => { - let missing_fields = ctx.sema.record_literal_missing_fields(record_expr); - add_default_update(acc, ctx, ty, &missing_fields); - } - }; - } -} - -fn add_default_update( +pub(crate) fn add_default_update( acc: &mut Completions, ctx: &CompletionContext<'_>, ty: Option, diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index e35f79d2b695..759742d34723 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -134,6 +134,7 @@ pub(crate) struct ExprCtx { pub(crate) in_condition: bool, pub(crate) incomplete_let: bool, pub(crate) ref_expr_parent: Option, + /// The surrounding RecordExpression we are completing a functional update pub(crate) is_func_update: Option, pub(crate) self_param: Option, pub(crate) innermost_ret_ty: Option, diff --git a/crates/ide-completion/src/tests/record.rs b/crates/ide-completion/src/tests/record.rs index f6accc68e5e8..e9ee51611796 100644 --- a/crates/ide-completion/src/tests/record.rs +++ b/crates/ide-completion/src/tests/record.rs @@ -103,47 +103,9 @@ fn foo(f: Struct) { } #[test] -fn functional_update() { - // FIXME: This should filter out all completions that do not have the type `Foo` - check( - r#" -//- minicore:default -struct Foo { foo1: u32, foo2: u32 } -impl Default for Foo { - fn default() -> Self { loop {} } -} +fn in_functional_update() { + cov_mark::check!(functional_update); -fn main() { - let thing = 1; - let foo = Foo { foo1: 0, foo2: 0 }; - let foo2 = Foo { thing, $0 } -} -"#, - expect![[r#" - fd ..Default::default() - fd foo1 u32 - fd foo2 u32 - "#]], - ); - check( - r#" -//- minicore:default -struct Foo { foo1: u32, foo2: u32 } -impl Default for Foo { - fn default() -> Self { loop {} } -} - -fn main() { - let thing = 1; - let foo = Foo { foo1: 0, foo2: 0 }; - let foo2 = Foo { thing, .$0 } -} -"#, - expect![[r#" - fd ..Default::default() - sn .. - "#]], - ); check( r#" //- minicore:default @@ -192,6 +154,55 @@ fn main() { ); } +#[test] +fn functional_update_no_dot() { + // FIXME: This should filter out all completions that do not have the type `Foo` + check( + r#" +//- minicore:default +struct Foo { foo1: u32, foo2: u32 } +impl Default for Foo { + fn default() -> Self { loop {} } +} + +fn main() { + let thing = 1; + let foo = Foo { foo1: 0, foo2: 0 }; + let foo2 = Foo { thing, $0 } +} +"#, + expect![[r#" + fd ..Default::default() + fd foo1 u32 + fd foo2 u32 + "#]], + ); +} + +#[test] +fn functional_update_one_dot() { + cov_mark::check!(functional_update_one_dot); + check( + r#" +//- minicore:default +struct Foo { foo1: u32, foo2: u32 } +impl Default for Foo { + fn default() -> Self { loop {} } +} + +fn main() { + let thing = 1; + let foo = Foo { foo1: 0, foo2: 0 }; + let foo2 = Foo { thing, .$0 } +} +"#, + expect![[r#" + fd ..Default::default() + sn .. + "#]], + ); +} + #[test] fn empty_union_literal() { check( From b3ac58dfb80e6dad9fc777f23247fd379424b65e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 9 Aug 2022 18:08:05 +0200 Subject: [PATCH 0107/2442] Add some more `cov_mark`s --- crates/ide-completion/src/completions/expr.rs | 4 +++- crates/ide-completion/src/completions/record.rs | 12 ++++++++---- crates/ide-completion/src/tests/record.rs | 1 + 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index e6c4bdf5206c..4d66af9e8d5b 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -231,7 +231,9 @@ pub(crate) fn complete_expr_path( cov_mark::hit!(functional_update); let missing_fields = ctx.sema.record_literal_missing_fields(record_expr); - add_default_update(acc, ctx, ty, &missing_fields); + if !missing_fields.is_empty() { + add_default_update(acc, ctx, ty); + } } }; } diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs index 3f85b45a13cb..bfb98b9f2777 100644 --- a/crates/ide-completion/src/completions/record.rs +++ b/crates/ide-completion/src/completions/record.rs @@ -59,7 +59,11 @@ pub(crate) fn complete_record_expr_fields( } _ => { let missing_fields = ctx.sema.record_literal_missing_fields(record_expr); - add_default_update(acc, ctx, ty, &missing_fields); + + if !missing_fields.is_empty() { + cov_mark::hit!(functional_update_field); + add_default_update(acc, ctx, ty); + } if dot_prefix { cov_mark::hit!(functional_update_one_dot); let mut item = @@ -78,14 +82,14 @@ pub(crate) fn add_default_update( acc: &mut Completions, ctx: &CompletionContext<'_>, ty: Option, - missing_fields: &[(hir::Field, hir::Type)], ) { let default_trait = ctx.famous_defs().core_default_Default(); - let impl_default_trait = default_trait + let impls_default_trait = default_trait .zip(ty.as_ref()) .map_or(false, |(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[])); - if impl_default_trait && !missing_fields.is_empty() { + if impls_default_trait { // FIXME: This should make use of scope_def like completions so we get all the other goodies + // that is we should handle this like actually completing the default function let completion_text = "..Default::default()"; let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text); let completion_text = diff --git a/crates/ide-completion/src/tests/record.rs b/crates/ide-completion/src/tests/record.rs index e9ee51611796..328faaa060f0 100644 --- a/crates/ide-completion/src/tests/record.rs +++ b/crates/ide-completion/src/tests/record.rs @@ -156,6 +156,7 @@ fn main() { #[test] fn functional_update_no_dot() { + cov_mark::check!(functional_update_field); // FIXME: This should filter out all completions that do not have the type `Foo` check( r#" From 49d24f639f60325000463f6bb20d832c0ac72da6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 9 Aug 2022 18:23:25 +0200 Subject: [PATCH 0108/2442] Recover from missing ellipsis in record literals for path expressions --- crates/parser/src/grammar/expressions.rs | 26 +++++++--- ...ord_literal_missing_ellipsis_recovery.rast | 43 ++++++++++++++++ ...ecord_literal_missing_ellipsis_recovery.rs | 3 ++ .../parser/inline/ok/0061_record_lit.rast | 49 +++++++++++++++++++ .../parser/inline/ok/0061_record_lit.rs | 2 + 5 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rast create mode 100644 crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rs diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs index e7402104eb83..dcaceade652a 100644 --- a/crates/parser/src/grammar/expressions.rs +++ b/crates/parser/src/grammar/expressions.rs @@ -564,8 +564,10 @@ fn path_expr(p: &mut Parser<'_>, r: Restrictions) -> (CompletedMarker, BlockLike // test record_lit // fn foo() { // S {}; +// S { x }; // S { x, y: 32, }; // S { x, y: 32, ..Default::default() }; +// S { x: ::default() }; // TupleStruct { 0: 1 }; // } pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) { @@ -582,16 +584,26 @@ pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) { match p.current() { IDENT | INT_NUMBER => { - // test_err record_literal_before_ellipsis_recovery + // test_err record_literal_missing_ellipsis_recovery // fn main() { - // S { field ..S::default() } + // S { S::default() } // } - if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) { - name_ref_or_index(p); - p.expect(T![:]); + if p.nth_at(1, T![::]) { + m.abandon(p); + p.expect(T![..]); + expr(p); + } else { + // test_err record_literal_before_ellipsis_recovery + // fn main() { + // S { field ..S::default() } + // } + if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) { + name_ref_or_index(p); + p.expect(T![:]); + } + expr(p); + m.complete(p, RECORD_EXPR_FIELD); } - expr(p); - m.complete(p, RECORD_EXPR_FIELD); } T![.] if p.at(T![..]) => { m.abandon(p); diff --git a/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rast b/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rast new file mode 100644 index 000000000000..0c5b618e6f05 --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rast @@ -0,0 +1,43 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "main" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + CALL_EXPR + PATH_EXPR + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" +error 19: expected DOT2 diff --git a/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rs b/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rs new file mode 100644 index 000000000000..1b594e8ab962 --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0014_record_literal_missing_ellipsis_recovery.rs @@ -0,0 +1,3 @@ +fn main() { + S { S::default() } +} diff --git a/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast b/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast index 9997d0ae348c..00948c322f4c 100644 --- a/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast +++ b/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast @@ -24,6 +24,26 @@ SOURCE_FILE R_CURLY "}" SEMICOLON ";" WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_EXPR_FIELD + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + WHITESPACE " " + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n " EXPR_STMT RECORD_EXPR PATH @@ -100,6 +120,35 @@ SOURCE_FILE R_CURLY "}" SEMICOLON ";" WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_EXPR_FIELD + NAME_REF + IDENT "x" + COLON ":" + WHITESPACE " " + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + COLON2 "::" + NAME_REF + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n " EXPR_STMT RECORD_EXPR PATH diff --git a/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs b/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs index 6285e5549772..86411fbb7dc0 100644 --- a/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs +++ b/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs @@ -1,6 +1,8 @@ fn foo() { S {}; + S { x }; S { x, y: 32, }; S { x, y: 32, ..Default::default() }; + S { x: ::default() }; TupleStruct { 0: 1 }; } From dc3219bb11f032e2e6f1d16deab2b5eabe9463d7 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Tue, 9 Aug 2022 16:25:25 -0400 Subject: [PATCH 0109/2442] Suggest `.await` when type impls IntoFuture --- crates/hir/src/lib.rs | 23 +++++++++++----- .../ide-completion/src/completions/keyword.rs | 26 +++++++++++++++++++ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 800ea58ba292..7f16634afe1a 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2780,19 +2780,28 @@ impl Type { /// Checks that particular type `ty` implements `std::future::Future`. /// This function is used in `.await` syntax completion. pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { - // FIXME: This should be checking for IntoFuture trait, but I don't know how to find the - // right TraitId in this crate. - let std_future_trait = db - .lang_item(self.env.krate, SmolStr::new_inline("future_trait")) - .and_then(|it| it.as_trait()); - let std_future_trait = match std_future_trait { + let trait_ = db + .lang_item(self.env.krate, SmolStr::new_inline("into_future")) + .and_then(|it| { + let into_future_fn = it.as_function()?; + let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?; + let into_future_trait = assoc_item.containing_trait_or_trait_impl(db)?; + Some(into_future_trait.id) + }) + .or_else(|| { + let future_trait = + db.lang_item(self.env.krate, SmolStr::new_inline("future_trait"))?; + future_trait.as_trait() + }); + + let trait_ = match trait_ { Some(it) => it, None => return false, }; let canonical_ty = Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), std_future_trait) + method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), trait_) } /// Checks that particular type `ty` implements `std::ops::FnOnce`. diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs index 032b23725f82..1d03c8cc5ca6 100644 --- a/crates/ide-completion/src/completions/keyword.rs +++ b/crates/ide-completion/src/completions/keyword.rs @@ -114,6 +114,32 @@ fn foo() { ); } + #[test] + fn test_completion_await_impls_into_future() { + check( + r#" +//- minicore: future +use core::future::*; +struct A {} +impl IntoFuture for A {} +fn foo(a: A) { a.$0 } +"#, + expect![[r#" + kw await expr.await + me into_future() (as IntoFuture) fn(self) -> ::IntoFuture + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + "#]], + ); + } + #[test] fn let_semi() { cov_mark::check!(let_semi); From f4f70c0e0da9783eb0b935e0c8698a9505c7b45e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 10 Aug 2022 10:49:49 +0300 Subject: [PATCH 0110/2442] Remove incomplete 1.64 ABI --- .../proc-macro-srv/src/abis/abi_1_64/mod.rs | 105 -- .../abis/abi_1_64/proc_macro/bridge/buffer.rs | 156 --- .../abis/abi_1_64/proc_macro/bridge/client.rs | 529 -------- .../abi_1_64/proc_macro/bridge/closure.rs | 32 - .../abis/abi_1_64/proc_macro/bridge/handle.rs | 89 -- .../abis/abi_1_64/proc_macro/bridge/mod.rs | 493 -------- .../abis/abi_1_64/proc_macro/bridge/rpc.rs | 304 ----- .../abi_1_64/proc_macro/bridge/scoped_cell.rs | 81 -- .../proc_macro/bridge/selfless_reify.rs | 84 -- .../abis/abi_1_64/proc_macro/bridge/server.rs | 339 ----- .../abis/abi_1_64/proc_macro/diagnostic.rs | 166 --- .../src/abis/abi_1_64/proc_macro/mod.rs | 1125 ----------------- .../src/abis/abi_1_64/proc_macro/quote.rs | 139 -- .../src/abis/abi_1_64/ra_server.rs | 791 ------------ crates/proc-macro-srv/src/abis/mod.rs | 11 +- 15 files changed, 1 insertion(+), 4443 deletions(-) delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/mod.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/buffer.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/client.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/closure.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/handle.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/mod.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/rpc.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/scoped_cell.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/selfless_reify.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/server.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/diagnostic.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/quote.rs delete mode 100644 crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/mod.rs b/crates/proc-macro-srv/src/abis/abi_1_64/mod.rs deleted file mode 100644 index 9d56f0eaf888..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/mod.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Proc macro ABI. - -#[allow(dead_code)] -#[doc(hidden)] -mod proc_macro; - -#[allow(dead_code)] -#[doc(hidden)] -mod ra_server; - -use libloading::Library; -use proc_macro_api::ProcMacroKind; - -use super::PanicMessage; - -pub use ra_server::TokenStream; - -pub(crate) struct Abi { - exported_macros: Vec, -} - -impl From for PanicMessage { - fn from(p: proc_macro::bridge::PanicMessage) -> Self { - Self { message: p.as_str().map(|s| s.to_string()) } - } -} - -impl Abi { - pub unsafe fn from_lib(lib: &Library, symbol_name: String) -> Result { - let macros: libloading::Symbol<'_, &&[proc_macro::bridge::client::ProcMacro]> = - lib.get(symbol_name.as_bytes())?; - Ok(Self { exported_macros: macros.to_vec() }) - } - - pub fn expand( - &self, - macro_name: &str, - macro_body: &tt::Subtree, - attributes: Option<&tt::Subtree>, - ) -> Result { - let parsed_body = TokenStream::with_subtree(macro_body.clone()); - - let parsed_attributes = - attributes.map_or(TokenStream::new(), |attr| TokenStream::with_subtree(attr.clone())); - - for proc_macro in &self.exported_macros { - match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { - trait_name, client, .. - } if *trait_name == macro_name => { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Bang { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - proc_macro::bridge::client::ProcMacro::Attr { name, client } - if *name == macro_name => - { - let res = client.run( - &proc_macro::bridge::server::SameThread, - ra_server::RustAnalyzer::default(), - parsed_attributes, - parsed_body, - true, - ); - return res.map(|it| it.into_subtree()).map_err(PanicMessage::from); - } - _ => continue, - } - } - - Err(proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()).into()) - } - - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - self.exported_macros - .iter() - .map(|proc_macro| match proc_macro { - proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { - (trait_name.to_string(), ProcMacroKind::CustomDerive) - } - proc_macro::bridge::client::ProcMacro::Bang { name, .. } => { - (name.to_string(), ProcMacroKind::FuncLike) - } - proc_macro::bridge::client::ProcMacro::Attr { name, .. } => { - (name.to_string(), ProcMacroKind::Attr) - } - }) - .collect() - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/buffer.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/buffer.rs deleted file mode 100644 index 48030f8d82dc..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/buffer.rs +++ /dev/null @@ -1,156 +0,0 @@ -//! Buffer management for same-process client<->server communication. - -use std::io::{self, Write}; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::slice; - -#[repr(C)] -pub struct Buffer { - data: *mut u8, - len: usize, - capacity: usize, - reserve: extern "C" fn(Buffer, usize) -> Buffer, - drop: extern "C" fn(Buffer), -} - -unsafe impl Sync for Buffer {} -unsafe impl Send for Buffer {} - -impl Default for Buffer { - #[inline] - fn default() -> Self { - Self::from(vec![]) - } -} - -impl Deref for Buffer { - type Target = [u8]; - #[inline] - fn deref(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.data as *const u8, self.len) } - } -} - -impl DerefMut for Buffer { - #[inline] - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.data, self.len) } - } -} - -impl Buffer { - #[inline] - pub(super) fn new() -> Self { - Self::default() - } - - #[inline] - pub(super) fn clear(&mut self) { - self.len = 0; - } - - #[inline] - pub(super) fn take(&mut self) -> Self { - mem::take(self) - } - - // We have the array method separate from extending from a slice. This is - // because in the case of small arrays, codegen can be more efficient - // (avoiding a memmove call). With extend_from_slice, LLVM at least - // currently is not able to make that optimization. - #[inline] - pub(super) fn extend_from_array(&mut self, xs: &[u8; N]) { - if xs.len() > (self.capacity - self.len) { - let b = self.take(); - *self = (b.reserve)(b, xs.len()); - } - unsafe { - xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); - self.len += xs.len(); - } - } - - #[inline] - pub(super) fn extend_from_slice(&mut self, xs: &[u8]) { - if xs.len() > (self.capacity - self.len) { - let b = self.take(); - *self = (b.reserve)(b, xs.len()); - } - unsafe { - xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); - self.len += xs.len(); - } - } - - #[inline] - pub(super) fn push(&mut self, v: u8) { - // The code here is taken from Vec::push, and we know that reserve() - // will panic if we're exceeding isize::MAX bytes and so there's no need - // to check for overflow. - if self.len == self.capacity { - let b = self.take(); - *self = (b.reserve)(b, 1); - } - unsafe { - *self.data.add(self.len) = v; - self.len += 1; - } - } -} - -impl Write for Buffer { - #[inline] - fn write(&mut self, xs: &[u8]) -> io::Result { - self.extend_from_slice(xs); - Ok(xs.len()) - } - - #[inline] - fn write_all(&mut self, xs: &[u8]) -> io::Result<()> { - self.extend_from_slice(xs); - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Drop for Buffer { - #[inline] - fn drop(&mut self) { - let b = self.take(); - (b.drop)(b); - } -} - -impl From> for Buffer { - fn from(mut v: Vec) -> Self { - let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity()); - mem::forget(v); - - // This utility function is nested in here because it can *only* - // be safely called on `Buffer`s created by *this* `proc_macro`. - fn to_vec(b: Buffer) -> Vec { - unsafe { - let Buffer { data, len, capacity, .. } = b; - mem::forget(b); - Vec::from_raw_parts(data, len, capacity) - } - } - - extern "C" fn reserve(b: Buffer, additional: usize) -> Buffer { - let mut v = to_vec(b); - v.reserve(additional); - Buffer::from(v) - } - - extern "C" fn drop(b: Buffer) { - mem::drop(to_vec(b)); - } - - Buffer { data, len, capacity, reserve, drop } - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/client.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/client.rs deleted file mode 100644 index 22bda8ba5a7c..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/client.rs +++ /dev/null @@ -1,529 +0,0 @@ -//! Client-side types. - -use super::*; - -use std::marker::PhantomData; - -macro_rules! define_handles { - ( - 'owned: $($oty:ident,)* - 'interned: $($ity:ident,)* - ) => { - #[repr(C)] - #[allow(non_snake_case)] - pub struct HandleCounters { - $($oty: AtomicUsize,)* - $($ity: AtomicUsize,)* - } - - impl HandleCounters { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - extern "C" fn get() -> &'static Self { - static COUNTERS: HandleCounters = HandleCounters { - $($oty: AtomicUsize::new(1),)* - $($ity: AtomicUsize::new(1),)* - }; - &COUNTERS - } - } - - // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. - #[repr(C)] - #[allow(non_snake_case)] - pub(super) struct HandleStore { - $($oty: handle::OwnedStore,)* - $($ity: handle::InternedStore,)* - } - - impl HandleStore { - pub(super) fn new(handle_counters: &'static HandleCounters) -> Self { - HandleStore { - $($oty: handle::OwnedStore::new(&handle_counters.$oty),)* - $($ity: handle::InternedStore::new(&handle_counters.$ity),)* - } - } - } - - $( - #[repr(C)] - pub(crate) struct $oty { - handle: handle::Handle, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual - // way of doing this, but that requires unstable features. - // rust-analyzer uses this code and avoids unstable features. - _marker: PhantomData<*mut ()>, - } - - // Forward `Drop::drop` to the inherent `drop` method. - impl Drop for $oty { - fn drop(&mut self) { - $oty { - handle: self.handle, - _marker: PhantomData, - }.drop(); - } - } - - impl Encode for $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - let handle = self.handle; - mem::forget(self); - handle.encode(w, s); - } - } - - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$oty.take(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode for &$oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl<'s, S: server::Types> Decode<'_, 's, HandleStore>> - for &'s Marked - { - fn decode(r: &mut Reader<'_>, s: &'s HandleStore>) -> Self { - &s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode for &mut $oty { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl<'s, S: server::Types> DecodeMut<'_, 's, HandleStore>> - for &'s mut Marked - { - fn decode( - r: &mut Reader<'_>, - s: &'s mut HandleStore> - ) -> Self { - &mut s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$oty.alloc(self).encode(w, s); - } - } - - impl DecodeMut<'_, '_, S> for $oty { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $oty { - handle: handle::Handle::decode(r, s), - _marker: PhantomData, - } - } - } - )* - - $( - #[repr(C)] - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - pub(crate) struct $ity { - handle: handle::Handle, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual - // way of doing this, but that requires unstable features. - // rust-analyzer uses this code and avoids unstable features. - _marker: PhantomData<*mut ()>, - } - - impl Encode for $ity { - fn encode(self, w: &mut Writer, s: &mut S) { - self.handle.encode(w, s); - } - } - - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$ity.copy(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$ity.alloc(self).encode(w, s); - } - } - - impl DecodeMut<'_, '_, S> for $ity { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - $ity { - handle: handle::Handle::decode(r, s), - _marker: PhantomData, - } - } - } - )* - } -} -define_handles! { - 'owned: - FreeFunctions, - TokenStream, - Literal, - SourceFile, - MultiSpan, - Diagnostic, - - 'interned: - Ident, - Span, -} - -// FIXME(eddyb) generate these impls by pattern-matching on the -// names of methods - also could use the presence of `fn drop` -// to distinguish between 'owned and 'interned, above. -// Alternatively, special "modes" could be listed of types in with_api -// instead of pattern matching on methods, here and in server decl. - -impl Clone for TokenStream { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Clone for Literal { - fn clone(&self) -> Self { - self.clone() - } -} - -impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Literal") - // format the kind without quotes, as in `kind: Float` - .field("kind", &format_args!("{}", &self.debug_kind())) - .field("symbol", &self.symbol()) - // format `Some("...")` on one line even in {:#?} mode - .field("suffix", &format_args!("{:?}", &self.suffix())) - .field("span", &self.span()) - .finish() - } -} - -impl Clone for SourceFile { - fn clone(&self) -> Self { - self.clone() - } -} - -impl Span { - pub(crate) fn def_site() -> Span { - Bridge::with(|bridge| bridge.globals.def_site) - } - - pub(crate) fn call_site() -> Span { - Bridge::with(|bridge| bridge.globals.call_site) - } - - pub(crate) fn mixed_site() -> Span { - Bridge::with(|bridge| bridge.globals.mixed_site) - } -} - -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.debug()) - } -} - -macro_rules! define_client_side { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $(impl $name { - $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* { - Bridge::with(|bridge| { - let mut buf = bridge.cached_buffer.take(); - - buf.clear(); - api_tags::Method::$name(api_tags::$name::$method).encode(&mut buf, &mut ()); - reverse_encode!(buf; $($arg),*); - - buf = bridge.dispatch.call(buf); - - let r = Result::<_, PanicMessage>::decode(&mut &buf[..], &mut ()); - - bridge.cached_buffer = buf; - - r.unwrap_or_else(|e| panic::resume_unwind(e.into())) - }) - })* - })* - } -} -with_api!(self, self, define_client_side); - -struct Bridge<'a> { - /// Reusable buffer (only `clear`-ed, never shrunk), primarily - /// used for making requests. - cached_buffer: Buffer, - - /// Server-side function that the client uses to make requests. - dispatch: closure::Closure<'a, Buffer, Buffer>, - - /// Provided globals for this macro expansion. - globals: ExpnGlobals, -} - -enum BridgeState<'a> { - /// No server is currently connected to this client. - NotConnected, - - /// A server is connected and available for requests. - Connected(Bridge<'a>), - - /// Access to the bridge is being exclusively acquired - /// (e.g., during `BridgeState::with`). - InUse, -} - -enum BridgeStateL {} - -impl<'a> scoped_cell::ApplyL<'a> for BridgeStateL { - type Out = BridgeState<'a>; -} - -thread_local! { - static BRIDGE_STATE: scoped_cell::ScopedCell = - scoped_cell::ScopedCell::new(BridgeState::NotConnected); -} - -impl BridgeState<'_> { - /// Take exclusive control of the thread-local - /// `BridgeState`, and pass it to `f`, mutably. - /// The state will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - /// - /// N.B., while `f` is running, the thread-local state - /// is `BridgeState::InUse`. - fn with(f: impl FnOnce(&mut BridgeState<'_>) -> R) -> R { - BRIDGE_STATE.with(|state| { - state.replace(BridgeState::InUse, |mut state| { - // FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone - f(&mut *state) - }) - }) - } -} - -impl Bridge<'_> { - fn with(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R { - BridgeState::with(|state| match state { - BridgeState::NotConnected => { - panic!("procedural macro API is used outside of a procedural macro"); - } - BridgeState::InUse => { - panic!("procedural macro API is used while it's already in use"); - } - BridgeState::Connected(bridge) => f(bridge), - }) - } -} - -pub(crate) fn is_available() -> bool { - BridgeState::with(|state| match state { - BridgeState::Connected(_) | BridgeState::InUse => true, - BridgeState::NotConnected => false, - }) -} - -/// A client-side RPC entry-point, which may be using a different `proc_macro` -/// from the one used by the server, but can be invoked compatibly. -/// -/// Note that the (phantom) `I` ("input") and `O` ("output") type parameters -/// decorate the `Client` with the RPC "interface" of the entry-point, but -/// do not themselves participate in ABI, at all, only facilitate type-checking. -/// -/// E.g. `Client` is the common proc macro interface, -/// used for `#[proc_macro] fn foo(input: TokenStream) -> TokenStream`, -/// indicating that the RPC input and output will be serialized token streams, -/// and forcing the use of APIs that take/return `S::TokenStream`, server-side. -#[repr(C)] -pub struct Client { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters, - - pub(super) run: extern "C" fn(BridgeConfig<'_>) -> Buffer, - - pub(super) _marker: PhantomData O>, -} - -impl Copy for Client {} -impl Clone for Client { - fn clone(&self) -> Self { - *self - } -} - -fn maybe_install_panic_hook(force_show_panics: bool) { - // Hide the default panic output within `proc_macro` expansions. - // NB. the server can't do this because it may use a different libstd. - static HIDE_PANICS_DURING_EXPANSION: Once = Once::new(); - HIDE_PANICS_DURING_EXPANSION.call_once(|| { - let prev = panic::take_hook(); - panic::set_hook(Box::new(move |info| { - let show = BridgeState::with(|state| match state { - BridgeState::NotConnected => true, - BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, - }); - if show { - prev(info) - } - })); - }); -} - -/// Client-side helper for handling client panics, entering the bridge, -/// deserializing input and serializing output. -// FIXME(eddyb) maybe replace `Bridge::enter` with this? -fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( - config: BridgeConfig<'_>, - f: impl FnOnce(A) -> R, -) -> Buffer { - let BridgeConfig { input: mut buf, dispatch, force_show_panics, .. } = config; - - panic::catch_unwind(panic::AssertUnwindSafe(|| { - maybe_install_panic_hook(force_show_panics); - - let reader = &mut &buf[..]; - let (globals, input) = <(ExpnGlobals, A)>::decode(reader, &mut ()); - - // Put the buffer we used for input back in the `Bridge` for requests. - let new_state = - BridgeState::Connected(Bridge { cached_buffer: buf.take(), dispatch, globals }); - - BRIDGE_STATE.with(|state| { - state.set(new_state, || { - let output = f(input); - - // Take the `cached_buffer` back out, for the output value. - buf = Bridge::with(|bridge| bridge.cached_buffer.take()); - - // HACK(eddyb) Separate encoding a success value (`Ok(output)`) - // from encoding a panic (`Err(e: PanicMessage)`) to avoid - // having handles outside the `bridge.enter(|| ...)` scope, and - // to catch panics that could happen while encoding the success. - // - // Note that panics should be impossible beyond this point, but - // this is defensively trying to avoid any accidental panicking - // reaching the `extern "C"` (which should `abort` but might not - // at the moment, so this is also potentially preventing UB). - buf.clear(); - Ok::<_, ()>(output).encode(&mut buf, &mut ()); - }) - }) - })) - .map_err(PanicMessage::from) - .unwrap_or_else(|e| { - buf.clear(); - Err::<(), _>(e).encode(&mut buf, &mut ()); - }); - buf -} - -impl Client { - pub const fn expand1( - f: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - Client { - get_handle_counters: HandleCounters::get, - run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { - run_client(bridge, |input| f(super::super::TokenStream(input)).0) - }), - _marker: PhantomData, - } - } -} - -impl Client<(super::super::TokenStream, super::super::TokenStream), super::super::TokenStream> { - pub const fn expand2( - f: impl Fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream - + Copy, - ) -> Self { - Client { - get_handle_counters: HandleCounters::get, - run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { - run_client(bridge, |(input, input2)| { - f(super::super::TokenStream(input), super::super::TokenStream(input2)).0 - }) - }), - _marker: PhantomData, - } - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum ProcMacro { - CustomDerive { - trait_name: &'static str, - attributes: &'static [&'static str], - client: Client, - }, - - Attr { - name: &'static str, - client: Client< - (super::super::TokenStream, super::super::TokenStream), - super::super::TokenStream, - >, - }, - - Bang { - name: &'static str, - client: Client, - }, -} - -impl ProcMacro { - pub fn name(&self) -> &'static str { - match self { - ProcMacro::CustomDerive { trait_name, .. } => trait_name, - ProcMacro::Attr { name, .. } => name, - ProcMacro::Bang { name, .. } => name, - } - } - - pub const fn custom_derive( - trait_name: &'static str, - attributes: &'static [&'static str], - expand: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } - } - - pub const fn attr( - name: &'static str, - expand: impl Fn(super::super::TokenStream, super::super::TokenStream) -> super::super::TokenStream - + Copy, - ) -> Self { - ProcMacro::Attr { name, client: Client::expand2(expand) } - } - - pub const fn bang( - name: &'static str, - expand: impl Fn(super::super::TokenStream) -> super::super::TokenStream + Copy, - ) -> Self { - ProcMacro::Bang { name, client: Client::expand1(expand) } - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/closure.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/closure.rs deleted file mode 100644 index d371ae3cea09..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/closure.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Closure type (equivalent to `&mut dyn FnMut(A) -> R`) that's `repr(C)`. - -use std::marker::PhantomData; - -#[repr(C)] -pub struct Closure<'a, A, R> { - call: unsafe extern "C" fn(*mut Env, A) -> R, - env: *mut Env, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing - // this, but that requires unstable features. rust-analyzer uses this code - // and avoids unstable features. - // - // The `'a` lifetime parameter represents the lifetime of `Env`. - _marker: PhantomData<*mut &'a mut ()>, -} - -struct Env; - -impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> { - fn from(f: &'a mut F) -> Self { - unsafe extern "C" fn call R>(env: *mut Env, arg: A) -> R { - (*(env as *mut _ as *mut F))(arg) - } - Closure { call: call::, env: f as *mut _ as *mut Env, _marker: PhantomData } - } -} - -impl<'a, A, R> Closure<'a, A, R> { - pub fn call(&mut self, arg: A) -> R { - unsafe { (self.call)(self.env, arg) } - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/handle.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/handle.rs deleted file mode 100644 index c219a9465d39..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/handle.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! Server-side handles and storage for per-handle data. - -use std::collections::{BTreeMap, HashMap}; -use std::hash::{BuildHasher, Hash}; -use std::num::NonZeroU32; -use std::ops::{Index, IndexMut}; -use std::sync::atomic::{AtomicUsize, Ordering}; - -pub(super) type Handle = NonZeroU32; - -/// A store that associates values of type `T` with numeric handles. A value can -/// be looked up using its handle. -pub(super) struct OwnedStore { - counter: &'static AtomicUsize, - data: BTreeMap, -} - -impl OwnedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { - // Ensure the handle counter isn't 0, which would panic later, - // when `NonZeroU32::new` (aka `Handle::new`) is called in `alloc`. - assert_ne!(counter.load(Ordering::SeqCst), 0); - - OwnedStore { counter, data: BTreeMap::new() } - } -} - -impl OwnedStore { - pub(super) fn alloc(&mut self, x: T) -> Handle { - let counter = self.counter.fetch_add(1, Ordering::SeqCst); - let handle = Handle::new(counter as u32).expect("`proc_macro` handle counter overflowed"); - assert!(self.data.insert(handle, x).is_none()); - handle - } - - pub(super) fn take(&mut self, h: Handle) -> T { - self.data.remove(&h).expect("use-after-free in `proc_macro` handle") - } -} - -impl Index for OwnedStore { - type Output = T; - fn index(&self, h: Handle) -> &T { - self.data.get(&h).expect("use-after-free in `proc_macro` handle") - } -} - -impl IndexMut for OwnedStore { - fn index_mut(&mut self, h: Handle) -> &mut T { - self.data.get_mut(&h).expect("use-after-free in `proc_macro` handle") - } -} - -// HACK(eddyb) deterministic `std::collections::hash_map::RandomState` replacement -// that doesn't require adding any dependencies to `proc_macro` (like `rustc-hash`). -#[derive(Clone)] -struct NonRandomState; - -impl BuildHasher for NonRandomState { - type Hasher = std::collections::hash_map::DefaultHasher; - #[inline] - fn build_hasher(&self) -> Self::Hasher { - Self::Hasher::new() - } -} - -/// Like `OwnedStore`, but avoids storing any value more than once. -pub(super) struct InternedStore { - owned: OwnedStore, - interner: HashMap, -} - -impl InternedStore { - pub(super) fn new(counter: &'static AtomicUsize) -> Self { - InternedStore { - owned: OwnedStore::new(counter), - interner: HashMap::with_hasher(NonRandomState), - } - } - - pub(super) fn alloc(&mut self, x: T) -> Handle { - let owned = &mut self.owned; - *self.interner.entry(x).or_insert_with(|| owned.alloc(x)) - } - - pub(super) fn copy(&mut self, h: Handle) -> T { - self.owned[h] - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/mod.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/mod.rs deleted file mode 100644 index ffd440793231..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/mod.rs +++ /dev/null @@ -1,493 +0,0 @@ -//! Internal interface for communicating between a `proc_macro` client -//! (a proc macro crate) and a `proc_macro` server (a compiler front-end). -//! -//! Serialization (with C ABI buffers) and unique integer handles are employed -//! to allow safely interfacing between two copies of `proc_macro` built -//! (from the same source) by different compilers with potentially mismatching -//! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap). - -#![deny(unsafe_code)] - -pub use super::{Delimiter, Level, LineColumn, Spacing}; -use std::fmt; -use std::hash::Hash; -use std::marker; -use std::mem; -use std::ops::Bound; -use std::panic; -use std::sync::atomic::AtomicUsize; -use std::sync::Once; -use std::thread; - -/// Higher-order macro describing the server RPC API, allowing automatic -/// generation of type-safe Rust APIs, both client-side and server-side. -/// -/// `with_api!(MySelf, my_self, my_macro)` expands to: -/// ```rust,ignore (pseudo-code) -/// my_macro! { -/// // ... -/// Literal { -/// // ... -/// fn character(ch: char) -> MySelf::Literal; -/// // ... -/// fn span(my_self: &MySelf::Literal) -> MySelf::Span; -/// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span); -/// }, -/// // ... -/// } -/// ``` -/// -/// The first two arguments serve to customize the arguments names -/// and argument/return types, to enable several different usecases: -/// -/// If `my_self` is just `self`, then each `fn` signature can be used -/// as-is for a method. If it's anything else (`self_` in practice), -/// then the signatures don't have a special `self` argument, and -/// can, therefore, have a different one introduced. -/// -/// If `MySelf` is just `Self`, then the types are only valid inside -/// a trait or a trait impl, where the trait has associated types -/// for each of the API types. If non-associated types are desired, -/// a module name (`self` in practice) can be used instead of `Self`. -macro_rules! with_api { - ($S:ident, $self:ident, $m:ident) => { - $m! { - FreeFunctions { - fn drop($self: $S::FreeFunctions); - fn track_env_var(var: &str, value: Option<&str>); - fn track_path(path: &str); - }, - TokenStream { - fn drop($self: $S::TokenStream); - fn clone($self: &$S::TokenStream) -> $S::TokenStream; - fn is_empty($self: &$S::TokenStream) -> bool; - fn expand_expr($self: &$S::TokenStream) -> Result<$S::TokenStream, ()>; - fn from_str(src: &str) -> $S::TokenStream; - fn to_string($self: &$S::TokenStream) -> String; - fn from_token_tree( - tree: TokenTree<$S::TokenStream, $S::Span, $S::Ident, $S::Literal>, - ) -> $S::TokenStream; - fn concat_trees( - base: Option<$S::TokenStream>, - trees: Vec>, - ) -> $S::TokenStream; - fn concat_streams( - base: Option<$S::TokenStream>, - streams: Vec<$S::TokenStream>, - ) -> $S::TokenStream; - fn into_trees( - $self: $S::TokenStream - ) -> Vec>; - }, - Ident { - fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident; - fn span($self: $S::Ident) -> $S::Span; - fn with_span($self: $S::Ident, span: $S::Span) -> $S::Ident; - }, - Literal { - fn drop($self: $S::Literal); - fn clone($self: &$S::Literal) -> $S::Literal; - fn from_str(s: &str) -> Result<$S::Literal, ()>; - fn to_string($self: &$S::Literal) -> String; - fn debug_kind($self: &$S::Literal) -> String; - fn symbol($self: &$S::Literal) -> String; - fn suffix($self: &$S::Literal) -> Option; - fn integer(n: &str) -> $S::Literal; - fn typed_integer(n: &str, kind: &str) -> $S::Literal; - fn float(n: &str) -> $S::Literal; - fn f32(n: &str) -> $S::Literal; - fn f64(n: &str) -> $S::Literal; - fn string(string: &str) -> $S::Literal; - fn character(ch: char) -> $S::Literal; - fn byte_string(bytes: &[u8]) -> $S::Literal; - fn span($self: &$S::Literal) -> $S::Span; - fn set_span($self: &mut $S::Literal, span: $S::Span); - fn subspan( - $self: &$S::Literal, - start: Bound, - end: Bound, - ) -> Option<$S::Span>; - }, - SourceFile { - fn drop($self: $S::SourceFile); - fn clone($self: &$S::SourceFile) -> $S::SourceFile; - fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool; - fn path($self: &$S::SourceFile) -> String; - fn is_real($self: &$S::SourceFile) -> bool; - }, - MultiSpan { - fn drop($self: $S::MultiSpan); - fn new() -> $S::MultiSpan; - fn push($self: &mut $S::MultiSpan, span: $S::Span); - }, - Diagnostic { - fn drop($self: $S::Diagnostic); - fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic; - fn sub( - $self: &mut $S::Diagnostic, - level: Level, - msg: &str, - span: $S::MultiSpan, - ); - fn emit($self: $S::Diagnostic); - }, - Span { - fn debug($self: $S::Span) -> String; - fn source_file($self: $S::Span) -> $S::SourceFile; - fn parent($self: $S::Span) -> Option<$S::Span>; - fn source($self: $S::Span) -> $S::Span; - fn start($self: $S::Span) -> LineColumn; - fn end($self: $S::Span) -> LineColumn; - fn before($self: $S::Span) -> $S::Span; - fn after($self: $S::Span) -> $S::Span; - fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; - fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; - fn source_text($self: $S::Span) -> Option; - fn save_span($self: $S::Span) -> usize; - fn recover_proc_macro_span(id: usize) -> $S::Span; - }, - } - }; -} - -// FIXME(eddyb) this calls `encode` for each argument, but in reverse, -// to match the ordering in `reverse_decode`. -macro_rules! reverse_encode { - ($writer:ident;) => {}; - ($writer:ident; $first:ident $(, $rest:ident)*) => { - reverse_encode!($writer; $($rest),*); - $first.encode(&mut $writer, &mut ()); - } -} - -// FIXME(eddyb) this calls `decode` for each argument, but in reverse, -// to avoid borrow conflicts from borrows started by `&mut` arguments. -macro_rules! reverse_decode { - ($reader:ident, $s:ident;) => {}; - ($reader:ident, $s:ident; $first:ident: $first_ty:ty $(, $rest:ident: $rest_ty:ty)*) => { - reverse_decode!($reader, $s; $($rest: $rest_ty),*); - let $first = <$first_ty>::decode(&mut $reader, $s); - } -} - -#[allow(unsafe_code)] -mod buffer; -#[forbid(unsafe_code)] -pub mod client; -#[allow(unsafe_code)] -mod closure; -#[forbid(unsafe_code)] -mod handle; -#[macro_use] -#[forbid(unsafe_code)] -mod rpc; -#[allow(unsafe_code)] -mod scoped_cell; -#[allow(unsafe_code)] -mod selfless_reify; -#[forbid(unsafe_code)] -pub mod server; - -use buffer::Buffer; -pub use rpc::PanicMessage; -use rpc::{Decode, DecodeMut, Encode, Reader, Writer}; - -/// Configuration for establishing an active connection between a server and a -/// client. The server creates the bridge config (`run_server` in `server.rs`), -/// then passes it to the client through the function pointer in the `run` field -/// of `client::Client`. The client constructs a local `Bridge` from the config -/// in TLS during its execution (`Bridge::{enter, with}` in `client.rs`). -#[repr(C)] -pub struct BridgeConfig<'a> { - /// Buffer used to pass initial input to the client. - input: Buffer, - - /// Server-side function that the client uses to make requests. - dispatch: closure::Closure<'a, Buffer, Buffer>, - - /// If 'true', always invoke the default panic hook - force_show_panics: bool, - - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing - // this, but that requires unstable features. rust-analyzer uses this code - // and avoids unstable features. - _marker: marker::PhantomData<*mut ()>, -} - -#[forbid(unsafe_code)] -#[allow(non_camel_case_types)] -mod api_tags { - use super::rpc::{DecodeMut, Encode, Reader, Writer}; - - macro_rules! declare_tags { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* - }),* $(,)?) => { - $( - pub(super) enum $name { - $($method),* - } - rpc_encode_decode!(enum $name { $($method),* }); - )* - - pub(super) enum Method { - $($name($name)),* - } - rpc_encode_decode!(enum Method { $($name(m)),* }); - } - } - with_api!(self, self, declare_tags); -} - -/// Helper to wrap associated types to allow trait impl dispatch. -/// That is, normally a pair of impls for `T::Foo` and `T::Bar` -/// can overlap, but if the impls are, instead, on types like -/// `Marked` and `Marked`, they can't. -trait Mark { - type Unmarked; - fn mark(unmarked: Self::Unmarked) -> Self; -} - -/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details). -trait Unmark { - type Unmarked; - fn unmark(self) -> Self::Unmarked; -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -struct Marked { - value: T, - _marker: marker::PhantomData, -} - -impl Mark for Marked { - type Unmarked = T; - fn mark(unmarked: Self::Unmarked) -> Self { - Marked { value: unmarked, _marker: marker::PhantomData } - } -} -impl Unmark for Marked { - type Unmarked = T; - fn unmark(self) -> Self::Unmarked { - self.value - } -} -impl<'a, T, M> Unmark for &'a Marked { - type Unmarked = &'a T; - fn unmark(self) -> Self::Unmarked { - &self.value - } -} -impl<'a, T, M> Unmark for &'a mut Marked { - type Unmarked = &'a mut T; - fn unmark(self) -> Self::Unmarked { - &mut self.value - } -} - -impl Mark for Vec { - type Unmarked = Vec; - fn mark(unmarked: Self::Unmarked) -> Self { - // Should be a no-op due to std's in-place collect optimizations. - unmarked.into_iter().map(T::mark).collect() - } -} -impl Unmark for Vec { - type Unmarked = Vec; - fn unmark(self) -> Self::Unmarked { - // Should be a no-op due to std's in-place collect optimizations. - self.into_iter().map(T::unmark).collect() - } -} - -macro_rules! mark_noop { - ($($ty:ty),* $(,)?) => { - $( - impl Mark for $ty { - type Unmarked = Self; - fn mark(unmarked: Self::Unmarked) -> Self { - unmarked - } - } - impl Unmark for $ty { - type Unmarked = Self; - fn unmark(self) -> Self::Unmarked { - self - } - } - )* - } -} -mark_noop! { - (), - bool, - char, - &'_ [u8], - &'_ str, - String, - u8, - usize, - Delimiter, - Level, - LineColumn, - Spacing, -} - -rpc_encode_decode!( - enum Delimiter { - Parenthesis, - Brace, - Bracket, - None, - } -); -rpc_encode_decode!( - enum Level { - Error, - Warning, - Note, - Help, - } -); -rpc_encode_decode!(struct LineColumn { line, column }); -rpc_encode_decode!( - enum Spacing { - Alone, - Joint, - } -); - -macro_rules! mark_compound { - (struct $name:ident <$($T:ident),+> { $($field:ident),* $(,)? }) => { - impl<$($T: Mark),+> Mark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn mark(unmarked: Self::Unmarked) -> Self { - $name { - $($field: Mark::mark(unmarked.$field)),* - } - } - } - impl<$($T: Unmark),+> Unmark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn unmark(self) -> Self::Unmarked { - $name { - $($field: Unmark::unmark(self.$field)),* - } - } - } - }; - (enum $name:ident <$($T:ident),+> { $($variant:ident $(($field:ident))?),* $(,)? }) => { - impl<$($T: Mark),+> Mark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn mark(unmarked: Self::Unmarked) -> Self { - match unmarked { - $($name::$variant $(($field))? => { - $name::$variant $((Mark::mark($field)))? - })* - } - } - } - impl<$($T: Unmark),+> Unmark for $name <$($T),+> { - type Unmarked = $name <$($T::Unmarked),+>; - fn unmark(self) -> Self::Unmarked { - match self { - $($name::$variant $(($field))? => { - $name::$variant $((Unmark::unmark($field)))? - })* - } - } - } - } -} - -macro_rules! compound_traits { - ($($t:tt)*) => { - rpc_encode_decode!($($t)*); - mark_compound!($($t)*); - }; -} - -compound_traits!( - enum Bound { - Included(x), - Excluded(x), - Unbounded, - } -); - -compound_traits!( - enum Option { - Some(t), - None, - } -); - -compound_traits!( - enum Result { - Ok(t), - Err(e), - } -); - -#[derive(Copy, Clone)] -pub struct DelimSpan { - pub open: Span, - pub close: Span, - pub entire: Span, -} - -impl DelimSpan { - pub fn from_single(span: Span) -> Self { - DelimSpan { open: span, close: span, entire: span } - } -} - -compound_traits!(struct DelimSpan { open, close, entire }); - -#[derive(Clone)] -pub struct Group { - pub delimiter: Delimiter, - pub stream: Option, - pub span: DelimSpan, -} - -compound_traits!(struct Group { delimiter, stream, span }); - -#[derive(Clone)] -pub struct Punct { - pub ch: u8, - pub joint: bool, - pub span: Span, -} - -compound_traits!(struct Punct { ch, joint, span }); - -#[derive(Clone)] -pub enum TokenTree { - Group(Group), - Punct(Punct), - Ident(Ident), - Literal(Literal), -} - -compound_traits!( - enum TokenTree { - Group(tt), - Punct(tt), - Ident(tt), - Literal(tt), - } -); - -/// Globals provided alongside the initial inputs for a macro expansion. -/// Provides values such as spans which are used frequently to avoid RPC. -#[derive(Clone)] -pub struct ExpnGlobals { - pub def_site: Span, - pub call_site: Span, - pub mixed_site: Span, -} - -compound_traits!( - struct ExpnGlobals { def_site, call_site, mixed_site } -); diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/rpc.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/rpc.rs deleted file mode 100644 index e9d7a46c06f6..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/rpc.rs +++ /dev/null @@ -1,304 +0,0 @@ -//! Serialization for client-server communication. - -use std::any::Any; -use std::char; -use std::io::Write; -use std::num::NonZeroU32; -use std::str; - -pub(super) type Writer = super::buffer::Buffer; - -pub(super) trait Encode: Sized { - fn encode(self, w: &mut Writer, s: &mut S); -} - -pub(super) type Reader<'a> = &'a [u8]; - -pub(super) trait Decode<'a, 's, S>: Sized { - fn decode(r: &mut Reader<'a>, s: &'s S) -> Self; -} - -pub(super) trait DecodeMut<'a, 's, S>: Sized { - fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self; -} - -macro_rules! rpc_encode_decode { - (le $ty:ty) => { - impl Encode for $ty { - fn encode(self, w: &mut Writer, _: &mut S) { - w.extend_from_array(&self.to_le_bytes()); - } - } - - impl DecodeMut<'_, '_, S> for $ty { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { - const N: usize = ::std::mem::size_of::<$ty>(); - - let mut bytes = [0; N]; - bytes.copy_from_slice(&r[..N]); - *r = &r[N..]; - - Self::from_le_bytes(bytes) - } - } - }; - (struct $name:ident $(<$($T:ident),+>)? { $($field:ident),* $(,)? }) => { - impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { - $(self.$field.encode(w, s);)* - } - } - - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> - for $name $(<$($T),+>)? - { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - $name { - $($field: DecodeMut::decode(r, s)),* - } - } - } - }; - (enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => { - impl),+)?> Encode for $name $(<$($T),+>)? { - fn encode(self, w: &mut Writer, s: &mut S) { - // HACK(eddyb): `Tag` enum duplicated between the - // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub const $variant: u8 = Tag::$variant as u8;)* - } - - match self { - $($name::$variant $(($field))* => { - tag::$variant.encode(w, s); - $($field.encode(w, s);)* - })* - } - } - } - - impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S> - for $name $(<$($T),+>)? - { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - // HACK(eddyb): `Tag` enum duplicated between the - // two impls as there's no other place to stash it. - #[allow(non_upper_case_globals)] - mod tag { - #[repr(u8)] enum Tag { $($variant),* } - - $(pub const $variant: u8 = Tag::$variant as u8;)* - } - - match u8::decode(r, s) { - $(tag::$variant => { - $(let $field = DecodeMut::decode(r, s);)* - $name::$variant $(($field))* - })* - _ => unreachable!(), - } - } - } - } -} - -impl Encode for () { - fn encode(self, _: &mut Writer, _: &mut S) {} -} - -impl DecodeMut<'_, '_, S> for () { - fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {} -} - -impl Encode for u8 { - fn encode(self, w: &mut Writer, _: &mut S) { - w.push(self); - } -} - -impl DecodeMut<'_, '_, S> for u8 { - fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { - let x = r[0]; - *r = &r[1..]; - x - } -} - -rpc_encode_decode!(le u32); -rpc_encode_decode!(le usize); - -impl Encode for bool { - fn encode(self, w: &mut Writer, s: &mut S) { - (self as u8).encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for bool { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - match u8::decode(r, s) { - 0 => false, - 1 => true, - _ => unreachable!(), - } - } -} - -impl Encode for char { - fn encode(self, w: &mut Writer, s: &mut S) { - (self as u32).encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for char { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - char::from_u32(u32::decode(r, s)).unwrap() - } -} - -impl Encode for NonZeroU32 { - fn encode(self, w: &mut Writer, s: &mut S) { - self.get().encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for NonZeroU32 { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - Self::new(u32::decode(r, s)).unwrap() - } -} - -impl, B: Encode> Encode for (A, B) { - fn encode(self, w: &mut Writer, s: &mut S) { - self.0.encode(w, s); - self.1.encode(w, s); - } -} - -impl<'a, S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> - for (A, B) -{ - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - (DecodeMut::decode(r, s), DecodeMut::decode(r, s)) - } -} - -impl Encode for &[u8] { - fn encode(self, w: &mut Writer, s: &mut S) { - self.len().encode(w, s); - w.write_all(self).unwrap(); - } -} - -impl<'a, S> DecodeMut<'a, '_, S> for &'a [u8] { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - let len = usize::decode(r, s); - let xs = &r[..len]; - *r = &r[len..]; - xs - } -} - -impl Encode for &str { - fn encode(self, w: &mut Writer, s: &mut S) { - self.as_bytes().encode(w, s); - } -} - -impl<'a, S> DecodeMut<'a, '_, S> for &'a str { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - str::from_utf8(<&[u8]>::decode(r, s)).unwrap() - } -} - -impl Encode for String { - fn encode(self, w: &mut Writer, s: &mut S) { - self[..].encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for String { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - <&str>::decode(r, s).to_string() - } -} - -impl> Encode for Vec { - fn encode(self, w: &mut Writer, s: &mut S) { - self.len().encode(w, s); - for x in self { - x.encode(w, s); - } - } -} - -impl<'a, S, T: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S> for Vec { - fn decode(r: &mut Reader<'a>, s: &mut S) -> Self { - let len = usize::decode(r, s); - let mut vec = Vec::with_capacity(len); - for _ in 0..len { - vec.push(T::decode(r, s)); - } - vec - } -} - -/// Simplified version of panic payloads, ignoring -/// types other than `&'static str` and `String`. -pub enum PanicMessage { - StaticStr(&'static str), - String(String), - Unknown, -} - -impl From> for PanicMessage { - fn from(payload: Box) -> Self { - if let Some(s) = payload.downcast_ref::<&'static str>() { - return PanicMessage::StaticStr(s); - } - if let Ok(s) = payload.downcast::() { - return PanicMessage::String(*s); - } - PanicMessage::Unknown - } -} - -impl Into> for PanicMessage { - fn into(self) -> Box { - match self { - PanicMessage::StaticStr(s) => Box::new(s), - PanicMessage::String(s) => Box::new(s), - PanicMessage::Unknown => { - struct UnknownPanicMessage; - Box::new(UnknownPanicMessage) - } - } - } -} - -impl PanicMessage { - pub fn as_str(&self) -> Option<&str> { - match self { - PanicMessage::StaticStr(s) => Some(s), - PanicMessage::String(s) => Some(s), - PanicMessage::Unknown => None, - } - } -} - -impl Encode for PanicMessage { - fn encode(self, w: &mut Writer, s: &mut S) { - self.as_str().encode(w, s); - } -} - -impl DecodeMut<'_, '_, S> for PanicMessage { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - match Option::::decode(r, s) { - Some(s) => PanicMessage::String(s), - None => PanicMessage::Unknown, - } - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/scoped_cell.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/scoped_cell.rs deleted file mode 100644 index 2cde1f65adf9..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/scoped_cell.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! `Cell` variant for (scoped) existential lifetimes. - -use std::cell::Cell; -use std::mem; -use std::ops::{Deref, DerefMut}; - -/// Type lambda application, with a lifetime. -#[allow(unused_lifetimes)] -pub trait ApplyL<'a> { - type Out; -} - -/// Type lambda taking a lifetime, i.e., `Lifetime -> Type`. -pub trait LambdaL: for<'a> ApplyL<'a> {} - -impl ApplyL<'a>> LambdaL for T {} - -// HACK(eddyb) work around projection limitations with a newtype -// FIXME(#52812) replace with `&'a mut >::Out` -pub struct RefMutL<'a, 'b, T: LambdaL>(&'a mut >::Out); - -impl<'a, 'b, T: LambdaL> Deref for RefMutL<'a, 'b, T> { - type Target = >::Out; - fn deref(&self) -> &Self::Target { - self.0 - } -} - -impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0 - } -} - -pub struct ScopedCell(Cell<>::Out>); - -impl ScopedCell { - pub const fn new(value: >::Out) -> Self { - ScopedCell(Cell::new(value)) - } - - /// Sets the value in `self` to `replacement` while - /// running `f`, which gets the old value, mutably. - /// The old value will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - pub fn replace<'a, R>( - &self, - replacement: >::Out, - f: impl for<'b, 'c> FnOnce(RefMutL<'b, 'c, T>) -> R, - ) -> R { - /// Wrapper that ensures that the cell always gets filled - /// (with the original state, optionally changed by `f`), - /// even if `f` had panicked. - struct PutBackOnDrop<'a, T: LambdaL> { - cell: &'a ScopedCell, - value: Option<>::Out>, - } - - impl<'a, T: LambdaL> Drop for PutBackOnDrop<'a, T> { - fn drop(&mut self) { - self.cell.0.set(self.value.take().unwrap()); - } - } - - let mut put_back_on_drop = PutBackOnDrop { - cell: self, - value: Some(self.0.replace(unsafe { - let erased = mem::transmute_copy(&replacement); - mem::forget(replacement); - erased - })), - }; - - f(RefMutL(put_back_on_drop.value.as_mut().unwrap())) - } - - /// Sets the value in `self` to `value` while running `f`. - pub fn set(&self, value: >::Out, f: impl FnOnce() -> R) -> R { - self.replace(value, |_| f()) - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/selfless_reify.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/selfless_reify.rs deleted file mode 100644 index 907ad256e4b4..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/selfless_reify.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! Abstraction for creating `fn` pointers from any callable that *effectively* -//! has the equivalent of implementing `Default`, even if the compiler neither -//! provides `Default` nor allows reifying closures (i.e. creating `fn` pointers) -//! other than those with absolutely no captures. -//! -//! More specifically, for a closure-like type to be "effectively `Default`": -//! * it must be a ZST (zero-sized type): no information contained within, so -//! that `Default`'s return value (if it were implemented) is unambiguous -//! * it must be `Copy`: no captured "unique ZST tokens" or any other similar -//! types that would make duplicating values at will unsound -//! * combined with the ZST requirement, this confers a kind of "telecopy" -//! ability: similar to `Copy`, but without keeping the value around, and -//! instead "reconstructing" it (a noop given it's a ZST) when needed -//! * it must be *provably* inhabited: no captured uninhabited types or any -//! other types that cannot be constructed by the user of this abstraction -//! * the proof is a value of the closure-like type itself, in a sense the -//! "seed" for the "telecopy" process made possible by ZST + `Copy` -//! * this requirement is the only reason an abstraction limited to a specific -//! usecase is required: ZST + `Copy` can be checked with *at worst* a panic -//! at the "attempted `::default()` call" time, but that doesn't guarantee -//! that the value can be soundly created, and attempting to use the typical -//! "proof ZST token" approach leads yet again to having a ZST + `Copy` type -//! that is not proof of anything without a value (i.e. isomorphic to a -//! newtype of the type it's trying to prove the inhabitation of) -//! -//! A more flexible (and safer) solution to the general problem could exist once -//! `const`-generic parameters can have type parameters in their types: -//! -//! ```rust,ignore (needs future const-generics) -//! extern "C" fn ffi_wrapper< -//! A, R, -//! F: Fn(A) -> R, -//! const f: F, // <-- this `const`-generic is not yet allowed -//! >(arg: A) -> R { -//! f(arg) -//! } -//! ``` - -use std::mem; - -// FIXME(eddyb) this could be `trait` impls except for the `const fn` requirement. -macro_rules! define_reify_functions { - ($( - fn $name:ident $(<$($param:ident),*>)? - for $(extern $abi:tt)? fn($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty; - )+) => { - $(pub const fn $name< - $($($param,)*)? - F: Fn($($arg_ty),*) -> $ret_ty + Copy - >(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty { - // FIXME(eddyb) describe the `F` type (e.g. via `type_name::`) once panic - // formatting becomes possible in `const fn`. - assert!(mem::size_of::() == 0, "selfless_reify: closure must be zero-sized"); - - $(extern $abi)? fn wrapper< - $($($param,)*)? - F: Fn($($arg_ty),*) -> $ret_ty + Copy - >($($arg: $arg_ty),*) -> $ret_ty { - let f = unsafe { - // SAFETY: `F` satisfies all criteria for "out of thin air" - // reconstructability (see module-level doc comment). - mem::MaybeUninit::::uninit().assume_init() - }; - f($($arg),*) - } - let _f_proof = f; - wrapper::< - $($($param,)*)? - F - > - })+ - } -} - -define_reify_functions! { - fn _reify_to_extern_c_fn_unary for extern "C" fn(arg: A) -> R; - - // HACK(eddyb) this abstraction is used with `for<'a> fn(BridgeConfig<'a>) - // -> T` but that doesn't work with just `reify_to_extern_c_fn_unary` - // because of the `fn` pointer type being "higher-ranked" (i.e. the - // `for<'a>` binder). - // FIXME(eddyb) try to remove the lifetime from `BridgeConfig`, that'd help. - fn reify_to_extern_c_fn_hrt_bridge for extern "C" fn(bridge: super::BridgeConfig<'_>) -> R; -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/server.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/server.rs deleted file mode 100644 index 6e7a8d8c10df..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/bridge/server.rs +++ /dev/null @@ -1,339 +0,0 @@ -//! Server-side traits. - -use super::*; - -// FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. -use super::client::HandleStore; - -pub trait Types { - type FreeFunctions: 'static; - type TokenStream: 'static + Clone; - type Ident: 'static + Copy + Eq + Hash; - type Literal: 'static + Clone; - type SourceFile: 'static + Clone; - type MultiSpan: 'static; - type Diagnostic: 'static; - type Span: 'static + Copy + Eq + Hash; -} - -/// Declare an associated fn of one of the traits below, adding necessary -/// default bodies. -macro_rules! associated_fn { - (fn drop(&mut self, $arg:ident: $arg_ty:ty)) => - (fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) }); - - (fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) => - (fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() }); - - ($($item:tt)*) => ($($item)*;) -} - -macro_rules! declare_server_traits { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - $(pub trait $name: Types { - $(associated_fn!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* - })* - - pub trait Server: Types $(+ $name)* { - fn globals(&mut self) -> ExpnGlobals; - } - } -} -with_api!(Self, self_, declare_server_traits); - -pub(super) struct MarkedTypes(S); - -impl Server for MarkedTypes { - fn globals(&mut self) -> ExpnGlobals { - <_>::mark(Server::globals(&mut self.0)) - } -} - -macro_rules! define_mark_types_impls { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - impl Types for MarkedTypes { - $(type $name = Marked;)* - } - - $(impl $name for MarkedTypes { - $(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)? { - <_>::mark($name::$method(&mut self.0, $($arg.unmark()),*)) - })* - })* - } -} -with_api!(Self, self_, define_mark_types_impls); - -struct Dispatcher { - handle_store: HandleStore, - server: S, -} - -macro_rules! define_dispatcher_impl { - ($($name:ident { - $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* - }),* $(,)?) => { - // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. - pub trait DispatcherTrait { - // HACK(eddyb) these are here to allow `Self::$name` to work below. - $(type $name;)* - fn dispatch(&mut self, buf: Buffer) -> Buffer; - } - - impl DispatcherTrait for Dispatcher> { - $(type $name = as Types>::$name;)* - fn dispatch(&mut self, mut buf: Buffer) -> Buffer { - let Dispatcher { handle_store, server } = self; - - let mut reader = &buf[..]; - match api_tags::Method::decode(&mut reader, &mut ()) { - $(api_tags::Method::$name(m) => match m { - $(api_tags::$name::$method => { - let mut call_method = || { - reverse_decode!(reader, handle_store; $($arg: $arg_ty),*); - $name::$method(server, $($arg),*) - }; - // HACK(eddyb) don't use `panic::catch_unwind` in a panic. - // If client and server happen to use the same `libstd`, - // `catch_unwind` asserts that the panic counter was 0, - // even when the closure passed to it didn't panic. - let r = if thread::panicking() { - Ok(call_method()) - } else { - panic::catch_unwind(panic::AssertUnwindSafe(call_method)) - .map_err(PanicMessage::from) - }; - - buf.clear(); - r.encode(&mut buf, handle_store); - })* - }),* - } - buf - } - } - } -} -with_api!(Self, self_, define_dispatcher_impl); - -pub trait ExecutionStrategy { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer; -} - -pub struct SameThread; - -impl ExecutionStrategy for SameThread { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - let mut dispatch = |buf| dispatcher.dispatch(buf); - - run_client(BridgeConfig { - input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }) - } -} - -// NOTE(eddyb) Two implementations are provided, the second one is a bit -// faster but neither is anywhere near as fast as same-thread execution. - -pub struct CrossThread1; - -impl ExecutionStrategy for CrossThread1 { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - use std::sync::mpsc::channel; - - let (req_tx, req_rx) = channel(); - let (res_tx, res_rx) = channel(); - - let join_handle = thread::spawn(move || { - let mut dispatch = |buf| { - req_tx.send(buf).unwrap(); - res_rx.recv().unwrap() - }; - - run_client(BridgeConfig { - input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }) - }); - - for b in req_rx { - res_tx.send(dispatcher.dispatch(b)).unwrap(); - } - - join_handle.join().unwrap() - } -} - -pub struct CrossThread2; - -impl ExecutionStrategy for CrossThread2 { - fn run_bridge_and_client( - &self, - dispatcher: &mut impl DispatcherTrait, - input: Buffer, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, - ) -> Buffer { - use std::sync::{Arc, Mutex}; - - enum State { - Req(T), - Res(T), - } - - let mut state = Arc::new(Mutex::new(State::Res(Buffer::new()))); - - let server_thread = thread::current(); - let state2 = state.clone(); - let join_handle = thread::spawn(move || { - let mut dispatch = |b| { - *state2.lock().unwrap() = State::Req(b); - server_thread.unpark(); - loop { - thread::park(); - if let State::Res(b) = &mut *state2.lock().unwrap() { - break b.take(); - } - } - }; - - let r = run_client(BridgeConfig { - input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }); - - // Wake up the server so it can exit the dispatch loop. - drop(state2); - server_thread.unpark(); - - r - }); - - // Check whether `state2` was dropped, to know when to stop. - while Arc::get_mut(&mut state).is_none() { - thread::park(); - let mut b = match &mut *state.lock().unwrap() { - State::Req(b) => b.take(), - _ => continue, - }; - b = dispatcher.dispatch(b.take()); - *state.lock().unwrap() = State::Res(b); - join_handle.thread().unpark(); - } - - join_handle.join().unwrap() - } -} - -fn run_server< - S: Server, - I: Encode>>, - O: for<'a, 's> DecodeMut<'a, 's, HandleStore>>, ->( - strategy: &impl ExecutionStrategy, - handle_counters: &'static client::HandleCounters, - server: S, - input: I, - run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, - force_show_panics: bool, -) -> Result { - let mut dispatcher = - Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; - - let globals = dispatcher.server.globals(); - - let mut buf = Buffer::new(); - (globals, input).encode(&mut buf, &mut dispatcher.handle_store); - - buf = strategy.run_bridge_and_client(&mut dispatcher, buf, run_client, force_show_panics); - - Result::decode(&mut &buf[..], &mut dispatcher.handle_store) -} - -impl client::Client { - pub fn run( - &self, - strategy: &impl ExecutionStrategy, - server: S, - input: S::TokenStream, - force_show_panics: bool, - ) -> Result - where - S: Server, - S::TokenStream: Default, - { - let client::Client { get_handle_counters, run, _marker } = *self; - run_server( - strategy, - get_handle_counters(), - server, - as Types>::TokenStream::mark(input), - run, - force_show_panics, - ) - .map(|s| as Types>::TokenStream>>::unmark(s).unwrap_or_default()) - } -} - -impl - client::Client< - (super::super::TokenStream, super::super::TokenStream), - super::super::TokenStream, - > -{ - pub fn run( - &self, - strategy: &impl ExecutionStrategy, - server: S, - input: S::TokenStream, - input2: S::TokenStream, - force_show_panics: bool, - ) -> Result - where - S: Server, - S::TokenStream: Default, - { - let client::Client { get_handle_counters, run, _marker } = *self; - run_server( - strategy, - get_handle_counters(), - server, - ( - as Types>::TokenStream::mark(input), - as Types>::TokenStream::mark(input2), - ), - run, - force_show_panics, - ) - .map(|s| as Types>::TokenStream>>::unmark(s).unwrap_or_default()) - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/diagnostic.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/diagnostic.rs deleted file mode 100644 index 3fade2dc4f9c..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/diagnostic.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! lib-proc-macro diagnostic -//! -//! Copy from -//! augmented with removing unstable features - -use super::Span; - -/// An enum representing a diagnostic level. -#[derive(Copy, Clone, Debug)] -#[non_exhaustive] -pub enum Level { - /// An error. - Error, - /// A warning. - Warning, - /// A note. - Note, - /// A help message. - Help, -} - -/// Trait implemented by types that can be converted into a set of `Span`s. -pub trait MultiSpan { - /// Converts `self` into a `Vec`. - fn into_spans(self) -> Vec; -} - -impl MultiSpan for Span { - fn into_spans(self) -> Vec { - vec![self] - } -} - -impl MultiSpan for Vec { - fn into_spans(self) -> Vec { - self - } -} - -impl<'a> MultiSpan for &'a [Span] { - fn into_spans(self) -> Vec { - self.to_vec() - } -} - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -macro_rules! diagnostic_child_methods { - ($spanned:ident, $regular:ident, $level:expr) => { - #[doc = concat!("Adds a new child diagnostics message to `self` with the [`", - stringify!($level), "`] level, and the given `spans` and `message`.")] - pub fn $spanned(mut self, spans: S, message: T) -> Diagnostic - where - S: MultiSpan, - T: Into, - { - self.children.push(Diagnostic::spanned(spans, $level, message)); - self - } - - #[doc = concat!("Adds a new child diagnostic message to `self` with the [`", - stringify!($level), "`] level, and the given `message`.")] - pub fn $regular>(mut self, message: T) -> Diagnostic { - self.children.push(Diagnostic::new($level, message)); - self - } - }; -} - -/// Iterator over the children diagnostics of a `Diagnostic`. -#[derive(Debug, Clone)] -pub struct Children<'a>(std::slice::Iter<'a, Diagnostic>); - -impl<'a> Iterator for Children<'a> { - type Item = &'a Diagnostic; - - fn next(&mut self) -> Option { - self.0.next() - } -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } - - /// Creates a new diagnostic with the given `level` and `message` pointing to - /// the given set of `spans`. - pub fn spanned(spans: S, level: Level, message: T) -> Diagnostic - where - S: MultiSpan, - T: Into, - { - Diagnostic { level, message: message.into(), spans: spans.into_spans(), children: vec![] } - } - - diagnostic_child_methods!(span_error, error, Level::Error); - diagnostic_child_methods!(span_warning, warning, Level::Warning); - diagnostic_child_methods!(span_note, note, Level::Note); - diagnostic_child_methods!(span_help, help, Level::Help); - - /// Returns the diagnostic `level` for `self`. - pub fn level(&self) -> Level { - self.level - } - - /// Sets the level in `self` to `level`. - pub fn set_level(&mut self, level: Level) { - self.level = level; - } - - /// Returns the message in `self`. - pub fn message(&self) -> &str { - &self.message - } - - /// Sets the message in `self` to `message`. - pub fn set_message>(&mut self, message: T) { - self.message = message.into(); - } - - /// Returns the `Span`s in `self`. - pub fn spans(&self) -> &[Span] { - &self.spans - } - - /// Sets the `Span`s in `self` to `spans`. - pub fn set_spans(&mut self, spans: S) { - self.spans = spans.into_spans(); - } - - /// Returns an iterator over the children diagnostics of `self`. - pub fn children(&self) -> Children<'_> { - Children(self.children.iter()) - } - - /// Emit the diagnostic. - pub fn emit(self) { - fn to_internal(spans: Vec) -> super::bridge::client::MultiSpan { - let mut multi_span = super::bridge::client::MultiSpan::new(); - for span in spans { - multi_span.push(span.0); - } - multi_span - } - - let mut diag = super::bridge::client::Diagnostic::new( - self.level, - &self.message[..], - to_internal(self.spans), - ); - for c in self.children { - diag.sub(c.level, &c.message[..], to_internal(c.spans)); - } - diag.emit(); - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs deleted file mode 100644 index 86a59b645590..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/mod.rs +++ /dev/null @@ -1,1125 +0,0 @@ -//! A support library for macro authors when defining new macros. -//! -//! This library, provided by the standard distribution, provides the types -//! consumed in the interfaces of procedurally defined macro definitions such as -//! function-like macros `#[proc_macro]`, macro attributes `#[proc_macro_attribute]` and -//! custom derive attributes`#[proc_macro_derive]`. -//! -//! See [the book] for more. -//! -//! [the book]: ../book/ch19-06-macros.html#procedural-macros-for-generating-code-from-attributes - -#[doc(hidden)] -pub mod bridge; - -mod diagnostic; - -pub use diagnostic::{Diagnostic, Level, MultiSpan}; - -use std::cmp::Ordering; -use std::ops::RangeBounds; -use std::path::PathBuf; -use std::str::FromStr; -use std::{error, fmt, iter, mem}; - -/// Determines whether proc_macro has been made accessible to the currently -/// running program. -/// -/// The proc_macro crate is only intended for use inside the implementation of -/// procedural macros. All the functions in this crate panic if invoked from -/// outside of a procedural macro, such as from a build script or unit test or -/// ordinary Rust binary. -/// -/// With consideration for Rust libraries that are designed to support both -/// macro and non-macro use cases, `proc_macro::is_available()` provides a -/// non-panicking way to detect whether the infrastructure required to use the -/// API of proc_macro is presently available. Returns true if invoked from -/// inside of a procedural macro, false if invoked from any other binary. -pub fn is_available() -> bool { - bridge::client::is_available() -} - -/// The main type provided by this crate, representing an abstract stream of -/// tokens, or, more specifically, a sequence of token trees. -/// The type provide interfaces for iterating over those token trees and, conversely, -/// collecting a number of token trees into one stream. -/// -/// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]` -/// and `#[proc_macro_derive]` definitions. -#[derive(Clone)] -pub struct TokenStream(Option); - -/// Error returned from `TokenStream::from_str`. -#[non_exhaustive] -#[derive(Debug)] -pub struct LexError; - -impl fmt::Display for LexError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("cannot parse string into token stream") - } -} - -impl error::Error for LexError {} - -/// Error returned from `TokenStream::expand_expr`. -#[non_exhaustive] -#[derive(Debug)] -pub struct ExpandError; - -impl fmt::Display for ExpandError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("macro expansion failed") - } -} - -impl error::Error for ExpandError {} - -impl TokenStream { - /// Returns an empty `TokenStream` containing no token trees. - pub fn new() -> TokenStream { - TokenStream(None) - } - - /// Checks if this `TokenStream` is empty. - pub fn is_empty(&self) -> bool { - self.0.as_ref().map(|h| h.is_empty()).unwrap_or(true) - } - - /// Parses this `TokenStream` as an expression and attempts to expand any - /// macros within it. Returns the expanded `TokenStream`. - /// - /// Currently only expressions expanding to literals will succeed, although - /// this may be relaxed in the future. - /// - /// NOTE: In error conditions, `expand_expr` may leave macros unexpanded, - /// report an error, failing compilation, and/or return an `Err(..)`. The - /// specific behavior for any error condition, and what conditions are - /// considered errors, is unspecified and may change in the future. - pub fn expand_expr(&self) -> Result { - let stream = self.0.as_ref().ok_or(ExpandError)?; - match bridge::client::TokenStream::expand_expr(stream) { - Ok(stream) => Ok(TokenStream(Some(stream))), - Err(_) => Err(ExpandError), - } - } -} - -/// Attempts to break the string into tokens and parse those tokens into a token stream. -/// May fail for a number of reasons, for example, if the string contains unbalanced delimiters -/// or characters not existing in the language. -/// All tokens in the parsed stream get `Span::call_site()` spans. -/// -/// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to -/// change these errors into `LexError`s later. -impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - Ok(TokenStream(Some(bridge::client::TokenStream::from_str(src)))) - } -} - -/// Prints the token stream as a string that is supposed to be losslessly convertible back -/// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters and negative numeric literals. -impl fmt::Display for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -/// Prints token in a form convenient for debugging. -impl fmt::Debug for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("TokenStream ")?; - f.debug_list().entries(self.clone()).finish() - } -} - -impl Default for TokenStream { - fn default() -> Self { - TokenStream::new() - } -} - -pub use quote::{quote, quote_span}; - -fn tree_to_bridge_tree( - tree: TokenTree, -) -> bridge::TokenTree< - bridge::client::TokenStream, - bridge::client::Span, - bridge::client::Ident, - bridge::client::Literal, -> { - match tree { - TokenTree::Group(tt) => bridge::TokenTree::Group(tt.0), - TokenTree::Punct(tt) => bridge::TokenTree::Punct(tt.0), - TokenTree::Ident(tt) => bridge::TokenTree::Ident(tt.0), - TokenTree::Literal(tt) => bridge::TokenTree::Literal(tt.0), - } -} - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream(Some(bridge::client::TokenStream::from_token_tree(tree_to_bridge_tree(tree)))) - } -} - -/// Non-generic helper for implementing `FromIterator` and -/// `Extend` with less monomorphization in calling crates. -struct ConcatStreamsHelper { - streams: Vec, -} - -impl ConcatStreamsHelper { - fn new(capacity: usize) -> Self { - ConcatStreamsHelper { streams: Vec::with_capacity(capacity) } - } - - fn push(&mut self, stream: TokenStream) { - if let Some(stream) = stream.0 { - self.streams.push(stream); - } - } - - fn build(mut self) -> TokenStream { - if self.streams.len() <= 1 { - TokenStream(self.streams.pop()) - } else { - TokenStream(Some(bridge::client::TokenStream::concat_streams(None, self.streams))) - } - } - - fn append_to(mut self, stream: &mut TokenStream) { - if self.streams.is_empty() { - return; - } - let base = stream.0.take(); - if base.is_none() && self.streams.len() == 1 { - stream.0 = self.streams.pop(); - } else { - stream.0 = Some(bridge::client::TokenStream::concat_streams(base, self.streams)); - } - } -} - -/// Collects a number of token trees into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let iter = streams.into_iter(); - let mut builder = ConcatStreamsHelper::new(iter.size_hint().0); - iter.for_each(|stream| builder.push(stream)); - builder.build() - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - // FIXME(eddyb) Use an optimized implementation if/when possible. - *self = iter::once(mem::replace(self, Self::new())).chain(streams).collect(); - } -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use super::{bridge, Group, Ident, Literal, Punct, TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - #[derive(Clone)] - pub struct IntoIter( - std::vec::IntoIter< - bridge::TokenTree< - bridge::client::TokenStream, - bridge::client::Span, - bridge::client::Ident, - bridge::client::Literal, - >, - >, - ); - - impl Iterator for IntoIter { - type Item = TokenTree; - - fn next(&mut self) -> Option { - self.0.next().map(|tree| match tree { - bridge::TokenTree::Group(tt) => TokenTree::Group(Group(tt)), - bridge::TokenTree::Punct(tt) => TokenTree::Punct(Punct(tt)), - bridge::TokenTree::Ident(tt) => TokenTree::Ident(Ident(tt)), - bridge::TokenTree::Literal(tt) => TokenTree::Literal(Literal(tt)), - }) - } - } - - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - IntoIter(self.0.map(|v| v.into_trees()).unwrap_or_default().into_iter()) - } - } -} - -#[doc(hidden)] -mod quote; - -/// A region of source code, along with macro expansion information. -#[derive(Copy, Clone)] -pub struct Span(bridge::client::Span); - -macro_rules! diagnostic_method { - ($name:ident, $level:expr) => { - /// Creates a new `Diagnostic` with the given `message` at the span - /// `self`. - pub fn $name>(self, message: T) -> Diagnostic { - Diagnostic::spanned(self, $level, message) - } - }; -} - -impl Span { - /// A span that resolves at the macro definition site. - pub fn def_site() -> Span { - Span(bridge::client::Span::def_site()) - } - - /// The span of the invocation of the current procedural macro. - /// Identifiers created with this span will be resolved as if they were written - /// directly at the macro call location (call-site hygiene) and other code - /// at the macro call site will be able to refer to them as well. - pub fn call_site() -> Span { - Span(bridge::client::Span::call_site()) - } - - /// A span that represents `macro_rules` hygiene, and sometimes resolves at the macro - /// definition site (local variables, labels, `$crate`) and sometimes at the macro - /// call site (everything else). - /// The span location is taken from the call-site. - pub fn mixed_site() -> Span { - Span(bridge::client::Span::mixed_site()) - } - - /// The original source file into which this span points. - pub fn source_file(&self) -> SourceFile { - SourceFile(self.0.source_file()) - } - - /// The `Span` for the tokens in the previous macro expansion from which - /// `self` was generated from, if any. - pub fn parent(&self) -> Option { - self.0.parent().map(Span) - } - - /// The span for the origin source code that `self` was generated from. If - /// this `Span` wasn't generated from other macro expansions then the return - /// value is the same as `*self`. - pub fn source(&self) -> Span { - Span(self.0.source()) - } - - /// Gets the starting line/column in the source file for this span. - pub fn start(&self) -> LineColumn { - self.0.start().add_1_to_column() - } - - /// Gets the ending line/column in the source file for this span. - pub fn end(&self) -> LineColumn { - self.0.end().add_1_to_column() - } - - /// Creates an empty span pointing to directly before this span. - pub fn before(&self) -> Span { - Span(self.0.before()) - } - - /// Creates an empty span pointing to directly after this span. - pub fn after(&self) -> Span { - Span(self.0.after()) - } - - /// Creates a new span encompassing `self` and `other`. - /// - /// Returns `None` if `self` and `other` are from different files. - pub fn join(&self, other: Span) -> Option { - self.0.join(other.0).map(Span) - } - - /// Creates a new span with the same line/column information as `self` but - /// that resolves symbols as though it were at `other`. - pub fn resolved_at(&self, other: Span) -> Span { - Span(self.0.resolved_at(other.0)) - } - - /// Creates a new span with the same name resolution behavior as `self` but - /// with the line/column information of `other`. - pub fn located_at(&self, other: Span) -> Span { - other.resolved_at(*self) - } - - /// Compares to spans to see if they're equal. - pub fn eq(&self, other: &Span) -> bool { - self.0 == other.0 - } - - /// Returns the source text behind a span. This preserves the original source - /// code, including spaces and comments. It only returns a result if the span - /// corresponds to real source code. - /// - /// Note: The observable result of a macro should only rely on the tokens and - /// not on this source text. The result of this function is a best effort to - /// be used for diagnostics only. - pub fn source_text(&self) -> Option { - self.0.source_text() - } - - // Used by the implementation of `Span::quote` - #[doc(hidden)] - pub fn save_span(&self) -> usize { - self.0.save_span() - } - - // Used by the implementation of `Span::quote` - #[doc(hidden)] - pub fn recover_proc_macro_span(id: usize) -> Span { - Span(bridge::client::Span::recover_proc_macro_span(id)) - } - - diagnostic_method!(error, Level::Error); - diagnostic_method!(warning, Level::Warning); - diagnostic_method!(note, Level::Note); - diagnostic_method!(help, Level::Help); -} - -/// Prints a span in a form convenient for debugging. -impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// A line-column pair representing the start or end of a `Span`. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct LineColumn { - /// The 1-indexed line in the source file on which the span starts or ends (inclusive). - pub line: usize, - /// The 1-indexed column (number of bytes in UTF-8 encoding) in the source - /// file on which the span starts or ends (inclusive). - pub column: usize, -} - -impl LineColumn { - fn add_1_to_column(self) -> Self { - LineColumn { line: self.line, column: self.column + 1 } - } -} - -impl Ord for LineColumn { - fn cmp(&self, other: &Self) -> Ordering { - self.line.cmp(&other.line).then(self.column.cmp(&other.column)) - } -} - -impl PartialOrd for LineColumn { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -/// The source file of a given `Span`. -#[derive(Clone)] -pub struct SourceFile(bridge::client::SourceFile); - -impl SourceFile { - /// Gets the path to this source file. - /// - /// ### Note - /// If the code span associated with this `SourceFile` was generated by an external macro, this - /// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check. - /// - /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on - /// the command line, the path as given might not actually be valid. - /// - /// [`is_real`]: Self::is_real - pub fn path(&self) -> PathBuf { - PathBuf::from(self.0.path()) - } - - /// Returns `true` if this source file is a real source file, and not generated by an external - /// macro's expansion. - pub fn is_real(&self) -> bool { - // This is a hack until intercrate spans are implemented and we can have real source files - // for spans generated in external macros. - // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368 - self.0.is_real() - } -} - -impl fmt::Debug for SourceFile { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SourceFile") - .field("path", &self.path()) - .field("is_real", &self.is_real()) - .finish() - } -} - -impl PartialEq for SourceFile { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -impl Eq for SourceFile {} - -/// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`). -#[derive(Clone)] -pub enum TokenTree { - /// A token stream surrounded by bracket delimiters. - Group(Group), - /// An identifier. - Ident(Ident), - /// A single punctuation character (`+`, `,`, `$`, etc.). - Punct(Punct), - /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc. - Literal(Literal), -} - -impl TokenTree { - /// Returns the span of this tree, delegating to the `span` method of - /// the contained token or a delimited stream. - pub fn span(&self) -> Span { - match *self { - TokenTree::Group(ref t) => t.span(), - TokenTree::Ident(ref t) => t.span(), - TokenTree::Punct(ref t) => t.span(), - TokenTree::Literal(ref t) => t.span(), - } - } - - /// Configures the span for *only this token*. - /// - /// Note that if this token is a `Group` then this method will not configure - /// the span of each of the internal tokens, this will simply delegate to - /// the `set_span` method of each variant. - pub fn set_span(&mut self, span: Span) { - match *self { - TokenTree::Group(ref mut t) => t.set_span(span), - TokenTree::Ident(ref mut t) => t.set_span(span), - TokenTree::Punct(ref mut t) => t.set_span(span), - TokenTree::Literal(ref mut t) => t.set_span(span), - } - } -} - -/// Prints token tree in a form convenient for debugging. -impl fmt::Debug for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Each of these has the name in the struct type in the derived debug, - // so don't bother with an extra layer of indirection - match *self { - TokenTree::Group(ref tt) => tt.fmt(f), - TokenTree::Ident(ref tt) => tt.fmt(f), - TokenTree::Punct(ref tt) => tt.fmt(f), - TokenTree::Literal(ref tt) => tt.fmt(f), - } - } -} - -impl From for TokenTree { - fn from(g: Group) -> TokenTree { - TokenTree::Group(g) - } -} - -impl From for TokenTree { - fn from(g: Ident) -> TokenTree { - TokenTree::Ident(g) - } -} - -impl From for TokenTree { - fn from(g: Punct) -> TokenTree { - TokenTree::Punct(g) - } -} - -impl From for TokenTree { - fn from(g: Literal) -> TokenTree { - TokenTree::Literal(g) - } -} - -/// Prints the token tree as a string that is supposed to be losslessly convertible back -/// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters and negative numeric literals. -impl fmt::Display for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -/// A delimited token stream. -/// -/// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s. -#[derive(Clone)] -pub struct Group(bridge::Group); - -/// Describes how a sequence of token trees is delimited. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Delimiter { - /// `( ... )` - Parenthesis, - /// `{ ... }` - Brace, - /// `[ ... ]` - Bracket, - /// `Ø ... Ø` - /// An invisible delimiter, that may, for example, appear around tokens coming from a - /// "macro variable" `$var`. It is important to preserve operator priorities in cases like - /// `$var * 3` where `$var` is `1 + 2`. - /// Invisible delimiters might not survive roundtrip of a token stream through a string. - None, -} - -impl Group { - /// Creates a new `Group` with the given delimiter and token stream. - /// - /// This constructor will set the span for this group to - /// `Span::call_site()`. To change the span you can use the `set_span` - /// method below. - pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { - Group(bridge::Group { - delimiter, - stream: stream.0, - span: bridge::DelimSpan::from_single(Span::call_site().0), - }) - } - - /// Returns the delimiter of this `Group` - pub fn delimiter(&self) -> Delimiter { - self.0.delimiter - } - - /// Returns the `TokenStream` of tokens that are delimited in this `Group`. - /// - /// Note that the returned token stream does not include the delimiter - /// returned above. - pub fn stream(&self) -> TokenStream { - TokenStream(self.0.stream.clone()) - } - - /// Returns the span for the delimiters of this token stream, spanning the - /// entire `Group`. - /// - /// ```text - /// pub fn span(&self) -> Span { - /// ^^^^^^^ - /// ``` - pub fn span(&self) -> Span { - Span(self.0.span.entire) - } - - /// Returns the span pointing to the opening delimiter of this group. - /// - /// ```text - /// pub fn span_open(&self) -> Span { - /// ^ - /// ``` - pub fn span_open(&self) -> Span { - Span(self.0.span.open) - } - - /// Returns the span pointing to the closing delimiter of this group. - /// - /// ```text - /// pub fn span_close(&self) -> Span { - /// ^ - /// ``` - pub fn span_close(&self) -> Span { - Span(self.0.span.close) - } - - /// Configures the span for this `Group`'s delimiters, but not its internal - /// tokens. - /// - /// This method will **not** set the span of all the internal tokens spanned - /// by this group, but rather it will only set the span of the delimiter - /// tokens at the level of the `Group`. - pub fn set_span(&mut self, span: Span) { - self.0.span = bridge::DelimSpan::from_single(span.0); - } -} - -/// Prints the group as a string that should be losslessly convertible back -/// into the same group (modulo spans), except for possibly `TokenTree::Group`s -/// with `Delimiter::None` delimiters. -impl fmt::Display for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Group") - .field("delimiter", &self.delimiter()) - .field("stream", &self.stream()) - .field("span", &self.span()) - .finish() - } -} - -/// A `Punct` is a single punctuation character such as `+`, `-` or `#`. -/// -/// Multi-character operators like `+=` are represented as two instances of `Punct` with different -/// forms of `Spacing` returned. -#[derive(Clone)] -pub struct Punct(bridge::Punct); - -/// Describes whether a `Punct` is followed immediately by another `Punct` ([`Spacing::Joint`]) or -/// by a different token or whitespace ([`Spacing::Alone`]). -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Spacing { - /// A `Punct` is not immediately followed by another `Punct`. - /// E.g. `+` is `Alone` in `+ =`, `+ident` and `+()`. - Alone, - /// A `Punct` is immediately followed by another `Punct`. - /// E.g. `+` is `Joint` in `+=` and `++`. - /// - /// Additionally, single quote `'` can join with identifiers to form lifetimes: `'ident`. - Joint, -} - -impl Punct { - /// Creates a new `Punct` from the given character and spacing. - /// The `ch` argument must be a valid punctuation character permitted by the language, - /// otherwise the function will panic. - /// - /// The returned `Punct` will have the default span of `Span::call_site()` - /// which can be further configured with the `set_span` method below. - pub fn new(ch: char, spacing: Spacing) -> Punct { - const LEGAL_CHARS: &[char] = &[ - '=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^', '&', '|', '@', '.', ',', ';', - ':', '#', '$', '?', '\'', - ]; - if !LEGAL_CHARS.contains(&ch) { - panic!("unsupported character `{:?}`", ch); - } - Punct(bridge::Punct { - ch: ch as u8, - joint: spacing == Spacing::Joint, - span: Span::call_site().0, - }) - } - - /// Returns the value of this punctuation character as `char`. - pub fn as_char(&self) -> char { - self.0.ch as char - } - - /// Returns the spacing of this punctuation character, indicating whether it's immediately - /// followed by another `Punct` in the token stream, so they can potentially be combined into - /// a multi-character operator (`Joint`), or it's followed by some other token or whitespace - /// (`Alone`) so the operator has certainly ended. - pub fn spacing(&self) -> Spacing { - if self.0.joint { - Spacing::Joint - } else { - Spacing::Alone - } - } - - /// Returns the span for this punctuation character. - pub fn span(&self) -> Span { - Span(self.0.span) - } - - /// Configure the span for this punctuation character. - pub fn set_span(&mut self, span: Span) { - self.0.span = span.0; - } -} - -/// Prints the punctuation character as a string that should be losslessly convertible -/// back into the same character. -impl fmt::Display for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Punct") - .field("ch", &self.as_char()) - .field("spacing", &self.spacing()) - .field("span", &self.span()) - .finish() - } -} - -impl PartialEq for Punct { - fn eq(&self, rhs: &char) -> bool { - self.as_char() == *rhs - } -} - -impl PartialEq for char { - fn eq(&self, rhs: &Punct) -> bool { - *self == rhs.as_char() - } -} - -/// An identifier (`ident`). -#[derive(Clone)] -pub struct Ident(bridge::client::Ident); - -impl Ident { - /// Creates a new `Ident` with the given `string` as well as the specified - /// `span`. - /// The `string` argument must be a valid identifier permitted by the - /// language (including keywords, e.g. `self` or `fn`). Otherwise, the function will panic. - /// - /// Note that `span`, currently in rustc, configures the hygiene information - /// for this identifier. - /// - /// As of this time `Span::call_site()` explicitly opts-in to "call-site" hygiene - /// meaning that identifiers created with this span will be resolved as if they were written - /// directly at the location of the macro call, and other code at the macro call site will be - /// able to refer to them as well. - /// - /// Later spans like `Span::def_site()` will allow to opt-in to "definition-site" hygiene - /// meaning that identifiers created with this span will be resolved at the location of the - /// macro definition and other code at the macro call site will not be able to refer to them. - /// - /// Due to the current importance of hygiene this constructor, unlike other - /// tokens, requires a `Span` to be specified at construction. - pub fn new(string: &str, span: Span) -> Ident { - Ident(bridge::client::Ident::new(string, span.0, false)) - } - - /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). - /// The `string` argument be a valid identifier permitted by the language - /// (including keywords, e.g. `fn`). Keywords which are usable in path segments - /// (e.g. `self`, `super`) are not supported, and will cause a panic. - pub fn new_raw(string: &str, span: Span) -> Ident { - Ident(bridge::client::Ident::new(string, span.0, true)) - } - - /// Returns the span of this `Ident`, encompassing the entire string returned - /// by [`to_string`](Self::to_string). - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configures the span of this `Ident`, possibly changing its hygiene context. - pub fn set_span(&mut self, span: Span) { - self.0 = self.0.with_span(span.0); - } -} - -/// Prints the identifier as a string that should be losslessly convertible -/// back into the same identifier. -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Ident") - .field("ident", &self.to_string()) - .field("span", &self.span()) - .finish() - } -} - -/// A literal string (`"hello"`), byte string (`b"hello"`), -/// character (`'a'`), byte character (`b'a'`), an integer or floating point number -/// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`). -/// Boolean literals like `true` and `false` do not belong here, they are `Ident`s. -#[derive(Clone)] -pub struct Literal(bridge::client::Literal); - -macro_rules! suffixed_int_literals { - ($($name:ident => $kind:ident,)*) => ($( - /// Creates a new suffixed integer literal with the specified value. - /// - /// This function will create an integer like `1u32` where the integer - /// value specified is the first part of the token and the integral is - /// also suffixed at the end. - /// Literals created from negative numbers might not survive round-trips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// Literals created through this method have the `Span::call_site()` - /// span by default, which can be configured with the `set_span` method - /// below. - pub fn $name(n: $kind) -> Literal { - Literal(bridge::client::Literal::typed_integer(&n.to_string(), stringify!($kind))) - } - )*) -} - -macro_rules! unsuffixed_int_literals { - ($($name:ident => $kind:ident,)*) => ($( - /// Creates a new unsuffixed integer literal with the specified value. - /// - /// This function will create an integer like `1` where the integer - /// value specified is the first part of the token. No suffix is - /// specified on this token, meaning that invocations like - /// `Literal::i8_unsuffixed(1)` are equivalent to - /// `Literal::u32_unsuffixed(1)`. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// Literals created through this method have the `Span::call_site()` - /// span by default, which can be configured with the `set_span` method - /// below. - pub fn $name(n: $kind) -> Literal { - Literal(bridge::client::Literal::integer(&n.to_string())) - } - )*) -} - -impl Literal { - suffixed_int_literals! { - u8_suffixed => u8, - u16_suffixed => u16, - u32_suffixed => u32, - u64_suffixed => u64, - u128_suffixed => u128, - usize_suffixed => usize, - i8_suffixed => i8, - i16_suffixed => i16, - i32_suffixed => i32, - i64_suffixed => i64, - i128_suffixed => i128, - isize_suffixed => isize, - } - - unsuffixed_int_literals! { - u8_unsuffixed => u8, - u16_unsuffixed => u16, - u32_unsuffixed => u32, - u64_unsuffixed => u64, - u128_unsuffixed => u128, - usize_unsuffixed => usize, - i8_unsuffixed => i8, - i16_unsuffixed => i16, - i32_unsuffixed => i32, - i64_unsuffixed => i64, - i128_unsuffixed => i128, - isize_unsuffixed => isize, - } - - /// Creates a new unsuffixed floating-point literal. - /// - /// This constructor is similar to those like `Literal::i8_unsuffixed` where - /// the float's value is emitted directly into the token but no suffix is - /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f32_unsuffixed(n: f32) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - let mut repr = n.to_string(); - if !repr.contains('.') { - repr.push_str(".0"); - } - Literal(bridge::client::Literal::float(&repr)) - } - - /// Creates a new suffixed floating-point literal. - /// - /// This constructor will create a literal like `1.0f32` where the value - /// specified is the preceding part of the token and `f32` is the suffix of - /// the token. This token will always be inferred to be an `f32` in the - /// compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f32_suffixed(n: f32) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - Literal(bridge::client::Literal::f32(&n.to_string())) - } - - /// Creates a new unsuffixed floating-point literal. - /// - /// This constructor is similar to those like `Literal::i8_unsuffixed` where - /// the float's value is emitted directly into the token but no suffix is - /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f64_unsuffixed(n: f64) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - let mut repr = n.to_string(); - if !repr.contains('.') { - repr.push_str(".0"); - } - Literal(bridge::client::Literal::float(&repr)) - } - - /// Creates a new suffixed floating-point literal. - /// - /// This constructor will create a literal like `1.0f64` where the value - /// specified is the preceding part of the token and `f64` is the suffix of - /// the token. This token will always be inferred to be an `f64` in the - /// compiler. - /// Literals created from negative numbers might not survive rountrips through - /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). - /// - /// # Panics - /// - /// This function requires that the specified float is finite, for - /// example if it is infinity or NaN this function will panic. - pub fn f64_suffixed(n: f64) -> Literal { - if !n.is_finite() { - panic!("Invalid float literal {n}"); - } - Literal(bridge::client::Literal::f64(&n.to_string())) - } - - /// String literal. - pub fn string(string: &str) -> Literal { - Literal(bridge::client::Literal::string(string)) - } - - /// Character literal. - pub fn character(ch: char) -> Literal { - Literal(bridge::client::Literal::character(ch)) - } - - /// Byte string literal. - pub fn byte_string(bytes: &[u8]) -> Literal { - Literal(bridge::client::Literal::byte_string(bytes)) - } - - /// Returns the span encompassing this literal. - pub fn span(&self) -> Span { - Span(self.0.span()) - } - - /// Configures the span associated for this literal. - pub fn set_span(&mut self, span: Span) { - self.0.set_span(span.0); - } - - /// Returns a `Span` that is a subset of `self.span()` containing only the - /// source bytes in range `range`. Returns `None` if the would-be trimmed - /// span is outside the bounds of `self`. - // FIXME(SergioBenitez): check that the byte range starts and ends at a - // UTF-8 boundary of the source. otherwise, it's likely that a panic will - // occur elsewhere when the source text is printed. - // FIXME(SergioBenitez): there is no way for the user to know what - // `self.span()` actually maps to, so this method can currently only be - // called blindly. For example, `to_string()` for the character 'c' returns - // "'\u{63}'"; there is no way for the user to know whether the source text - // was 'c' or whether it was '\u{63}'. - pub fn subspan>(&self, range: R) -> Option { - self.0.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span) - } -} - -/// Parse a single literal from its stringified representation. -/// -/// In order to parse successfully, the input string must not contain anything -/// but the literal token. Specifically, it must not contain whitespace or -/// comments in addition to the literal. -/// -/// The resulting literal token will have a `Span::call_site()` span. -/// -/// NOTE: some errors may cause panics instead of returning `LexError`. We -/// reserve the right to change these errors into `LexError`s later. -impl FromStr for Literal { - type Err = LexError; - - fn from_str(src: &str) -> Result { - match bridge::client::Literal::from_str(src) { - Ok(literal) => Ok(Literal(literal)), - Err(()) => Err(LexError), - } - } -} - -/// Prints the literal as a string that should be losslessly convertible -/// back into the same literal (except for possible rounding for floating point literals). -impl fmt::Display for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// Tracked access to environment variables. -pub mod tracked_env { - use std::env::{self, VarError}; - use std::ffi::OsStr; - - /// Retrieve an environment variable and add it to build dependency info. - /// Build system executing the compiler will know that the variable was accessed during - /// compilation, and will be able to rerun the build when the value of that variable changes. - /// Besides the dependency tracking this function should be equivalent to `env::var` from the - /// standard library, except that the argument must be UTF-8. - pub fn var + AsRef>(key: K) -> Result { - let key: &str = key.as_ref(); - let value = env::var(key); - super::bridge::client::FreeFunctions::track_env_var(key, value.as_deref().ok()); - value - } -} - -/// Tracked access to additional files. -pub mod tracked_path { - - /// Track a file explicitly. - /// - /// Commonly used for tracking asset preprocessing. - pub fn path>(path: P) { - let path: &str = path.as_ref(); - super::bridge::client::FreeFunctions::track_path(path); - } -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/quote.rs b/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/quote.rs deleted file mode 100644 index 39309faa4121..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/proc_macro/quote.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! # Quasiquoter -//! This file contains the implementation internals of the quasiquoter provided by `quote!`. - -//! This quasiquoter uses macros 2.0 hygiene to reliably access -//! items from `proc_macro`, to build a `proc_macro::TokenStream`. - -use super::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; - -macro_rules! quote_tt { - (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; - ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) }; - ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; - (,) => { Punct::new(',', Spacing::Alone) }; - (.) => { Punct::new('.', Spacing::Alone) }; - (;) => { Punct::new(';', Spacing::Alone) }; - (!) => { Punct::new('!', Spacing::Alone) }; - (<) => { Punct::new('<', Spacing::Alone) }; - (>) => { Punct::new('>', Spacing::Alone) }; - (&) => { Punct::new('&', Spacing::Alone) }; - (=) => { Punct::new('=', Spacing::Alone) }; - ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) }; -} - -macro_rules! quote_ts { - ((@ $($t:tt)*)) => { $($t)* }; - (::) => { - [ - TokenTree::from(Punct::new(':', Spacing::Joint)), - TokenTree::from(Punct::new(':', Spacing::Alone)), - ].iter() - .cloned() - .map(|mut x| { - x.set_span(Span::def_site()); - x - }) - .collect::() - }; - ($t:tt) => { TokenTree::from(quote_tt!($t)) }; -} - -/// Simpler version of the real `quote!` macro, implemented solely -/// through `macro_rules`, for bootstrapping the real implementation -/// (see the `quote` function), which does not have access to the -/// real `quote!` macro due to the `proc_macro` crate not being -/// able to depend on itself. -/// -/// Note: supported tokens are a subset of the real `quote!`, but -/// unquoting is different: instead of `$x`, this uses `(@ expr)`. -macro_rules! quote { - () => { TokenStream::new() }; - ($($t:tt)*) => { - [ - $(TokenStream::from(quote_ts!($t)),)* - ].iter().cloned().collect::() - }; -} - -/// Quote a `TokenStream` into a `TokenStream`. -/// This is the actual implementation of the `quote!()` proc macro. -/// -/// It is loaded by the compiler in `register_builtin_macros`. -pub fn quote(stream: TokenStream) -> TokenStream { - if stream.is_empty() { - return quote!(super::TokenStream::new()); - } - let proc_macro_crate = quote!(crate); - let mut after_dollar = false; - let tokens = stream - .into_iter() - .filter_map(|tree| { - if after_dollar { - after_dollar = false; - match tree { - TokenTree::Ident(_) => { - return Some(quote!(Into::::into( - Clone::clone(&(@ tree))),)); - } - TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} - _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), - } - } else if let TokenTree::Punct(ref tt) = tree { - if tt.as_char() == '$' { - after_dollar = true; - return None; - } - } - - Some(quote!(super::TokenStream::from((@ match tree { - TokenTree::Punct(tt) => quote!(super::TokenTree::Punct(super::Punct::new( - (@ TokenTree::from(Literal::character(tt.as_char()))), - (@ match tt.spacing() { - Spacing::Alone => quote!(super::Spacing::Alone), - Spacing::Joint => quote!(super::Spacing::Joint), - }), - ))), - TokenTree::Group(tt) => quote!(super::TokenTree::Group(super::Group::new( - (@ match tt.delimiter() { - Delimiter::Parenthesis => quote!(super::Delimiter::Parenthesis), - Delimiter::Brace => quote!(super::Delimiter::Brace), - Delimiter::Bracket => quote!(super::Delimiter::Bracket), - Delimiter::None => quote!(super::Delimiter::None), - }), - (@ quote(tt.stream())), - ))), - TokenTree::Ident(tt) => quote!(super::TokenTree::Ident(super::Ident::new( - (@ TokenTree::from(Literal::string(&tt.to_string()))), - (@ quote_span(proc_macro_crate.clone(), tt.span())), - ))), - TokenTree::Literal(tt) => quote!(super::TokenTree::Literal({ - let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) - .parse::() - .unwrap() - .into_iter(); - if let (Some(super::TokenTree::Literal(mut lit)), None) = - (iter.next(), iter.next()) - { - lit.set_span((@ quote_span(proc_macro_crate.clone(), tt.span()))); - lit - } else { - unreachable!() - } - })) - })),)) - }) - .collect::(); - - if after_dollar { - panic!("unexpected trailing `$` in `quote!`"); - } - - quote!([(@ tokens)].iter().cloned().collect::()) -} - -/// Quote a `Span` into a `TokenStream`. -/// This is needed to implement a custom quoter. -pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream { - let id = span.save_span(); - quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id))))) -} diff --git a/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs b/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs deleted file mode 100644 index d8aa1ec429a7..000000000000 --- a/crates/proc-macro-srv/src/abis/abi_1_64/ra_server.rs +++ /dev/null @@ -1,791 +0,0 @@ -//! Rustc proc-macro server implementation with tt -//! -//! Based on idea from -//! The lib-proc-macro server backend is `TokenStream`-agnostic, such that -//! we could provide any TokenStream implementation. -//! The original idea from fedochet is using proc-macro2 as backend, -//! we use tt instead for better integration with RA. -//! -//! FIXME: No span and source file information is implemented yet - -use super::proc_macro::bridge::{self, server}; - -use std::collections::HashMap; -use std::hash::Hash; -use std::ops::Bound; -use std::{ascii, vec::IntoIter}; - -type Group = tt::Subtree; -type TokenTree = tt::TokenTree; -type Punct = tt::Punct; -type Spacing = tt::Spacing; -type Literal = tt::Literal; -type Span = tt::TokenId; - -#[derive(Debug, Default, Clone)] -pub struct TokenStream { - pub token_trees: Vec, -} - -impl TokenStream { - pub fn new() -> Self { - TokenStream::default() - } - - pub fn with_subtree(subtree: tt::Subtree) -> Self { - if subtree.delimiter.is_some() { - TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] } - } else { - TokenStream { token_trees: subtree.token_trees } - } - } - - pub fn into_subtree(self) -> tt::Subtree { - tt::Subtree { delimiter: None, token_trees: self.token_trees } - } - - pub fn is_empty(&self) -> bool { - self.token_trees.is_empty() - } -} - -/// Creates a token stream containing a single token tree. -impl From for TokenStream { - fn from(tree: TokenTree) -> TokenStream { - TokenStream { token_trees: vec![tree] } - } -} - -/// Collects a number of token trees into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(trees: I) -> Self { - trees.into_iter().map(TokenStream::from).collect() - } -} - -/// A "flattening" operation on token streams, collects token trees -/// from multiple token streams into a single stream. -impl FromIterator for TokenStream { - fn from_iter>(streams: I) -> Self { - let mut builder = TokenStreamBuilder::new(); - streams.into_iter().for_each(|stream| builder.push(stream)); - builder.build() - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, trees: I) { - self.extend(trees.into_iter().map(TokenStream::from)); - } -} - -impl Extend for TokenStream { - fn extend>(&mut self, streams: I) { - for item in streams { - for tkn in item { - match tkn { - tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => { - self.token_trees.extend(subtree.token_trees); - } - _ => { - self.token_trees.push(tkn); - } - } - } - } - } -} - -#[derive(Clone)] -pub struct SourceFile { - // FIXME stub -} - -type Level = super::proc_macro::Level; -type LineColumn = super::proc_macro::LineColumn; - -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } -} - -// Rustc Server Ident has to be `Copyable` -// We use a stub here for bypassing -#[derive(Hash, Eq, PartialEq, Copy, Clone)] -pub struct IdentId(u32); - -#[derive(Clone, Hash, Eq, PartialEq)] -struct IdentData(tt::Ident); - -#[derive(Default)] -struct IdentInterner { - idents: HashMap, - ident_data: Vec, -} - -impl IdentInterner { - fn intern(&mut self, data: &IdentData) -> u32 { - if let Some(index) = self.idents.get(data) { - return *index; - } - - let index = self.idents.len() as u32; - self.ident_data.push(data.clone()); - self.idents.insert(data.clone(), index); - index - } - - fn get(&self, index: u32) -> &IdentData { - &self.ident_data[index as usize] - } - - #[allow(unused)] - fn get_mut(&mut self, index: u32) -> &mut IdentData { - self.ident_data.get_mut(index as usize).expect("Should be consistent") - } -} - -pub struct TokenStreamBuilder { - acc: TokenStream, -} - -/// Public implementation details for the `TokenStream` type, such as iterators. -pub mod token_stream { - use std::str::FromStr; - - use super::{TokenStream, TokenTree}; - - /// An iterator over `TokenStream`'s `TokenTree`s. - /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, - /// and returns whole groups as token trees. - impl IntoIterator for TokenStream { - type Item = TokenTree; - type IntoIter = super::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.token_trees.into_iter() - } - } - - type LexError = String; - - /// Attempts to break the string into tokens and parse those tokens into a token stream. - /// May fail for a number of reasons, for example, if the string contains unbalanced delimiters - /// or characters not existing in the language. - /// All tokens in the parsed stream get `Span::call_site()` spans. - /// - /// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to - /// change these errors into `LexError`s later. - impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - let (subtree, _token_map) = - mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; - - let subtree = subtree_replace_token_ids_with_unspecified(subtree); - Ok(TokenStream::with_subtree(subtree)) - } - } - - impl ToString for TokenStream { - fn to_string(&self) -> String { - tt::pretty(&self.token_trees) - } - } - - fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree { - tt::Subtree { - delimiter: subtree - .delimiter - .map(|d| tt::Delimiter { id: tt::TokenId::unspecified(), ..d }), - token_trees: subtree - .token_trees - .into_iter() - .map(token_tree_replace_token_ids_with_unspecified) - .collect(), - } - } - - fn token_tree_replace_token_ids_with_unspecified(tt: tt::TokenTree) -> tt::TokenTree { - match tt { - tt::TokenTree::Leaf(leaf) => { - tt::TokenTree::Leaf(leaf_replace_token_ids_with_unspecified(leaf)) - } - tt::TokenTree::Subtree(subtree) => { - tt::TokenTree::Subtree(subtree_replace_token_ids_with_unspecified(subtree)) - } - } - } - - fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf { - match leaf { - tt::Leaf::Literal(lit) => { - tt::Leaf::Literal(tt::Literal { id: tt::TokenId::unspecified(), ..lit }) - } - tt::Leaf::Punct(punct) => { - tt::Leaf::Punct(tt::Punct { id: tt::TokenId::unspecified(), ..punct }) - } - tt::Leaf::Ident(ident) => { - tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), ..ident }) - } - } - } -} - -impl TokenStreamBuilder { - fn new() -> TokenStreamBuilder { - TokenStreamBuilder { acc: TokenStream::new() } - } - - fn push(&mut self, stream: TokenStream) { - self.acc.extend(stream.into_iter()) - } - - fn build(self) -> TokenStream { - self.acc - } -} - -pub struct FreeFunctions; - -#[derive(Clone)] -pub struct TokenStreamIter { - trees: IntoIter, -} - -#[derive(Default)] -pub struct RustAnalyzer { - ident_interner: IdentInterner, - // FIXME: store span information here. -} - -impl server::Types for RustAnalyzer { - type FreeFunctions = FreeFunctions; - type TokenStream = TokenStream; - type Ident = IdentId; - type Literal = Literal; - type SourceFile = SourceFile; - type Diagnostic = Diagnostic; - type Span = Span; - type MultiSpan = Vec; -} - -impl server::FreeFunctions for RustAnalyzer { - fn track_env_var(&mut self, _var: &str, _value: Option<&str>) { - // FIXME: track env var accesses - // https://github.com/rust-lang/rust/pull/71858 - } - fn track_path(&mut self, _path: &str) {} -} - -impl server::TokenStream for RustAnalyzer { - fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { - stream.is_empty() - } - fn from_str(&mut self, src: &str) -> Self::TokenStream { - use std::str::FromStr; - - Self::TokenStream::from_str(src).expect("cannot parse string") - } - fn to_string(&mut self, stream: &Self::TokenStream) -> String { - stream.to_string() - } - fn from_token_tree( - &mut self, - tree: bridge::TokenTree, - ) -> Self::TokenStream { - match tree { - bridge::TokenTree::Group(group) => { - let group = Group { - delimiter: delim_to_internal(group.delimiter), - token_trees: match group.stream { - Some(stream) => stream.into_iter().collect(), - None => Vec::new(), - }, - }; - let tree = TokenTree::from(group); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Ident(IdentId(index)) => { - let IdentData(ident) = self.ident_interner.get(index).clone(); - let ident: tt::Ident = ident; - let leaf = tt::Leaf::from(ident); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Literal(literal) => { - let leaf = tt::Leaf::from(literal); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - - bridge::TokenTree::Punct(p) => { - let punct = tt::Punct { - char: p.ch as char, - spacing: if p.joint { Spacing::Joint } else { Spacing::Alone }, - id: p.span, - }; - let leaf = tt::Leaf::from(punct); - let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) - } - } - } - - fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result { - Ok(self_.clone()) - } - - fn concat_trees( - &mut self, - base: Option, - trees: Vec>, - ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); - if let Some(base) = base { - builder.push(base); - } - for tree in trees { - builder.push(self.from_token_tree(tree)); - } - builder.build() - } - - fn concat_streams( - &mut self, - base: Option, - streams: Vec, - ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); - if let Some(base) = base { - builder.push(base); - } - for stream in streams { - builder.push(stream); - } - builder.build() - } - - fn into_trees( - &mut self, - stream: Self::TokenStream, - ) -> Vec> { - stream - .into_iter() - .map(|tree| match tree { - tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { - bridge::TokenTree::Ident(IdentId(self.ident_interner.intern(&IdentData(ident)))) - } - tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => bridge::TokenTree::Literal(lit), - tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => { - bridge::TokenTree::Punct(bridge::Punct { - ch: punct.char as u8, - joint: punct.spacing == Spacing::Joint, - span: punct.id, - }) - } - tt::TokenTree::Subtree(subtree) => bridge::TokenTree::Group(bridge::Group { - delimiter: delim_to_external(subtree.delimiter), - stream: if subtree.token_trees.is_empty() { - None - } else { - Some(subtree.token_trees.into_iter().collect()) - }, - span: bridge::DelimSpan::from_single( - subtree.delimiter.map_or(Span::unspecified(), |del| del.id), - ), - }), - }) - .collect() - } -} - -fn delim_to_internal(d: bridge::Delimiter) -> Option { - let kind = match d { - bridge::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis, - bridge::Delimiter::Brace => tt::DelimiterKind::Brace, - bridge::Delimiter::Bracket => tt::DelimiterKind::Bracket, - bridge::Delimiter::None => return None, - }; - Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind }) -} - -fn delim_to_external(d: Option) -> bridge::Delimiter { - match d.map(|it| it.kind) { - Some(tt::DelimiterKind::Parenthesis) => bridge::Delimiter::Parenthesis, - Some(tt::DelimiterKind::Brace) => bridge::Delimiter::Brace, - Some(tt::DelimiterKind::Bracket) => bridge::Delimiter::Bracket, - None => bridge::Delimiter::None, - } -} - -fn spacing_to_internal(spacing: bridge::Spacing) -> Spacing { - match spacing { - bridge::Spacing::Alone => Spacing::Alone, - bridge::Spacing::Joint => Spacing::Joint, - } -} - -fn spacing_to_external(spacing: Spacing) -> bridge::Spacing { - match spacing { - Spacing::Alone => bridge::Spacing::Alone, - Spacing::Joint => bridge::Spacing::Joint, - } -} - -impl server::Ident for RustAnalyzer { - fn new(&mut self, string: &str, span: Self::Span, _is_raw: bool) -> Self::Ident { - IdentId(self.ident_interner.intern(&IdentData(tt::Ident { text: string.into(), id: span }))) - } - - fn span(&mut self, ident: Self::Ident) -> Self::Span { - self.ident_interner.get(ident.0).0.id - } - fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident { - let data = self.ident_interner.get(ident.0); - let new = IdentData(tt::Ident { id: span, ..data.0.clone() }); - IdentId(self.ident_interner.intern(&new)) - } -} - -impl server::Literal for RustAnalyzer { - fn debug_kind(&mut self, _literal: &Self::Literal) -> String { - // r-a: debug_kind and suffix are unsupported; corresponding client code has been changed to not call these. - // They must still be present to be ABI-compatible and work with upstream proc_macro. - "".to_owned() - } - fn from_str(&mut self, s: &str) -> Result { - Ok(Literal { text: s.into(), id: tt::TokenId::unspecified() }) - } - fn symbol(&mut self, literal: &Self::Literal) -> String { - literal.text.to_string() - } - fn suffix(&mut self, _literal: &Self::Literal) -> Option { - None - } - - fn to_string(&mut self, literal: &Self::Literal) -> String { - literal.to_string() - } - - fn integer(&mut self, n: &str) -> Self::Literal { - let n = match n.parse::() { - Ok(n) => n.to_string(), - Err(_) => n.parse::().unwrap().to_string(), - }; - Literal { text: n.into(), id: tt::TokenId::unspecified() } - } - - fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal { - macro_rules! def_suffixed_integer { - ($kind:ident, $($ty:ty),*) => { - match $kind { - $( - stringify!($ty) => { - let n: $ty = n.parse().unwrap(); - format!(concat!("{}", stringify!($ty)), n) - } - )* - _ => unimplemented!("unknown args for typed_integer: n {}, kind {}", n, $kind), - } - } - } - - let text = def_suffixed_integer! {kind, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize}; - - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn float(&mut self, n: &str) -> Self::Literal { - let n: f64 = n.parse().unwrap(); - let mut text = f64::to_string(&n); - if !text.contains('.') { - text += ".0" - } - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn f32(&mut self, n: &str) -> Self::Literal { - let n: f32 = n.parse().unwrap(); - let text = format!("{}f32", n); - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn f64(&mut self, n: &str) -> Self::Literal { - let n: f64 = n.parse().unwrap(); - let text = format!("{}f64", n); - Literal { text: text.into(), id: tt::TokenId::unspecified() } - } - - fn string(&mut self, string: &str) -> Self::Literal { - let mut escaped = String::new(); - for ch in string.chars() { - escaped.extend(ch.escape_debug()); - } - Literal { text: format!("\"{}\"", escaped).into(), id: tt::TokenId::unspecified() } - } - - fn character(&mut self, ch: char) -> Self::Literal { - Literal { text: format!("'{}'", ch).into(), id: tt::TokenId::unspecified() } - } - - fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal { - let string = bytes - .iter() - .cloned() - .flat_map(ascii::escape_default) - .map(Into::::into) - .collect::(); - - Literal { text: format!("b\"{}\"", string).into(), id: tt::TokenId::unspecified() } - } - - fn span(&mut self, literal: &Self::Literal) -> Self::Span { - literal.id - } - - fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) { - literal.id = span; - } - - fn subspan( - &mut self, - _literal: &Self::Literal, - _start: Bound, - _end: Bound, - ) -> Option { - // FIXME handle span - None - } -} - -impl server::SourceFile for RustAnalyzer { - // FIXME these are all stubs - fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool { - true - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - -impl server::Diagnostic for RustAnalyzer { - fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic { - let mut diag = Diagnostic::new(level, msg); - diag.spans = spans; - diag - } - - fn sub( - &mut self, - _diag: &mut Self::Diagnostic, - _level: Level, - _msg: &str, - _spans: Self::MultiSpan, - ) { - // FIXME handle diagnostic - // - } - - fn emit(&mut self, _diag: Self::Diagnostic) { - // FIXME handle diagnostic - // diag.emit() - } -} - -impl server::Span for RustAnalyzer { - fn debug(&mut self, span: Self::Span) -> String { - format!("{:?}", span.0) - } - fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile { - SourceFile {} - } - fn save_span(&mut self, _span: Self::Span) -> usize { - // FIXME stub - 0 - } - fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span { - // FIXME stub - tt::TokenId::unspecified() - } - /// Recent feature, not yet in the proc_macro - /// - /// See PR: - /// https://github.com/rust-lang/rust/pull/55780 - fn source_text(&mut self, _span: Self::Span) -> Option { - None - } - - fn parent(&mut self, _span: Self::Span) -> Option { - // FIXME handle span - None - } - fn source(&mut self, span: Self::Span) -> Self::Span { - // FIXME handle span - span - } - fn start(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn end(&mut self, _span: Self::Span) -> LineColumn { - // FIXME handle span - LineColumn { line: 0, column: 0 } - } - fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option { - // Just return the first span again, because some macros will unwrap the result. - Some(first) - } - fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span { - // FIXME handle span - tt::TokenId::unspecified() - } - - fn after(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } - - fn before(&mut self, _self_: Self::Span) -> Self::Span { - tt::TokenId::unspecified() - } -} - -impl server::MultiSpan for RustAnalyzer { - fn new(&mut self) -> Self::MultiSpan { - // FIXME handle span - vec![] - } - - fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) { - //TODP - other.push(span) - } -} - -impl server::Server for RustAnalyzer { - fn globals(&mut self) -> bridge::ExpnGlobals { - bridge::ExpnGlobals { - def_site: Span::unspecified(), - call_site: Span::unspecified(), - mixed_site: Span::unspecified(), - } - } -} - -#[cfg(test)] -mod tests { - use super::super::proc_macro::bridge::server::Literal; - use super::*; - - #[test] - fn test_ra_server_literals() { - let mut srv = RustAnalyzer { ident_interner: IdentInterner::default() }; - assert_eq!(srv.integer("1234").text, "1234"); - - assert_eq!(srv.typed_integer("12", "u8").text, "12u8"); - assert_eq!(srv.typed_integer("255", "u16").text, "255u16"); - assert_eq!(srv.typed_integer("1234", "u32").text, "1234u32"); - assert_eq!(srv.typed_integer("15846685", "u64").text, "15846685u64"); - assert_eq!(srv.typed_integer("15846685258", "u128").text, "15846685258u128"); - assert_eq!(srv.typed_integer("156788984", "usize").text, "156788984usize"); - assert_eq!(srv.typed_integer("127", "i8").text, "127i8"); - assert_eq!(srv.typed_integer("255", "i16").text, "255i16"); - assert_eq!(srv.typed_integer("1234", "i32").text, "1234i32"); - assert_eq!(srv.typed_integer("15846685", "i64").text, "15846685i64"); - assert_eq!(srv.typed_integer("15846685258", "i128").text, "15846685258i128"); - assert_eq!(srv.float("0").text, "0.0"); - assert_eq!(srv.float("15684.5867").text, "15684.5867"); - assert_eq!(srv.f32("15684.58").text, "15684.58f32"); - assert_eq!(srv.f64("15684.58").text, "15684.58f64"); - - assert_eq!(srv.string("hello_world").text, "\"hello_world\""); - assert_eq!(srv.character('c').text, "'c'"); - assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); - - // u128::max - assert_eq!( - srv.integer("340282366920938463463374607431768211455").text, - "340282366920938463463374607431768211455" - ); - // i128::min - assert_eq!( - srv.integer("-170141183460469231731687303715884105728").text, - "-170141183460469231731687303715884105728" - ); - } - - #[test] - fn test_ra_server_to_string() { - let s = TokenStream { - token_trees: vec![ - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "struct".into(), - id: tt::TokenId::unspecified(), - })), - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "T".into(), - id: tt::TokenId::unspecified(), - })), - tt::TokenTree::Subtree(tt::Subtree { - delimiter: Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Brace, - }), - token_trees: vec![], - }), - ], - }; - - assert_eq!(s.to_string(), "struct T {}"); - } - - #[test] - fn test_ra_server_from_str() { - use std::str::FromStr; - let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree { - delimiter: Some(tt::Delimiter { - id: tt::TokenId::unspecified(), - kind: tt::DelimiterKind::Parenthesis, - }), - token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "a".into(), - id: tt::TokenId::unspecified(), - }))], - }); - - let t1 = TokenStream::from_str("(a)").unwrap(); - assert_eq!(t1.token_trees.len(), 1); - assert_eq!(t1.token_trees[0], subtree_paren_a); - - let t2 = TokenStream::from_str("(a);").unwrap(); - assert_eq!(t2.token_trees.len(), 2); - assert_eq!(t2.token_trees[0], subtree_paren_a); - - let underscore = TokenStream::from_str("_").unwrap(); - assert_eq!( - underscore.token_trees[0], - tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "_".into(), - id: tt::TokenId::unspecified(), - })) - ); - } -} diff --git a/crates/proc-macro-srv/src/abis/mod.rs b/crates/proc-macro-srv/src/abis/mod.rs index 705d09ea9458..f7d3a30919e1 100644 --- a/crates/proc-macro-srv/src/abis/mod.rs +++ b/crates/proc-macro-srv/src/abis/mod.rs @@ -25,7 +25,6 @@ mod abi_1_58; mod abi_1_63; -mod abi_1_64; #[cfg(feature = "sysroot-abi")] mod abi_sysroot; @@ -34,12 +33,11 @@ include!(concat!(env!("OUT_DIR"), "/rustc_version.rs")); // Used by `test/utils.rs` #[cfg(test)] -pub(crate) use abi_1_64::TokenStream as TestTokenStream; +pub(crate) use abi_1_63::TokenStream as TestTokenStream; use super::dylib::LoadProcMacroDylibError; pub(crate) use abi_1_58::Abi as Abi_1_58; pub(crate) use abi_1_63::Abi as Abi_1_63; -pub(crate) use abi_1_64::Abi as Abi_1_64; #[cfg(feature = "sysroot-abi")] pub(crate) use abi_sysroot::Abi as Abi_Sysroot; use libloading::Library; @@ -58,7 +56,6 @@ impl PanicMessage { pub(crate) enum Abi { Abi1_58(Abi_1_58), Abi1_63(Abi_1_63), - Abi1_64(Abi_1_64), #[cfg(feature = "sysroot-abi")] AbiSysroot(Abi_Sysroot), } @@ -120,10 +117,6 @@ impl Abi { let inner = unsafe { Abi_1_63::from_lib(lib, symbol_name) }?; Ok(Abi::Abi1_63(inner)) } - (1, 64..) => { - let inner = unsafe { Abi_1_64::from_lib(lib, symbol_name) }?; - Ok(Abi::Abi1_64(inner)) - } _ => Err(LoadProcMacroDylibError::UnsupportedABI), } } @@ -137,7 +130,6 @@ impl Abi { match self { Self::Abi1_58(abi) => abi.expand(macro_name, macro_body, attributes), Self::Abi1_63(abi) => abi.expand(macro_name, macro_body, attributes), - Self::Abi1_64(abi) => abi.expand(macro_name, macro_body, attributes), #[cfg(feature = "sysroot-abi")] Self::AbiSysroot(abi) => abi.expand(macro_name, macro_body, attributes), } @@ -147,7 +139,6 @@ impl Abi { match self { Self::Abi1_58(abi) => abi.list_macros(), Self::Abi1_63(abi) => abi.list_macros(), - Self::Abi1_64(abi) => abi.list_macros(), #[cfg(feature = "sysroot-abi")] Self::AbiSysroot(abi) => abi.list_macros(), } From 25d4fbe9dae2b875ebfa81a28e10796475def74b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 10 Aug 2022 10:23:46 +0200 Subject: [PATCH 0111/2442] Re-try build script building with --keep-going --- crates/project-model/src/build_scripts.rs | 35 ++++++++++++++++------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index 4b00479a4c9c..84e772d1684a 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -39,7 +39,7 @@ pub(crate) struct BuildScriptOutput { } impl WorkspaceBuildScripts { - fn build_command(config: &CargoConfig, toolchain: &Option) -> Command { + fn build_command(config: &CargoConfig) -> Command { if let Some([program, args @ ..]) = config.run_build_script_command.as_deref() { let mut cmd = Command::new(program); cmd.args(args); @@ -71,15 +71,6 @@ impl WorkspaceBuildScripts { } } - const RUST_1_62: Version = Version::new(1, 62, 0); - - match toolchain { - Some(v) if v >= &RUST_1_62 => { - cmd.args(&["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1"); - } - _ => (), - } - cmd } @@ -89,8 +80,30 @@ impl WorkspaceBuildScripts { progress: &dyn Fn(String), toolchain: &Option, ) -> io::Result { - let mut cmd = Self::build_command(config, toolchain); + const RUST_1_62: Version = Version::new(1, 62, 0); + match Self::run_(Self::build_command(config), config, workspace, progress) { + Ok(WorkspaceBuildScripts { error: Some(error), .. }) + if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) => + { + // building build scripts failed, attempt to build with --keep-going so + // that we potentially get more build data + let mut cmd = Self::build_command(config); + cmd.args(&["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1"); + let mut res = Self::run_(cmd, config, workspace, progress)?; + res.error = Some(error); + Ok(res) + } + res => res, + } + } + + fn run_( + mut cmd: Command, + config: &CargoConfig, + workspace: &CargoWorkspace, + progress: &dyn Fn(String), + ) -> io::Result { if config.wrap_rustc_in_build_scripts { // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use // that to compile only proc macros and build scripts during the initial From 23e17cd5819a21731122b4dc4975170e0efc4ca2 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Wed, 10 Aug 2022 16:28:56 +0800 Subject: [PATCH 0112/2442] Improve insert whitespace in mbe --- crates/hir-expand/src/builtin_fn_macro.rs | 8 ++++++-- crates/mbe/src/syntax_bridge.rs | 11 +---------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index c21b35cdc091..8befa7f7da72 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -251,9 +251,13 @@ fn format_args_expand( } for arg in &mut args { // Remove `key =`. - if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint) + if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=') { - arg.token_trees.drain(..2); + // but not with `==` + if !matches!(arg.token_trees.get(2), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' ) + { + arg.token_trees.drain(..2); + } } } let _format_string = args.remove(0); diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index aca6ecd424e4..e4c56565b92d 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs @@ -228,16 +228,7 @@ fn convert_tokens(conv: &mut C) -> tt::Subtree { } let spacing = match conv.peek().map(|next| next.kind(conv)) { - Some(kind) - if !kind.is_trivia() - && kind.is_punct() - && kind != T!['['] - && kind != T!['{'] - && kind != T!['('] - && kind != UNDERSCORE => - { - tt::Spacing::Joint - } + Some(kind) if !kind.is_trivia() => tt::Spacing::Joint, _ => tt::Spacing::Alone, }; let char = match token.to_char(conv) { From c47914c6cfbce6e99bdeb5b8183b9655673b1110 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Wed, 10 Aug 2022 16:29:23 +0800 Subject: [PATCH 0113/2442] Fixes tests --- crates/hir-def/src/macro_expansion_tests/mbe.rs | 12 ++++++------ .../src/macro_expansion_tests/mbe/regression.rs | 4 ++-- .../src/macro_expansion_tests/mbe/tt_conversion.rs | 2 +- .../src/macro_expansion_tests/proc_macros.rs | 2 +- crates/hir-expand/src/fixup.rs | 14 +++++++------- .../src/handlers/add_missing_impl_members.rs | 2 +- crates/proc-macro-srv/src/tests/mod.rs | 6 +++--- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs index 30d39d52f385..457e43925c63 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -885,7 +885,7 @@ macro_rules! m { ($t:ty) => ( fn bar() -> $ t {} ) } -fn bar() -> & 'a Baz {} +fn bar() -> &'a Baz {} fn bar() -> extern "Rust"fn() -> Ret {} "#]], @@ -1578,7 +1578,7 @@ macro_rules !register_methods { ($$($val: expr), *) = > { struct Foo; impl Foo { - $(fn $method()-> & 'static[u32] { + $(fn $method()-> &'static[u32] { &[$$($$val), *] } )* @@ -1591,10 +1591,10 @@ macro_rules !implement_methods { ($($val: expr), *) = > { struct Foo; impl Foo { - fn alpha()-> & 'static[u32] { + fn alpha()-> &'static[u32] { &[$($val), *] } - fn beta()-> & 'static[u32] { + fn beta()-> &'static[u32] { &[$($val), *] } } @@ -1602,10 +1602,10 @@ macro_rules !implement_methods { } struct Foo; impl Foo { - fn alpha() -> & 'static[u32] { + fn alpha() -> &'static[u32] { &[1, 2, 3] } - fn beta() -> & 'static[u32] { + fn beta() -> &'static[u32] { &[1, 2, 3] } } diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs index 2dff4adf2ee8..d2505e7cafe5 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs @@ -166,7 +166,7 @@ macro_rules! int_base { } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Binary for isize { - fn fmt(&self , f: &mut fmt::Formatter< '_>) -> fmt::Result { + fn fmt(&self , f: &mut fmt::Formatter<'_>) -> fmt::Result { Binary.fmt_int(*self as usize, f) } } @@ -724,7 +724,7 @@ macro_rules! delegate_impl { } } } -impl <> Data for & 'amut G where G: Data {} +impl <> Data for &'amut G where G: Data {} "##]], ); } diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs b/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs index 0710b1ac3d69..b8d2ca687c9e 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs @@ -78,7 +78,7 @@ m!(static bar: &'static str = "hello";); macro_rules! m { ($($t:tt)*) => { $($t)*} } -static bar: & 'static str = "hello"; +static bar: &'static str = "hello"; "#]], ); } diff --git a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs index 72c44a0fbcb2..029821e5e87f 100644 --- a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs +++ b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs @@ -87,7 +87,7 @@ fn foo() { bar.; blub } fn foo() { bar.; blub } fn foo() { - bar. ; + bar.; blub }"##]], ); diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index 46257b6bc4dc..893e6fe4b824 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -468,7 +468,7 @@ fn foo() { } "#, expect![[r#" -fn foo () {a . __ra_fixup} +fn foo () {a .__ra_fixup} "#]], ) } @@ -478,11 +478,11 @@ fn foo () {a . __ra_fixup} check( r#" fn foo() { - a. ; + a.; } "#, expect![[r#" -fn foo () {a . __ra_fixup ;} +fn foo () {a .__ra_fixup ;} "#]], ) } @@ -492,12 +492,12 @@ fn foo () {a . __ra_fixup ;} check( r#" fn foo() { - a. ; + a.; bar(); } "#, expect![[r#" -fn foo () {a . __ra_fixup ; bar () ;} +fn foo () {a .__ra_fixup ; bar () ;} "#]], ) } @@ -525,7 +525,7 @@ fn foo() { } "#, expect![[r#" -fn foo () {let x = a . __ra_fixup ;} +fn foo () {let x = a .__ra_fixup ;} "#]], ) } @@ -541,7 +541,7 @@ fn foo() { } "#, expect![[r#" -fn foo () {a . b ; bar () ;} +fn foo () {a .b ; bar () ;} "#]], ) } diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index c808c010c672..62cf5ab4f37a 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -944,7 +944,7 @@ foo!(); struct Foo(usize); impl FooB for Foo { - $0fn foo< 'lt>(& 'lt self){} + $0fn foo<'lt>(&'lt self){} } "#, ) diff --git a/crates/proc-macro-srv/src/tests/mod.rs b/crates/proc-macro-srv/src/tests/mod.rs index 07222907f088..6339d56d0179 100644 --- a/crates/proc-macro-srv/src/tests/mod.rs +++ b/crates/proc-macro-srv/src/tests/mod.rs @@ -19,7 +19,7 @@ fn test_derive_error() { expect![[r##" SUBTREE $ IDENT compile_error 4294967295 - PUNCH ! [alone] 4294967295 + PUNCH ! [joint] 4294967295 SUBTREE () 4294967295 LITERAL "#[derive(DeriveError)] struct S ;" 4294967295 PUNCH ; [alone] 4294967295"##]], @@ -109,7 +109,7 @@ fn test_fn_like_macro_clone_literals() { PUNCH , [alone] 4294967295 LITERAL 2_u32 4294967295 PUNCH , [alone] 4294967295 - PUNCH - [alone] 4294967295 + PUNCH - [joint] 4294967295 LITERAL 4i64 4294967295 PUNCH , [alone] 4294967295 LITERAL 3.14f32 4294967295 @@ -130,7 +130,7 @@ fn test_attr_macro() { expect![[r##" SUBTREE $ IDENT compile_error 4294967295 - PUNCH ! [alone] 4294967295 + PUNCH ! [joint] 4294967295 SUBTREE () 4294967295 LITERAL "#[attr_error(some arguments)] mod m {}" 4294967295 PUNCH ; [alone] 4294967295"##]], From 7c568961fd0e1d4ccce04797acfbb07e5f30b551 Mon Sep 17 00:00:00 2001 From: Tiddo Langerak Date: Tue, 9 Aug 2022 09:41:56 +0300 Subject: [PATCH 0114/2442] Feat: extracted method from trait impl is placed in existing impl Previously, when triggering a method extraction from within a trait impl block, then this would always create a new impl block for the struct, even if there already is one. Now, it'll put the extracted method in the matching existing block if it exists. --- .../src/handlers/extract_function.rs | 272 +++++++++++++++++- 1 file changed, 268 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 52a55ead3af9..40d0327ef718 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -109,8 +109,6 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let params = body.extracted_function_params(ctx, &container_info, locals_used.iter().copied()); - let extracted_from_trait_impl = body.extracted_from_trait_impl(); - let name = make_function_name(&semantics_scope); let fun = Function { @@ -129,8 +127,13 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op builder.replace(target_range, make_call(ctx, &fun, old_indent)); + let has_impl_wrapper = insert_after + .ancestors() + .find(|a| a.kind() == SyntaxKind::IMPL && a != &insert_after) + .is_some(); + let fn_def = match fun.self_param_adt(ctx) { - Some(adt) if extracted_from_trait_impl => { + Some(adt) if anchor == Anchor::Method && !has_impl_wrapper => { let fn_def = format_function(ctx, module, &fun, old_indent, new_indent + 1); generate_impl_text(&adt, &fn_def).replace("{\n\n", "{") } @@ -271,7 +274,7 @@ enum FunType { } /// Where to put extracted function definition -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq, Clone, Copy)] enum Anchor { /// Extract free function and put right after current top-level function Freestanding, @@ -1244,6 +1247,15 @@ fn node_to_insert_after(body: &FunctionBody, anchor: Anchor) -> Option break, + SyntaxKind::IMPL => { + if body.extracted_from_trait_impl() && matches!(anchor, Anchor::Method) { + let impl_node = find_non_trait_impl(&next_ancestor); + let target_node = impl_node.as_ref().and_then(last_impl_member); + if target_node.is_some() { + return target_node; + } + } + } SyntaxKind::ITEM_LIST if !matches!(anchor, Anchor::Freestanding) => continue, SyntaxKind::ITEM_LIST => { if ancestors.peek().map(SyntaxNode::kind) == Some(SyntaxKind::MODULE) { @@ -1264,6 +1276,28 @@ fn node_to_insert_after(body: &FunctionBody, anchor: Anchor) -> Option Option { + let impl_type = Some(impl_type_name(trait_impl)?); + + let mut sibblings = trait_impl.parent()?.children(); + sibblings.find(|s| impl_type_name(s) == impl_type && !is_trait_impl(s)) +} + +fn last_impl_member(impl_node: &SyntaxNode) -> Option { + impl_node.children().find(|c| c.kind() == SyntaxKind::ASSOC_ITEM_LIST)?.last_child() +} + +fn is_trait_impl(node: &SyntaxNode) -> bool { + match ast::Impl::cast(node.clone()) { + Some(c) => c.trait_().is_some(), + None => false, + } +} + +fn impl_type_name(impl_node: &SyntaxNode) -> Option { + Some(ast::Impl::cast(impl_node.clone())?.self_ty()?.to_string()) +} + fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> String { let ret_ty = fun.return_type(ctx); @@ -5058,6 +5092,236 @@ impl Struct { ); } + #[test] + fn extract_method_from_trait_with_existing_non_empty_impl_block() { + check_assist( + extract_function, + r#" +struct Struct(i32); +trait Trait { + fn bar(&self) -> i32; +} + +impl Struct { + fn foo() {} +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + $0self.0 + 2$0 + } +} +"#, + r#" +struct Struct(i32); +trait Trait { + fn bar(&self) -> i32; +} + +impl Struct { + fn foo() {} + + fn $0fun_name(&self) -> i32 { + self.0 + 2 + } +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + self.fun_name() + } +} +"#, + ) + } + + #[test] + fn extract_function_from_trait_with_existing_non_empty_impl_block() { + check_assist( + extract_function, + r#" +struct Struct(i32); +trait Trait { + fn bar(&self) -> i32; +} + +impl Struct { + fn foo() {} +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + let three_squared = $03 * 3$0; + self.0 + three_squared + } +} +"#, + r#" +struct Struct(i32); +trait Trait { + fn bar(&self) -> i32; +} + +impl Struct { + fn foo() {} +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + let three_squared = fun_name(); + self.0 + three_squared + } +} + +fn $0fun_name() -> i32 { + 3 * 3 +} +"#, + ) + } + + #[test] + fn extract_method_from_trait_with_multiple_existing_impl_blocks() { + check_assist( + extract_function, + r#" +struct Struct(i32); +struct StructBefore(i32); +struct StructAfter(i32); +trait Trait { + fn bar(&self) -> i32; +} + +impl StructBefore { + fn foo(){} +} + +impl Struct { + fn foo(){} +} + +impl StructAfter { + fn foo(){} +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + $0self.0 + 2$0 + } +} +"#, + r#" +struct Struct(i32); +struct StructBefore(i32); +struct StructAfter(i32); +trait Trait { + fn bar(&self) -> i32; +} + +impl StructBefore { + fn foo(){} +} + +impl Struct { + fn foo(){} + + fn $0fun_name(&self) -> i32 { + self.0 + 2 + } +} + +impl StructAfter { + fn foo(){} +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + self.fun_name() + } +} +"#, + ) + } + + #[test] + fn extract_method_from_trait_with_multiple_existing_trait_impl_blocks() { + check_assist( + extract_function, + r#" +struct Struct(i32); +trait Trait { + fn bar(&self) -> i32; +} +trait TraitBefore { + fn before(&self) -> i32; +} +trait TraitAfter { + fn after(&self) -> i32; +} + +impl TraitBefore for Struct { + fn before(&self) -> i32 { + 42 + } +} + +impl Struct { + fn foo(){} +} + +impl TraitAfter for Struct { + fn after(&self) -> i32 { + 42 + } +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + $0self.0 + 2$0 + } +} +"#, + r#" +struct Struct(i32); +trait Trait { + fn bar(&self) -> i32; +} +trait TraitBefore { + fn before(&self) -> i32; +} +trait TraitAfter { + fn after(&self) -> i32; +} + +impl TraitBefore for Struct { + fn before(&self) -> i32 { + 42 + } +} + +impl Struct { + fn foo(){} + + fn $0fun_name(&self) -> i32 { + self.0 + 2 + } +} + +impl TraitAfter for Struct { + fn after(&self) -> i32 { + 42 + } +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + self.fun_name() + } +} +"#, + ) + } + #[test] fn closure_arguments() { check_assist( From ffc6b42901fc1f64c812df571110e665de75da45 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Wed, 10 Aug 2022 19:17:13 +0900 Subject: [PATCH 0115/2442] fix: infer byte string pattern as `&[u8]` when matched against slices --- crates/hir-ty/src/infer/pat.rs | 33 ++++++++++++++++++--- crates/hir-ty/src/tests/patterns.rs | 45 +++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs index 5e7320a5dd30..53259d66dec6 100644 --- a/crates/hir-ty/src/infer/pat.rs +++ b/crates/hir-ty/src/infer/pat.rs @@ -14,8 +14,9 @@ use crate::{ consteval::intern_const_scalar, infer::{BindingMode, Expectation, InferenceContext, TypeMismatch}, lower::lower_to_chalk_mutability, - static_lifetime, ConcreteConst, ConstValue, Interner, Substitution, Ty, TyBuilder, TyExt, - TyKind, + primitive::UintTy, + static_lifetime, ConcreteConst, ConstValue, Interner, Scalar, Substitution, Ty, TyBuilder, + TyExt, TyKind, }; use super::PatLike; @@ -294,7 +295,29 @@ impl<'a> InferenceContext<'a> { let start_ty = self.infer_expr(*start, &Expectation::has_type(expected.clone())); self.infer_expr(*end, &Expectation::has_type(start_ty)) } - Pat::Lit(expr) => self.infer_expr(*expr, &Expectation::has_type(expected.clone())), + &Pat::Lit(expr) => { + // FIXME: using `Option` here is a workaround until we can use if-let chains in stable. + let mut pat_ty = None; + + // Like slice patterns, byte string patterns can denote both `&[u8; N]` and `&[u8]`. + if let Expr::Literal(Literal::ByteString(_)) = self.body[expr] { + if let Some((inner, ..)) = expected.as_reference() { + let inner = self.resolve_ty_shallow(inner); + if matches!(inner.kind(Interner), TyKind::Slice(_)) { + let elem_ty = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner); + let slice_ty = TyKind::Slice(elem_ty).intern(Interner); + let ty = TyKind::Ref(Mutability::Not, static_lifetime(), slice_ty) + .intern(Interner); + self.write_expr_ty(expr, ty.clone()); + pat_ty = Some(ty); + } + } + } + + pat_ty.unwrap_or_else(|| { + self.infer_expr(expr, &Expectation::has_type(expected.clone())) + }) + } Pat::Box { inner } => match self.resolve_boxed_box() { Some(box_adt) => { let (inner_ty, alloc_ty) = match expected.as_adt() { @@ -343,7 +366,9 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { // FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented. Pat::Path(..) => true, Pat::ConstBlock(..) => true, - Pat::Lit(expr) => !matches!(body[*expr], Expr::Literal(Literal::String(..))), + Pat::Lit(expr) => { + !matches!(body[*expr], Expr::Literal(Literal::String(..) | Literal::ByteString(..))) + } Pat::Bind { mode: BindingAnnotation::Mutable | BindingAnnotation::Unannotated, subpat: Some(subpat), diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs index 399553356b04..94efe7bc11a8 100644 --- a/crates/hir-ty/src/tests/patterns.rs +++ b/crates/hir-ty/src/tests/patterns.rs @@ -315,6 +315,51 @@ fn infer_pattern_match_string_literal() { ); } +#[test] +fn infer_pattern_match_byte_string_literal() { + check_infer_with_mismatches( + r#" + //- minicore: index + struct S; + impl core::ops::Index for [T; N] { + type Output = [u8]; + fn index(&self, index: core::ops::RangeFull) -> &Self::Output { + loop {} + } + } + fn test(v: [u8; 3]) { + if let b"foo" = &v[S] {} + if let b"foo" = &v {} + } + "#, + expect![[r#" + 105..109 'self': &[T; N] + 111..116 'index': {unknown} + 157..180 '{ ... }': &[u8] + 167..174 'loop {}': ! + 172..174 '{}': () + 191..192 'v': [u8; 3] + 203..261 '{ ...v {} }': () + 209..233 'if let...[S] {}': () + 212..230 'let b"... &v[S]': bool + 216..222 'b"foo"': &[u8] + 216..222 'b"foo"': &[u8] + 225..230 '&v[S]': &[u8] + 226..227 'v': [u8; 3] + 226..230 'v[S]': [u8] + 228..229 'S': S + 231..233 '{}': () + 238..259 'if let... &v {}': () + 241..256 'let b"foo" = &v': bool + 245..251 'b"foo"': &[u8; 3] + 245..251 'b"foo"': &[u8; 3] + 254..256 '&v': &[u8; 3] + 255..256 'v': [u8; 3] + 257..259 '{}': () + "#]], + ); +} + #[test] fn infer_pattern_match_or() { check_infer_with_mismatches( From 7402366877b3f50563cba4ba919cdc88c6220d14 Mon Sep 17 00:00:00 2001 From: Tiddo Langerak Date: Wed, 10 Aug 2022 17:03:15 +0300 Subject: [PATCH 0116/2442] Avoid cloning IMPL node if we don't have to --- crates/ide-assists/src/handlers/extract_function.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 40d0327ef718..969b0c1fb3f3 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -1288,6 +1288,9 @@ fn last_impl_member(impl_node: &SyntaxNode) -> Option { } fn is_trait_impl(node: &SyntaxNode) -> bool { + if !ast::Impl::can_cast(node.kind()) { + return false; + } match ast::Impl::cast(node.clone()) { Some(c) => c.trait_().is_some(), None => false, @@ -1295,6 +1298,9 @@ fn is_trait_impl(node: &SyntaxNode) -> bool { } fn impl_type_name(impl_node: &SyntaxNode) -> Option { + if !ast::Impl::can_cast(impl_node.kind()) { + return None; + } Some(ast::Impl::cast(impl_node.clone())?.self_ty()?.to_string()) } From 53ec791dc6b22e581f9e5aabeda5edfc806564cb Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Mon, 1 Aug 2022 14:20:05 +0900 Subject: [PATCH 0117/2442] Add `UnescapedName` and make `Name` hold escaped name --- crates/hir-expand/src/name.rs | 54 +++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 47d191822d84..18b0793f10ec 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -7,6 +7,10 @@ use syntax::{ast, SmolStr, SyntaxKind}; /// `Name` is a wrapper around string, which is used in hir for both references /// and declarations. In theory, names should also carry hygiene info, but we are /// not there yet! +/// +/// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it +/// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the +/// name without "r#". #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Name(Repr); @@ -14,6 +18,10 @@ pub struct Name(Repr); #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct EscapedName<'a>(&'a Name); +/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier. +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct UnescapedName<'a>(&'a Name); + #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] enum Repr { Text(SmolStr), @@ -49,6 +57,35 @@ impl<'a> fmt::Display for EscapedName<'a> { } } +impl<'a> fmt::Display for UnescapedName<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.0 .0 { + Repr::Text(text) => { + let text = text.strip_prefix("r#").unwrap_or(text); + fmt::Display::fmt(&text, f) + } + Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), + } + } +} + +impl<'a> UnescapedName<'a> { + /// Returns the textual representation of this name as a [`SmolStr`]. Prefer using this over + /// [`ToString::to_string`] if possible as this conversion is cheaper in the general case. + pub fn to_smol_str(&self) -> SmolStr { + match &self.0 .0 { + Repr::Text(it) => { + if let Some(stripped) = it.strip_prefix("r#") { + SmolStr::new(stripped) + } else { + it.clone() + } + } + Repr::TupleField(it) => SmolStr::new(&it.to_string()), + } + } +} + impl<'a> EscapedName<'a> { pub fn is_escaped(&self) -> bool { match &self.0 .0 { @@ -97,9 +134,11 @@ impl Name { /// Resolve a name from the text of token. fn resolve(raw_text: &str) -> Name { + // When `raw_text` starts with "r#" but the name does not coincide with any + // keyword, we never need the prefix so we strip it. match raw_text.strip_prefix("r#") { - Some(text) => Name::new_text(SmolStr::new(text)), - None => Name::new_text(raw_text.into()), + Some(text) if !is_raw_identifier(text) => Name::new_text(SmolStr::new(text)), + _ => Name::new_text(raw_text.into()), } } @@ -145,6 +184,17 @@ impl Name { pub fn escaped(&self) -> EscapedName<'_> { EscapedName(self) } + + pub fn unescaped(&self) -> UnescapedName<'_> { + UnescapedName(self) + } + + pub fn is_escaped(&self) -> bool { + match &self.0 { + Repr::Text(it) => it.starts_with("r#"), + Repr::TupleField(_) => false, + } + } } pub trait AsName { From 4322cf7f5b4cc31ae88320add185184f5d58abb7 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Mon, 1 Aug 2022 15:19:49 +0900 Subject: [PATCH 0118/2442] Remove `EscapedName` --- crates/hir-expand/src/mod_path.rs | 4 +- crates/hir-expand/src/name.rs | 48 ------------------- .../src/completions/item_list/trait_impl.rs | 3 +- crates/ide-completion/src/render.rs | 8 ++-- crates/ide-completion/src/render/const_.rs | 2 +- crates/ide-completion/src/render/function.rs | 6 +-- crates/ide-completion/src/render/macro_.rs | 2 +- crates/ide-completion/src/render/pattern.rs | 8 ++-- .../ide-completion/src/render/type_alias.rs | 4 +- .../src/render/union_literal.rs | 10 ++-- crates/ide-completion/src/render/variant.rs | 4 +- 11 files changed, 26 insertions(+), 73 deletions(-) diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs index fea09521e87c..ed9d90298871 100644 --- a/crates/hir-expand/src/mod_path.rs +++ b/crates/hir-expand/src/mod_path.rs @@ -134,9 +134,9 @@ impl ModPath { } first_segment = false; if escaped { - segment.escaped().fmt(f)? - } else { segment.fmt(f)? + } else { + segment.unescaped().fmt(f)? }; } Ok(()) diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 18b0793f10ec..87c663eec8e8 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -14,10 +14,6 @@ use syntax::{ast, SmolStr, SyntaxKind}; #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Name(Repr); -/// `EscapedName` will add a prefix "r#" to the wrapped `Name` when it is a raw identifier -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct EscapedName<'a>(&'a Name); - /// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct UnescapedName<'a>(&'a Name); @@ -42,21 +38,6 @@ fn is_raw_identifier(name: &str) -> bool { is_keyword && !matches!(name, "self" | "crate" | "super" | "Self") } -impl<'a> fmt::Display for EscapedName<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.0 .0 { - Repr::Text(text) => { - if is_raw_identifier(text) { - write!(f, "r#{}", &text) - } else { - fmt::Display::fmt(&text, f) - } - } - Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), - } - } -} - impl<'a> fmt::Display for UnescapedName<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.0 .0 { @@ -86,31 +67,6 @@ impl<'a> UnescapedName<'a> { } } -impl<'a> EscapedName<'a> { - pub fn is_escaped(&self) -> bool { - match &self.0 .0 { - Repr::Text(it) => is_raw_identifier(&it), - Repr::TupleField(_) => false, - } - } - - /// Returns the textual representation of this name as a [`SmolStr`]. - /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in - /// the general case. - pub fn to_smol_str(&self) -> SmolStr { - match &self.0 .0 { - Repr::Text(it) => { - if is_raw_identifier(&it) { - SmolStr::from_iter(["r#", &it]) - } else { - it.clone() - } - } - Repr::TupleField(it) => SmolStr::new(&it.to_string()), - } - } -} - impl Name { /// Note: this is private to make creating name from random string hard. /// Hopefully, this should allow us to integrate hygiene cleaner in the @@ -181,10 +137,6 @@ impl Name { } } - pub fn escaped(&self) -> EscapedName<'_> { - EscapedName(self) - } - pub fn unescaped(&self) -> UnescapedName<'_> { UnescapedName(self) } diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs index e9256803cc4f..785db6fde1d5 100644 --- a/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -233,7 +233,8 @@ fn add_type_alias_impl( type_alias: hir::TypeAlias, ) { let alias_name = type_alias.name(ctx.db); - let (alias_name, escaped_name) = (alias_name.to_smol_str(), alias_name.escaped().to_smol_str()); + let (alias_name, escaped_name) = + (alias_name.unescaped().to_smol_str(), alias_name.to_smol_str()); let label = format!("type {} =", alias_name); let replacement = format!("type {} = ", escaped_name); diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 946134b0ff95..6c466777a102 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -117,7 +117,7 @@ pub(crate) fn render_field( ) -> CompletionItem { let is_deprecated = ctx.is_deprecated(field); let name = field.name(ctx.db()); - let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); + let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str()); let mut item = CompletionItem::new( SymbolKind::Field, ctx.source_range(), @@ -283,8 +283,8 @@ fn render_resolution_path( let name = local_name.to_smol_str(); let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution); - if local_name.escaped().is_escaped() { - item.insert_text(local_name.escaped().to_smol_str()); + if local_name.is_escaped() { + item.insert_text(local_name.to_smol_str()); } // Add `<>` for generic types let type_path_no_ty_args = matches!( @@ -306,7 +306,7 @@ fn render_resolution_path( item.lookup_by(name.clone()) .label(SmolStr::from_iter([&name, "<…>"])) .trigger_call_info() - .insert_snippet(cap, format!("{}<$0>", local_name.escaped())); + .insert_snippet(cap, format!("{}<$0>", local_name)); } } } diff --git a/crates/ide-completion/src/render/const_.rs b/crates/ide-completion/src/render/const_.rs index a810eef18dd1..93ea825e0042 100644 --- a/crates/ide-completion/src/render/const_.rs +++ b/crates/ide-completion/src/render/const_.rs @@ -13,7 +13,7 @@ pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option { let db = ctx.db(); let name = const_.name(db)?; - let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); + let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str()); let detail = const_.display(db).to_string(); let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), name.clone()); diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs index 4b5535718c5d..2a90703b09ec 100644 --- a/crates/ide-completion/src/render/function.rs +++ b/crates/ide-completion/src/render/function.rs @@ -52,10 +52,10 @@ fn render( let (call, escaped_call) = match &func_kind { FuncKind::Method(_, Some(receiver)) => ( - format!("{}.{}", receiver, &name).into(), - format!("{}.{}", receiver.escaped(), name.escaped()).into(), + format!("{}.{}", receiver.unescaped(), name.unescaped()).into(), + format!("{}.{}", receiver, name).into(), ), - _ => (name.to_smol_str(), name.escaped().to_smol_str()), + _ => (name.unescaped().to_smol_str(), name.to_smol_str()), }; let mut item = CompletionItem::new( if func.self_param(db).is_some() { diff --git a/crates/ide-completion/src/render/macro_.rs b/crates/ide-completion/src/render/macro_.rs index ca2269f1398f..eabd0bd17d65 100644 --- a/crates/ide-completion/src/render/macro_.rs +++ b/crates/ide-completion/src/render/macro_.rs @@ -46,7 +46,7 @@ fn render( ctx.source_range() }; - let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); + let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str()); let docs = ctx.docs(macro_); let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default(); let is_fn_like = macro_.is_fn_like(completion.db); diff --git a/crates/ide-completion/src/render/pattern.rs b/crates/ide-completion/src/render/pattern.rs index 34a384f2f7ae..4f4c06402706 100644 --- a/crates/ide-completion/src/render/pattern.rs +++ b/crates/ide-completion/src/render/pattern.rs @@ -31,7 +31,7 @@ pub(crate) fn render_struct_pat( } let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())); - let (name, escaped_name) = (name.to_smol_str(), name.escaped().to_smol_str()); + let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str()); let kind = strukt.kind(ctx.db()); let label = format_literal_label(name.as_str(), kind); let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?; @@ -56,7 +56,7 @@ pub(crate) fn render_variant_pat( Some(path) => (path.to_string().into(), path.escaped().to_string().into()), None => { let name = local_name.unwrap_or_else(|| variant.name(ctx.db())); - (name.to_smol_str(), name.escaped().to_smol_str()) + (name.unescaped().to_smol_str(), name.to_smol_str()) } }; @@ -146,7 +146,7 @@ fn render_record_as_pat( format!( "{name} {{ {}{} }}", fields.enumerate().format_with(", ", |(idx, field), f| { - f(&format_args!("{}${}", field.name(db).escaped(), idx + 1)) + f(&format_args!("{}${}", field.name(db), idx + 1)) }), if fields_omitted { ", .." } else { "" }, name = name @@ -155,7 +155,7 @@ fn render_record_as_pat( None => { format!( "{name} {{ {}{} }}", - fields.map(|field| field.name(db).escaped().to_smol_str()).format(", "), + fields.map(|field| field.name(db).to_smol_str()).format(", "), if fields_omitted { ", .." } else { "" }, name = name ) diff --git a/crates/ide-completion/src/render/type_alias.rs b/crates/ide-completion/src/render/type_alias.rs index f1b23c76e7b4..de919429f2f9 100644 --- a/crates/ide-completion/src/render/type_alias.rs +++ b/crates/ide-completion/src/render/type_alias.rs @@ -32,11 +32,11 @@ fn render( let name = type_alias.name(db); let (name, escaped_name) = if with_eq { ( + SmolStr::from_iter([&name.unescaped().to_smol_str(), " = "]), SmolStr::from_iter([&name.to_smol_str(), " = "]), - SmolStr::from_iter([&name.escaped().to_smol_str(), " = "]), ) } else { - (name.to_smol_str(), name.escaped().to_smol_str()) + (name.unescaped().to_smol_str(), name.to_smol_str()) }; let detail = type_alias.display(db).to_string(); diff --git a/crates/ide-completion/src/render/union_literal.rs b/crates/ide-completion/src/render/union_literal.rs index 9c9540a9bd96..b04c8e3bf9d1 100644 --- a/crates/ide-completion/src/render/union_literal.rs +++ b/crates/ide-completion/src/render/union_literal.rs @@ -22,7 +22,7 @@ pub(crate) fn render_union_literal( let (qualified_name, escaped_qualified_name) = match path { Some(p) => (p.to_string(), p.escaped().to_string()), - None => (name.to_string(), name.escaped().to_string()), + None => (name.unescaped().to_string(), name.to_string()), }; let mut item = CompletionItem::new( @@ -42,15 +42,15 @@ pub(crate) fn render_union_literal( format!( "{} {{ ${{1|{}|}}: ${{2:()}} }}$0", escaped_qualified_name, - fields.iter().map(|field| field.name(ctx.db()).escaped().to_smol_str()).format(",") + fields.iter().map(|field| field.name(ctx.db()).to_smol_str()).format(",") ) } else { format!( "{} {{ {} }}", escaped_qualified_name, - fields.iter().format_with(", ", |field, f| { - f(&format_args!("{}: ()", field.name(ctx.db()).escaped())) - }) + fields + .iter() + .format_with(", ", |field, f| { f(&format_args!("{}: ()", field.name(ctx.db()))) }) ) }; diff --git a/crates/ide-completion/src/render/variant.rs b/crates/ide-completion/src/render/variant.rs index 003a0c11ed2f..664845330eb8 100644 --- a/crates/ide-completion/src/render/variant.rs +++ b/crates/ide-completion/src/render/variant.rs @@ -24,9 +24,9 @@ pub(crate) fn render_record_lit( ) -> RenderedLiteral { let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| { if snippet_cap.is_some() { - f(&format_args!("{}: ${{{}:()}}", field.name(db).escaped(), idx + 1)) + f(&format_args!("{}: ${{{}:()}}", field.name(db), idx + 1)) } else { - f(&format_args!("{}: ()", field.name(db).escaped())) + f(&format_args!("{}: ()", field.name(db))) } }); From 8fe73a224005a153c89a40243e71a021e9304958 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Mon, 1 Aug 2022 15:20:14 +0900 Subject: [PATCH 0119/2442] Make tests pass --- crates/hir-def/src/nameres/mod_resolution.rs | 2 ++ crates/hir-def/src/nameres/tests/mod_resolution.rs | 4 ++-- crates/ide-completion/src/render.rs | 3 ++- crates/ide-completion/src/render/function.rs | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/hir-def/src/nameres/mod_resolution.rs b/crates/hir-def/src/nameres/mod_resolution.rs index 52a620fe22f6..99f7f1b549e2 100644 --- a/crates/hir-def/src/nameres/mod_resolution.rs +++ b/crates/hir-def/src/nameres/mod_resolution.rs @@ -73,10 +73,12 @@ impl ModDir { candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner)) } None if file_id.is_include_macro(db.upcast()) => { + let name = name.unescaped(); candidate_files.push(format!("{}.rs", name)); candidate_files.push(format!("{}/mod.rs", name)); } None => { + let name = name.unescaped(); candidate_files.push(format!("{}{}.rs", self.dir_path.0, name)); candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name)); } diff --git a/crates/hir-def/src/nameres/tests/mod_resolution.rs b/crates/hir-def/src/nameres/tests/mod_resolution.rs index 79a74873b4a4..3fa585574dee 100644 --- a/crates/hir-def/src/nameres/tests/mod_resolution.rs +++ b/crates/hir-def/src/nameres/tests/mod_resolution.rs @@ -132,9 +132,9 @@ pub struct Bar; expect![[r#" crate Bar: t v - async: t + r#async: t - crate::async + crate::r#async Bar: t v "#]], ); diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 6c466777a102..693007ca3071 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -342,7 +342,8 @@ fn render_resolution_simple_( let ctx = ctx.import_to_add(import_to_add); let kind = res_to_kind(resolution); - let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.to_smol_str()); + let mut item = + CompletionItem::new(kind, ctx.source_range(), local_name.unescaped().to_smol_str()); item.set_relevance(ctx.completion_relevance()) .set_documentation(scope_def_docs(db, resolution)) .set_deprecated(scope_def_is_deprecated(&ctx, resolution)); diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs index 2a90703b09ec..9cf64691298e 100644 --- a/crates/ide-completion/src/render/function.rs +++ b/crates/ide-completion/src/render/function.rs @@ -96,7 +96,7 @@ fn render( item.set_documentation(ctx.docs(func)) .set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func)) .detail(detail(db, func)) - .lookup_by(name.to_smol_str()); + .lookup_by(name.unescaped().to_smol_str()); match ctx.completion.config.snippet_cap { Some(cap) => { From 018266a7ff6d06747e798afdf84faadb7567d179 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 11 Aug 2022 02:17:15 +0900 Subject: [PATCH 0120/2442] Make `ModPath` display escaped path --- crates/hir-expand/src/mod_path.rs | 12 ++++++------ crates/ide-completion/src/render/literal.rs | 2 +- crates/ide-completion/src/render/pattern.rs | 2 +- crates/ide-completion/src/render/union_literal.rs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs index ed9d90298871..d0f73ec8208c 100644 --- a/crates/hir-expand/src/mod_path.rs +++ b/crates/hir-expand/src/mod_path.rs @@ -22,7 +22,7 @@ pub struct ModPath { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct EscapedModPath<'a>(&'a ModPath); +pub struct UnescapedModPath<'a>(&'a ModPath); #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum PathKind { @@ -102,8 +102,8 @@ impl ModPath { } } - pub fn escaped(&self) -> EscapedModPath<'_> { - EscapedModPath(self) + pub fn unescaped(&self) -> UnescapedModPath<'_> { + UnescapedModPath(self) } fn _fmt(&self, f: &mut fmt::Formatter<'_>, escaped: bool) -> fmt::Result { @@ -145,13 +145,13 @@ impl ModPath { impl Display for ModPath { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self._fmt(f, false) + self._fmt(f, true) } } -impl<'a> Display for EscapedModPath<'a> { +impl<'a> Display for UnescapedModPath<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0._fmt(f, true) + self.0._fmt(f, false) } } diff --git a/crates/ide-completion/src/render/literal.rs b/crates/ide-completion/src/render/literal.rs index 91a253f8fc8c..707dea206be5 100644 --- a/crates/ide-completion/src/render/literal.rs +++ b/crates/ide-completion/src/render/literal.rs @@ -73,7 +73,7 @@ fn render( None => (name.clone().into(), name.into(), false), }; let (qualified_name, escaped_qualified_name) = - (qualified_name.to_string(), qualified_name.escaped().to_string()); + (qualified_name.unescaped().to_string(), qualified_name.to_string()); let snippet_cap = ctx.snippet_cap(); let mut rendered = match kind { diff --git a/crates/ide-completion/src/render/pattern.rs b/crates/ide-completion/src/render/pattern.rs index 4f4c06402706..1c1299e33b67 100644 --- a/crates/ide-completion/src/render/pattern.rs +++ b/crates/ide-completion/src/render/pattern.rs @@ -53,7 +53,7 @@ pub(crate) fn render_variant_pat( let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?; let (name, escaped_name) = match path { - Some(path) => (path.to_string().into(), path.escaped().to_string().into()), + Some(path) => (path.unescaped().to_string().into(), path.to_string().into()), None => { let name = local_name.unwrap_or_else(|| variant.name(ctx.db())); (name.unescaped().to_smol_str(), name.to_smol_str()) diff --git a/crates/ide-completion/src/render/union_literal.rs b/crates/ide-completion/src/render/union_literal.rs index b04c8e3bf9d1..bb32330f276d 100644 --- a/crates/ide-completion/src/render/union_literal.rs +++ b/crates/ide-completion/src/render/union_literal.rs @@ -21,7 +21,7 @@ pub(crate) fn render_union_literal( let name = local_name.unwrap_or_else(|| un.name(ctx.db())); let (qualified_name, escaped_qualified_name) = match path { - Some(p) => (p.to_string(), p.escaped().to_string()), + Some(p) => (p.unescaped().to_string(), p.to_string()), None => (name.unescaped().to_string(), name.to_string()), }; From ba6db3e9b054902549a0cf487cd7f69db2654aa1 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Sat, 30 Jul 2022 22:28:34 +0900 Subject: [PATCH 0121/2442] Add test for runnables with raw identifiers --- crates/ide/src/runnables.rs | 186 ++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index b0853b10fde2..0181c6b8e456 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -2225,4 +2225,190 @@ macro_rules! foo { "#]], ); } + + #[test] + fn test_paths_with_raw_ident() { + check( + r#" +//- /lib.rs +$0 +mod r#mod { + #[test] + fn r#fn() {} + + /// ``` + /// ``` + fn r#for() {} + + /// ``` + /// ``` + struct r#struct(r#type); + + /// ``` + /// ``` + impl r#struct { + /// ``` + /// ``` + fn r#fn() {} + } + + enum r#enum {} + impl r#struct { + /// ``` + /// ``` + fn r#fn() {} + } + + trait r#trait {} + + /// ``` + /// ``` + impl r#trait for r#struct {} +} +"#, + &[TestMod, Test, DocTest, DocTest, DocTest, DocTest, DocTest, DocTest], + expect![[r#" + [ + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 1..461, + focus_range: 5..10, + name: "r#mod", + kind: Module, + description: "mod r#mod", + }, + kind: TestMod { + path: "r#mod", + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 17..41, + focus_range: 32..36, + name: "r#fn", + kind: Function, + }, + kind: Test { + test_id: Path( + "r#mod::r#fn", + ), + attr: TestAttr { + ignore: false, + }, + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 47..84, + name: "r#for", + }, + kind: DocTest { + test_id: Path( + "r#mod::r#for", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 90..146, + name: "r#struct", + }, + kind: DocTest { + test_id: Path( + "r#mod::r#struct", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 152..266, + focus_range: 189..205, + name: "impl", + kind: Impl, + }, + kind: DocTest { + test_id: Path( + "r#struct", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 216..260, + name: "r#fn", + }, + kind: DocTest { + test_id: Path( + "r#mod::r#struct::r#fn", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 323..367, + name: "r#fn", + }, + kind: DocTest { + test_id: Path( + "r#mod::r#struct::r#fn", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 401..459, + focus_range: 445..456, + name: "impl", + kind: Impl, + }, + kind: DocTest { + test_id: Path( + "r#struct", + ), + }, + cfg: None, + }, + ] + "#]], + ) + } } From 1bb58205f0b09ccdb1a8915cfdede35bd2c09da4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 11 Aug 2022 10:41:30 +0200 Subject: [PATCH 0122/2442] Fix panic in no_such_field when using tuple fields on record structs --- crates/hir/src/source_analyzer.rs | 1 + .../src/handlers/no_such_field.rs | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index f5e2e4430709..ae2896e19329 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -368,6 +368,7 @@ impl SourceAnalyzer { let local = if field.name_ref().is_some() { None } else { + // Shorthand syntax, resolve to the local let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone())); match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { Some(ValueNs::LocalBinding(pat_id)) => { diff --git a/crates/ide-diagnostics/src/handlers/no_such_field.rs b/crates/ide-diagnostics/src/handlers/no_such_field.rs index e032c578f028..a80299106bd3 100644 --- a/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -68,7 +68,7 @@ fn missing_record_expr_field_fixes( } let new_field = make::record_field( None, - make::name(&record_expr_field.field_name()?.text()), + make::name(&record_expr_field.field_name()?.ident_token()?.text()), make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), ); @@ -109,7 +109,7 @@ fn missing_record_expr_field_fixes( #[cfg(test)] mod tests { - use crate::tests::{check_diagnostics, check_fix}; + use crate::tests::{check_diagnostics, check_fix, check_no_fix}; #[test] fn no_such_field_diagnostics() { @@ -277,6 +277,20 @@ struct Foo { bar: i32, pub(crate) baz: bool } +"#, + ) + } + + #[test] + fn test_tuple_field_on_record_struct() { + check_no_fix( + r#" +struct Struct {} +fn main() { + Struct { + 0$0: 0 + } +} "#, ) } From 1ce978370bd190d952d0d31bb09d934895278238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Fri, 12 Aug 2022 18:19:48 +0300 Subject: [PATCH 0123/2442] Use Node 16 in CI workflows --- .github/workflows/ci.yaml | 2 +- .github/workflows/release.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0c81ff0789fb..a70252fa65a5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -101,7 +101,7 @@ jobs: - name: Install Nodejs uses: actions/setup-node@v1 with: - node-version: 14.x + node-version: 16.x - name: Install xvfb if: matrix.os == 'ubuntu-latest' diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ca8eb1309de3..d5d8df2345fa 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -68,7 +68,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@v1 with: - node-version: 14.x + node-version: 16.x - name: Update apt repositories if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf' @@ -133,7 +133,7 @@ jobs: container: image: rust:alpine volumes: - - /usr/local/cargo/registry + - /usr/local/cargo/registry:/usr/local/cargo/registry steps: - name: Install dependencies @@ -176,7 +176,7 @@ jobs: - name: Install Nodejs uses: actions/setup-node@v1 with: - node-version: 14.x + node-version: 16.x - run: echo "TAG=$(date --iso -u)" >> $GITHUB_ENV if: github.ref == 'refs/heads/release' From 19da03291d5253f658e29dbe916e41b4c0cfefee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Fri, 12 Aug 2022 18:22:14 +0300 Subject: [PATCH 0124/2442] Upgrade npm lockfile --- editors/code/package-lock.json | 3974 +++++++++++++++++++++++++++++++- 1 file changed, 3962 insertions(+), 12 deletions(-) diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 0436681b1a0a..3ff4b6897a16 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -1,8 +1,3956 @@ { "name": "rust-analyzer", "version": "0.5.0-dev", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "rust-analyzer", + "version": "0.5.0-dev", + "license": "MIT OR Apache-2.0", + "dependencies": { + "d3": "^7.6.1", + "d3-graphviz": "^4.1.1", + "vscode-languageclient": "^8.0.0-next.14" + }, + "devDependencies": { + "@types/node": "~16.11.7", + "@types/vscode": "~1.66.0", + "@typescript-eslint/eslint-plugin": "^5.30.5", + "@typescript-eslint/parser": "^5.30.5", + "@vscode/test-electron": "^2.1.5", + "cross-env": "^7.0.3", + "esbuild": "^0.14.48", + "eslint": "^8.19.0", + "eslint-config-prettier": "^8.5.0", + "ovsx": "^0.5.1", + "prettier": "^2.7.1", + "tslib": "^2.4.0", + "typescript": "^4.7.4", + "vsce": "^2.9.2" + }, + "engines": { + "vscode": "^1.66.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@hpcc-js/wasm": { + "version": "1.12.8", + "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-1.12.8.tgz", + "integrity": "sha512-n4q9ARKco2hpCLsuVaW6Az3cDVaua7B3DSONHkc49WtEzgY/btvcDG5Zr1P6PZDv0sQ7oPnAi9Y+W2DI++MgcQ==", + "dependencies": { + "yargs": "^17.3.1" + }, + "bin": { + "dot-wasm": "bin/cli.js" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "16.11.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.43.tgz", + "integrity": "sha512-GqWykok+3uocgfAJM8imbozrqLnPyTrpFlrryURQlw1EesPUCx5XxTiucWDSFF9/NUEXDuD4bnvHm8xfVGWTpQ==", + "dev": true + }, + "node_modules/@types/vscode": { + "version": "1.66.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.66.0.tgz", + "integrity": "sha512-ZfJck4M7nrGasfs4A4YbUoxis3Vu24cETw3DERsNYtDZmYSYtk6ljKexKFKhImO/ZmY6ZMsmegu2FPkXoUFImA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz", + "integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.30.5", + "@typescript-eslint/type-utils": "5.30.5", + "@typescript-eslint/utils": "5.30.5", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz", + "integrity": "sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.30.5", + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/typescript-estree": "5.30.5", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz", + "integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/visitor-keys": "5.30.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz", + "integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.30.5", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz", + "integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz", + "integrity": "sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/visitor-keys": "5.30.5", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz", + "integrity": "sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.30.5", + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/typescript-estree": "5.30.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz", + "integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.30.5", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vscode/test-electron": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.5.tgz", + "integrity": "sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==", + "dev": true, + "dependencies": { + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "rimraf": "^3.0.2", + "unzipper": "^0.10.11" + }, + "engines": { + "node": ">=8.9.3" + } + }, + "node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/azure-devops-node-api": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", + "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==", + "dev": true, + "dependencies": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dev": true, + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "dev": true + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "dev": true, + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "dev": true, + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/d3": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.6.1.tgz", + "integrity": "sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz", + "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush/node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.0.tgz", + "integrity": "sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", + "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag/node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz", + "integrity": "sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-graphviz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-4.1.1.tgz", + "integrity": "sha512-s0IVbKf8rs4eJI2xo5Umr7nXDX/LEZw/x2WtKxmlyQxR0qUY49UiLhBNOX7VDHZywMle43NKEXnU6fn22fpJvQ==", + "dependencies": { + "@hpcc-js/wasm": "1.12.8", + "d3-dispatch": "^2.0.0", + "d3-format": "^2.0.0", + "d3-interpolate": "^2.0.1", + "d3-path": "^2.0.0", + "d3-timer": "^2.0.0", + "d3-transition": "^2.0.0", + "d3-zoom": "^2.0.0" + }, + "peerDependencies": { + "d3-selection": "^2.0.0" + } + }, + "node_modules/d3-graphviz/node_modules/d3-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", + "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" + }, + "node_modules/d3-graphviz/node_modules/d3-dispatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", + "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==" + }, + "node_modules/d3-graphviz/node_modules/d3-drag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz", + "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==", + "dependencies": { + "d3-dispatch": "1 - 2", + "d3-selection": "2" + } + }, + "node_modules/d3-graphviz/node_modules/d3-ease": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz", + "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==" + }, + "node_modules/d3-graphviz/node_modules/d3-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", + "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" + }, + "node_modules/d3-graphviz/node_modules/d3-interpolate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", + "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", + "dependencies": { + "d3-color": "1 - 2" + } + }, + "node_modules/d3-graphviz/node_modules/d3-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz", + "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==" + }, + "node_modules/d3-graphviz/node_modules/d3-timer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", + "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" + }, + "node_modules/d3-graphviz/node_modules/d3-transition": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz", + "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==", + "dependencies": { + "d3-color": "1 - 2", + "d3-dispatch": "1 - 2", + "d3-ease": "1 - 2", + "d3-interpolate": "1 - 2", + "d3-timer": "1 - 2" + }, + "peerDependencies": { + "d3-selection": "2" + } + }, + "node_modules/d3-graphviz/node_modules/d3-zoom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz", + "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==", + "dependencies": { + "d3-dispatch": "1 - 2", + "d3-drag": "2", + "d3-interpolate": "1 - 2", + "d3-selection": "2", + "d3-transition": "2" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", + "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", + "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==" + }, + "node_modules/d3-shape": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.1.0.tgz", + "integrity": "sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3/node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "dependencies": { + "robust-predicates": "^3.0.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz", + "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz", + "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "esbuild-android-64": "0.14.48", + "esbuild-android-arm64": "0.14.48", + "esbuild-darwin-64": "0.14.48", + "esbuild-darwin-arm64": "0.14.48", + "esbuild-freebsd-64": "0.14.48", + "esbuild-freebsd-arm64": "0.14.48", + "esbuild-linux-32": "0.14.48", + "esbuild-linux-64": "0.14.48", + "esbuild-linux-arm": "0.14.48", + "esbuild-linux-arm64": "0.14.48", + "esbuild-linux-mips64le": "0.14.48", + "esbuild-linux-ppc64le": "0.14.48", + "esbuild-linux-riscv64": "0.14.48", + "esbuild-linux-s390x": "0.14.48", + "esbuild-netbsd-64": "0.14.48", + "esbuild-openbsd-64": "0.14.48", + "esbuild-sunos-64": "0.14.48", + "esbuild-windows-32": "0.14.48", + "esbuild-windows-64": "0.14.48", + "esbuild-windows-arm64": "0.14.48" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz", + "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz", + "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz", + "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz", + "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz", + "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz", + "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz", + "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz", + "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz", + "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz", + "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz", + "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz", + "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz", + "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz", + "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz", + "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz", + "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz", + "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz", + "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz", + "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz", + "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", + "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "dependencies": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.16.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", + "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-abi": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz", + "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ovsx": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.1.tgz", + "integrity": "sha512-3OWq0l7DuVHi2bd2aQe5+QVQlFIqvrcw3/2vGXL404L6Tr+R4QHtzfnYYghv8CCa85xJHjU0RhcaC7pyXkAUbg==", + "dev": true, + "dependencies": { + "commander": "^6.1.0", + "follow-redirects": "^1.14.6", + "is-ci": "^2.0.0", + "leven": "^3.1.0", + "tmp": "^0.2.1", + "vsce": "^2.6.3" + }, + "bin": { + "ovsx": "lib/ovsx" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ovsx/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", + "dev": true, + "dependencies": { + "semver": "^5.1.0" + } + }, + "node_modules/parse-semver/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/parse5": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", + "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==", + "dev": true, + "dependencies": { + "entities": "^4.3.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz", + "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-rest-client": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz", + "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==", + "dev": true, + "dependencies": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/underscore": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz", + "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==", + "dev": true + }, + "node_modules/unzipper": { + "version": "0.10.11", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", + "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/vsce": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.9.2.tgz", + "integrity": "sha512-xyLqL4U82BilUX1t6Ym2opQEa2tLGWYjbgB7+ETeNVXlIJz5sWBJjQJSYJVFOKJSpiOtQclolu88cj7oY6vvPQ==", + "dev": true, + "dependencies": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.1.0", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "keytar": "^7.7.0", + "leven": "^3.1.0", + "markdown-it": "^12.3.2", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^5.1.0", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.4.23", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/vsce/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/vsce/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/vsce/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/vsce/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/vsce/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/vsce/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/vsce/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/vsce/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/vsce/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.0.0-next.7", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.7.tgz", + "integrity": "sha512-JX/F31LEsims0dAlOTKFE4E+AJMiJvdRSRViifFJSqSN7EzeYyWlfuDchF7g91oRNPZOIWfibTkDf3/UMsQGzQ==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageclient": { + "version": "8.0.0-next.14", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.0-next.14.tgz", + "integrity": "sha512-NqjkOuDTMu8uo+PhoMsV72VO9Gd3wBi/ZpOrkRUOrWKQo7yUdiIw183g8wjH8BImgbK9ZP51HM7TI0ZhCnI1Mw==", + "dependencies": { + "minimatch": "^3.0.4", + "semver": "^7.3.5", + "vscode-languageserver-protocol": "3.17.0-next.16" + }, + "engines": { + "vscode": "^1.66.0" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.0-next.16", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.16.tgz", + "integrity": "sha512-tx4DnXw9u3N7vw+bx6n2NKp6FoxoNwiP/biH83AS30I2AnTGyLd7afSeH6Oewn2E8jvB7K15bs12sMppkKOVeQ==", + "dependencies": { + "vscode-jsonrpc": "8.0.0-next.7", + "vscode-languageserver-types": "3.17.0-next.9" + } + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.0-next.9", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.9.tgz", + "integrity": "sha512-9/PeDNPYduaoXRUzYpqmu4ZV9L01HGo0wH9FUt+sSHR7IXwA7xoXBfNUlv8gB9H0D2WwEmMomSy1NmhjKQyn3A==" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3" + } + } + }, "dependencies": { "@eslint/eslintrc": { "version": "1.3.0", @@ -213,7 +4161,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "agent-base": { "version": "6.0.2", @@ -1278,7 +5227,8 @@ "version": "8.5.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true + "dev": true, + "requires": {} }, "eslint-scope": { "version": "5.1.1", @@ -2348,6 +6298,15 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -2358,15 +6317,6 @@ "strip-ansi": "^6.0.1" } }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", From fd58459373c285df53e6254782e83d70440f192e Mon Sep 17 00:00:00 2001 From: shoffmeister Date: Thu, 11 Aug 2022 13:36:41 +0200 Subject: [PATCH 0125/2442] Take into account renamed extension id when launching Signed-off-by: Stefan Hoffmeister --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 021b8f048cf2..1e21214ffc4b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -78,7 +78,7 @@ "request": "launch", "runtimeExecutable": "${execPath}", "args": [ - "--disable-extension", "matklad.rust-analyzer", + "--disable-extension", "rust-lang.rust-analyzer", "--extensionDevelopmentPath=${workspaceFolder}/editors/code" ], "outFiles": [ From 72ae308c73a2d9d71715ec35ba1f644989338761 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 13 Aug 2022 12:13:48 +0200 Subject: [PATCH 0126/2442] Do not unconditionally succeed RUSTC_WRAPPER checks when run by build scripts rust-analyzer's RUSTC_WRAPPER unconditionally succeeds `cargo check` invocations tripping up build scripts using `cargo check` to probe for successful compilations. To prevent this from happening the RUSTC_WRAPPER now checks if it's run from a build script by looking for the `CARGO_CFG_TARGET_ARCH` env var that cargo sets only when running build scripts. --- crates/rust-analyzer/src/bin/rustc_wrapper.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/bin/rustc_wrapper.rs b/crates/rust-analyzer/src/bin/rustc_wrapper.rs index 2f6d4706d879..38e9c7dd7e11 100644 --- a/crates/rust-analyzer/src/bin/rustc_wrapper.rs +++ b/crates/rust-analyzer/src/bin/rustc_wrapper.rs @@ -17,6 +17,11 @@ pub(crate) fn run_rustc_skipping_cargo_checking( rustc_executable: OsString, args: Vec, ) -> io::Result { + // `CARGO_CFG_TARGET_ARCH` is only set by cargo when executing build scripts + // We don't want to exit out checks unconditionally with success if a build + // script tries to invoke checks themselves + // See https://github.com/rust-lang/rust-analyzer/issues/12973 for context + let not_invoked_by_build_script = std::env::var_os("CARGO_CFG_TARGET_ARCH").is_none(); let is_cargo_check = args.iter().any(|arg| { let arg = arg.to_string_lossy(); // `cargo check` invokes `rustc` with `--emit=metadata` argument. @@ -29,7 +34,7 @@ pub(crate) fn run_rustc_skipping_cargo_checking( // The default output filename is CRATE_NAME.rmeta. arg.starts_with("--emit=") && arg.contains("metadata") && !arg.contains("link") }); - if is_cargo_check { + if not_invoked_by_build_script && is_cargo_check { return Ok(ExitCode(Some(0))); } run_rustc(rustc_executable, args) From 038c36a1f5195d96d9247529d9cc1e14f00c8c17 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 13 Aug 2022 20:03:06 +0200 Subject: [PATCH 0127/2442] Simplify `GlobalState::handle_event` --- crates/rust-analyzer/src/main_loop.rs | 381 +++++++++++++------------- 1 file changed, 192 insertions(+), 189 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index b504c2487826..92b6be22e762 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -9,6 +9,7 @@ use std::{ use always_assert::always; use crossbeam_channel::{select, Receiver}; +use flycheck::FlycheckHandle; use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath}; use itertools::Itertools; use lsp_server::{Connection, Notification, Request}; @@ -205,81 +206,14 @@ impl GlobalState { } lsp_server::Message::Response(resp) => self.complete_request(resp), }, - Event::Task(mut task) => { + Event::Task(task) => { let _p = profile::span("GlobalState::handle_event/task"); let mut prime_caches_progress = Vec::new(); - loop { - match task { - Task::Response(response) => self.respond(response), - Task::Retry(req) => self.on_request(req), - Task::Diagnostics(diagnostics_per_file) => { - for (file_id, diagnostics) in diagnostics_per_file { - self.diagnostics.set_native_diagnostics(file_id, diagnostics) - } - } - Task::PrimeCaches(progress) => match progress { - PrimeCachesProgress::Begin => prime_caches_progress.push(progress), - PrimeCachesProgress::Report(_) => { - match prime_caches_progress.last_mut() { - Some(last @ PrimeCachesProgress::Report(_)) => { - // Coalesce subsequent update events. - *last = progress; - } - _ => prime_caches_progress.push(progress), - } - } - PrimeCachesProgress::End { .. } => prime_caches_progress.push(progress), - }, - Task::FetchWorkspace(progress) => { - let (state, msg) = match progress { - ProjectWorkspaceProgress::Begin => (Progress::Begin, None), - ProjectWorkspaceProgress::Report(msg) => { - (Progress::Report, Some(msg)) - } - ProjectWorkspaceProgress::End(workspaces) => { - self.fetch_workspaces_queue.op_completed(workspaces); - let old = Arc::clone(&self.workspaces); - self.switch_workspaces("fetched workspace".to_string()); - let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces); - - if self.config.run_build_scripts() && workspaces_updated { - self.fetch_build_data_queue - .request_op(format!("workspace updated")); - } - - (Progress::End, None) - } - }; - - self.report_progress("Fetching", state, msg, None); - } - Task::FetchBuildData(progress) => { - let (state, msg) = match progress { - BuildDataProgress::Begin => (Some(Progress::Begin), None), - BuildDataProgress::Report(msg) => { - (Some(Progress::Report), Some(msg)) - } - BuildDataProgress::End(build_data_result) => { - self.fetch_build_data_queue.op_completed(build_data_result); - - self.switch_workspaces("fetched build data".to_string()); - - (Some(Progress::End), None) - } - }; - - if let Some(state) = state { - self.report_progress("Loading", state, msg, None); - } - } - } - - // Coalesce multiple task events into one loop turn - task = match self.task_pool.receiver.try_recv() { - Ok(task) => task, - Err(_) => break, - }; + self.handle_task(&mut prime_caches_progress, task); + // Coalesce multiple task events into one loop turn + while let Ok(task) = self.task_pool.receiver.try_recv() { + self.handle_task(&mut prime_caches_progress, task); } for progress in prime_caches_progress { @@ -326,119 +260,20 @@ impl GlobalState { self.report_progress("Indexing", state, message, Some(fraction)); } } - Event::Vfs(mut task) => { + Event::Vfs(message) => { let _p = profile::span("GlobalState::handle_event/vfs"); - loop { - match task { - vfs::loader::Message::Loaded { files } => { - let vfs = &mut self.vfs.write().0; - for (path, contents) in files { - let path = VfsPath::from(path); - if !self.mem_docs.contains(&path) { - vfs.set_file_contents(path, contents); - } - } - } - vfs::loader::Message::Progress { n_total, n_done, config_version } => { - always!(config_version <= self.vfs_config_version); - - self.vfs_progress_config_version = config_version; - self.vfs_progress_n_total = n_total; - self.vfs_progress_n_done = n_done; - - let state = if n_done == 0 { - Progress::Begin - } else if n_done < n_total { - Progress::Report - } else { - assert_eq!(n_done, n_total); - Progress::End - }; - self.report_progress( - "Roots Scanned", - state, - Some(format!("{}/{}", n_done, n_total)), - Some(Progress::fraction(n_done, n_total)), - ) - } - } - // Coalesce many VFS event into a single loop turn - task = match self.loader.receiver.try_recv() { - Ok(task) => task, - Err(_) => break, - } + self.handle_vfs_msg(message); + // Coalesce many VFS event into a single loop turn + while let Ok(message) = self.loader.receiver.try_recv() { + self.handle_vfs_msg(message); } } - Event::Flycheck(mut task) => { + Event::Flycheck(message) => { let _p = profile::span("GlobalState::handle_event/flycheck"); - loop { - match task { - flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => { - let snap = self.snapshot(); - let diagnostics = - crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( - &self.config.diagnostics_map(), - &diagnostic, - &workspace_root, - &snap, - ); - for diag in diagnostics { - match url_to_file_id(&self.vfs.read().0, &diag.url) { - Ok(file_id) => self.diagnostics.add_check_diagnostic( - id, - file_id, - diag.diagnostic, - diag.fix, - ), - Err(err) => { - tracing::error!( - "File with cargo diagnostic not found in VFS: {}", - err - ); - } - }; - } - } - - flycheck::Message::Progress { id, progress } => { - let (state, message) = match progress { - flycheck::Progress::DidStart => { - self.diagnostics.clear_check(id); - (Progress::Begin, None) - } - flycheck::Progress::DidCheckCrate(target) => { - (Progress::Report, Some(target)) - } - flycheck::Progress::DidCancel => (Progress::End, None), - flycheck::Progress::DidFinish(result) => { - if let Err(err) = result { - self.show_and_log_error( - "cargo check failed".to_string(), - Some(err.to_string()), - ); - } - (Progress::End, None) - } - }; - - // When we're running multiple flychecks, we have to include a disambiguator in - // the title, or the editor complains. Note that this is a user-facing string. - let title = if self.flycheck.len() == 1 { - match self.config.flycheck() { - Some(config) => format!("{}", config), - None => "cargo check".to_string(), - } - } else { - format!("cargo check (#{})", id + 1) - }; - self.report_progress(&title, state, message, None); - } - } - // Coalesce many flycheck updates into a single loop turn - task = match self.flycheck_receiver.try_recv() { - Ok(task) => task, - Err(_) => break, - } + self.handle_flycheck_msg(message); + // Coalesce many flycheck updates into a single loop turn + while let Ok(message) = self.flycheck_receiver.try_recv() { + self.handle_flycheck_msg(message); } } } @@ -447,13 +282,13 @@ impl GlobalState { let memdocs_added_or_removed = self.mem_docs.take_changes(); if self.is_quiescent() { - if !was_quiescent - && !self.fetch_workspaces_queue.op_requested() - && !self.fetch_build_data_queue.op_requested() - { - for flycheck in &self.flycheck { - flycheck.update(); - } + let became_quiescent = !(was_quiescent + || self.fetch_workspaces_queue.op_requested() + || self.fetch_build_data_queue.op_requested()); + + if became_quiescent { + // Project has loaded properly, kick off initial flycheck + self.flycheck.iter().for_each(FlycheckHandle::update); if self.config.prefill_caches() { self.prime_caches_queue.request_op("became quiescent".to_string()); } @@ -495,8 +330,9 @@ impl GlobalState { let url = file_id_to_url(&self.vfs.read().0, file_id); let mut diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect::>(); - // https://github.com/rust-lang/rust-analyzer/issues/11404 for d in &mut diagnostics { + // https://github.com/rust-lang/rust-analyzer/issues/11404 + // FIXME: We should move this workaround into the client code if d.message.is_empty() { d.message = " ".to_string(); } @@ -575,11 +411,171 @@ impl GlobalState { Ok(()) } + fn handle_task(&mut self, prime_caches_progress: &mut Vec, task: Task) { + match task { + Task::Response(response) => self.respond(response), + Task::Retry(req) => self.on_request(req), + Task::Diagnostics(diagnostics_per_file) => { + for (file_id, diagnostics) in diagnostics_per_file { + self.diagnostics.set_native_diagnostics(file_id, diagnostics) + } + } + Task::PrimeCaches(progress) => match progress { + PrimeCachesProgress::Begin => prime_caches_progress.push(progress), + PrimeCachesProgress::Report(_) => { + match prime_caches_progress.last_mut() { + Some(last @ PrimeCachesProgress::Report(_)) => { + // Coalesce subsequent update events. + *last = progress; + } + _ => prime_caches_progress.push(progress), + } + } + PrimeCachesProgress::End { .. } => prime_caches_progress.push(progress), + }, + Task::FetchWorkspace(progress) => { + let (state, msg) = match progress { + ProjectWorkspaceProgress::Begin => (Progress::Begin, None), + ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)), + ProjectWorkspaceProgress::End(workspaces) => { + self.fetch_workspaces_queue.op_completed(workspaces); + + let old = Arc::clone(&self.workspaces); + self.switch_workspaces("fetched workspace".to_string()); + let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces); + + if self.config.run_build_scripts() && workspaces_updated { + self.fetch_build_data_queue.request_op(format!("workspace updated")); + } + + (Progress::End, None) + } + }; + + self.report_progress("Fetching", state, msg, None); + } + Task::FetchBuildData(progress) => { + let (state, msg) = match progress { + BuildDataProgress::Begin => (Some(Progress::Begin), None), + BuildDataProgress::Report(msg) => (Some(Progress::Report), Some(msg)), + BuildDataProgress::End(build_data_result) => { + self.fetch_build_data_queue.op_completed(build_data_result); + + self.switch_workspaces("fetched build data".to_string()); + + (Some(Progress::End), None) + } + }; + + if let Some(state) = state { + self.report_progress("Loading", state, msg, None); + } + } + } + } + + fn handle_vfs_msg(&mut self, message: vfs::loader::Message) { + match message { + vfs::loader::Message::Loaded { files } => { + let vfs = &mut self.vfs.write().0; + for (path, contents) in files { + let path = VfsPath::from(path); + if !self.mem_docs.contains(&path) { + vfs.set_file_contents(path, contents); + } + } + } + vfs::loader::Message::Progress { n_total, n_done, config_version } => { + always!(config_version <= self.vfs_config_version); + + self.vfs_progress_config_version = config_version; + self.vfs_progress_n_total = n_total; + self.vfs_progress_n_done = n_done; + + let state = if n_done == 0 { + Progress::Begin + } else if n_done < n_total { + Progress::Report + } else { + assert_eq!(n_done, n_total); + Progress::End + }; + self.report_progress( + "Roots Scanned", + state, + Some(format!("{}/{}", n_done, n_total)), + Some(Progress::fraction(n_done, n_total)), + ) + } + } + } + + fn handle_flycheck_msg(&mut self, message: flycheck::Message) { + match message { + flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => { + let snap = self.snapshot(); + let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( + &self.config.diagnostics_map(), + &diagnostic, + &workspace_root, + &snap, + ); + for diag in diagnostics { + match url_to_file_id(&self.vfs.read().0, &diag.url) { + Ok(file_id) => self.diagnostics.add_check_diagnostic( + id, + file_id, + diag.diagnostic, + diag.fix, + ), + Err(err) => { + tracing::error!("File with cargo diagnostic not found in VFS: {}", err); + } + }; + } + } + + flycheck::Message::Progress { id, progress } => { + let (state, message) = match progress { + flycheck::Progress::DidStart => { + self.diagnostics.clear_check(id); + (Progress::Begin, None) + } + flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)), + flycheck::Progress::DidCancel => (Progress::End, None), + flycheck::Progress::DidFinish(result) => { + if let Err(err) = result { + self.show_and_log_error( + "cargo check failed".to_string(), + Some(err.to_string()), + ); + } + (Progress::End, None) + } + }; + + // When we're running multiple flychecks, we have to include a disambiguator in + // the title, or the editor complains. Note that this is a user-facing string. + let title = if self.flycheck.len() == 1 { + match self.config.flycheck() { + Some(config) => format!("{}", config), + None => "cargo check".to_string(), + } + } else { + format!("cargo check (#{})", id + 1) + }; + self.report_progress(&title, state, message, None); + } + } + } + + /// Registers and handles a request. This should only be called once per incoming request. fn on_new_request(&mut self, request_received: Instant, req: Request) { self.register_request(&req, request_received); self.on_request(req); } + /// Handles a request. fn on_request(&mut self, req: Request) { if self.shutdown_requested { self.respond(lsp_server::Response::new_err( @@ -670,6 +666,7 @@ impl GlobalState { .finish(); } + /// Handles an incoming notification. fn on_notification(&mut self, not: Notification) -> Result<()> { NotificationDispatcher { not: Some(not), global_state: self } .on::(|this, params| { @@ -743,6 +740,8 @@ impl GlobalState { let mut updated = false; if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) { let (vfs, _) = &*this.vfs.read(); + + // Trigger flychecks for all workspaces that depend on the saved file if let Some(file_id) = vfs.file_id(&vfs_path) { let analysis = this.analysis_host.analysis(); // Crates containing or depending on the saved file @@ -800,6 +799,8 @@ impl GlobalState { } } } + + // Re-fetch workspaces if a workspace related file has changed if let Some(abs_path) = vfs_path.as_path() { if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) { this.fetch_workspaces_queue @@ -807,6 +808,8 @@ impl GlobalState { } } } + + // No specific flycheck was triggered, so let's trigger all of them. if !updated { for flycheck in &this.flycheck { flycheck.update(); From ec8256dd8027bbe5493698e4b9125f1f0cf8c646 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 13 Aug 2022 20:18:21 +0200 Subject: [PATCH 0128/2442] Move VSCode diagnostics workaroudn into client code --- crates/rust-analyzer/src/handlers.rs | 3 +-- crates/rust-analyzer/src/main_loop.rs | 22 ++++------------------ editors/code/src/client.ts | 9 +++++++++ 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 47daa732d5d3..943d043bc199 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -1320,8 +1320,7 @@ pub(crate) fn publish_diagnostics( .unwrap(), }), source: Some("rust-analyzer".to_string()), - // https://github.com/rust-lang/rust-analyzer/issues/11404 - message: if !d.message.is_empty() { d.message } else { " ".to_string() }, + message: d.message, related_information: None, tags: if d.unused { Some(vec![DiagnosticTag::UNNECESSARY]) } else { None }, data: None, diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 92b6be22e762..77419998249f 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -327,29 +327,15 @@ impl GlobalState { continue; } - let url = file_id_to_url(&self.vfs.read().0, file_id); - let mut diagnostics = + let uri = file_id_to_url(&self.vfs.read().0, file_id); + let diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect::>(); - for d in &mut diagnostics { - // https://github.com/rust-lang/rust-analyzer/issues/11404 - // FIXME: We should move this workaround into the client code - if d.message.is_empty() { - d.message = " ".to_string(); - } - if let Some(rds) = d.related_information.as_mut() { - for rd in rds { - if rd.message.is_empty() { - rd.message = " ".to_string(); - } - } - } - } - let version = from_proto::vfs_path(&url) + let version = from_proto::vfs_path(&uri) .map(|path| self.mem_docs.get(&path).map(|it| it.version)) .unwrap_or_default(); self.send_notification::( - lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version }, + lsp_types::PublishDiagnosticsParams { uri, diagnostics, version }, ); } } diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 8a2dea6b35b7..40ba17844bee 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -105,6 +105,15 @@ export async function createClient( traceOutputChannel: traceOutputChannel(), outputChannel: outputChannel(), middleware: { + async handleDiagnostics(uri, diagnostics, next) { + // Workaround for https://github.com/microsoft/vscode/issues/155531 + for (const diagnostic of diagnostics) { + if (!diagnostic.message) { + diagnostic.message = " "; + } + } + next(uri, diagnostics); + }, async provideHover( document: vscode.TextDocument, position: vscode.Position, From 614969baa770360b711881a3d9776d60937c98db Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 13 Aug 2022 20:49:00 +0200 Subject: [PATCH 0129/2442] Pad empty diagnostic messages in relatedInformation as well --- editors/code/src/client.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 40ba17844bee..27ab31db8db4 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -111,6 +111,13 @@ export async function createClient( if (!diagnostic.message) { diagnostic.message = " "; } + if (diagnostic.relatedInformation) { + for (const relatedInformation of diagnostic.relatedInformation) { + if (!relatedInformation.message) { + relatedInformation.message = " "; + } + } + } } next(uri, diagnostics); }, From c61237b2b293d6f62270f6047ca11306f6871c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sun, 14 Aug 2022 20:52:43 +0300 Subject: [PATCH 0130/2442] Remove redundant --pre-release flag from publish --- .github/workflows/release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d5d8df2345fa..3c36c4fb84a2 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -253,9 +253,9 @@ jobs: - name: Publish Extension (Code Marketplace, nightly) if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') working-directory: ./editors/code - run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix --pre-release + run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix - name: Publish Extension (OpenVSX, nightly) if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') working-directory: ./editors/code - run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix --pre-release + run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix From dcbe892d7ceec113a148a89bc6d1c339c55586d1 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 15 Aug 2022 13:51:45 +0200 Subject: [PATCH 0131/2442] Add an HIR pretty-printer --- crates/hir-def/src/body.rs | 5 + crates/hir-def/src/body/pretty.rs | 621 +++++++++++++++++++++++++ crates/hir-def/src/builtin_type.rs | 35 ++ crates/hir-def/src/expr.rs | 6 +- crates/hir-def/src/item_tree/pretty.rs | 179 +------ crates/hir-def/src/item_tree/tests.rs | 12 +- crates/hir-def/src/lib.rs | 1 + crates/hir-def/src/pretty.rs | 209 +++++++++ crates/hir-def/src/type_ref.rs | 4 + crates/hir/src/lib.rs | 29 +- crates/ide/src/view_hir.rs | 14 +- editors/code/src/commands.ts | 2 +- 12 files changed, 914 insertions(+), 203 deletions(-) create mode 100644 crates/hir-def/src/body/pretty.rs create mode 100644 crates/hir-def/src/pretty.rs diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 080a307b1f8a..1d818d96267c 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -4,6 +4,7 @@ mod lower; #[cfg(test)] mod tests; pub mod scope; +mod pretty; use std::{ops::Index, sync::Arc}; @@ -352,6 +353,10 @@ impl Body { } } + pub fn pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String { + pretty::print_body_hir(db, self, owner) + } + fn new( db: &dyn DefDatabase, expander: Expander, diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs new file mode 100644 index 000000000000..ddd476efe5c4 --- /dev/null +++ b/crates/hir-def/src/body/pretty.rs @@ -0,0 +1,621 @@ +//! A pretty-printer for HIR. + +use std::fmt::{self, Write}; + +use crate::{ + expr::{Array, BindingAnnotation, Literal, Statement}, + pretty::{print_generic_args, print_path, print_type_ref}, + type_ref::TypeRef, +}; + +use super::*; + +pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String { + let needs_semi; + let header = match owner { + DefWithBodyId::FunctionId(it) => { + needs_semi = false; + let item_tree_id = it.lookup(db).id; + format!("fn {}(…) ", item_tree_id.item_tree(db)[item_tree_id.value].name) + } + DefWithBodyId::StaticId(it) => { + needs_semi = true; + let item_tree_id = it.lookup(db).id; + format!("static {} = ", item_tree_id.item_tree(db)[item_tree_id.value].name) + } + DefWithBodyId::ConstId(it) => { + needs_semi = true; + let item_tree_id = it.lookup(db).id; + let name = match &item_tree_id.item_tree(db)[item_tree_id.value].name { + Some(name) => name.to_string(), + None => "_".to_string(), + }; + format!("const {} = ", name) + } + }; + + let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false }; + p.print_expr(body.body_expr); + if needs_semi { + p.buf.push(';'); + } + p.buf +} + +macro_rules! w { + ($dst:expr, $($arg:tt)*) => { + { let _ = write!($dst, $($arg)*); } + }; +} + +macro_rules! wln { + ($dst:expr) => { + { let _ = writeln!($dst); } + }; + ($dst:expr, $($arg:tt)*) => { + { let _ = writeln!($dst, $($arg)*); } + }; +} + +struct Printer<'a> { + body: &'a Body, + buf: String, + indent_level: usize, + needs_indent: bool, +} + +impl<'a> Write for Printer<'a> { + fn write_str(&mut self, s: &str) -> fmt::Result { + for line in s.split_inclusive('\n') { + if self.needs_indent { + match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() { + Some('\n') | None => {} + _ => self.buf.push('\n'), + } + self.buf.push_str(&" ".repeat(self.indent_level)); + self.needs_indent = false; + } + + self.buf.push_str(line); + self.needs_indent = line.ends_with('\n'); + } + + Ok(()) + } +} + +impl<'a> Printer<'a> { + fn indented(&mut self, f: impl FnOnce(&mut Self)) { + self.indent_level += 1; + wln!(self); + f(self); + self.indent_level -= 1; + self.buf = self.buf.trim_end_matches('\n').to_string(); + } + + fn whitespace(&mut self) { + match self.buf.chars().next_back() { + None | Some('\n' | ' ') => {} + _ => self.buf.push(' '), + } + } + + fn newline(&mut self) { + match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() { + Some('\n') | None => {} + _ => writeln!(self).unwrap(), + } + } + + fn print_expr(&mut self, expr: ExprId) { + let expr = &self.body[expr]; + + match expr { + Expr::Missing => w!(self, "�"), + Expr::Underscore => w!(self, "_"), + Expr::Path(path) => self.print_path(path), + Expr::If { condition, then_branch, else_branch } => { + w!(self, "if "); + self.print_expr(*condition); + w!(self, " "); + self.print_expr(*then_branch); + if let Some(els) = *else_branch { + w!(self, " else "); + self.print_expr(els); + } + } + Expr::Let { pat, expr } => { + w!(self, "let "); + self.print_pat(*pat); + w!(self, " = "); + self.print_expr(*expr); + } + Expr::Loop { body, label } => { + if let Some(lbl) = label { + w!(self, "{}: ", self.body[*lbl].name); + } + w!(self, "loop "); + self.print_expr(*body); + } + Expr::While { condition, body, label } => { + if let Some(lbl) = label { + w!(self, "{}: ", self.body[*lbl].name); + } + w!(self, "while "); + self.print_expr(*condition); + self.print_expr(*body); + } + Expr::For { iterable, pat, body, label } => { + if let Some(lbl) = label { + w!(self, "{}: ", self.body[*lbl].name); + } + w!(self, "for "); + self.print_pat(*pat); + w!(self, " in "); + self.print_expr(*iterable); + self.print_expr(*body); + } + Expr::Call { callee, args, is_assignee_expr: _ } => { + self.print_expr(*callee); + w!(self, "("); + if !args.is_empty() { + self.indented(|p| { + for arg in &**args { + p.print_expr(*arg); + wln!(p, ","); + } + }); + } + w!(self, ")"); + } + Expr::MethodCall { receiver, method_name, args, generic_args } => { + self.print_expr(*receiver); + w!(self, ".{}", method_name); + if let Some(args) = generic_args { + w!(self, "::<"); + print_generic_args(args, self).unwrap(); + w!(self, ">"); + } + w!(self, "("); + if !args.is_empty() { + self.indented(|p| { + for arg in &**args { + p.print_expr(*arg); + wln!(p, ","); + } + }); + } + w!(self, ")"); + } + Expr::Match { expr, arms } => { + w!(self, "match "); + self.print_expr(*expr); + w!(self, " {{"); + self.indented(|p| { + for arm in &**arms { + p.print_pat(arm.pat); + if let Some(guard) = arm.guard { + w!(p, " if "); + p.print_expr(guard); + } + w!(p, " => "); + p.print_expr(arm.expr); + wln!(p, ","); + } + }); + wln!(self, "}}"); + } + Expr::Continue { label } => { + w!(self, "continue"); + if let Some(label) = label { + w!(self, " {}", label); + } + } + Expr::Break { expr, label } => { + w!(self, "break"); + if let Some(label) = label { + w!(self, " {}", label); + } + if let Some(expr) = expr { + self.whitespace(); + self.print_expr(*expr); + } + } + Expr::Return { expr } => { + w!(self, "return"); + if let Some(expr) = expr { + self.whitespace(); + self.print_expr(*expr); + } + } + Expr::Yield { expr } => { + w!(self, "yield"); + if let Some(expr) = expr { + self.whitespace(); + self.print_expr(*expr); + } + } + Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => { + match path { + Some(path) => self.print_path(path), + None => w!(self, "�"), + } + + w!(self, "{{"); + self.indented(|p| { + for field in &**fields { + w!(p, "{}: ", field.name); + p.print_expr(field.expr); + wln!(p, ","); + } + if let Some(spread) = spread { + w!(p, ".."); + p.print_expr(*spread); + wln!(p); + } + if *ellipsis { + wln!(p, ".."); + } + }); + w!(self, "}}"); + } + Expr::Field { expr, name } => { + self.print_expr(*expr); + w!(self, ".{}", name); + } + Expr::Await { expr } => { + self.print_expr(*expr); + w!(self, ".await"); + } + Expr::Try { expr } => { + self.print_expr(*expr); + w!(self, "?"); + } + Expr::TryBlock { body } => { + w!(self, "try "); + self.print_expr(*body); + } + Expr::Async { body } => { + w!(self, "async "); + self.print_expr(*body); + } + Expr::Const { body } => { + w!(self, "const "); + self.print_expr(*body); + } + Expr::Cast { expr, type_ref } => { + self.print_expr(*expr); + w!(self, " as "); + self.print_type_ref(type_ref); + } + Expr::Ref { expr, rawness, mutability } => { + w!(self, "&"); + if rawness.is_raw() { + w!(self, "raw "); + } + if mutability.is_mut() { + w!(self, "mut "); + } + self.print_expr(*expr); + } + Expr::Box { expr } => { + w!(self, "box "); + self.print_expr(*expr); + } + Expr::UnaryOp { expr, op } => { + let op = match op { + ast::UnaryOp::Deref => "*", + ast::UnaryOp::Not => "!", + ast::UnaryOp::Neg => "-", + }; + w!(self, "{}", op); + self.print_expr(*expr); + } + Expr::BinaryOp { lhs, rhs, op } => { + let (bra, ket) = match op { + None | Some(ast::BinaryOp::Assignment { .. }) => ("", ""), + _ => ("(", ")"), + }; + w!(self, "{}", bra); + self.print_expr(*lhs); + w!(self, "{} ", ket); + match op { + Some(op) => w!(self, "{}", op), + None => w!(self, "�"), // :) + } + w!(self, " {}", bra); + self.print_expr(*rhs); + w!(self, "{}", ket); + } + Expr::Range { lhs, rhs, range_type } => { + if let Some(lhs) = lhs { + w!(self, "("); + self.print_expr(*lhs); + w!(self, ") "); + } + let range = match range_type { + ast::RangeOp::Exclusive => "..", + ast::RangeOp::Inclusive => "..=", + }; + w!(self, "{}", range); + if let Some(rhs) = rhs { + w!(self, "("); + self.print_expr(*rhs); + w!(self, ") "); + } + } + Expr::Index { base, index } => { + self.print_expr(*base); + w!(self, "["); + self.print_expr(*index); + w!(self, "]"); + } + Expr::Closure { args, arg_types, ret_type, body } => { + w!(self, "|"); + for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() { + if i != 0 { + w!(self, ", "); + } + self.print_pat(*pat); + if let Some(ty) = ty { + w!(self, ": "); + self.print_type_ref(ty); + } + } + w!(self, "|"); + if let Some(ret_ty) = ret_type { + w!(self, " -> "); + self.print_type_ref(ret_ty); + } + self.whitespace(); + self.print_expr(*body); + } + Expr::Tuple { exprs, is_assignee_expr: _ } => { + w!(self, "("); + for expr in exprs.iter() { + self.print_expr(*expr); + w!(self, ", "); + } + w!(self, ")"); + } + Expr::Unsafe { body } => { + w!(self, "unsafe "); + self.print_expr(*body); + } + Expr::Array(arr) => { + w!(self, "["); + if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) { + self.indented(|p| match arr { + Array::ElementList { elements, is_assignee_expr: _ } => { + for elem in elements.iter() { + p.print_expr(*elem); + w!(p, ", "); + } + } + Array::Repeat { initializer, repeat } => { + p.print_expr(*initializer); + w!(p, "; "); + p.print_expr(*repeat); + } + }); + self.newline(); + } + w!(self, "]"); + } + Expr::Literal(lit) => self.print_literal(lit), + Expr::Block { id: _, statements, tail, label } => { + self.whitespace(); + if let Some(lbl) = label { + w!(self, "{}: ", self.body[*lbl].name); + } + w!(self, "{{"); + if !statements.is_empty() || tail.is_some() { + self.indented(|p| { + for stmt in &**statements { + p.print_stmt(stmt); + } + if let Some(tail) = tail { + p.print_expr(*tail); + } + p.newline(); + }); + } + w!(self, "}}"); + } + Expr::MacroStmts { statements, tail } => { + w!(self, "{{ // macro statements"); + self.indented(|p| { + for stmt in statements.iter() { + p.print_stmt(stmt); + } + if let Some(tail) = tail { + p.print_expr(*tail); + } + }); + self.newline(); + w!(self, "}}"); + } + } + } + + fn print_pat(&mut self, pat: PatId) { + let pat = &self.body[pat]; + + match pat { + Pat::Missing => w!(self, "�"), + Pat::Wild => w!(self, "_"), + Pat::Tuple { args, ellipsis } => { + w!(self, "("); + for (i, pat) in args.iter().enumerate() { + if i != 0 { + w!(self, ", "); + } + if *ellipsis == Some(i) { + w!(self, ".., "); + } + self.print_pat(*pat); + } + w!(self, ")"); + } + Pat::Or(pats) => { + for (i, pat) in pats.iter().enumerate() { + if i != 0 { + w!(self, " | "); + } + self.print_pat(*pat); + } + } + Pat::Record { path, args, ellipsis } => { + match path { + Some(path) => self.print_path(path), + None => w!(self, "�"), + } + + w!(self, " {{"); + self.indented(|p| { + for arg in args.iter() { + w!(p, "{}: ", arg.name); + p.print_pat(arg.pat); + wln!(p, ","); + } + if *ellipsis { + wln!(p, ".."); + } + }); + w!(self, "}}"); + } + Pat::Range { start, end } => { + self.print_expr(*start); + w!(self, "..."); + self.print_expr(*end); + } + Pat::Slice { prefix, slice, suffix } => { + w!(self, "["); + for pat in prefix.iter() { + self.print_pat(*pat); + w!(self, ", "); + } + if let Some(pat) = slice { + self.print_pat(*pat); + w!(self, ", "); + } + for pat in suffix.iter() { + self.print_pat(*pat); + w!(self, ", "); + } + w!(self, "]"); + } + Pat::Path(path) => self.print_path(path), + Pat::Lit(expr) => self.print_expr(*expr), + Pat::Bind { mode, name, subpat } => { + let mode = match mode { + BindingAnnotation::Unannotated => "", + BindingAnnotation::Mutable => "mut ", + BindingAnnotation::Ref => "ref ", + BindingAnnotation::RefMut => "ref mut ", + }; + w!(self, "{}{}", mode, name); + if let Some(pat) = subpat { + self.whitespace(); + self.print_pat(*pat); + } + } + Pat::TupleStruct { path, args, ellipsis } => { + match path { + Some(path) => self.print_path(path), + None => w!(self, "�"), + } + w!(self, "("); + for (i, arg) in args.iter().enumerate() { + if i != 0 { + w!(self, ", "); + } + if *ellipsis == Some(i) { + w!(self, ", .."); + } + self.print_pat(*arg); + } + w!(self, ")"); + } + Pat::Ref { pat, mutability } => { + w!(self, "&"); + if mutability.is_mut() { + w!(self, "mut "); + } + self.print_pat(*pat); + } + Pat::Box { inner } => { + w!(self, "box "); + self.print_pat(*inner); + } + Pat::ConstBlock(c) => { + w!(self, "const "); + self.print_expr(*c); + } + } + } + + fn print_stmt(&mut self, stmt: &Statement) { + match stmt { + Statement::Let { pat, type_ref, initializer, else_branch } => { + w!(self, "let "); + self.print_pat(*pat); + if let Some(ty) = type_ref { + w!(self, ": "); + self.print_type_ref(ty); + } + if let Some(init) = initializer { + w!(self, " = "); + self.print_expr(*init); + } + if let Some(els) = else_branch { + w!(self, " else "); + self.print_expr(*els); + } + wln!(self, ";"); + } + Statement::Expr { expr, has_semi } => { + self.print_expr(*expr); + if *has_semi { + w!(self, ";"); + } + wln!(self); + } + } + } + + fn print_literal(&mut self, literal: &Literal) { + match literal { + Literal::String(it) => w!(self, "{:?}", it), + Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()), + Literal::Char(it) => w!(self, "'{}'", it.escape_debug()), + Literal::Bool(it) => w!(self, "{}", it), + Literal::Int(i, suffix) => { + w!(self, "{}", i); + if let Some(suffix) = suffix { + w!(self, "{}", suffix); + } + } + Literal::Uint(i, suffix) => { + w!(self, "{}", i); + if let Some(suffix) = suffix { + w!(self, "{}", suffix); + } + } + Literal::Float(f, suffix) => { + w!(self, "{}", f); + if let Some(suffix) = suffix { + w!(self, "{}", suffix); + } + } + } + } + + fn print_type_ref(&mut self, ty: &TypeRef) { + print_type_ref(ty, self).unwrap(); + } + + fn print_path(&mut self, path: &Path) { + print_path(path, self).unwrap(); + } +} diff --git a/crates/hir-def/src/builtin_type.rs b/crates/hir-def/src/builtin_type.rs index 25a408036ff7..dd69c3ab4731 100644 --- a/crates/hir-def/src/builtin_type.rs +++ b/crates/hir-def/src/builtin_type.rs @@ -156,3 +156,38 @@ impl BuiltinFloat { Some(res) } } + +impl fmt::Display for BuiltinInt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + BuiltinInt::Isize => "isize", + BuiltinInt::I8 => "i8", + BuiltinInt::I16 => "i16", + BuiltinInt::I32 => "i32", + BuiltinInt::I64 => "i64", + BuiltinInt::I128 => "i128", + }) + } +} + +impl fmt::Display for BuiltinUint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + BuiltinUint::Usize => "usize", + BuiltinUint::U8 => "u8", + BuiltinUint::U16 => "u16", + BuiltinUint::U32 => "u32", + BuiltinUint::U64 => "u64", + BuiltinUint::U128 => "u128", + }) + } +} + +impl fmt::Display for BuiltinFloat { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + BuiltinFloat::F32 => "f32", + BuiltinFloat::F64 => "f64", + }) + } +} diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs index c1b3788acb7d..4381b43c258b 100644 --- a/crates/hir-def/src/expr.rs +++ b/crates/hir-def/src/expr.rs @@ -12,6 +12,8 @@ //! //! See also a neighboring `body` module. +use std::fmt; + use hir_expand::name::Name; use la_arena::{Idx, RawIdx}; @@ -52,8 +54,8 @@ impl FloatTypeWrapper { } } -impl std::fmt::Display for FloatTypeWrapper { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for FloatTypeWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", f64::from_bits(self.0)) } } diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index f12d9a1273cc..34dd817fd130 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -2,13 +2,10 @@ use std::fmt::{self, Write}; -use itertools::Itertools; - use crate::{ attr::RawAttrs, generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget}, - path::GenericArg, - type_ref::TraitBoundModifier, + pretty::{print_path, print_type_bounds, print_type_ref}, visibility::RawVisibility, }; @@ -464,183 +461,15 @@ impl<'a> Printer<'a> { } fn print_type_ref(&mut self, type_ref: &TypeRef) { - // FIXME: deduplicate with `HirDisplay` impl - match type_ref { - TypeRef::Never => w!(self, "!"), - TypeRef::Placeholder => w!(self, "_"), - TypeRef::Tuple(fields) => { - w!(self, "("); - for (i, field) in fields.iter().enumerate() { - if i != 0 { - w!(self, ", "); - } - self.print_type_ref(field); - } - w!(self, ")"); - } - TypeRef::Path(path) => self.print_path(path), - TypeRef::RawPtr(pointee, mtbl) => { - let mtbl = match mtbl { - Mutability::Shared => "*const", - Mutability::Mut => "*mut", - }; - w!(self, "{} ", mtbl); - self.print_type_ref(pointee); - } - TypeRef::Reference(pointee, lt, mtbl) => { - let mtbl = match mtbl { - Mutability::Shared => "", - Mutability::Mut => "mut ", - }; - w!(self, "&"); - if let Some(lt) = lt { - w!(self, "{} ", lt.name); - } - w!(self, "{}", mtbl); - self.print_type_ref(pointee); - } - TypeRef::Array(elem, len) => { - w!(self, "["); - self.print_type_ref(elem); - w!(self, "; {}]", len); - } - TypeRef::Slice(elem) => { - w!(self, "["); - self.print_type_ref(elem); - w!(self, "]"); - } - TypeRef::Fn(args_and_ret, varargs) => { - let ((_, return_type), args) = - args_and_ret.split_last().expect("TypeRef::Fn is missing return type"); - w!(self, "fn("); - for (i, (_, typeref)) in args.iter().enumerate() { - if i != 0 { - w!(self, ", "); - } - self.print_type_ref(typeref); - } - if *varargs { - if !args.is_empty() { - w!(self, ", "); - } - w!(self, "..."); - } - w!(self, ") -> "); - self.print_type_ref(return_type); - } - TypeRef::Macro(_ast_id) => { - w!(self, ""); - } - TypeRef::Error => w!(self, "{{unknown}}"), - TypeRef::ImplTrait(bounds) => { - w!(self, "impl "); - self.print_type_bounds(bounds); - } - TypeRef::DynTrait(bounds) => { - w!(self, "dyn "); - self.print_type_bounds(bounds); - } - } + print_type_ref(type_ref, self).unwrap(); } fn print_type_bounds(&mut self, bounds: &[Interned]) { - for (i, bound) in bounds.iter().enumerate() { - if i != 0 { - w!(self, " + "); - } - - match bound.as_ref() { - TypeBound::Path(path, modifier) => { - match modifier { - TraitBoundModifier::None => (), - TraitBoundModifier::Maybe => w!(self, "?"), - } - self.print_path(path) - } - TypeBound::ForLifetime(lifetimes, path) => { - w!(self, "for<{}> ", lifetimes.iter().format(", ")); - self.print_path(path); - } - TypeBound::Lifetime(lt) => w!(self, "{}", lt.name), - TypeBound::Error => w!(self, "{{unknown}}"), - } - } + print_type_bounds(bounds, self).unwrap(); } fn print_path(&mut self, path: &Path) { - match path.type_anchor() { - Some(anchor) => { - w!(self, "<"); - self.print_type_ref(anchor); - w!(self, ">::"); - } - None => match path.kind() { - PathKind::Plain => {} - PathKind::Super(0) => w!(self, "self::"), - PathKind::Super(n) => { - for _ in 0..*n { - w!(self, "super::"); - } - } - PathKind::Crate => w!(self, "crate::"), - PathKind::Abs => w!(self, "::"), - PathKind::DollarCrate(_) => w!(self, "$crate::"), - }, - } - - for (i, segment) in path.segments().iter().enumerate() { - if i != 0 { - w!(self, "::"); - } - - w!(self, "{}", segment.name); - if let Some(generics) = segment.args_and_bindings { - // NB: these are all in type position, so `::<` turbofish syntax is not necessary - w!(self, "<"); - let mut first = true; - let args = if generics.has_self_type { - let (self_ty, args) = generics.args.split_first().unwrap(); - w!(self, "Self="); - self.print_generic_arg(self_ty); - first = false; - args - } else { - &generics.args - }; - for arg in args { - if !first { - w!(self, ", "); - } - first = false; - self.print_generic_arg(arg); - } - for binding in &generics.bindings { - if !first { - w!(self, ", "); - } - first = false; - w!(self, "{}", binding.name); - if !binding.bounds.is_empty() { - w!(self, ": "); - self.print_type_bounds(&binding.bounds); - } - if let Some(ty) = &binding.type_ref { - w!(self, " = "); - self.print_type_ref(ty); - } - } - - w!(self, ">"); - } - } - } - - fn print_generic_arg(&mut self, arg: &GenericArg) { - match arg { - GenericArg::Type(ty) => self.print_type_ref(ty), - GenericArg::Const(c) => w!(self, "{}", c), - GenericArg::Lifetime(lt) => w!(self, "{}", lt.name), - } + print_path(path, self).unwrap(); } fn print_generic_params(&mut self, params: &GenericParams) { diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs index 5cdf36cc61b8..e30d9652bb5d 100644 --- a/crates/hir-def/src/item_tree/tests.rs +++ b/crates/hir-def/src/item_tree/tests.rs @@ -283,10 +283,10 @@ struct S { "#, expect![[r#" pub(self) struct S { - pub(self) a: Mixed<'a, T, Item = (), OtherItem = u8>, - pub(self) b: Qualified::Syntax, - pub(self) c: ::Path<'a>, - pub(self) d: dyn for<'a> Trait<'a>, + pub(self) a: Mixed::<'a, T, Item = (), OtherItem = u8>, + pub(self) b: Qualified::::Syntax, + pub(self) c: ::Path::<'a>, + pub(self) d: dyn for<'a> Trait::<'a>, } "#]], ) @@ -329,7 +329,7 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {} T: Copy, U: ?Sized; - impl<'a, 'b, T, const K: u8> S<'a, 'b, T, K> + impl<'a, 'b, T, const K: u8> S::<'a, 'b, T, K> where T: Copy, T: 'a, @@ -352,7 +352,7 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {} where Self: Super, T: 'a, - Self: for<'a> Tr<'a, T> + Self: for<'a> Tr::<'a, T> { } "#]], diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 56603f4b1545..32ebfda4fd92 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -53,6 +53,7 @@ pub mod import_map; mod test_db; #[cfg(test)] mod macro_expansion_tests; +mod pretty; use std::{ hash::{Hash, Hasher}, diff --git a/crates/hir-def/src/pretty.rs b/crates/hir-def/src/pretty.rs new file mode 100644 index 000000000000..6636c8a23ca5 --- /dev/null +++ b/crates/hir-def/src/pretty.rs @@ -0,0 +1,209 @@ +//! Display and pretty printing routines. + +use std::fmt::{self, Write}; + +use hir_expand::mod_path::PathKind; +use itertools::Itertools; + +use crate::{ + intern::Interned, + path::{GenericArg, GenericArgs, Path}, + type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef}, +}; + +pub(crate) fn print_path(path: &Path, buf: &mut dyn Write) -> fmt::Result { + match path.type_anchor() { + Some(anchor) => { + write!(buf, "<")?; + print_type_ref(anchor, buf)?; + write!(buf, ">::")?; + } + None => match path.kind() { + PathKind::Plain => {} + PathKind::Super(0) => write!(buf, "self")?, + PathKind::Super(n) => { + for i in 0..*n { + if i == 0 { + buf.write_str("super")?; + } else { + buf.write_str("::super")?; + } + } + } + PathKind::Crate => write!(buf, "crate")?, + PathKind::Abs => {} + PathKind::DollarCrate(_) => write!(buf, "$crate")?, + }, + } + + for (i, segment) in path.segments().iter().enumerate() { + if i != 0 || !matches!(path.kind(), PathKind::Plain) { + write!(buf, "::")?; + } + + write!(buf, "{}", segment.name)?; + if let Some(generics) = segment.args_and_bindings { + write!(buf, "::<")?; + print_generic_args(generics, buf)?; + + write!(buf, ">")?; + } + } + + Ok(()) +} + +pub(crate) fn print_generic_args(generics: &GenericArgs, buf: &mut dyn Write) -> fmt::Result { + let mut first = true; + let args = if generics.has_self_type { + let (self_ty, args) = generics.args.split_first().unwrap(); + write!(buf, "Self=")?; + print_generic_arg(self_ty, buf)?; + first = false; + args + } else { + &generics.args + }; + for arg in args { + if !first { + write!(buf, ", ")?; + } + first = false; + print_generic_arg(arg, buf)?; + } + for binding in &generics.bindings { + if !first { + write!(buf, ", ")?; + } + first = false; + write!(buf, "{}", binding.name)?; + if !binding.bounds.is_empty() { + write!(buf, ": ")?; + print_type_bounds(&binding.bounds, buf)?; + } + if let Some(ty) = &binding.type_ref { + write!(buf, " = ")?; + print_type_ref(ty, buf)?; + } + } + Ok(()) +} + +pub(crate) fn print_generic_arg(arg: &GenericArg, buf: &mut dyn Write) -> fmt::Result { + match arg { + GenericArg::Type(ty) => print_type_ref(ty, buf), + GenericArg::Const(c) => write!(buf, "{}", c), + GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name), + } +} + +pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Result { + // FIXME: deduplicate with `HirDisplay` impl + match type_ref { + TypeRef::Never => write!(buf, "!")?, + TypeRef::Placeholder => write!(buf, "_")?, + TypeRef::Tuple(fields) => { + write!(buf, "(")?; + for (i, field) in fields.iter().enumerate() { + if i != 0 { + write!(buf, ", ")?; + } + print_type_ref(field, buf)?; + } + write!(buf, ")")?; + } + TypeRef::Path(path) => print_path(path, buf)?, + TypeRef::RawPtr(pointee, mtbl) => { + let mtbl = match mtbl { + Mutability::Shared => "*const", + Mutability::Mut => "*mut", + }; + write!(buf, "{} ", mtbl)?; + print_type_ref(pointee, buf)?; + } + TypeRef::Reference(pointee, lt, mtbl) => { + let mtbl = match mtbl { + Mutability::Shared => "", + Mutability::Mut => "mut ", + }; + write!(buf, "&")?; + if let Some(lt) = lt { + write!(buf, "{} ", lt.name)?; + } + write!(buf, "{}", mtbl)?; + print_type_ref(pointee, buf)?; + } + TypeRef::Array(elem, len) => { + write!(buf, "[")?; + print_type_ref(elem, buf)?; + write!(buf, "; {}]", len)?; + } + TypeRef::Slice(elem) => { + write!(buf, "[")?; + print_type_ref(elem, buf)?; + write!(buf, "]")?; + } + TypeRef::Fn(args_and_ret, varargs) => { + let ((_, return_type), args) = + args_and_ret.split_last().expect("TypeRef::Fn is missing return type"); + write!(buf, "fn(")?; + for (i, (_, typeref)) in args.iter().enumerate() { + if i != 0 { + write!(buf, ", ")?; + } + print_type_ref(typeref, buf)?; + } + if *varargs { + if !args.is_empty() { + write!(buf, ", ")?; + } + write!(buf, "...")?; + } + write!(buf, ") -> ")?; + print_type_ref(return_type, buf)?; + } + TypeRef::Macro(_ast_id) => { + write!(buf, "")?; + } + TypeRef::Error => write!(buf, "{{unknown}}")?, + TypeRef::ImplTrait(bounds) => { + write!(buf, "impl ")?; + print_type_bounds(bounds, buf)?; + } + TypeRef::DynTrait(bounds) => { + write!(buf, "dyn ")?; + print_type_bounds(bounds, buf)?; + } + } + + Ok(()) +} + +pub(crate) fn print_type_bounds( + bounds: &[Interned], + buf: &mut dyn Write, +) -> fmt::Result { + for (i, bound) in bounds.iter().enumerate() { + if i != 0 { + write!(buf, " + ")?; + } + + match bound.as_ref() { + TypeBound::Path(path, modifier) => { + match modifier { + TraitBoundModifier::None => (), + TraitBoundModifier::Maybe => write!(buf, "?")?, + } + print_path(path, buf)?; + } + TypeBound::ForLifetime(lifetimes, path) => { + write!(buf, "for<{}> ", lifetimes.iter().format(", "))?; + print_path(path, buf)?; + } + TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name)?, + TypeBound::Error => write!(buf, "{{unknown}}")?, + } + } + + Ok(()) +} diff --git a/crates/hir-def/src/type_ref.rs b/crates/hir-def/src/type_ref.rs index 9248059627d2..5b4c71be7fb8 100644 --- a/crates/hir-def/src/type_ref.rs +++ b/crates/hir-def/src/type_ref.rs @@ -77,6 +77,10 @@ impl Rawness { Rawness::Ref } } + + pub fn is_raw(&self) -> bool { + matches!(self, Self::RawPtr) + } } #[derive(Clone, PartialEq, Eq, Hash, Debug)] diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8f984210e117..3561bdeba7f5 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -72,7 +72,7 @@ use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; use once_cell::unsync::Lazy; use rustc_hash::FxHashSet; -use stdx::{format_to, impl_from, never}; +use stdx::{impl_from, never}; use syntax::{ ast::{self, HasAttrs as _, HasDocComments, HasName}, AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T, @@ -1136,6 +1136,20 @@ impl DefWithBody { } } + fn id(&self) -> DefWithBodyId { + match self { + DefWithBody::Function(it) => it.id.into(), + DefWithBody::Static(it) => it.id.into(), + DefWithBody::Const(it) => it.id.into(), + } + } + + /// A textual representation of the HIR of this def's body for debugging purposes. + pub fn debug_hir(self, db: &dyn HirDatabase) -> String { + let body = db.body(self.id()); + body.pretty_print(db.upcast(), self.id()) + } + pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { let krate = self.module(db).id.krate(); @@ -1470,19 +1484,6 @@ impl Function { let def_map = db.crate_def_map(loc.krate(db).into()); def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() }) } - - /// A textual representation of the HIR of this function for debugging purposes. - pub fn debug_hir(self, db: &dyn HirDatabase) -> String { - let body = db.body(self.id.into()); - - let mut result = String::new(); - format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db)); - for (id, expr) in body.exprs.iter() { - format_to!(result, "{:?}: {:?}\n", id, expr); - } - - result - } } // Note: logically, this belongs to `hir_ty`, but we are not using it there yet. diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs index bf0835ed7e0d..d2bbbf6d26ab 100644 --- a/crates/ide/src/view_hir.rs +++ b/crates/ide/src/view_hir.rs @@ -1,4 +1,4 @@ -use hir::{Function, Semantics}; +use hir::{DefWithBody, Semantics}; use ide_db::base_db::FilePosition; use ide_db::RootDatabase; use syntax::{algo::find_node_at_offset, ast, AstNode}; @@ -19,8 +19,12 @@ fn body_hir(db: &RootDatabase, position: FilePosition) -> Option { let sema = Semantics::new(db); let source_file = sema.parse(position.file_id); - let function = find_node_at_offset::(source_file.syntax(), position.offset)?; - - let function: Function = sema.to_def(&function)?; - Some(function.debug_hir(db)) + let item = find_node_at_offset::(source_file.syntax(), position.offset)?; + let def: DefWithBody = match item { + ast::Item::Fn(it) => sema.to_def(&it)?.into(), + ast::Item::Const(it) => sema.to_def(&it)?.into(), + ast::Item::Static(it) => sema.to_def(&it)?.into(), + _ => return None, + }; + Some(def.debug_hir(db)) } diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 1b793bb0b15c..f58de9da1bfe 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -433,7 +433,7 @@ export function syntaxTree(ctx: Ctx): Cmd { // The contents of the file come from the `TextDocumentContentProvider` export function viewHir(ctx: Ctx): Cmd { const tdcp = new (class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse("rust-analyzer-hir://viewHir/hir.txt"); + readonly uri = vscode.Uri.parse("rust-analyzer-hir://viewHir/hir.rs"); readonly eventEmitter = new vscode.EventEmitter(); constructor() { vscode.workspace.onDidChangeTextDocument( From 3f149a63d226cbdedd466d872677da765ada9df8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 15 Aug 2022 16:16:59 +0200 Subject: [PATCH 0132/2442] Simplify --- crates/hir-expand/src/ast_id_map.rs | 21 ++++++++------------- crates/hir-expand/src/db.rs | 6 +++++- crates/hir-expand/src/lib.rs | 1 - crates/ide/src/hover.rs | 2 ++ 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/crates/hir-expand/src/ast_id_map.rs b/crates/hir-expand/src/ast_id_map.rs index c1ddef03ba3b..11c0a6764e9d 100644 --- a/crates/hir-expand/src/ast_id_map.rs +++ b/crates/hir-expand/src/ast_id_map.rs @@ -15,7 +15,7 @@ use std::{ use la_arena::{Arena, Idx}; use profile::Count; use rustc_hash::FxHasher; -use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; +use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; /// `AstId` points to an AST node in a specific file. pub struct FileAstId { @@ -92,18 +92,12 @@ impl AstIdMap { // change parent's id. This means that, say, adding a new function to a // trait does not change ids of top-level items, which helps caching. bdfs(node, |it| { - match_ast! { - match it { - ast::Item(module_item) => { - res.alloc(module_item.syntax()); - true - }, - ast::BlockExpr(block) => { - res.alloc(block.syntax()); - true - }, - _ => false, - } + let kind = it.kind(); + if ast::Item::can_cast(kind) || ast::BlockExpr::can_cast(kind) { + res.alloc(&it); + true + } else { + false } }); res.map = hashbrown::HashMap::with_capacity_and_hasher(res.arena.len(), ()); @@ -123,6 +117,7 @@ impl AstIdMap { let raw = self.erased_ast_id(item.syntax()); FileAstId { raw, _ty: PhantomData } } + fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId { let ptr = SyntaxNodePtr::new(item); let hash = hash_ptr(&ptr); diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index bd60c3d26868..bc97ee15c7d3 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -321,7 +321,11 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet), BuiltIn(BuiltinFnLikeExpander, AstId), - // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander BuiltInAttr(BuiltinAttrExpander, AstId), BuiltInDerive(BuiltinDeriveExpander, AstId), BuiltInEager(EagerExpander, AstId), diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 3ada181f1ed2..fa2c6f09ab4b 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -119,6 +119,8 @@ pub(crate) fn hover( } let in_attr = matches!(original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind()))); + // prefer descending the same token kind in attribute expansions, in normal macros text + // equivalency is more important let descended = if in_attr { [sema.descend_into_macros_with_kind_preference(original_token.clone())].into() } else { From 88b19cc39b14446cc12e02a20c6f489f9883b760 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 15 Aug 2022 16:41:51 +0200 Subject: [PATCH 0133/2442] Make resolve_name_in_module a bit more lazy --- crates/hir-def/src/nameres/path_resolution.rs | 32 +++++++++---------- crates/hir-def/src/per_ns.rs | 12 +++++++ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index cc5fc0a52a1f..32514ffb135e 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -397,14 +397,15 @@ impl DefMap { Some(_) | None => from_scope.or(from_builtin), }, }; - let from_extern_prelude = self - .extern_prelude - .get(name) - .map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public)); - let from_prelude = self.resolve_in_prelude(db, name); + let extern_prelude = || { + self.extern_prelude + .get(name) + .map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public)) + }; + let prelude = || self.resolve_in_prelude(db, name); - from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude) + from_legacy_macro.or(from_scope_or_builtin).or_else(extern_prelude).or_else(prelude) } fn resolve_name_in_crate_root_or_extern_prelude( @@ -412,20 +413,19 @@ impl DefMap { db: &dyn DefDatabase, name: &Name, ) -> PerNs { - let arc; - let crate_def_map = match self.block { + let from_crate_root = match self.block { Some(_) => { - arc = self.crate_root(db).def_map(db); - &arc + let def_map = self.crate_root(db).def_map(db); + def_map[def_map.root].scope.get(name) } - None => self, + None => self[self.root].scope.get(name), + }; + let from_extern_prelude = || { + self.resolve_name_in_extern_prelude(db, name) + .map_or(PerNs::none(), |it| PerNs::types(it.into(), Visibility::Public)) }; - let from_crate_root = crate_def_map[crate_def_map.root].scope.get(name); - let from_extern_prelude = self - .resolve_name_in_extern_prelude(db, name) - .map_or(PerNs::none(), |it| PerNs::types(it.into(), Visibility::Public)); - from_crate_root.or(from_extern_prelude) + from_crate_root.or_else(from_extern_prelude) } fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs { diff --git a/crates/hir-def/src/per_ns.rs b/crates/hir-def/src/per_ns.rs index bf5bf10c4caa..2bc1f8e926e9 100644 --- a/crates/hir-def/src/per_ns.rs +++ b/crates/hir-def/src/per_ns.rs @@ -43,6 +43,10 @@ impl PerNs { self.types.is_none() && self.values.is_none() && self.macros.is_none() } + pub fn is_full(&self) -> bool { + self.types.is_some() && self.values.is_some() && self.macros.is_some() + } + pub fn take_types(self) -> Option { self.types.map(|it| it.0) } @@ -84,6 +88,14 @@ impl PerNs { } } + pub fn or_else(self, f: impl FnOnce() -> PerNs) -> PerNs { + if self.is_full() { + self + } else { + self.or(f()) + } + } + pub fn iter_items(self) -> impl Iterator { let _p = profile::span("PerNs::iter_items"); self.types From 8c60813096fca9ce5b81bdb22894ca1e1240fdb5 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 15 Aug 2022 17:44:52 +0200 Subject: [PATCH 0134/2442] Fix lowering of empty macro expressions in trailing position --- crates/hir-def/src/body/lower.rs | 10 +++++++++- crates/hir-ty/src/tests/regression.rs | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 66f9c24e8724..f6ec8bf7e9e0 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -551,9 +551,17 @@ impl ExprCollector<'_> { } } ast::Expr::MacroStmts(e) => { - let statements = e.statements().filter_map(|s| self.collect_stmt(s)).collect(); + let statements: Box<[_]> = + e.statements().filter_map(|s| self.collect_stmt(s)).collect(); let tail = e.expr().map(|e| self.collect_expr(e)); + if e.syntax().children().next().is_none() { + // HACK: make sure that macros that expand to nothing aren't treated as a `()` + // expression when used in block tail position. + cov_mark::hit!(empty_macro_in_trailing_position_is_removed); + return None; + } + self.alloc_expr(Expr::MacroStmts { tail, statements }, syntax_ptr) } ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr), diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 93a88ab58ef8..1b5ed0603bfd 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -1648,3 +1648,20 @@ fn main() { "#]], ); } + +#[test] +fn trailing_empty_macro() { + cov_mark::check!(empty_macro_in_trailing_position_is_removed); + check_no_mismatches( + r#" +macro_rules! m2 { + ($($t:tt)*) => {$($t)*}; +} + +fn macrostmts() -> u8 { + m2! { 0 } + m2! {} +} + "#, + ); +} From 91358bd937ff0fdace4371f313fa0cda42d3d81c Mon Sep 17 00:00:00 2001 From: yue4u Date: Tue, 16 Aug 2022 01:24:21 +0900 Subject: [PATCH 0135/2442] fix: format literal lookup --- .../ide-completion/src/completions/record.rs | 10 +++++----- crates/ide-completion/src/render.rs | 4 +++- crates/ide-completion/src/render/literal.rs | 16 ++++++++++------ crates/ide-completion/src/render/pattern.rs | 18 ++++++++++++------ .../ide-completion/src/render/union_literal.rs | 9 ++++++--- crates/ide-completion/src/render/variant.rs | 9 +++++++++ crates/ide-completion/src/tests/pattern.rs | 2 +- 7 files changed, 46 insertions(+), 22 deletions(-) diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs index bfb98b9f2777..5d96fbd30a81 100644 --- a/crates/ide-completion/src/completions/record.rs +++ b/crates/ide-completion/src/completions/record.rs @@ -129,7 +129,7 @@ mod tests { #[test] fn literal_struct_completion_edit() { check_edit( - "FooDesc {…}", + "FooDesc{}", r#" struct FooDesc { pub bar: bool } @@ -154,7 +154,7 @@ fn baz() { #[test] fn literal_struct_impl_self_completion() { check_edit( - "Self {…}", + "Self{}", r#" struct Foo { bar: u64, @@ -180,7 +180,7 @@ impl Foo { ); check_edit( - "Self(…)", + "Self()", r#" mod submod { pub struct Foo(pub u64); @@ -209,7 +209,7 @@ impl submod::Foo { #[test] fn literal_struct_completion_from_sub_modules() { check_edit( - "submod::Struct {…}", + "submod::Struct{}", r#" mod submod { pub struct Struct { @@ -238,7 +238,7 @@ fn f() -> submod::Struct { #[test] fn literal_struct_complexion_module() { check_edit( - "FooDesc {…}", + "FooDesc{}", r#" mod _69latrick { pub struct FooDesc { pub six: bool, pub neuf: Vec, pub bar: bool } diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 693007ca3071..a2cf6d68e5b3 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -565,6 +565,7 @@ fn main() { Foo::Fo$0 } kind: SymbolKind( Variant, ), + lookup: "Foo{}", detail: "Foo { x: i32, y: i32 }", }, ] @@ -591,6 +592,7 @@ fn main() { Foo::Fo$0 } kind: SymbolKind( Variant, ), + lookup: "Foo()", detail: "Foo(i32, i32)", }, ] @@ -707,7 +709,7 @@ fn main() { let _: m::Spam = S$0 } kind: SymbolKind( Variant, ), - lookup: "Spam::Bar(…)", + lookup: "Spam::Bar()", detail: "m::Spam::Bar(i32)", relevance: CompletionRelevance { exact_name_match: false, diff --git a/crates/ide-completion/src/render/literal.rs b/crates/ide-completion/src/render/literal.rs index 707dea206be5..af9c88a7e0a6 100644 --- a/crates/ide-completion/src/render/literal.rs +++ b/crates/ide-completion/src/render/literal.rs @@ -10,8 +10,8 @@ use crate::{ render::{ compute_ref_match, compute_type_match, variant::{ - format_literal_label, render_record_lit, render_tuple_lit, visible_fields, - RenderedLiteral, + format_literal_label, format_literal_lookup, render_record_lit, render_tuple_lit, + visible_fields, RenderedLiteral, }, RenderContext, }, @@ -97,13 +97,20 @@ fn render( if !should_add_parens { kind = StructKind::Unit; } + let label = format_literal_label(&qualified_name, kind); + let lookup = if qualified { + format_literal_lookup(&short_qualified_name.to_string(), kind) + } else { + format_literal_lookup(&qualified_name, kind) + }; let mut item = CompletionItem::new( CompletionItemKind::SymbolKind(thing.symbol_kind()), ctx.source_range(), - format_literal_label(&qualified_name, kind), + label, ); + item.lookup_by(lookup); item.detail(rendered.detail); match snippet_cap { @@ -111,9 +118,6 @@ fn render( None => item.insert_text(rendered.literal), }; - if qualified { - item.lookup_by(format_literal_label(&short_qualified_name.to_string(), kind)); - } item.set_documentation(thing.docs(db)).set_deprecated(thing.is_deprecated(&ctx)); let ty = thing.ty(db); diff --git a/crates/ide-completion/src/render/pattern.rs b/crates/ide-completion/src/render/pattern.rs index 1c1299e33b67..c845ff21aaba 100644 --- a/crates/ide-completion/src/render/pattern.rs +++ b/crates/ide-completion/src/render/pattern.rs @@ -8,7 +8,7 @@ use syntax::SmolStr; use crate::{ context::{ParamContext, ParamKind, PathCompletionCtx, PatternContext}, render::{ - variant::{format_literal_label, visible_fields}, + variant::{format_literal_label, format_literal_lookup, visible_fields}, RenderContext, }, CompletionItem, CompletionItemKind, @@ -34,9 +34,10 @@ pub(crate) fn render_struct_pat( let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str()); let kind = strukt.kind(ctx.db()); let label = format_literal_label(name.as_str(), kind); + let lookup = format_literal_lookup(name.as_str(), kind); let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?; - Some(build_completion(ctx, label, pat, strukt)) + Some(build_completion(ctx, label, lookup, pat, strukt)) } pub(crate) fn render_variant_pat( @@ -60,11 +61,14 @@ pub(crate) fn render_variant_pat( } }; - let (label, pat) = match path_ctx { - Some(PathCompletionCtx { has_call_parens: true, .. }) => (name, escaped_name.to_string()), + let (label, lookup, pat) = match path_ctx { + Some(PathCompletionCtx { has_call_parens: true, .. }) => { + (name.clone(), name, escaped_name.to_string()) + } _ => { let kind = variant.kind(ctx.db()); let label = format_literal_label(name.as_str(), kind); + let lookup = format_literal_lookup(name.as_str(), kind); let pat = render_pat( &ctx, pattern_ctx, @@ -73,16 +77,17 @@ pub(crate) fn render_variant_pat( &visible_fields, fields_omitted, )?; - (label, pat) + (label, lookup, pat) } }; - Some(build_completion(ctx, label, pat, variant)) + Some(build_completion(ctx, label, lookup, pat, variant)) } fn build_completion( ctx: RenderContext<'_>, label: SmolStr, + lookup: SmolStr, pat: String, def: impl HasAttrs + Copy, ) -> CompletionItem { @@ -90,6 +95,7 @@ fn build_completion( item.set_documentation(ctx.docs(def)) .set_deprecated(ctx.is_deprecated(def)) .detail(&pat) + .lookup_by(lookup) .set_relevance(ctx.completion_relevance()); match ctx.snippet_cap() { Some(snippet_cap) => item.insert_snippet(snippet_cap, pat), diff --git a/crates/ide-completion/src/render/union_literal.rs b/crates/ide-completion/src/render/union_literal.rs index bb32330f276d..54e97dd57ba8 100644 --- a/crates/ide-completion/src/render/union_literal.rs +++ b/crates/ide-completion/src/render/union_literal.rs @@ -6,7 +6,7 @@ use itertools::Itertools; use crate::{ render::{ - variant::{format_literal_label, visible_fields}, + variant::{format_literal_label, format_literal_lookup, visible_fields}, RenderContext, }, CompletionItem, CompletionItemKind, @@ -24,13 +24,16 @@ pub(crate) fn render_union_literal( Some(p) => (p.unescaped().to_string(), p.to_string()), None => (name.unescaped().to_string(), name.to_string()), }; - + let label = format_literal_label(&name.to_smol_str(), StructKind::Record); + let lookup = format_literal_lookup(&name.to_smol_str(), StructKind::Record); let mut item = CompletionItem::new( CompletionItemKind::SymbolKind(SymbolKind::Union), ctx.source_range(), - format_literal_label(&name.to_smol_str(), StructKind::Record), + label, ); + item.lookup_by(lookup); + let fields = un.fields(ctx.db()); let (fields, fields_omitted) = visible_fields(ctx.completion, &fields, un)?; diff --git a/crates/ide-completion/src/render/variant.rs b/crates/ide-completion/src/render/variant.rs index 664845330eb8..24e6abdc9ad6 100644 --- a/crates/ide-completion/src/render/variant.rs +++ b/crates/ide-completion/src/render/variant.rs @@ -94,3 +94,12 @@ pub(crate) fn format_literal_label(name: &str, kind: StructKind) -> SmolStr { StructKind::Unit => name.into(), } } + +/// Format a struct, etc. literal option for lookup used in completions filtering. +pub(crate) fn format_literal_lookup(name: &str, kind: StructKind) -> SmolStr { + match kind { + StructKind::Tuple => SmolStr::from_iter([name, "()"]), + StructKind::Record => SmolStr::from_iter([name, "{}"]), + StructKind::Unit => name.into(), + } +} diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs index 30ddbe2dc6f6..85c4dbd6625d 100644 --- a/crates/ide-completion/src/tests/pattern.rs +++ b/crates/ide-completion/src/tests/pattern.rs @@ -467,7 +467,7 @@ fn foo() { fn completes_enum_variant_pat() { cov_mark::check!(enum_variant_pattern_path); check_edit( - "RecordVariant {…}", + "RecordVariant{}", r#" enum Enum { RecordVariant { field: u32 } From 14db0809335f51e5f239682d63895866f4ebdb8c Mon Sep 17 00:00:00 2001 From: Aleksandr Pak Date: Tue, 16 Aug 2022 17:06:32 +0300 Subject: [PATCH 0136/2442] feat: add inline_type_alias_uses assist --- .../src/handlers/inline_type_alias.rs | 234 +++++++++++++++--- crates/ide-assists/src/lib.rs | 1 + crates/ide-assists/src/tests/generated.rs | 25 ++ 3 files changed, 227 insertions(+), 33 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_type_alias.rs b/crates/ide-assists/src/handlers/inline_type_alias.rs index 054663a06a11..6b1cf9b90dc2 100644 --- a/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -1,9 +1,9 @@ // Some ideas for future improvements: // - Support replacing aliases which are used in expressions, e.g. `A::new()`. -// - "inline_alias_to_users" assist #10881. // - Remove unused aliases if there are no longer any users, see inline_call.rs. use hir::{HasSource, PathResolution}; +use ide_db::{defs::Definition, search::FileReference}; use itertools::Itertools; use std::collections::HashMap; use syntax::{ @@ -16,6 +16,78 @@ use crate::{ AssistId, AssistKind, }; +// Assist: inline_type_alias_uses +// +// Inline a type alias into all of its uses where possible. +// +// ``` +// type $0A = i32; +// fn id(x: A) -> A { +// x +// }; +// fn foo() { +// let _: A = 3; +// } +// ``` +// -> +// ``` +// type A = i32; +// fn id(x: i32) -> i32 { +// x +// }; +// fn foo() { +// let _: i32 = 3; +// } +pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let name = ctx.find_node_at_offset::()?; + let ast_alias = name.syntax().parent().and_then(ast::TypeAlias::cast)?; + + let hir_alias = ctx.sema.to_def(&ast_alias)?; + let concrete_type = ast_alias.ty()?; + + let usages = Definition::TypeAlias(hir_alias).usages(&ctx.sema); + if !usages.at_least_one() { + return None; + } + + // until this is ok + + acc.add( + AssistId("inline_type_alias_uses", AssistKind::RefactorInline), + "Inline type alias into all uses", + name.syntax().text_range(), + |builder| { + let usages = usages.all(); + + let mut inline_refs_for_file = |file_id, refs: Vec| { + builder.edit_file(file_id); + + let path_types: Vec = refs + .into_iter() + .filter_map(|file_ref| match file_ref.name { + ast::NameLike::NameRef(path_type) => { + path_type.syntax().ancestors().find_map(ast::PathType::cast) + } + _ => None, + }) + .collect(); + + for (target, replacement) in path_types.into_iter().filter_map(|path_type| { + let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type); + let target = path_type.syntax().text_range(); + Some((target, replacement)) + }) { + builder.replace(target, replacement); + } + }; + + for (file_id, refs) in usages.into_iter() { + inline_refs_for_file(file_id, refs); + } + }, + ) +} + // Assist: inline_type_alias // // Replace a type alias with its concrete type. @@ -36,11 +108,6 @@ use crate::{ // } // ``` pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - enum Replacement { - Generic { lifetime_map: LifetimeMap, const_and_type_map: ConstAndTypeMap }, - Plain, - } - let alias_instance = ctx.find_node_at_offset::()?; let concrete_type; let replacement; @@ -59,23 +126,7 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> O _ => { let alias = get_type_alias(&ctx, &alias_instance)?; concrete_type = alias.ty()?; - - replacement = if let Some(alias_generics) = alias.generic_param_list() { - if alias_generics.generic_params().next().is_none() { - cov_mark::hit!(no_generics_params); - return None; - } - - let instance_args = - alias_instance.syntax().descendants().find_map(ast::GenericArgList::cast); - - Replacement::Generic { - lifetime_map: LifetimeMap::new(&instance_args, &alias_generics)?, - const_and_type_map: ConstAndTypeMap::new(&instance_args, &alias_generics)?, - } - } else { - Replacement::Plain - }; + replacement = inline(&alias, &alias_instance)?; } } @@ -85,19 +136,45 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> O AssistId("inline_type_alias", AssistKind::RefactorInline), "Inline type alias", target, - |builder| { - let replacement_text = match replacement { - Replacement::Generic { lifetime_map, const_and_type_map } => { - create_replacement(&lifetime_map, &const_and_type_map, &concrete_type) - } - Replacement::Plain => concrete_type.to_string(), - }; - - builder.replace(target, replacement_text); - }, + |builder| builder.replace(target, replacement.to_text(&concrete_type)), ) } +impl Replacement { + fn to_text(&self, concrete_type: &ast::Type) -> String { + match self { + Replacement::Generic { lifetime_map, const_and_type_map } => { + create_replacement(&lifetime_map, &const_and_type_map, &concrete_type) + } + Replacement::Plain => concrete_type.to_string(), + } + } +} + +enum Replacement { + Generic { lifetime_map: LifetimeMap, const_and_type_map: ConstAndTypeMap }, + Plain, +} + +fn inline(alias_def: &ast::TypeAlias, alias_instance: &ast::PathType) -> Option { + let repl = if let Some(alias_generics) = alias_def.generic_param_list() { + if alias_generics.generic_params().next().is_none() { + cov_mark::hit!(no_generics_params); + return None; + } + let instance_args = + alias_instance.syntax().descendants().find_map(ast::GenericArgList::cast); + + Replacement::Generic { + lifetime_map: LifetimeMap::new(&instance_args, &alias_generics)?, + const_and_type_map: ConstAndTypeMap::new(&instance_args, &alias_generics)?, + } + } else { + Replacement::Plain + }; + Some(repl) +} + struct LifetimeMap(HashMap); impl LifetimeMap { @@ -835,4 +912,95 @@ trait Tr { "#, ); } + + mod inline_type_alias_uses { + use crate::{handlers::inline_type_alias::inline_type_alias_uses, tests::check_assist}; + + #[test] + fn inline_uses() { + check_assist( + inline_type_alias_uses, + r#" +type $0A = u32; + +fn foo() { + let _: A = 3; + let _: A = 4; +} +"#, + r#" +type A = u32; + +fn foo() { + let _: u32 = 3; + let _: u32 = 4; +} +"#, + ); + } + + #[test] + fn inline_uses_across_files() { + check_assist( + inline_type_alias_uses, + r#" +//- /lib.rs +mod foo; +type $0T = Vec; +fn f() -> T<&str> { + vec!["hello"] +} + +//- /foo.rs +use super::T; +fn foo() { + let _: T = Vec::new(); +} +"#, + r#" +//- /lib.rs +mod foo; +type T = Vec; +fn f() -> Vec<&str> { + vec!["hello"] +} + +//- /foo.rs +use super::T; +fn foo() { + let _: Vec = Vec::new(); +} +"#, + ); + } + + #[test] + fn inline_uses_across_files_fails() { + check_assist( + inline_type_alias_uses, + r#" +//- /lib.rs +mod foo; +type $0I = i32; + +//- /foo.rs +use super::I; +fn foo() { + let _: I = 0; +} +"#, + r#" +//- /lib.rs +mod foo; +type I = i32; + +//- /foo.rs +use super::I; +fn foo() { + let _: i32 = 0; +} +"#, + ); + } + } } diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index fe87aa15fcf2..7fb35143fa2f 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -243,6 +243,7 @@ mod handlers { inline_call::inline_into_callers, inline_local_variable::inline_local_variable, inline_type_alias::inline_type_alias, + inline_type_alias::inline_type_alias_uses, introduce_named_generic::introduce_named_generic, introduce_named_lifetime::introduce_named_lifetime, invert_if::invert_if, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 6eaab48a32ba..22319f36134f 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1356,6 +1356,31 @@ fn main() { ) } +#[test] +fn doctest_inline_type_alias_uses() { + check_doc_test( + "inline_type_alias_uses", + r#####" +type $0A = i32; +fn id(x: A) -> A { + x +}; +fn foo() { + let _: A = 3; +} +"#####, + r#####" +type A = i32; +fn id(x: i32) -> i32 { + x +}; +fn foo() { + let _: i32 = 3; +} +"#####, + ) +} + #[test] fn doctest_introduce_named_generic() { check_doc_test( From 0616cee92b47b539a802171f7e6817663175502d Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 16 Aug 2022 16:51:40 +0200 Subject: [PATCH 0137/2442] Add a setting for keyword hover popups --- crates/ide/src/hover.rs | 1 + crates/ide/src/hover/render.rs | 2 +- crates/ide/src/hover/tests.rs | 42 +++++++++++++++++++++++++----- crates/ide/src/static_index.rs | 7 +++-- crates/rust-analyzer/src/config.rs | 4 +++ docs/user/generated_config.adoc | 6 +++++ editors/code/package.json | 5 ++++ 7 files changed, 57 insertions(+), 10 deletions(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index fa2c6f09ab4b..3687b597fc64 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -27,6 +27,7 @@ use crate::{ pub struct HoverConfig { pub links_in_hover: bool, pub documentation: Option, + pub keywords: bool, } impl HoverConfig { diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 6c50a4e6adc0..d52adaee535f 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -230,7 +230,7 @@ pub(super) fn keyword( config: &HoverConfig, token: &SyntaxToken, ) -> Option { - if !token.kind().is_keyword() || !config.documentation.is_some() { + if !token.kind().is_keyword() || !config.documentation.is_some() || !config.keywords { return None; } let parent = token.parent()?; diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index c6274264b8f1..685eb4521ebd 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -8,7 +8,11 @@ fn check_hover_no_result(ra_fixture: &str) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) }, + &HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap(); @@ -20,7 +24,11 @@ fn check(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) }, + &HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() @@ -37,7 +45,11 @@ fn check_hover_no_links(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: false, documentation: Some(HoverDocFormat::Markdown) }, + &HoverConfig { + links_in_hover: false, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() @@ -54,7 +66,11 @@ fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::PlainText) }, + &HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::PlainText), + keywords: true, + }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() @@ -71,7 +87,11 @@ fn check_actions(ra_fixture: &str, expect: Expect) { let (analysis, file_id, position) = fixture::range_or_position(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) }, + &HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }, FileRange { file_id, range: position.range_or_empty() }, ) .unwrap() @@ -83,7 +103,11 @@ fn check_hover_range(ra_fixture: &str, expect: Expect) { let (analysis, range) = fixture::range(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: false, documentation: Some(HoverDocFormat::Markdown) }, + &HoverConfig { + links_in_hover: false, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }, range, ) .unwrap() @@ -95,7 +119,11 @@ fn check_hover_range_no_results(ra_fixture: &str) { let (analysis, range) = fixture::range(ra_fixture); let hover = analysis .hover( - &HoverConfig { links_in_hover: false, documentation: Some(HoverDocFormat::Markdown) }, + &HoverConfig { + links_in_hover: false, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }, range, ) .unwrap(); diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index cc79ee55b7da..9e5eb909508f 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -130,8 +130,11 @@ impl StaticIndex<'_> { syntax::NodeOrToken::Node(_) => None, syntax::NodeOrToken::Token(x) => Some(x), }); - let hover_config = - HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) }; + let hover_config = HoverConfig { + links_in_hover: true, + documentation: Some(HoverDocFormat::Markdown), + keywords: true, + }; let tokens = tokens.filter(|token| { matches!( token.kind(), diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 1629c1dd328a..f2fae586024a 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -244,6 +244,9 @@ config_data! { /// Whether to show documentation on hover. hover_documentation_enable: bool = "true", + /// Whether to show keyword hover popups. Only applies when + /// `#rust-analyzer.hover.documentation.enable#` is set. + hover_documentation_keywords: bool = "true", /// Use markdown syntax for links in hover. hover_links_enable: bool = "true", @@ -1187,6 +1190,7 @@ impl Config { HoverDocFormat::PlainText } }), + keywords: self.data.hover_documentation_keywords, } } diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index b0f2f1614dbf..00a6e3c43c5c 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -318,6 +318,12 @@ Whether to show `Run` action. Only applies when -- Whether to show documentation on hover. -- +[[rust-analyzer.hover.documentation.keywords]]rust-analyzer.hover.documentation.keywords (default: `true`):: ++ +-- +Whether to show keyword hover popups. Only applies when +`#rust-analyzer.hover.documentation.enable#` is set. +-- [[rust-analyzer.hover.links.enable]]rust-analyzer.hover.links.enable (default: `true`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index fbdc69c80137..6352e9681107 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -756,6 +756,11 @@ "default": true, "type": "boolean" }, + "rust-analyzer.hover.documentation.keywords": { + "markdownDescription": "Whether to show keyword hover popups. Only applies when\n`#rust-analyzer.hover.documentation.enable#` is set.", + "default": true, + "type": "boolean" + }, "rust-analyzer.hover.links.enable": { "markdownDescription": "Use markdown syntax for links in hover.", "default": true, From 6d6356b103225522166496975f98b15d9827b6c8 Mon Sep 17 00:00:00 2001 From: Aleksandr Pak Date: Tue, 16 Aug 2022 18:29:22 +0300 Subject: [PATCH 0138/2442] fixup! feat: add inline_type_alias_uses assist --- crates/ide-assists/src/handlers/inline_type_alias.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_type_alias.rs b/crates/ide-assists/src/handlers/inline_type_alias.rs index 6b1cf9b90dc2..c4e5bc9c7cbc 100644 --- a/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -975,7 +975,7 @@ fn foo() { } #[test] - fn inline_uses_across_files_fails() { + fn inline_uses_across_files_2() { check_assist( inline_type_alias_uses, r#" @@ -990,11 +990,6 @@ fn foo() { } "#, r#" -//- /lib.rs -mod foo; -type I = i32; - -//- /foo.rs use super::I; fn foo() { let _: i32 = 0; From ad7a1ed8cc9ba44c6a294317a2289a0b6fd75219 Mon Sep 17 00:00:00 2001 From: Dominik Gschwind Date: Tue, 16 Aug 2022 17:30:17 +0200 Subject: [PATCH 0139/2442] fix: Fix panics on GATs involving const generics This workaround avoids constant crashing of rust analyzer when using GATs with const generics, even when the const generics are only on the `impl` block. The workaround treats GATs as non-existing if either itself or the parent has const generics and removes relevant panicking code-paths. --- crates/hir-ty/src/lower.rs | 9 ++++++++- crates/hir-ty/src/tests/regression.rs | 21 +++++++++++++++++++++ crates/hir-ty/src/utils.rs | 18 ++++++++++-------- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 239f66bcb7e7..3ec321ad3714 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -509,7 +509,14 @@ impl<'a> TyLoweringContext<'a> { TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into())) } ParamLoweringMode::Variable => { - let idx = generics.param_idx(param_id.into()).expect("matching generics"); + let idx = match generics.param_idx(param_id.into()) { + None => { + never!("no matching generics"); + return (TyKind::Error.intern(Interner), None); + } + Some(idx) => idx, + }; + TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) } } diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 93a88ab58ef8..9b64fccccd24 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -1526,6 +1526,27 @@ unsafe impl Storage for InlineStorage { ); } +#[test] +fn gat_crash_3() { + cov_mark::check!(ignore_gats); + check_no_mismatches( + r#" +trait Collection { + type Item; + type Member: Collection; + fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>; +} +struct ConstGen { + data: [T; N], +} +impl Collection for ConstGen { + type Item = T; + type Member = ConstGen; +} + "#, + ); +} + #[test] fn cfgd_out_self_param() { cov_mark::check!(cfgd_out_self_param); diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 83319755da73..bdb9ade9c856 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -176,10 +176,16 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) { let params = db.generic_params(def); + let parent_params = &parent_generics.as_ref().unwrap().params; let has_consts = params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_))); - return if has_consts { - // XXX: treat const generic associated types as not existing to avoid crashes (#11769) + let parent_has_consts = + parent_params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_))); + return if has_consts || parent_has_consts { + // XXX: treat const generic associated types as not existing to avoid crashes + // (#11769, #12193) + // Note: also crashes when the parent has const generics (also even if the GAT + // doesn't use them), see `tests::regression::gat_crash_3` for an example. // // Chalk expects the inner associated type's parameters to come // *before*, not after the trait's generics as we've always done it. @@ -264,12 +270,8 @@ impl Generics { fn find_param(&self, param: TypeOrConstParamId) -> Option<(usize, &TypeOrConstParamData)> { if param.parent == self.def { - let (idx, (_local_id, data)) = self - .params - .iter() - .enumerate() - .find(|(_, (idx, _))| *idx == param.local_id) - .unwrap(); + let (idx, (_local_id, data)) = + self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?; let parent_len = self.parent_generics().map_or(0, Generics::len); Some((parent_len + idx, data)) } else { From 7fb7c248c7b37699da7eb5944f45a9b59121b827 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 16 Aug 2022 18:12:15 +0200 Subject: [PATCH 0140/2442] Add `.enable` suffix --- crates/rust-analyzer/src/config.rs | 6 +++--- docs/user/generated_config.adoc | 2 +- editors/code/package.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index f2fae586024a..e63cfb163caa 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -243,10 +243,10 @@ config_data! { hover_actions_run_enable: bool = "true", /// Whether to show documentation on hover. - hover_documentation_enable: bool = "true", + hover_documentation_enable: bool = "true", /// Whether to show keyword hover popups. Only applies when /// `#rust-analyzer.hover.documentation.enable#` is set. - hover_documentation_keywords: bool = "true", + hover_documentation_keywords_enable: bool = "true", /// Use markdown syntax for links in hover. hover_links_enable: bool = "true", @@ -1190,7 +1190,7 @@ impl Config { HoverDocFormat::PlainText } }), - keywords: self.data.hover_documentation_keywords, + keywords: self.data.hover_documentation_keywords_enable, } } diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 00a6e3c43c5c..e3dbeec1fbd2 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -318,7 +318,7 @@ Whether to show `Run` action. Only applies when -- Whether to show documentation on hover. -- -[[rust-analyzer.hover.documentation.keywords]]rust-analyzer.hover.documentation.keywords (default: `true`):: +[[rust-analyzer.hover.documentation.keywords.enable]]rust-analyzer.hover.documentation.keywords.enable (default: `true`):: + -- Whether to show keyword hover popups. Only applies when diff --git a/editors/code/package.json b/editors/code/package.json index 6352e9681107..0714b356fe03 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -756,7 +756,7 @@ "default": true, "type": "boolean" }, - "rust-analyzer.hover.documentation.keywords": { + "rust-analyzer.hover.documentation.keywords.enable": { "markdownDescription": "Whether to show keyword hover popups. Only applies when\n`#rust-analyzer.hover.documentation.enable#` is set.", "default": true, "type": "boolean" From 1f73cbe8390d4a8ebe4e4039891567d8358c2c70 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 16 Aug 2022 19:13:10 +0200 Subject: [PATCH 0141/2442] Revert #12947, trigger workspace switches on all structure changes again --- crates/rust-analyzer/src/global_state.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index b5f6aef2e1a8..c55bbbbe6ef7 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -8,7 +8,7 @@ use std::{sync::Arc, time::Instant}; use crossbeam_channel::{unbounded, Receiver, Sender}; use flycheck::FlycheckHandle; use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId}; -use ide_db::base_db::{CrateId, FileLoader, SourceDatabase, SourceDatabaseExt}; +use ide_db::base_db::{CrateId, FileLoader, SourceDatabase}; use lsp_types::{SemanticTokens, Url}; use parking_lot::{Mutex, RwLock}; use proc_macro_api::ProcMacroServer; @@ -176,9 +176,9 @@ impl GlobalState { pub(crate) fn process_changes(&mut self) -> bool { let _p = profile::span("GlobalState::process_changes"); - let mut fs_refresh_changes = Vec::new(); // A file was added or deleted let mut has_structure_changes = false; + let mut workspace_structure_change = None; let (change, changed_files) = { let mut change = Change::new(); @@ -192,7 +192,7 @@ impl GlobalState { if let Some(path) = vfs.file_path(file.file_id).as_path() { let path = path.to_path_buf(); if reload::should_refresh_for_change(&path, file.change_kind) { - fs_refresh_changes.push((path, file.file_id)); + workspace_structure_change = Some(path); } if file.is_created_or_deleted() { has_structure_changes = true; @@ -227,11 +227,10 @@ impl GlobalState { { let raw_database = self.analysis_host.raw_database(); - let workspace_structure_change = - fs_refresh_changes.into_iter().find(|&(_, file_id)| { - !raw_database.source_root(raw_database.file_source_root(file_id)).is_library - }); - if let Some((path, _)) = workspace_structure_change { + // FIXME: ideally we should only trigger a workspace fetch for non-library changes + // but somethings going wrong with the source root business when we add a new local + // crate see https://github.com/rust-lang/rust-analyzer/issues/13029 + if let Some(path) = workspace_structure_change { self.fetch_workspaces_queue .request_op(format!("workspace vfs file change: {}", path.display())); } From a0b257c9d91d00c054376facc6681f563f1a5e1b Mon Sep 17 00:00:00 2001 From: David Barsky Date: Tue, 16 Aug 2022 13:38:50 -0400 Subject: [PATCH 0142/2442] chore: remove unused `currentExtensionIsNightly()` in config.ts --- editors/code/src/config.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 1c58040d58c2..b83582a344a9 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -5,8 +5,6 @@ import { log } from "./util"; export type UpdatesChannel = "stable" | "nightly"; -const NIGHTLY_TAG = "nightly"; - export type RunnableEnvCfg = | undefined | Record @@ -175,10 +173,6 @@ export class Config { gotoTypeDef: this.get("hover.actions.gotoTypeDef.enable"), }; } - - get currentExtensionIsNightly() { - return this.package.releaseTag === NIGHTLY_TAG; - } } export async function updateConfig(config: vscode.WorkspaceConfiguration) { From 39d17efde7d2da436f349c1b0ca55c37bae0254f Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Sat, 13 Aug 2022 13:29:41 -0500 Subject: [PATCH 0143/2442] feat: Generate static method using Self::assoc() syntax This change improves the `generate_function` assist to support generating static methods/associated functions using the `Self::assoc()` syntax. Previously, one could generate a static method, but only when specifying the type name directly (like `Foo::assoc()`). After this change, `Self` is supported as well as the type name. Fixes #13012 --- .../src/handlers/generate_function.rs | 64 +++++++++++++++---- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index d564a0540898..49345cb983fd 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -61,7 +61,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { } let fn_name = &*name_ref.text(); - let target_module; + let mut target_module = None; let mut adt_name = None; let (target, file, insert_offset) = match path.qualifier() { @@ -78,16 +78,11 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { } } - let current_module = ctx.sema.scope(call.syntax())?.module(); - let module = adt.module(ctx.sema.db); - target_module = if current_module == module { None } else { Some(module) }; - if current_module.krate() != module.krate() { - return None; - } - let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?; - let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?; - adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None }; - (target, file, insert_offset) + static_method_target(ctx, &call, adt, &mut target_module, fn_name, &mut adt_name)? + } + Some(hir::PathResolution::SelfType(impl_)) => { + let adt = impl_.self_ty(ctx.db()).as_adt()?; + static_method_target(ctx, &call, adt, &mut target_module, fn_name, &mut adt_name)? } _ => { return None; @@ -399,6 +394,26 @@ fn get_method_target( Some((target.clone(), get_insert_offset(&target))) } +fn static_method_target( + ctx: &AssistContext<'_>, + call: &CallExpr, + adt: hir::Adt, + target_module: &mut Option, + fn_name: &str, + adt_name: &mut Option, +) -> Option<(GeneratedFunctionTarget, FileId, TextSize)> { + let current_module = ctx.sema.scope(call.syntax())?.module(); + let module = adt.module(ctx.sema.db); + *target_module = if current_module == module { None } else { Some(module) }; + if current_module.krate() != module.krate() { + return None; + } + let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?; + let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?; + *adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None }; + Some((target, file, insert_offset)) +} + fn get_insert_offset(target: &GeneratedFunctionTarget) -> TextSize { match &target { GeneratedFunctionTarget::BehindItem(it) => it.text_range().end(), @@ -1633,6 +1648,33 @@ fn bar() ${0:-> _} { ) } + #[test] + fn create_static_method_within_an_impl_with_self_syntax() { + check_assist( + generate_function, + r" +struct S; +impl S { + fn foo(&self) { + Self::bar$0(); + } +} +", + r" +struct S; +impl S { + fn foo(&self) { + Self::bar(); + } + + fn bar() ${0:-> _} { + todo!() + } +} +", + ) + } + #[test] fn no_panic_on_invalid_global_path() { check_assist( From cebf95718c32b1024a6845992bee96c50f830f3a Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Tue, 16 Aug 2022 17:53:10 -0400 Subject: [PATCH 0144/2442] Find IntoFuture::IntoFuture's poll method --- crates/hir/src/lib.rs | 5 +-- crates/hir/src/source_analyzer.rs | 34 ++++++++++++++++---- crates/ide-completion/src/completions/dot.rs | 2 +- crates/ide/src/goto_definition.rs | 34 ++++++++++++++++++++ 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 7f16634afe1a..46d24b9f1463 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2777,9 +2777,10 @@ impl Type { self.ty.is_unknown() } - /// Checks that particular type `ty` implements `std::future::Future`. + /// Checks that particular type `ty` implements `std::future::IntoFuture` or + /// `std::future::Future`. /// This function is used in `.await` syntax completion. - pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { + pub fn impls_into_future(&self, db: &dyn HirDatabase) -> bool { let trait_ = db .lang_item(self.env.krate, SmolStr::new_inline("into_future")) .and_then(|it| { diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 756772cf84e5..9418afa91dae 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -27,6 +27,7 @@ use hir_def::{ use hir_expand::{ builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, + mod_path::path, name, name::{AsName, Name}, HirFileId, InFile, @@ -269,16 +270,35 @@ impl SourceAnalyzer { db: &dyn HirDatabase, await_expr: &ast::AwaitExpr, ) -> Option { - // FIXME This should be pointing to the poll of IntoFuture::Output's Future impl, but I - // don't know how to resolve the Output type so that we can query for its poll method. - let ty = self.ty_of_expr(db, &await_expr.expr()?.into())?; + let mut ty = self.ty_of_expr(db, &await_expr.expr()?.into())?.clone(); - let op_fn = db + let into_future_trait = self + .resolver + .resolve_known_trait(db.upcast(), &path![core::future::IntoFuture]) + .map(Trait::from); + + if let Some(into_future_trait) = into_future_trait { + let type_ = Type::new_with_resolver(db, &self.resolver, ty.clone()); + if type_.impls_trait(db, into_future_trait, &[]) { + let items = into_future_trait.items(db); + let into_future_type = items.into_iter().find_map(|item| match item { + AssocItem::TypeAlias(alias) + if alias.name(db) == hir_expand::name![IntoFuture] => + { + Some(alias) + } + _ => None, + })?; + let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?; + ty = future_trait.ty; + } + } + + let poll_fn = db .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())? .as_function()?; - let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build(); - - Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build(); + Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs)) } pub(crate) fn resolve_prefix_expr( diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs index cf40ca489c00..02004ff7b686 100644 --- a/crates/ide-completion/src/completions/dot.rs +++ b/crates/ide-completion/src/completions/dot.rs @@ -19,7 +19,7 @@ pub(crate) fn complete_dot( }; // Suggest .await syntax for types that implement Future trait - if receiver_ty.impls_future(ctx.db) { + if receiver_ty.impls_into_future(ctx.db) { let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await"); item.detail("expr.await"); diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index b2123b9a8793..c7a922e6cc6a 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -1664,6 +1664,40 @@ fn f() { ); } + #[test] + fn goto_await_into_future_poll() { + check( + r#" +//- minicore: future + +struct Futurable; + +impl core::future::IntoFuture for Futurable { + type IntoFuture = MyFut; +} + +struct MyFut; + +impl core::future::Future for MyFut { + type Output = (); + + fn poll( + //^^^^ + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_> + ) -> std::task::Poll + { + () + } +} + +fn f() { + Futurable.await$0; +} +"#, + ); + } + #[test] fn goto_try_op() { check( From 557c5b4dc57cb0fd5455bec35f2a97a4626e3df1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 17 Aug 2022 09:32:25 +0200 Subject: [PATCH 0145/2442] minor: Change tracing event level in apply_change --- crates/ide-db/src/apply_change.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs index f8134c552f75..b1ee9b58d5ba 100644 --- a/crates/ide-db/src/apply_change.rs +++ b/crates/ide-db/src/apply_change.rs @@ -20,7 +20,7 @@ impl RootDatabase { pub fn apply_change(&mut self, change: Change) { let _p = profile::span("RootDatabase::apply_change"); self.request_cancellation(); - tracing::info!("apply_change {:?}", change); + tracing::trace!("apply_change {:?}", change); if let Some(roots) = &change.roots { let mut local_roots = FxHashSet::default(); let mut library_roots = FxHashSet::default(); From a3409c3a83fb1d8139bac8b3e438f56f2ac633a3 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Tue, 16 Aug 2022 10:08:45 +0900 Subject: [PATCH 0146/2442] fix: escape keywords used as names in earlier editions --- crates/hir-expand/src/name.rs | 10 ++++++++-- crates/ide-db/src/search.rs | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 87c663eec8e8..a1bb353374be 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -90,10 +90,16 @@ impl Name { /// Resolve a name from the text of token. fn resolve(raw_text: &str) -> Name { - // When `raw_text` starts with "r#" but the name does not coincide with any - // keyword, we never need the prefix so we strip it. match raw_text.strip_prefix("r#") { + // When `raw_text` starts with "r#" but the name does not coincide with any + // keyword, we never need the prefix so we strip it. Some(text) if !is_raw_identifier(text) => Name::new_text(SmolStr::new(text)), + // Keywords (in the current edition) *can* be used as a name in earlier editions of + // Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their + // escaped form. + None if is_raw_identifier(raw_text) => { + Name::new_text(SmolStr::from_iter(["r#", raw_text])) + } _ => Name::new_text(raw_text.into()), } } diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 9eaabeec7a4e..2f4aa113170a 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -402,7 +402,9 @@ impl<'a> FindUsages<'a> { .or_else(|| ty.as_builtin().map(|builtin| builtin.name())) }) }; - self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.to_smol_str()) + // We need to unescape the name in case it is written without "r#" in earlier + // editions of Rust where it isn't a keyword. + self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.unescaped().to_smol_str()) } }; let name = match &name { From 313b004ef76d3352f36e5128b16ca5212de97d49 Mon Sep 17 00:00:00 2001 From: Aleksandr Pak Date: Wed, 17 Aug 2022 12:50:33 +0300 Subject: [PATCH 0147/2442] fixup! feat: add inline_type_alias_uses assist --- crates/ide-assists/src/handlers/inline_type_alias.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/inline_type_alias.rs b/crates/ide-assists/src/handlers/inline_type_alias.rs index c4e5bc9c7cbc..9adf6381c1cb 100644 --- a/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -66,7 +66,7 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) .into_iter() .filter_map(|file_ref| match file_ref.name { ast::NameLike::NameRef(path_type) => { - path_type.syntax().ancestors().find_map(ast::PathType::cast) + path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast) } _ => None, }) From 23747419ca52414d3ecf6f69f1e530e47ab1e937 Mon Sep 17 00:00:00 2001 From: Dezhi Wu Date: Wed, 17 Aug 2022 21:44:58 +0800 Subject: [PATCH 0148/2442] fix: a bunch of typos This PR will fix some typos detected by [typos]. There are also some other typos in the function names, variable names, and file names, which I leave as they are. I'm more certain that typos in comments should be fixed. [typos]: https://github.com/crate-ci/typos --- crates/flycheck/src/lib.rs | 2 +- crates/hir-def/src/nameres/proc_macro.rs | 2 +- crates/hir-expand/src/lib.rs | 2 +- crates/ide-assists/src/handlers/extract_module.rs | 6 +++--- .../src/handlers/replace_turbofish_with_explicit_type.rs | 2 +- crates/ide-assists/src/utils/suggest_name.rs | 4 ++-- .../ide-completion/src/completions/postfix/format_like.rs | 4 ++-- crates/ide-completion/src/tests/flyimport.rs | 2 +- crates/ide-db/src/rename.rs | 2 +- crates/ide-diagnostics/src/handlers/missing_match_arms.rs | 2 +- crates/mbe/src/expander/matcher.rs | 2 +- crates/project-model/src/lib.rs | 2 +- crates/project-model/src/workspace.rs | 2 +- crates/rust-analyzer/src/bin/logger.rs | 2 +- crates/syntax/src/hacks.rs | 2 +- crates/vfs/src/lib.rs | 2 +- docs/dev/architecture.md | 2 +- editors/code/src/commands.ts | 2 +- editors/code/src/toolchain.ts | 2 +- 19 files changed, 23 insertions(+), 23 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 3347940ec6d6..2bebea2fbfef 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -345,7 +345,7 @@ impl CargoActor { // // Because cargo only outputs one JSON object per line, we can // simply skip a line if it doesn't parse, which just ignores any - // erroneus output. + // erroneous output. let mut error = String::new(); let mut read_at_least_one_message = false; diff --git a/crates/hir-def/src/nameres/proc_macro.rs b/crates/hir-def/src/nameres/proc_macro.rs index 5089ef2d8171..52b79cd0fdda 100644 --- a/crates/hir-def/src/nameres/proc_macro.rs +++ b/crates/hir-def/src/nameres/proc_macro.rs @@ -45,7 +45,7 @@ impl Attrs { kind: ProcMacroKind::CustomDerive { helpers: Box::new([]) }, }), - // `#[proc_macro_derive(Trait, attibutes(helper1, helper2, ...))]` + // `#[proc_macro_derive(Trait, attributes(helper1, helper2, ...))]` [ TokenTree::Leaf(Leaf::Ident(trait_name)), TokenTree::Leaf(Leaf::Punct(comma)), diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index f6b97fd5405a..d753d88470c4 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -616,7 +616,7 @@ impl ExpansionInfo { let token_id = match token_id_in_attr_input { Some(token_id) => token_id, - // the token is not inside an attribute's input so do the lookup in the macro_arg as ususal + // the token is not inside an attribute's input so do the lookup in the macro_arg as usual None => { let relative_range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?; diff --git a/crates/ide-assists/src/handlers/extract_module.rs b/crates/ide-assists/src/handlers/extract_module.rs index b3c4d306ac1c..897980c66504 100644 --- a/crates/ide-assists/src/handlers/extract_module.rs +++ b/crates/ide-assists/src/handlers/extract_module.rs @@ -29,7 +29,7 @@ use super::remove_unused_param::range_to_remove; // Assist: extract_module // -// Extracts a selected region as seperate module. All the references, visibility and imports are +// Extracts a selected region as separate module. All the references, visibility and imports are // resolved. // // ``` @@ -105,7 +105,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti // //- Thirdly, resolving all the imports this includes removing paths from imports // outside the module, shifting/cloning them inside new module, or shifting the imports, or making - // new import statemnts + // new import statements //We are getting item usages and record_fields together, record_fields //for change_visibility and usages for first point mentioned above in the process @@ -661,7 +661,7 @@ fn check_intersection_and_push( import_path: TextRange, ) { if import_paths_to_be_removed.len() > 0 { - // Text ranges recieved here for imports are extended to the + // Text ranges received here for imports are extended to the // next/previous comma which can cause intersections among them // and later deletion of these can cause panics similar // to reported in #11766. So to mitigate it, we diff --git a/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs b/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs index 6112e09455a4..5242f3b5100c 100644 --- a/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs +++ b/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs @@ -88,7 +88,7 @@ pub(crate) fn replace_turbofish_with_explicit_type( }, ); } else if let Some(InferType(t)) = let_stmt.ty() { - // If there's a type inferrence underscore, we can offer to replace it with the type in + // If there's a type inference underscore, we can offer to replace it with the type in // the turbofish. // let x: _ = fn::<...>(); let underscore_range = t.syntax().text_range(); diff --git a/crates/ide-assists/src/utils/suggest_name.rs b/crates/ide-assists/src/utils/suggest_name.rs index 779cdbc93c54..662ddd063f32 100644 --- a/crates/ide-assists/src/utils/suggest_name.rs +++ b/crates/ide-assists/src/utils/suggest_name.rs @@ -75,7 +75,7 @@ pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr { /// In current implementation, the function tries to get the name from /// the following sources: /// -/// * if expr is an argument to function/method, use paramter name +/// * if expr is an argument to function/method, use parameter name /// * if expr is a function/method call, use function name /// * expression type name if it exists (E.g. `()`, `fn() -> ()` or `!` do not have names) /// * fallback: `var_name` @@ -85,7 +85,7 @@ pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr { /// Currently it sticks to the first name found. // FIXME: Microoptimize and return a `SmolStr` here. pub(crate) fn for_variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> String { - // `from_param` does not benifit from stripping + // `from_param` does not benefit from stripping // it need the largest context possible // so we check firstmost if let Some(name) = from_param(expr, sema) { diff --git a/crates/ide-completion/src/completions/postfix/format_like.rs b/crates/ide-completion/src/completions/postfix/format_like.rs index 6b94347e0ad0..b273a4cb53ba 100644 --- a/crates/ide-completion/src/completions/postfix/format_like.rs +++ b/crates/ide-completion/src/completions/postfix/format_like.rs @@ -173,7 +173,7 @@ impl FormatStrParser { } } (State::Expr, ':') if chars.peek().copied() == Some(':') => { - // path seperator + // path separator current_expr.push_str("::"); chars.next(); } @@ -185,7 +185,7 @@ impl FormatStrParser { current_expr = String::new(); self.state = State::FormatOpts; } else { - // We're inside of braced expression, assume that it's a struct field name/value delimeter. + // We're inside of braced expression, assume that it's a struct field name/value delimiter. current_expr.push(chr); } } diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs index 0bba7f2459ca..a63ef006875b 100644 --- a/crates/ide-completion/src/tests/flyimport.rs +++ b/crates/ide-completion/src/tests/flyimport.rs @@ -159,7 +159,7 @@ pub mod some_module { pub struct ThiiiiiirdStruct; // contains all letters from the query, but not in the beginning, displayed second pub struct AfterThirdStruct; - // contains all letters from the query in the begginning, displayed first + // contains all letters from the query in the beginning, displayed first pub struct ThirdStruct; } diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index 517fe3f246d0..49b81265ea5b 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -82,7 +82,7 @@ impl Definition { } /// Textual range of the identifier which will change when renaming this - /// `Definition`. Note that some definitions, like buitin types, can't be + /// `Definition`. Note that some definitions, like builtin types, can't be /// renamed. pub fn range_for_rename(self, sema: &Semantics<'_, RootDatabase>) -> Option { let res = match self { diff --git a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs index 9e66fbfb7522..5fcaf405b14b 100644 --- a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs +++ b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs @@ -750,7 +750,7 @@ fn main() { enum Foo { A } fn main() { // FIXME: this should not bail out but current behavior is such as the old algorithm. - // ExprValidator::validate_match(..) checks types of top level patterns incorrecly. + // ExprValidator::validate_match(..) checks types of top level patterns incorrectly. match Foo::A { ref _x => {} Foo::A => {} diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index 5020e9abaf31..c1aa14d6b7e7 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -321,7 +321,7 @@ struct MatchState<'t> { /// The KleeneOp of this sequence if we are in a repetition. sep_kind: Option, - /// Number of tokens of seperator parsed + /// Number of tokens of separator parsed sep_parsed: Option, /// Matched meta variables bindings diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs index e3f83084ac8a..b81b7432f655 100644 --- a/crates/project-model/src/lib.rs +++ b/crates/project-model/src/lib.rs @@ -3,7 +3,7 @@ //! //! Pure model is represented by the [`base_db::CrateGraph`] from another crate. //! -//! In this crate, we are conserned with "real world" project models. +//! In this crate, we are concerned with "real world" project models. //! //! Specifically, here we have a representation for a Cargo project //! ([`CargoWorkspace`]) and for manually specified layout ([`ProjectJson`]). diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index daabb299f76c..8d6f50f5587c 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -770,7 +770,7 @@ fn handle_rustc_crates( queue.push_back(root_pkg); while let Some(pkg) = queue.pop_front() { // Don't duplicate packages if they are dependended on a diamond pattern - // N.B. if this line is ommitted, we try to analyse over 4_800_000 crates + // N.B. if this line is omitted, we try to analyse over 4_800_000 crates // which is not ideal if rustc_pkg_crates.contains_key(&pkg) { continue; diff --git a/crates/rust-analyzer/src/bin/logger.rs b/crates/rust-analyzer/src/bin/logger.rs index 0b69f75bc0db..298814af5a46 100644 --- a/crates/rust-analyzer/src/bin/logger.rs +++ b/crates/rust-analyzer/src/bin/logger.rs @@ -52,7 +52,7 @@ impl Logger { // merge chalk filter to our main filter (from RA_LOG env). // // The acceptable syntax of CHALK_DEBUG is `target[span{field=value}]=level`. - // As the value should only affect chalk crates, we'd better mannually + // As the value should only affect chalk crates, we'd better manually // specify the target. And for simplicity, CHALK_DEBUG only accept the value // that specify level. let chalk_level_dir = std::env::var("CHALK_DEBUG") diff --git a/crates/syntax/src/hacks.rs b/crates/syntax/src/hacks.rs index a047f61fa03c..ec3d3d444c36 100644 --- a/crates/syntax/src/hacks.rs +++ b/crates/syntax/src/hacks.rs @@ -1,4 +1,4 @@ -//! Things which exist to solve practial issues, but which shouldn't exist. +//! Things which exist to solve practical issues, but which shouldn't exist. //! //! Please avoid adding new usages of the functions in this module diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 10fae41d081c..7badb1c363b4 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -64,7 +64,7 @@ pub struct FileId(pub u32); /// Storage for all files read by rust-analyzer. /// -/// For more informations see the [crate-level](crate) documentation. +/// For more information see the [crate-level](crate) documentation. #[derive(Default)] pub struct Vfs { interner: PathInterner, diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index 51e26c58a917..c173a239feab 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md @@ -485,7 +485,7 @@ Mind the code--architecture gap: at the moment, we are using fewer feature flags ### Serialization In Rust, it is easy (often too easy) to add serialization to any type by adding `#[derive(Serialize)]`. -This easiness is misleading -- serializable types impose significant backwards compatability constraints. +This easiness is misleading -- serializable types impose significant backwards compatibility constraints. If a type is serializable, then it is a part of some IPC boundary. You often don't control the other side of this boundary, so changing serializable types is hard. diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index f58de9da1bfe..12f666401fd1 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -655,7 +655,7 @@ function crateGraph(ctx: Ctx, full: boolean): Cmd { html, body { margin:0; padding:0; overflow:hidden } svg { position:fixed; top:0; left:0; height:100%; width:100% } - /* Disable the graphviz backgroud and fill the polygons */ + /* Disable the graphviz background and fill the polygons */ .graph > polygon { display:none; } :is(.node,.edge) polygon { fill: white; } diff --git a/editors/code/src/toolchain.ts b/editors/code/src/toolchain.ts index bac163da9f37..e1ca49542802 100644 --- a/editors/code/src/toolchain.ts +++ b/editors/code/src/toolchain.ts @@ -158,7 +158,7 @@ export const getPathForExecutable = memoizeAsync( try { // hmm, `os.homedir()` seems to be infallible - // it is not mentioned in docs and cannot be infered by the type signature... + // it is not mentioned in docs and cannot be inferred by the type signature... const standardPath = vscode.Uri.joinPath( vscode.Uri.file(os.homedir()), ".cargo", From 85b9568e2d7cc3c4b9a9d420ab3d4b91037bc6a5 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Wed, 17 Aug 2022 11:57:14 -0500 Subject: [PATCH 0149/2442] feat: Run test mod from anywhere in parent file The "Run" feature of rust-analyzer is super useful, especially for running individual tests or test-modules during development. One common pattern in rust development is to develop tests in the same file as production code, inside a module (usually called `test` or `tests`) marked with `#[cfg(test)]`. Unforunately, this pattern is not well supported by r-a today, as a test module won't show up as a runnable unless the cursor is inside it. In my experience, it is quite common to want to run the tests associated with some production code immediately after editing it, not only after editing the tests themselves. As such it would be better if test modules were available from the "Run" menu even when the cursor is outside the test module. This change updates the filtration logic for runnables in `handlers::handle_runnables` to special case `RunnableKind::TestMod`, making test modules available regardless of the cursor location. Other `RunnableKind`s are unnaffected. Fixes #9589 --- crates/rust-analyzer/src/handlers.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 943d043bc199..6337d49c2407 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -703,10 +703,8 @@ pub(crate) fn handle_runnables( let mut res = Vec::new(); for runnable in snap.analysis.runnables(file_id)? { - if let Some(offset) = offset { - if !runnable.nav.full_range.contains_inclusive(offset) { - continue; - } + if should_skip_for_offset(&runnable, offset) { + continue; } if should_skip_target(&runnable, cargo_spec.as_ref()) { continue; @@ -772,6 +770,14 @@ pub(crate) fn handle_runnables( Ok(res) } +fn should_skip_for_offset(runnable: &Runnable, offset: Option) -> bool { + match offset { + None => false, + _ if matches!(&runnable.kind, RunnableKind::TestMod { .. }) => false, + Some(offset) => !runnable.nav.full_range.contains_inclusive(offset), + } +} + pub(crate) fn handle_related_tests( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, From 12abaf8ddde026fd733c7e783cc3081f4c22cce2 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 18 Aug 2022 01:30:04 +0900 Subject: [PATCH 0150/2442] fix: resolve associated types of bare dyn types --- crates/hir-ty/src/lower.rs | 61 +++++++++++++------------------ crates/hir-ty/src/tests/traits.rs | 28 ++++++++++++++ 2 files changed, 54 insertions(+), 35 deletions(-) diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 239f66bcb7e7..ae115c8c0da8 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -238,18 +238,7 @@ impl<'a> TyLoweringContext<'a> { }) .intern(Interner) } - TypeRef::DynTrait(bounds) => { - let self_ty = - TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); - let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - QuantifiedWhereClauses::from_iter( - Interner, - bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)), - ) - }); - let bounds = crate::make_single_type_binders(bounds); - TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner) - } + TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds), TypeRef::ImplTrait(bounds) => { match self.impl_trait_mode { ImplTraitLoweringMode::Opaque => { @@ -468,29 +457,10 @@ impl<'a> TyLoweringContext<'a> { } } 0 => { - let self_ty = Some( - TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) - .intern(Interner), - ); - let trait_ref = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - ctx.lower_trait_ref_from_resolved_path( - trait_, - resolved_segment, - self_ty, - ) - }); - let dyn_ty = DynTy { - bounds: crate::make_single_type_binders( - QuantifiedWhereClauses::from_iter( - Interner, - Some(crate::wrap_empty_binders(WhereClause::Implemented( - trait_ref, - ))), - ), - ), - lifetime: static_lifetime(), - }; - TyKind::Dyn(dyn_ty).intern(Interner) + // Trait object type without dyn; this should be handled in upstream. See + // `lower_path()`. + stdx::never!("unexpected fully resolved trait path"); + TyKind::Error.intern(Interner) } _ => { // FIXME report error (ambiguous associated type) @@ -555,11 +525,20 @@ impl<'a> TyLoweringContext<'a> { let (ty, res) = self.lower_ty_ext(type_ref); return self.lower_ty_relative_path(ty, res, path.segments()); } + let (resolution, remaining_index) = match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { Some(it) => it, None => return (TyKind::Error.intern(Interner), None), }; + + if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() { + // trait object type without dyn + let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None); + let ty = self.lower_dyn_trait(&[Interned::new(bound)]); + return (ty, None); + } + let (resolved_segment, remaining_segments) = match remaining_index { None => ( path.segments().last().expect("resolved path has at least one element"), @@ -987,6 +966,18 @@ impl<'a> TyLoweringContext<'a> { }) } + fn lower_dyn_trait(&self, bounds: &[Interned]) -> Ty { + let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); + let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { + QuantifiedWhereClauses::from_iter( + Interner, + bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)), + ) + }); + let bounds = crate::make_single_type_binders(bounds); + TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner) + } + fn lower_impl_trait( &self, bounds: &[Interned], diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 75802a5eb4db..c128a051f72b 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -1476,6 +1476,34 @@ fn test(x: Trait, y: &Trait) -> u64 { 165..172 'z.foo()': u64 "#]], ); + + check_infer_with_mismatches( + r#" +//- minicore: fn, coerce_unsized +struct S; +impl S { + fn foo(&self) {} +} +fn f(_: &Fn(S)) {} +fn main() { + f(&|number| number.foo()); +} + "#, + expect![[r#" + 31..35 'self': &S + 37..39 '{}': () + 47..48 '_': &dyn Fn(S) + 58..60 '{}': () + 71..105 '{ ...()); }': () + 77..78 'f': fn f(&dyn Fn(S)) + 77..102 'f(&|nu...foo())': () + 79..101 '&|numb....foo()': &|S| -> () + 80..101 '|numbe....foo()': |S| -> () + 81..87 'number': S + 89..95 'number': S + 89..101 'number.foo()': () + "#]], + ) } #[test] From dac27679f75725c8a3e8ff5fc009f3bc59ce3523 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 18 Aug 2022 08:46:06 +0900 Subject: [PATCH 0151/2442] fix: resolve path `Self` alone in value namespace --- crates/hir-ty/src/infer.rs | 1 + crates/hir-ty/src/tests/patterns.rs | 36 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 46eeea0e6fc4..7440439522e0 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -734,6 +734,7 @@ impl<'a> InferenceContext<'a> { let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); return (ty, Some(strukt.into())); } + ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None), _ => return (self.err_ty(), None), }, Some(ResolveValueResult::Partial(typens, unresolved)) => (typens, Some(unresolved)), diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs index 94efe7bc11a8..eb04bf87783b 100644 --- a/crates/hir-ty/src/tests/patterns.rs +++ b/crates/hir-ty/src/tests/patterns.rs @@ -488,6 +488,42 @@ fn infer_adt_pattern() { ); } +#[test] +fn tuple_struct_destructured_with_self() { + check_infer( + r#" +struct Foo(usize,); +impl Foo { + fn f() { + let Self(s,) = &Foo(0,); + let Self(s,) = &mut Foo(0,); + let Self(s,) = Foo(0,); + } +} + "#, + expect![[r#" + 42..151 '{ ... }': () + 56..64 'Self(s,)': Foo + 61..62 's': &usize + 67..75 '&Foo(0,)': &Foo + 68..71 'Foo': Foo(usize) -> Foo + 68..75 'Foo(0,)': Foo + 72..73 '0': usize + 89..97 'Self(s,)': Foo + 94..95 's': &mut usize + 100..112 '&mut Foo(0,)': &mut Foo + 105..108 'Foo': Foo(usize) -> Foo + 105..112 'Foo(0,)': Foo + 109..110 '0': usize + 126..134 'Self(s,)': Foo + 131..132 's': usize + 137..140 'Foo': Foo(usize) -> Foo + 137..144 'Foo(0,)': Foo + 141..142 '0': usize + "#]], + ); +} + #[test] fn enum_variant_through_self_in_pattern() { check_infer( From 581a01d0cc608d02090a5fd6d4fdc8a7b71b5c34 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Thu, 18 Aug 2022 13:42:10 -0400 Subject: [PATCH 0152/2442] Migrate `syntax::make` to use format arg captures --- crates/syntax/src/ast/make.rs | 263 +++++++++++++++++----------------- 1 file changed, 132 insertions(+), 131 deletions(-) diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 037de876d45c..83f8bbac5880 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -25,7 +25,7 @@ pub mod ext { return from_text(&name.text()); fn from_text(text: &str) -> ast::IdentPat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } pub fn ident_path(ident: &str) -> ast::Path { @@ -60,10 +60,10 @@ pub mod ext { expr_from_text("todo!()") } pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr { - expr_from_text(&format!("{}::default()", ty)) + expr_from_text(&format!("{ty}::default()")) } pub fn expr_ty_new(ty: &ast::Type) -> ast::Expr { - expr_from_text(&format!("{}::new()", ty)) + expr_from_text(&format!("{ty}::new()")) } pub fn zero_number() -> ast::Expr { @@ -92,18 +92,20 @@ pub mod ext { ty_path(ident_path("bool")) } pub fn ty_option(t: ast::Type) -> ast::Type { - ty_from_text(&format!("Option<{}>", t)) + ty_from_text(&format!("Option<{t}>")) } pub fn ty_result(t: ast::Type, e: ast::Type) -> ast::Type { - ty_from_text(&format!("Result<{}, {}>", t, e)) + ty_from_text(&format!("Result<{t}, {e}>")) } } -pub fn name(text: &str) -> ast::Name { - ast_from_text(&format!("mod {}{};", raw_ident_esc(text), text)) +pub fn name(name: &str) -> ast::Name { + let raw_escape = raw_ident_esc(name); + ast_from_text(&format!("mod {raw_escape}{name};")) } -pub fn name_ref(text: &str) -> ast::NameRef { - ast_from_text(&format!("fn f() {{ {}{}; }}", raw_ident_esc(text), text)) +pub fn name_ref(name_ref: &str) -> ast::NameRef { + let raw_escape = raw_ident_esc(name_ref); + ast_from_text(&format!("fn f() {{ {raw_escape}{name_ref}; }}")) } fn raw_ident_esc(ident: &str) -> &'static str { let is_keyword = parser::SyntaxKind::from_keyword(ident).is_some(); @@ -118,10 +120,10 @@ pub fn lifetime(text: &str) -> ast::Lifetime { let mut text = text; let tmp; if never!(!text.starts_with('\'')) { - tmp = format!("'{}", text); + tmp = format!("'{text}"); text = &tmp; } - ast_from_text(&format!("fn f<{}>() {{ }}", text)) + ast_from_text(&format!("fn f<{text}>() {{ }}")) } // FIXME: replace stringly-typed constructor with a family of typed ctors, a-la @@ -142,16 +144,16 @@ pub fn ty_tuple(types: impl IntoIterator) -> ast::Type { contents.push(','); } - ty_from_text(&format!("({})", contents)) + ty_from_text(&format!("({contents})")) } pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type { - ty_from_text(&if exclusive { format!("&mut {}", target) } else { format!("&{}", target) }) + ty_from_text(&if exclusive { format!("&mut {target}") } else { format!("&{target}") }) } pub fn ty_path(path: ast::Path) -> ast::Type { ty_from_text(&path.to_string()) } fn ty_from_text(text: &str) -> ast::Type { - ast_from_text(&format!("type _T = {};", text)) + ast_from_text(&format!("type _T = {text};")) } pub fn assoc_item_list() -> ast::AssocItemList { @@ -171,7 +173,7 @@ pub fn impl_( Some(params) => params.to_string(), None => String::new(), }; - ast_from_text(&format!("impl{} {}{} {{}}", params, ty, ty_params)) + ast_from_text(&format!("impl{params} {ty}{ty_params} {{}}")) } pub fn impl_trait( @@ -180,7 +182,7 @@ pub fn impl_trait( ty_params: Option, ) -> ast::Impl { let ty_params = ty_params.map_or_else(String::new, |params| params.to_string()); - ast_from_text(&format!("impl{2} {} for {}{2} {{}}", trait_, ty, ty_params)) + ast_from_text(&format!("impl{ty_params} {trait_} for {ty}{ty_params} {{}}")) } pub(crate) fn generic_arg_list() -> ast::GenericArgList { @@ -188,13 +190,13 @@ pub(crate) fn generic_arg_list() -> ast::GenericArgList { } pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment { - ast_from_text(&format!("type __ = {};", name_ref)) + ast_from_text(&format!("type __ = {name_ref};")) } pub fn path_segment_ty(type_ref: ast::Type, trait_ref: Option) -> ast::PathSegment { let text = match trait_ref { - Some(trait_ref) => format!("fn f(x: <{} as {}>) {{}}", type_ref, trait_ref), - None => format!("fn f(x: <{}>) {{}}", type_ref), + Some(trait_ref) => format!("fn f(x: <{type_ref} as {trait_ref}>) {{}}"), + None => format!("fn f(x: <{type_ref}>) {{}}"), }; ast_from_text(&text) } @@ -212,15 +214,15 @@ pub fn path_segment_crate() -> ast::PathSegment { } pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path { - ast_from_text(&format!("type __ = {};", segment)) + ast_from_text(&format!("type __ = {segment};")) } pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { - ast_from_text(&format!("{}::{}", qual, segment)) + ast_from_text(&format!("{qual}::{segment}")) } // FIXME: path concatenation operation doesn't make sense as AST op. pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path { - ast_from_text(&format!("type __ = {}::{};", first, second)) + ast_from_text(&format!("type __ = {first}::{second};")) } pub fn path_from_segments( @@ -229,20 +231,20 @@ pub fn path_from_segments( ) -> ast::Path { let segments = segments.into_iter().map(|it| it.syntax().clone()).join("::"); ast_from_text(&if is_abs { - format!("fn f(x: ::{}) {{}}", segments) + format!("fn f(x: ::{segments}) {{}}") } else { - format!("fn f(x: {}) {{}}", segments) + format!("fn f(x: {segments}) {{}}") }) } pub fn join_paths(paths: impl IntoIterator) -> ast::Path { let paths = paths.into_iter().map(|it| it.syntax().clone()).join("::"); - ast_from_text(&format!("type __ = {};", paths)) + ast_from_text(&format!("type __ = {paths};")) } // FIXME: should not be pub pub fn path_from_text(text: &str) -> ast::Path { - ast_from_text(&format!("fn main() {{ let test = {}; }}", text)) + ast_from_text(&format!("fn main() {{ let test = {text}; }}")) } pub fn use_tree_glob() -> ast::UseTree { @@ -257,50 +259,50 @@ pub fn use_tree( let mut buf = "use ".to_string(); buf += &path.syntax().to_string(); if let Some(use_tree_list) = use_tree_list { - format_to!(buf, "::{}", use_tree_list); + format_to!(buf, "::{use_tree_list}"); } if add_star { buf += "::*"; } if let Some(alias) = alias { - format_to!(buf, " {}", alias); + format_to!(buf, " {alias}"); } ast_from_text(&buf) } pub fn use_tree_list(use_trees: impl IntoIterator) -> ast::UseTreeList { let use_trees = use_trees.into_iter().map(|it| it.syntax().clone()).join(", "); - ast_from_text(&format!("use {{{}}};", use_trees)) + ast_from_text(&format!("use {{{use_trees}}};")) } pub fn use_(visibility: Option, use_tree: ast::UseTree) -> ast::Use { let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!("{}use {};", visibility, use_tree)) + ast_from_text(&format!("{visibility}use {use_tree};")) } pub fn record_expr(path: ast::Path, fields: ast::RecordExprFieldList) -> ast::RecordExpr { - ast_from_text(&format!("fn f() {{ {} {} }}", path, fields)) + ast_from_text(&format!("fn f() {{ {path} {fields} }}")) } pub fn record_expr_field_list( fields: impl IntoIterator, ) -> ast::RecordExprFieldList { let fields = fields.into_iter().join(", "); - ast_from_text(&format!("fn f() {{ S {{ {} }} }}", fields)) + ast_from_text(&format!("fn f() {{ S {{ {fields} }} }}")) } pub fn record_expr_field(name: ast::NameRef, expr: Option) -> ast::RecordExprField { return match expr { - Some(expr) => from_text(&format!("{}: {}", name, expr)), + Some(expr) => from_text(&format!("{name}: {expr}")), None => from_text(&name.to_string()), }; fn from_text(text: &str) -> ast::RecordExprField { - ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text)) + ast_from_text(&format!("fn f() {{ S {{ {text}, }} }}")) } } @@ -311,9 +313,9 @@ pub fn record_field( ) -> ast::RecordField { let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!("struct S {{ {}{}: {}, }}", visibility, name, ty)) + ast_from_text(&format!("struct S {{ {visibility}{name}: {ty}, }}")) } // TODO @@ -323,13 +325,13 @@ pub fn block_expr( ) -> ast::BlockExpr { let mut buf = "{\n".to_string(); for stmt in stmts.into_iter() { - format_to!(buf, " {}\n", stmt); + format_to!(buf, " {stmt}\n"); } if let Some(tail_expr) = tail_expr { - format_to!(buf, " {}\n", tail_expr); + format_to!(buf, " {tail_expr}\n"); } buf += "}"; - ast_from_text(&format!("fn f() {}", buf)) + ast_from_text(&format!("fn f() {buf}")) } /// Ideally this function wouldn't exist since it involves manual indenting. @@ -343,18 +345,18 @@ pub fn hacky_block_expr_with_comments( let mut buf = "{\n".to_string(); for node_or_token in elements.into_iter() { match node_or_token { - rowan::NodeOrToken::Node(n) => format_to!(buf, " {}\n", n), + rowan::NodeOrToken::Node(n) => format_to!(buf, " {n}\n"), rowan::NodeOrToken::Token(t) if t.kind() == SyntaxKind::COMMENT => { - format_to!(buf, " {}\n", t) + format_to!(buf, " {t}\n") } _ => (), } } if let Some(tail_expr) = tail_expr { - format_to!(buf, " {}\n", tail_expr); + format_to!(buf, " {tail_expr}\n"); } buf += "}"; - ast_from_text(&format!("fn f() {}", buf)) + ast_from_text(&format!("fn f() {buf}")) } pub fn expr_unit() -> ast::Expr { @@ -362,7 +364,7 @@ pub fn expr_unit() -> ast::Expr { } pub fn expr_literal(text: &str) -> ast::Literal { assert_eq!(text.trim(), text); - ast_from_text(&format!("fn f() {{ let _ = {}; }}", text)) + ast_from_text(&format!("fn f() {{ let _ = {text}; }}")) } pub fn expr_empty_block() -> ast::Expr { @@ -373,41 +375,41 @@ pub fn expr_path(path: ast::Path) -> ast::Expr { } pub fn expr_continue(label: Option) -> ast::Expr { match label { - Some(label) => expr_from_text(&format!("continue {}", label)), + Some(label) => expr_from_text(&format!("continue {label}")), None => expr_from_text("continue"), } } // Consider `op: SyntaxKind` instead for nicer syntax at the call-site? pub fn expr_bin_op(lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::Expr { - expr_from_text(&format!("{} {} {}", lhs, op, rhs)) + expr_from_text(&format!("{lhs} {op} {rhs}")) } pub fn expr_break(label: Option, expr: Option) -> ast::Expr { let mut s = String::from("break"); if let Some(label) = label { - format_to!(s, " {}", label); + format_to!(s, " {label}"); } if let Some(expr) = expr { - format_to!(s, " {}", expr); + format_to!(s, " {expr}"); } expr_from_text(&s) } pub fn expr_return(expr: Option) -> ast::Expr { match expr { - Some(expr) => expr_from_text(&format!("return {}", expr)), + Some(expr) => expr_from_text(&format!("return {expr}")), None => expr_from_text("return"), } } pub fn expr_try(expr: ast::Expr) -> ast::Expr { - expr_from_text(&format!("{}?", expr)) + expr_from_text(&format!("{expr}?")) } pub fn expr_await(expr: ast::Expr) -> ast::Expr { - expr_from_text(&format!("{}.await", expr)) + expr_from_text(&format!("{expr}.await")) } pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr { - expr_from_text(&format!("match {} {}", expr, match_arm_list)) + expr_from_text(&format!("match {expr} {match_arm_list}")) } pub fn expr_if( condition: ast::Expr, @@ -415,66 +417,67 @@ pub fn expr_if( else_branch: Option, ) -> ast::Expr { let else_branch = match else_branch { - Some(ast::ElseBranch::Block(block)) => format!("else {}", block), - Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {}", if_expr), + Some(ast::ElseBranch::Block(block)) => format!("else {block}"), + Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"), None => String::new(), }; - expr_from_text(&format!("if {} {} {}", condition, then_branch, else_branch)) + expr_from_text(&format!("if {condition} {then_branch} {else_branch}")) } pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::Expr { - expr_from_text(&format!("for {} in {} {}", pat, expr, block)) + expr_from_text(&format!("for {pat} in {expr} {block}")) } pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr { - expr_from_text(&format!("loop {}", block)) + expr_from_text(&format!("loop {block}")) } pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr { let token = token(op); - expr_from_text(&format!("{}{}", token, expr)) + expr_from_text(&format!("{token}{expr}")) } pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr { - expr_from_text(&format!("{}{}", f, arg_list)) + expr_from_text(&format!("{f}{arg_list}")) } pub fn expr_method_call( receiver: ast::Expr, method: ast::NameRef, arg_list: ast::ArgList, ) -> ast::Expr { - expr_from_text(&format!("{}.{}{}", receiver, method, arg_list)) + expr_from_text(&format!("{receiver}.{method}{arg_list}")) } pub fn expr_macro_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr { - expr_from_text(&format!("{}!{}", f, arg_list)) + expr_from_text(&format!("{f}!{arg_list}")) } pub fn expr_ref(expr: ast::Expr, exclusive: bool) -> ast::Expr { - expr_from_text(&if exclusive { format!("&mut {}", expr) } else { format!("&{}", expr) }) + expr_from_text(&if exclusive { format!("&mut {expr}") } else { format!("&{expr}") }) } pub fn expr_closure(pats: impl IntoIterator, expr: ast::Expr) -> ast::Expr { let params = pats.into_iter().join(", "); - expr_from_text(&format!("|{}| {}", params, expr)) + expr_from_text(&format!("|{params}| {expr}")) } pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr { - expr_from_text(&format!("{}.{}", receiver, field)) + expr_from_text(&format!("{receiver}.{field}")) } pub fn expr_paren(expr: ast::Expr) -> ast::Expr { - expr_from_text(&format!("({})", expr)) + expr_from_text(&format!("({expr})")) } pub fn expr_tuple(elements: impl IntoIterator) -> ast::Expr { let expr = elements.into_iter().format(", "); - expr_from_text(&format!("({})", expr)) + expr_from_text(&format!("({expr})")) } pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr { - expr_from_text(&format!("{} = {}", lhs, rhs)) + expr_from_text(&format!("{lhs} = {rhs}")) } fn expr_from_text(text: &str) -> ast::Expr { - ast_from_text(&format!("const C: () = {};", text)) + ast_from_text(&format!("const C: () = {text};")) } pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr { - ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr)) + ast_from_text(&format!("const _: () = while let {pattern} = {expr} {{}};")) } pub fn arg_list(args: impl IntoIterator) -> ast::ArgList { - ast_from_text(&format!("fn main() {{ ()({}) }}", args.into_iter().format(", "))) + let args = args.into_iter().format(", "); + ast_from_text(&format!("fn main() {{ ()({args}) }}")) } pub fn ident_pat(ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat { @@ -485,7 +488,7 @@ pub fn ident_pat(ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat { if mut_ { s.push_str("mut "); } - format_to!(s, "{}", name); + format_to!(s, "{name}"); s.push_str(": ())"); ast_from_text(&s) } @@ -494,7 +497,7 @@ pub fn wildcard_pat() -> ast::WildcardPat { return from_text("_"); fn from_text(text: &str) -> ast::WildcardPat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } @@ -502,7 +505,7 @@ pub fn literal_pat(lit: &str) -> ast::LiteralPat { return from_text(lit); fn from_text(text: &str) -> ast::LiteralPat { - ast_from_text(&format!("fn f() {{ match x {{ {} => {{}} }} }}", text)) + ast_from_text(&format!("fn f() {{ match x {{ {text} => {{}} }} }}")) } } @@ -515,10 +518,10 @@ pub fn tuple_pat(pats: impl IntoIterator) -> ast::TuplePat { if count == 1 { pats_str.push(','); } - return from_text(&format!("({})", pats_str)); + return from_text(&format!("({pats_str})")); fn from_text(text: &str) -> ast::TuplePat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } @@ -527,46 +530,46 @@ pub fn tuple_struct_pat( pats: impl IntoIterator, ) -> ast::TupleStructPat { let pats_str = pats.into_iter().join(", "); - return from_text(&format!("{}({})", path, pats_str)); + return from_text(&format!("{path}({pats_str})")); fn from_text(text: &str) -> ast::TupleStructPat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } pub fn record_pat(path: ast::Path, pats: impl IntoIterator) -> ast::RecordPat { let pats_str = pats.into_iter().join(", "); - return from_text(&format!("{} {{ {} }}", path, pats_str)); + return from_text(&format!("{path} {{ {pats_str} }}")); fn from_text(text: &str) -> ast::RecordPat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } pub fn record_pat_with_fields(path: ast::Path, fields: ast::RecordPatFieldList) -> ast::RecordPat { - ast_from_text(&format!("fn f({} {}: ()))", path, fields)) + ast_from_text(&format!("fn f({path} {fields}: ()))")) } pub fn record_pat_field_list( fields: impl IntoIterator, ) -> ast::RecordPatFieldList { let fields = fields.into_iter().join(", "); - ast_from_text(&format!("fn f(S {{ {} }}: ()))", fields)) + ast_from_text(&format!("fn f(S {{ {fields} }}: ()))")) } pub fn record_pat_field(name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPatField { - ast_from_text(&format!("fn f(S {{ {}: {} }}: ()))", name_ref, pat)) + ast_from_text(&format!("fn f(S {{ {name_ref}: {pat} }}: ()))")) } pub fn record_pat_field_shorthand(name_ref: ast::NameRef) -> ast::RecordPatField { - ast_from_text(&format!("fn f(S {{ {} }}: ()))", name_ref)) + ast_from_text(&format!("fn f(S {{ {name_ref} }}: ()))")) } /// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise. pub fn path_pat(path: ast::Path) -> ast::Pat { return from_text(&path.to_string()); fn from_text(text: &str) -> ast::Pat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } @@ -577,12 +580,12 @@ pub fn match_arm( ) -> ast::MatchArm { let pats_str = pats.into_iter().join(" | "); return match guard { - Some(guard) => from_text(&format!("{} if {} => {}", pats_str, guard, expr)), - None => from_text(&format!("{} => {}", pats_str, expr)), + Some(guard) => from_text(&format!("{pats_str} if {guard} => {expr}")), + None => from_text(&format!("{pats_str} => {expr}")), }; fn from_text(text: &str) -> ast::MatchArm { - ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text)) + ast_from_text(&format!("fn f() {{ match () {{{text}}} }}")) } } @@ -592,10 +595,10 @@ pub fn match_arm_with_guard( expr: ast::Expr, ) -> ast::MatchArm { let pats_str = pats.into_iter().join(" | "); - return from_text(&format!("{} if {} => {}", pats_str, guard, expr)); + return from_text(&format!("{pats_str} if {guard} => {expr}")); fn from_text(text: &str) -> ast::MatchArm { - ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text)) + ast_from_text(&format!("fn f() {{ match () {{{text}}} }}")) } } @@ -605,13 +608,14 @@ pub fn match_arm_list(arms: impl IntoIterator) -> ast::Mat .map(|arm| { let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like()); let comma = if needs_comma { "," } else { "" }; - format!(" {}{}\n", arm.syntax(), comma) + let arm = arm.syntax(); + format!(" {arm}{comma}\n") }) .collect::(); return from_text(&arms_str); fn from_text(text: &str) -> ast::MatchArmList { - ast_from_text(&format!("fn f() {{ match () {{\n{}}} }}", text)) + ast_from_text(&format!("fn f() {{ match () {{\n{text}}} }}")) } } @@ -620,10 +624,10 @@ pub fn where_pred( bounds: impl IntoIterator, ) -> ast::WherePred { let bounds = bounds.into_iter().join(" + "); - return from_text(&format!("{}: {}", path, bounds)); + return from_text(&format!("{path}: {bounds}")); fn from_text(text: &str) -> ast::WherePred { - ast_from_text(&format!("fn f() where {} {{ }}", text)) + ast_from_text(&format!("fn f() where {text} {{ }}")) } } @@ -632,7 +636,7 @@ pub fn where_clause(preds: impl IntoIterator) -> ast::Whe return from_text(preds.as_str()); fn from_text(text: &str) -> ast::WhereClause { - ast_from_text(&format!("fn f() where {} {{ }}", text)) + ast_from_text(&format!("fn f() where {text} {{ }}")) } } @@ -642,19 +646,19 @@ pub fn let_stmt( initializer: Option, ) -> ast::LetStmt { let mut text = String::new(); - format_to!(text, "let {}", pattern); + format_to!(text, "let {pattern}"); if let Some(ty) = ty { - format_to!(text, ": {}", ty); + format_to!(text, ": {ty}"); } match initializer { - Some(it) => format_to!(text, " = {};", it), + Some(it) => format_to!(text, " = {it};"), None => format_to!(text, ";"), }; - ast_from_text(&format!("fn f() {{ {} }}", text)) + ast_from_text(&format!("fn f() {{ {text} }}")) } pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt { let semi = if expr.is_block_like() { "" } else { ";" }; - ast_from_text(&format!("fn f() {{ {}{} (); }}", expr, semi)) + ast_from_text(&format!("fn f() {{ {expr}{semi} (); }}")) } pub fn item_const( @@ -665,13 +669,13 @@ pub fn item_const( ) -> ast::Const { let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!("{} const {}: {} = {};", visibility, name, ty, expr)) + ast_from_text(&format!("{visibility} const {name}: {ty} = {expr};")) } pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param { - ast_from_text(&format!("fn f({}: {}) {{ }}", pat, ty)) + ast_from_text(&format!("fn f({pat}: {ty}) {{ }}")) } pub fn self_param() -> ast::SelfParam { @@ -679,7 +683,7 @@ pub fn self_param() -> ast::SelfParam { } pub fn ret_type(ty: ast::Type) -> ast::RetType { - ast_from_text(&format!("fn f() -> {} {{ }}", ty)) + ast_from_text(&format!("fn f() -> {ty} {{ }}")) } pub fn param_list( @@ -688,30 +692,30 @@ pub fn param_list( ) -> ast::ParamList { let args = pats.into_iter().join(", "); let list = match self_param { - Some(self_param) if args.is_empty() => format!("fn f({}) {{ }}", self_param), - Some(self_param) => format!("fn f({}, {}) {{ }}", self_param, args), - None => format!("fn f({}) {{ }}", args), + Some(self_param) if args.is_empty() => format!("fn f({self_param}) {{ }}"), + Some(self_param) => format!("fn f({self_param}, {args}) {{ }}"), + None => format!("fn f({args}) {{ }}"), }; ast_from_text(&list) } pub fn type_param(name: ast::Name, ty: Option) -> ast::TypeParam { let bound = match ty { - Some(it) => format!(": {}", it), + Some(it) => format!(": {it}"), None => String::new(), }; - ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound)) + ast_from_text(&format!("fn f<{name}{bound}>() {{ }}")) } pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam { - ast_from_text(&format!("fn f<{}>() {{ }}", lifetime)) + ast_from_text(&format!("fn f<{lifetime}>() {{ }}")) } pub fn generic_param_list( pats: impl IntoIterator, ) -> ast::GenericParamList { let args = pats.into_iter().join(", "); - ast_from_text(&format!("fn f<{}>() {{ }}", args)) + ast_from_text(&format!("fn f<{args}>() {{ }}")) } pub fn visibility_pub_crate() -> ast::Visibility { @@ -724,33 +728,33 @@ pub fn visibility_pub() -> ast::Visibility { pub fn tuple_field_list(fields: impl IntoIterator) -> ast::TupleFieldList { let fields = fields.into_iter().join(", "); - ast_from_text(&format!("struct f({});", fields)) + ast_from_text(&format!("struct f({fields});")) } pub fn record_field_list( fields: impl IntoIterator, ) -> ast::RecordFieldList { let fields = fields.into_iter().join(", "); - ast_from_text(&format!("struct f {{ {} }}", fields)) + ast_from_text(&format!("struct f {{ {fields} }}")) } pub fn tuple_field(visibility: Option, ty: ast::Type) -> ast::TupleField { let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!("struct f({}{});", visibility, ty)) + ast_from_text(&format!("struct f({visibility}{ty});")) } pub fn variant(name: ast::Name, field_list: Option) -> ast::Variant { let field_list = match field_list { None => String::new(), Some(it) => match it { - ast::FieldList::RecordFieldList(record) => format!(" {}", record), - ast::FieldList::TupleFieldList(tuple) => format!("{}", tuple), + ast::FieldList::RecordFieldList(record) => format!(" {record}"), + ast::FieldList::TupleFieldList(tuple) => format!("{tuple}"), }, }; - ast_from_text(&format!("enum f {{ {}{} }}", name, field_list)) + ast_from_text(&format!("enum f {{ {name}{field_list} }}")) } pub fn fn_( @@ -763,23 +767,22 @@ pub fn fn_( is_async: bool, ) -> ast::Fn { let type_params = match type_params { - Some(type_params) => format!("{}", type_params), + Some(type_params) => format!("{type_params}"), None => "".into(), }; let ret_type = match ret_type { - Some(ret_type) => format!("{} ", ret_type), + Some(ret_type) => format!("{ret_type} "), None => "".into(), }; let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; let async_literal = if is_async { "async " } else { "" }; ast_from_text(&format!( - "{}{}fn {}{}{} {}{}", - visibility, async_literal, fn_name, type_params, params, ret_type, body + "{visibility}{async_literal}fn {fn_name}{type_params}{params} {ret_type}{body}", )) } @@ -793,13 +796,10 @@ pub fn struct_( let type_params = generic_param_list.map_or_else(String::new, |it| it.to_string()); let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!( - "{}struct {}{}{}{}", - visibility, strukt_name, type_params, field_list, semicolon - )) + ast_from_text(&format!("{visibility}struct {strukt_name}{type_params}{field_list}{semicolon}",)) } #[track_caller] @@ -808,7 +808,8 @@ fn ast_from_text(text: &str) -> N { let node = match parse.tree().syntax().descendants().find_map(N::cast) { Some(it) => it, None => { - panic!("Failed to make ast node `{}` from text {}", std::any::type_name::(), text) + let node = std::any::type_name::(); + panic!("Failed to make ast node `{node}` from text {text}") } }; let node = node.clone_subtree(); @@ -824,7 +825,7 @@ pub fn token(kind: SyntaxKind) -> SyntaxToken { .descendants_with_tokens() .filter_map(|it| it.into_token()) .find(|it| it.kind() == kind) - .unwrap_or_else(|| panic!("unhandled token: {:?}", kind)) + .unwrap_or_else(|| panic!("unhandled token: {kind:?}")) } pub mod tokens { @@ -863,7 +864,7 @@ pub mod tokens { pub fn literal(text: &str) -> SyntaxToken { assert_eq!(text.trim(), text); - let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {}; }}", text)); + let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {text}; }}")); lit.syntax().first_child_or_token().unwrap().into_token().unwrap() } From d39677c1ebca7a764172abe1999123d7100963d7 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Thu, 18 Aug 2022 18:10:37 -0500 Subject: [PATCH 0153/2442] Rename static_method_target -> assoc_fn_target --- crates/ide-assists/src/handlers/generate_function.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index 49345cb983fd..f5d2b27cb25c 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -78,11 +78,11 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { } } - static_method_target(ctx, &call, adt, &mut target_module, fn_name, &mut adt_name)? + assoc_fn_target(ctx, &call, adt, &mut target_module, fn_name, &mut adt_name)? } Some(hir::PathResolution::SelfType(impl_)) => { let adt = impl_.self_ty(ctx.db()).as_adt()?; - static_method_target(ctx, &call, adt, &mut target_module, fn_name, &mut adt_name)? + assoc_fn_target(ctx, &call, adt, &mut target_module, fn_name, &mut adt_name)? } _ => { return None; @@ -394,7 +394,7 @@ fn get_method_target( Some((target.clone(), get_insert_offset(&target))) } -fn static_method_target( +fn assoc_fn_target( ctx: &AssistContext<'_>, call: &CallExpr, adt: hir::Adt, From 61308607893b1a3c2a9de19d2f80c811d7ad643b Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Thu, 18 Aug 2022 18:12:53 -0500 Subject: [PATCH 0154/2442] use fn_name instead of name_ref.text() --- crates/ide-assists/src/handlers/generate_function.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index f5d2b27cb25c..20855adf3c5f 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -73,7 +73,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) => { if let hir::Adt::Enum(_) = adt { // Don't suggest generating function if the name starts with an uppercase letter - if name_ref.text().starts_with(char::is_uppercase) { + if fn_name.starts_with(char::is_uppercase) { return None; } } From 30eabeb95d047b91268a70c5170b6374c6bab622 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Thu, 18 Aug 2022 18:14:51 -0500 Subject: [PATCH 0155/2442] extract fn_target_info --- .../src/handlers/generate_function.rs | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index 20855adf3c5f..ba8bfe0c19bc 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -61,9 +61,31 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { } let fn_name = &*name_ref.text(); + let (target_module, adt_name, target, file, insert_offset) = + fn_target_info(path, ctx, &call, fn_name)?; + let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?; + let text_range = call.syntax().text_range(); + let label = format!("Generate {} function", function_builder.fn_name); + add_func_to_accumulator( + acc, + ctx, + text_range, + function_builder, + insert_offset, + file, + adt_name, + label, + ) +} + +fn fn_target_info( + path: ast::Path, + ctx: &AssistContext<'_>, + call: &CallExpr, + fn_name: &str, +) -> Option<(Option, Option, GeneratedFunctionTarget, FileId, TextSize)> { let mut target_module = None; let mut adt_name = None; - let (target, file, insert_offset) = match path.qualifier() { Some(qualifier) => match ctx.sema.resolve_path(&qualifier) { Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => { @@ -78,11 +100,11 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { } } - assoc_fn_target(ctx, &call, adt, &mut target_module, fn_name, &mut adt_name)? + assoc_fn_target(ctx, call, adt, &mut target_module, fn_name, &mut adt_name)? } Some(hir::PathResolution::SelfType(impl_)) => { let adt = impl_.self_ty(ctx.db()).as_adt()?; - assoc_fn_target(ctx, &call, adt, &mut target_module, fn_name, &mut adt_name)? + assoc_fn_target(ctx, call, adt, &mut target_module, fn_name, &mut adt_name)? } _ => { return None; @@ -93,19 +115,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { get_fn_target(ctx, &target_module, call.clone())? } }; - let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?; - let text_range = call.syntax().text_range(); - let label = format!("Generate {} function", function_builder.fn_name); - add_func_to_accumulator( - acc, - ctx, - text_range, - function_builder, - insert_offset, - file, - adt_name, - label, - ) + Some((target_module, adt_name, target, file, insert_offset)) } fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { From e513d7b5049092c3797cc30e13d658efb11ad17a Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Thu, 18 Aug 2022 18:20:06 -0500 Subject: [PATCH 0156/2442] Replace tuple with TargetInfo struct --- .../ide-assists/src/handlers/generate_function.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index ba8bfe0c19bc..dee5fea2330f 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -61,7 +61,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { } let fn_name = &*name_ref.text(); - let (target_module, adt_name, target, file, insert_offset) = + let TargetInfo { target_module, adt_name, target, file, insert_offset } = fn_target_info(path, ctx, &call, fn_name)?; let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?; let text_range = call.syntax().text_range(); @@ -78,12 +78,20 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { ) } +struct TargetInfo { + target_module: Option, + adt_name: Option, + target: GeneratedFunctionTarget, + file: FileId, + insert_offset: TextSize, +} + fn fn_target_info( path: ast::Path, ctx: &AssistContext<'_>, call: &CallExpr, fn_name: &str, -) -> Option<(Option, Option, GeneratedFunctionTarget, FileId, TextSize)> { +) -> Option { let mut target_module = None; let mut adt_name = None; let (target, file, insert_offset) = match path.qualifier() { @@ -115,7 +123,7 @@ fn fn_target_info( get_fn_target(ctx, &target_module, call.clone())? } }; - Some((target_module, adt_name, target, file, insert_offset)) + Some(TargetInfo { target_module, adt_name, target, file, insert_offset }) } fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { From e27af5fae3e44ebd2339c3dd3fcaa1e9b59de598 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Thu, 18 Aug 2022 18:21:58 -0500 Subject: [PATCH 0157/2442] Reorder args with flip_comma --- crates/ide-assists/src/handlers/generate_function.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index dee5fea2330f..2283805a3055 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -62,7 +62,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let fn_name = &*name_ref.text(); let TargetInfo { target_module, adt_name, target, file, insert_offset } = - fn_target_info(path, ctx, &call, fn_name)?; + fn_target_info(ctx, path, &call, fn_name)?; let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?; let text_range = call.syntax().text_range(); let label = format!("Generate {} function", function_builder.fn_name); @@ -87,8 +87,8 @@ struct TargetInfo { } fn fn_target_info( - path: ast::Path, ctx: &AssistContext<'_>, + path: ast::Path, call: &CallExpr, fn_name: &str, ) -> Option { From 2086c48cff23aff651c18636e8227993a85cd6ac Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Thu, 18 Aug 2022 18:26:54 -0500 Subject: [PATCH 0158/2442] Remove mut out params via assoc_fn_target_info --- .../src/handlers/generate_function.rs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index 2283805a3055..adb5ec2b99d0 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -92,8 +92,8 @@ fn fn_target_info( call: &CallExpr, fn_name: &str, ) -> Option { - let mut target_module = None; - let mut adt_name = None; + let target_module; + let adt_name = None; let (target, file, insert_offset) = match path.qualifier() { Some(qualifier) => match ctx.sema.resolve_path(&qualifier) { Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => { @@ -108,11 +108,11 @@ fn fn_target_info( } } - assoc_fn_target(ctx, call, adt, &mut target_module, fn_name, &mut adt_name)? + return assoc_fn_target_info(ctx, call, adt, fn_name); } Some(hir::PathResolution::SelfType(impl_)) => { let adt = impl_.self_ty(ctx.db()).as_adt()?; - assoc_fn_target(ctx, call, adt, &mut target_module, fn_name, &mut adt_name)? + return assoc_fn_target_info(ctx, call, adt, fn_name); } _ => { return None; @@ -412,6 +412,18 @@ fn get_method_target( Some((target.clone(), get_insert_offset(&target))) } +fn assoc_fn_target_info( + ctx: &AssistContext<'_>, + call: &CallExpr, + adt: hir::Adt, + fn_name: &str, +) -> Option { + let mut target_module = None; + let mut adt_name = None; + let (target, file, insert_offset) = + assoc_fn_target(ctx, call, adt, &mut target_module, fn_name, &mut adt_name)?; + Some(TargetInfo { target_module, adt_name, target, file, insert_offset }) +} fn assoc_fn_target( ctx: &AssistContext<'_>, call: &CallExpr, From 96c04c5e1c54ceef0b16679ecb71f64548150826 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Thu, 18 Aug 2022 18:28:14 -0500 Subject: [PATCH 0159/2442] inline assoc_fn_target --- .../src/handlers/generate_function.rs | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index adb5ec2b99d0..6c045a3333df 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -420,29 +420,22 @@ fn assoc_fn_target_info( ) -> Option { let mut target_module = None; let mut adt_name = None; - let (target, file, insert_offset) = - assoc_fn_target(ctx, call, adt, &mut target_module, fn_name, &mut adt_name)?; + let (target, file, insert_offset) = { + let target_module: &mut Option = &mut target_module; + let adt_name: &mut Option = &mut adt_name; + let current_module = ctx.sema.scope(call.syntax())?.module(); + let module = adt.module(ctx.sema.db); + *target_module = if current_module == module { None } else { Some(module) }; + if current_module.krate() != module.krate() { + return None; + } + let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?; + let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?; + *adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None }; + Some((target, file, insert_offset)) + }?; Some(TargetInfo { target_module, adt_name, target, file, insert_offset }) } -fn assoc_fn_target( - ctx: &AssistContext<'_>, - call: &CallExpr, - adt: hir::Adt, - target_module: &mut Option, - fn_name: &str, - adt_name: &mut Option, -) -> Option<(GeneratedFunctionTarget, FileId, TextSize)> { - let current_module = ctx.sema.scope(call.syntax())?.module(); - let module = adt.module(ctx.sema.db); - *target_module = if current_module == module { None } else { Some(module) }; - if current_module.krate() != module.krate() { - return None; - } - let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?; - let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?; - *adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None }; - Some((target, file, insert_offset)) -} fn get_insert_offset(target: &GeneratedFunctionTarget) -> TextSize { match &target { From 2e4a4f1a9c1cba63ec44562f0ab0d5b5783ad561 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Thu, 18 Aug 2022 18:28:43 -0500 Subject: [PATCH 0160/2442] Cleanup inline --- .../src/handlers/generate_function.rs | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index 6c045a3333df..cf28f49e034a 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -418,22 +418,15 @@ fn assoc_fn_target_info( adt: hir::Adt, fn_name: &str, ) -> Option { - let mut target_module = None; - let mut adt_name = None; - let (target, file, insert_offset) = { - let target_module: &mut Option = &mut target_module; - let adt_name: &mut Option = &mut adt_name; - let current_module = ctx.sema.scope(call.syntax())?.module(); - let module = adt.module(ctx.sema.db); - *target_module = if current_module == module { None } else { Some(module) }; - if current_module.krate() != module.krate() { - return None; - } - let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?; - let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?; - *adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None }; - Some((target, file, insert_offset)) - }?; + let current_module = ctx.sema.scope(call.syntax())?.module(); + let module = adt.module(ctx.sema.db); + let target_module = if current_module == module { None } else { Some(module) }; + if current_module.krate() != module.krate() { + return None; + } + let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?; + let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?; + let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None }; Some(TargetInfo { target_module, adt_name, target, file, insert_offset }) } From d8e7419c647ff1cd24263fb8e6fbfd609d17d05b Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Thu, 18 Aug 2022 18:32:35 -0500 Subject: [PATCH 0161/2442] Generate and use TargetInfo::new --- .../src/handlers/generate_function.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index cf28f49e034a..892b166a2ce9 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -86,6 +86,18 @@ struct TargetInfo { insert_offset: TextSize, } +impl TargetInfo { + fn new( + target_module: Option, + adt_name: Option, + target: GeneratedFunctionTarget, + file: FileId, + insert_offset: TextSize, + ) -> Self { + Self { target_module, adt_name, target, file, insert_offset } + } +} + fn fn_target_info( ctx: &AssistContext<'_>, path: ast::Path, @@ -123,7 +135,7 @@ fn fn_target_info( get_fn_target(ctx, &target_module, call.clone())? } }; - Some(TargetInfo { target_module, adt_name, target, file, insert_offset }) + Some(TargetInfo::new(target_module, adt_name, target, file, insert_offset)) } fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { @@ -427,7 +439,7 @@ fn assoc_fn_target_info( let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?; let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?; let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None }; - Some(TargetInfo { target_module, adt_name, target, file, insert_offset }) + Some(TargetInfo::new(target_module, adt_name, target, file, insert_offset)) } fn get_insert_offset(target: &GeneratedFunctionTarget) -> TextSize { From 48ea3825b8951a39e27503ea16cacc9147255d79 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Thu, 18 Aug 2022 18:39:42 -0500 Subject: [PATCH 0162/2442] Introduce and use get_fn_target_info --- .../src/handlers/generate_function.rs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index 892b166a2ce9..e26c76da1891 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -104,13 +104,10 @@ fn fn_target_info( call: &CallExpr, fn_name: &str, ) -> Option { - let target_module; - let adt_name = None; - let (target, file, insert_offset) = match path.qualifier() { + match path.qualifier() { Some(qualifier) => match ctx.sema.resolve_path(&qualifier) { Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => { - target_module = Some(module); - get_fn_target(ctx, &target_module, call.clone())? + get_fn_target_info(ctx, &Some(module), call.clone()) } Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) => { if let hir::Adt::Enum(_) = adt { @@ -120,22 +117,16 @@ fn fn_target_info( } } - return assoc_fn_target_info(ctx, call, adt, fn_name); + assoc_fn_target_info(ctx, call, adt, fn_name) } Some(hir::PathResolution::SelfType(impl_)) => { let adt = impl_.self_ty(ctx.db()).as_adt()?; - return assoc_fn_target_info(ctx, call, adt, fn_name); - } - _ => { - return None; + assoc_fn_target_info(ctx, call, adt, fn_name) } + _ => None, }, - _ => { - target_module = None; - get_fn_target(ctx, &target_module, call.clone())? - } - }; - Some(TargetInfo::new(target_module, adt_name, target, file, insert_offset)) + _ => get_fn_target_info(ctx, &None, call.clone()), + } } fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { @@ -391,6 +382,15 @@ fn make_return_type( (ret_type, should_focus_return_type) } +fn get_fn_target_info( + ctx: &AssistContext<'_>, + target_module: &Option, + call: CallExpr, +) -> Option { + let (target, file, insert_offset) = get_fn_target(ctx, target_module, call)?; + Some(TargetInfo::new(*target_module, None, target, file, insert_offset)) +} + fn get_fn_target( ctx: &AssistContext<'_>, target_module: &Option, From b6fe46055bd9b16fd74df43cbbcb89e612a82b4d Mon Sep 17 00:00:00 2001 From: ice1000 Date: Fri, 19 Aug 2022 01:06:00 +0000 Subject: [PATCH 0163/2442] feat: Improved inline_call to replace `Self` --- .../ide-assists/src/handlers/inline_call.rs | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs index 80d3b9255936..c78c5eaa9f42 100644 --- a/crates/ide-assists/src/handlers/inline_call.rs +++ b/crates/ide-assists/src/handlers/inline_call.rs @@ -13,7 +13,7 @@ use ide_db::{ use itertools::{izip, Itertools}; use syntax::{ ast::{self, edit_in_place::Indent, HasArgList, PathExpr}, - ted, AstNode, + ted, AstNode, SyntaxKind, }; use crate::{ @@ -311,6 +311,16 @@ fn inline( } else { fn_body.clone_for_update() }; + // TODO: use if-let chains - https://github.com/rust-lang/rust/pull/94927 + if let Some(i) = body.syntax().ancestors().find_map(ast::Impl::cast) { + if let Some(st) = i.self_ty() { + for tok in body.syntax().descendants_with_tokens().filter_map(|t| t.into_token()) { + if tok.kind() == SyntaxKind::SELF_TYPE_KW { + ted::replace(tok, st.syntax()); + } + } + } + } let usages_for_locals = |local| { Definition::Local(local) .usages(sema) @@ -345,6 +355,7 @@ fn inline( } }) .collect(); + if function.self_param(sema.db).is_some() { let this = || make::name_ref("this").syntax().clone_for_update(); if let Some(self_local) = params[0].2.as_local(sema.db) { @@ -1188,6 +1199,31 @@ fn bar() -> u32 { x } } +"#, + ) + } + + #[test] + fn inline_call_with_self_type() { + check_assist( + inline_call, + r#" +struct A(u32); +impl A { + fn f() -> Self { Self(114514) } +} +fn main() { + A::f$0(); +} +"#, + r#" +struct A(u32); +impl A { + fn f() -> Self { Self(114514) } +} +fn main() { + A(114514); +} "#, ) } From 5a6c51ebb8549467abeeac69bc2e12494cde5b29 Mon Sep 17 00:00:00 2001 From: ice1000 Date: Fri, 19 Aug 2022 01:08:59 +0000 Subject: [PATCH 0164/2442] fix: use functional programming --- crates/ide-assists/src/handlers/inline_call.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs index c78c5eaa9f42..b5d092e39b02 100644 --- a/crates/ide-assists/src/handlers/inline_call.rs +++ b/crates/ide-assists/src/handlers/inline_call.rs @@ -13,7 +13,7 @@ use ide_db::{ use itertools::{izip, Itertools}; use syntax::{ ast::{self, edit_in_place::Indent, HasArgList, PathExpr}, - ted, AstNode, SyntaxKind, + ted, AstNode, NodeOrToken, SyntaxKind, }; use crate::{ @@ -311,15 +311,12 @@ fn inline( } else { fn_body.clone_for_update() }; - // TODO: use if-let chains - https://github.com/rust-lang/rust/pull/94927 - if let Some(i) = body.syntax().ancestors().find_map(ast::Impl::cast) { - if let Some(st) = i.self_ty() { - for tok in body.syntax().descendants_with_tokens().filter_map(|t| t.into_token()) { - if tok.kind() == SyntaxKind::SELF_TYPE_KW { - ted::replace(tok, st.syntax()); - } - } - } + if let Some(t) = body.syntax().ancestors().find_map(ast::Impl::cast).and_then(|i| i.self_ty()) { + body.syntax() + .descendants_with_tokens() + .filter_map(NodeOrToken::into_token) + .filter(|tok| tok.kind() == SyntaxKind::SELF_TYPE_KW) + .for_each(|tok| ted::replace(tok, t.syntax())); } let usages_for_locals = |local| { Definition::Local(local) From 45b7b6a60a7404d093f4afe81a0da10824cef7b8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 19 Aug 2022 08:52:31 +0200 Subject: [PATCH 0165/2442] Implement lsp extension for cancelling running flychecks --- crates/flycheck/src/lib.rs | 26 ++++++++++++++++++----- crates/rust-analyzer/src/handlers.rs | 6 ++++++ crates/rust-analyzer/src/lsp_ext.rs | 8 +++++++ crates/rust-analyzer/src/main_loop.rs | 7 ++++--- docs/dev/lsp-extensions.md | 2 +- editors/code/package.json | 5 +++++ editors/code/src/commands.ts | 6 ++++++ editors/code/src/lsp_ext.ts | 30 +++++++++++++++------------ editors/code/src/main.ts | 1 + 9 files changed, 69 insertions(+), 22 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 2bebea2fbfef..c22945c81fcb 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -77,8 +77,13 @@ impl FlycheckHandle { } /// Schedule a re-start of the cargo check worker. - pub fn update(&self) { - self.sender.send(Restart).unwrap(); + pub fn restart(&self) { + self.sender.send(Restart::Yes).unwrap(); + } + + /// Stop this cargo check worker. + pub fn cancel(&self) { + self.sender.send(Restart::No).unwrap(); } pub fn id(&self) -> usize { @@ -122,7 +127,10 @@ pub enum Progress { DidCancel, } -struct Restart; +enum Restart { + Yes, + No, +} struct FlycheckActor { id: usize, @@ -149,6 +157,7 @@ impl FlycheckActor { config: FlycheckConfig, workspace_root: AbsPathBuf, ) -> FlycheckActor { + tracing::info!(%id, ?workspace_root, "Spawning flycheck"); FlycheckActor { id, sender, config, workspace_root, cargo_handle: None } } fn progress(&self, progress: Progress) { @@ -164,10 +173,13 @@ impl FlycheckActor { fn run(mut self, inbox: Receiver) { while let Some(event) = self.next_event(&inbox) { match event { - Event::Restart(Restart) => { + Event::Restart(Restart::No) => { + self.cancel_check_process(); + } + Event::Restart(Restart::Yes) => { // Cancel the previously spawned process self.cancel_check_process(); - while let Ok(Restart) = inbox.recv_timeout(Duration::from_millis(50)) {} + while let Ok(_) = inbox.recv_timeout(Duration::from_millis(50)) {} let command = self.check_command(); tracing::debug!(?command, "will restart flycheck"); @@ -223,6 +235,10 @@ impl FlycheckActor { fn cancel_check_process(&mut self) { if let Some(cargo_handle) = self.cargo_handle.take() { + tracing::debug!( + command = ?self.check_command(), + "did cancel flycheck" + ); cargo_handle.cancel(); self.progress(Progress::DidCancel); } diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 6337d49c2407..fdb3205b0a95 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -51,6 +51,12 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result< Ok(()) } +pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> Result<()> { + let _p = profile::span("handle_stop_flycheck"); + state.flycheck.iter().for_each(|flycheck| flycheck.cancel()); + Ok(()) +} + pub(crate) fn handle_analyzer_status( snap: GlobalStateSnapshot, params: lsp_ext::AnalyzerStatusParams, diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 5f0e108624b2..e61c8b643d2d 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -129,6 +129,14 @@ pub struct ExpandedMacro { pub expansion: String, } +pub enum CancelFlycheck {} + +impl Request for CancelFlycheck { + type Params = (); + type Result = (); + const METHOD: &'static str = "rust-analyzer/cancelFlycheck"; +} + pub enum MatchingBrace {} impl Request for MatchingBrace { diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 77419998249f..f187547019a1 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -288,7 +288,7 @@ impl GlobalState { if became_quiescent { // Project has loaded properly, kick off initial flycheck - self.flycheck.iter().for_each(FlycheckHandle::update); + self.flycheck.iter().for_each(FlycheckHandle::restart); if self.config.prefill_caches() { self.prime_caches_queue.request_op("became quiescent".to_string()); } @@ -590,6 +590,7 @@ impl GlobalState { .on_sync_mut::(handlers::handle_workspace_reload) .on_sync_mut::(handlers::handle_memory_usage) .on_sync_mut::(handlers::handle_shuffle_crate_graph) + .on_sync_mut::(handlers::handle_cancel_flycheck) .on_sync::(handlers::handle_join_lines) .on_sync::(handlers::handle_on_enter) .on_sync::(handlers::handle_selection_range) @@ -779,7 +780,7 @@ impl GlobalState { for (id, _) in workspace_ids.clone() { if id == flycheck.id() { updated = true; - flycheck.update(); + flycheck.restart(); continue; } } @@ -798,7 +799,7 @@ impl GlobalState { // No specific flycheck was triggered, so let's trigger all of them. if !updated { for flycheck in &this.flycheck { - flycheck.update(); + flycheck.restart(); } } Ok(()) diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 5040643d34a3..6d2c7d7b0634 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ diff --git a/.github/ISSUE_TEMPLATE/critical_nightly_regression.md b/.github/ISSUE_TEMPLATE/critical_nightly_regression.md index a0b1627d7e2e..ad220ff65ca1 100644 --- a/.github/ISSUE_TEMPLATE/critical_nightly_regression.md +++ b/.github/ISSUE_TEMPLATE/critical_nightly_regression.md @@ -2,8 +2,8 @@ name: Critical Nightly Regression about: You are using nightly rust-analyzer and the latest version is unusable. title: '' -labels: '' -assignees: 'matklad' +labels: 'Broken Window' +assignees: '' --- @@ -14,4 +14,3 @@ Please try to provide information which will help us to fix the issue faster. Mi --> This is a serious regression in nightly and it's important to fix it before the next release. -@matklad, please take a look. From 1dcc25a70afdc484081c0fc5cda1f8911d6660b8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 5 Nov 2022 16:28:04 +0100 Subject: [PATCH 0536/2442] internal: Use a process group for flycheck --- Cargo.lock | 24 ++++++++++++++++++++++++ crates/flycheck/Cargo.toml | 1 + crates/flycheck/src/lib.rs | 19 +++++++++++-------- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8931c17bbdc1..c04906c45383 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -221,6 +221,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "command-group" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a8a86f409b4a59df3a3e4bee2de0b83f1755fdd2a25e3a9684c396fc4bed2c" +dependencies = [ + "nix", + "winapi", +] + [[package]] name = "countme" version = "3.0.1" @@ -390,6 +400,7 @@ name = "flycheck" version = "0.0.0" dependencies = [ "cargo_metadata", + "command-group", "crossbeam-channel", "jod-thread", "paths", @@ -970,6 +981,19 @@ dependencies = [ "windows-sys 0.28.0", ] +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + [[package]] name = "notify" version = "5.0.0" diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index 2ad32d24837d..6871f90015fe 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml @@ -17,6 +17,7 @@ rustc-hash = "1.1.0" serde = { version = "1.0.137", features = ["derive"] } serde_json = "1.0.86" jod-thread = "0.1.2" +command-group = "1.0.8" toolchain = { path = "../toolchain", version = "0.0.0" } stdx = { path = "../stdx", version = "0.0.0" } diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 8a91d6066614..1758c9c27a24 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -10,11 +10,12 @@ use std::{ time::Duration, }; +use command_group::{CommandGroup, GroupChild}; use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; use paths::AbsPathBuf; use rustc_hash::FxHashMap; use serde::Deserialize; -use stdx::{process::streaming_output, JodChild}; +use stdx::process::streaming_output; pub use cargo_metadata::diagnostic::{ Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan, @@ -359,6 +360,8 @@ impl FlycheckActor { } } +struct JodChild(GroupChild); + /// A handle to a cargo process used for fly-checking. struct CargoHandle { /// The handle to the actual cargo process. As we cannot cancel directly from with @@ -371,10 +374,10 @@ struct CargoHandle { impl CargoHandle { fn spawn(mut command: Command) -> std::io::Result { command.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null()); - let mut child = JodChild::spawn(command)?; + let mut child = command.group_spawn().map(JodChild)?; - let stdout = child.stdout.take().unwrap(); - let stderr = child.stderr.take().unwrap(); + let stdout = child.0.inner().stdout.take().unwrap(); + let stderr = child.0.inner().stderr.take().unwrap(); let (sender, receiver) = unbounded(); let actor = CargoActor::new(sender, stdout, stderr); @@ -386,13 +389,13 @@ impl CargoHandle { } fn cancel(mut self) { - let _ = self.child.kill(); - let _ = self.child.wait(); + let _ = self.child.0.kill(); + let _ = self.child.0.wait(); } fn join(mut self) -> io::Result<()> { - let _ = self.child.kill(); - let exit_status = self.child.wait()?; + let _ = self.child.0.kill(); + let exit_status = self.child.0.wait()?; let (read_at_least_one_message, error) = self.thread.join()?; if read_at_least_one_message || exit_status.success() { Ok(()) From 935eb3f63424d62ae9d76502aeb7074ce6713000 Mon Sep 17 00:00:00 2001 From: Rongjian Zhang Date: Sun, 6 Nov 2022 01:33:57 +0800 Subject: [PATCH 0537/2442] docs: fix adoc links --- docs/user/manual.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 62e1c5b41b6d..49500e390a50 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -489,9 +489,9 @@ You can follow instructions for installing < Date: Mon, 7 Nov 2022 12:53:33 +0200 Subject: [PATCH 0538/2442] Fix typos --- crates/flycheck/src/lib.rs | 2 +- crates/hir-expand/src/lib.rs | 4 ++-- crates/rust-analyzer/src/config.rs | 2 +- crates/rust-analyzer/src/line_index.rs | 2 +- crates/syntax/src/tests/sourcegen_ast.rs | 2 +- docs/user/generated_config.adoc | 2 +- editors/code/package.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 1758c9c27a24..ff507a52d550 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -365,7 +365,7 @@ struct JodChild(GroupChild); /// A handle to a cargo process used for fly-checking. struct CargoHandle { /// The handle to the actual cargo process. As we cannot cancel directly from with - /// a read syscall dropping and therefor terminating the process is our best option. + /// a read syscall dropping and therefore terminating the process is our best option. child: JodChild, thread: jod_thread::JoinHandle>, receiver: Receiver, diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index a5b499fe8d9d..7352b003a491 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -814,7 +814,7 @@ impl<'a> InFile<&'a SyntaxNode> { pub fn original_syntax_node(self, db: &dyn db::AstDatabase) -> Option> { // This kind of upmapping can only be achieved in attribute expanded files, - // as we don't have node inputs otherwise and therefor can't find an `N` node in the input + // as we don't have node inputs otherwise and therefore can't find an `N` node in the input if !self.file_id.is_macro() { return Some(self.map(Clone::clone)); } else if !self.file_id.is_attr_macro(db) { @@ -926,7 +926,7 @@ impl InFile { pub fn original_ast_node(self, db: &dyn db::AstDatabase) -> Option> { // This kind of upmapping can only be achieved in attribute expanded files, - // as we don't have node inputs otherwise and therefor can't find an `N` node in the input + // as we don't have node inputs otherwise and therefore can't find an `N` node in the input if !self.file_id.is_macro() { return Some(self); } else if !self.file_id.is_attr_macro(db) { diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 4072ae585dbd..c278ba2d7c5b 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -157,7 +157,7 @@ config_data! { checkOnSave_noDefaultFeatures: Option = "null", /// Override the command rust-analyzer uses instead of `cargo check` for /// diagnostics on save. The command is required to output json and - /// should therefor include `--message-format=json` or a similar option. + /// should therefore include `--message-format=json` or a similar option. /// /// If you're changing this because you're using some tool wrapping /// Cargo, you might also want to change diff --git a/crates/rust-analyzer/src/line_index.rs b/crates/rust-analyzer/src/line_index.rs index 7636c3da7f9a..2945dba12f25 100644 --- a/crates/rust-analyzer/src/line_index.rs +++ b/crates/rust-analyzer/src/line_index.rs @@ -42,7 +42,7 @@ impl LineEndings { loop { let idx = match find_crlf(&tail[gap_len..]) { None if crlf_seen => tail.len(), - // SAFETY: buf is unchanged and therefor still contains utf8 data + // SAFETY: buf is unchanged and therefore still contains utf8 data None => return (unsafe { String::from_utf8_unchecked(buf) }, LineEndings::Unix), Some(idx) => { crlf_seen = true; diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs index 70b54843dbaa..712ef5f63b65 100644 --- a/crates/syntax/src/tests/sourcegen_ast.rs +++ b/crates/syntax/src/tests/sourcegen_ast.rs @@ -86,7 +86,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { .traits .iter() .filter(|trait_name| { - // Loops have two expressions so this might collide, therefor manual impl it + // Loops have two expressions so this might collide, therefore manual impl it node.name != "ForExpr" && node.name != "WhileExpr" || trait_name.as_str() != "HasLoopBody" }) diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 36794efe4272..f171eb41bfd7 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -173,7 +173,7 @@ Whether to pass `--no-default-features` to Cargo. Defaults to -- Override the command rust-analyzer uses instead of `cargo check` for diagnostics on save. The command is required to output json and -should therefor include `--message-format=json` or a similar option. +should therefore include `--message-format=json` or a similar option. If you're changing this because you're using some tool wrapping Cargo, you might also want to change diff --git a/editors/code/package.json b/editors/code/package.json index 1a97a9c08937..4357dc73067f 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -623,7 +623,7 @@ ] }, "rust-analyzer.checkOnSave.overrideCommand": { - "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefor include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", + "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", "default": null, "type": [ "null", From f24fbc20274962860e15e1160bfdaade543092bf Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 11:58:57 +0100 Subject: [PATCH 0539/2442] rustfmt --- crates/ide-assists/src/handlers/extract_function.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index c40fb291a32a..f24a6aacc900 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -127,10 +127,8 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op builder.replace(target_range, make_call(ctx, &fun, old_indent)); - let has_impl_wrapper = insert_after - .ancestors() - .find(|a| a.kind() == SyntaxKind::IMPL && a != &insert_after) - .is_some(); + let has_impl_wrapper = + insert_after.ancestors().any(|a| a.kind() == SyntaxKind::IMPL && a != insert_after); let fn_def = match fun.self_param_adt(ctx) { Some(adt) if anchor == Anchor::Method && !has_impl_wrapper => { @@ -1250,8 +1248,7 @@ fn node_to_insert_after(body: &FunctionBody, anchor: Anchor) -> Option { if body.extracted_from_trait_impl() && matches!(anchor, Anchor::Method) { let impl_node = find_non_trait_impl(&next_ancestor); - let target_node = impl_node.as_ref().and_then(last_impl_member); - if target_node.is_some() { + if let target_node @ Some(_) = impl_node.as_ref().and_then(last_impl_member) { return target_node; } } @@ -1281,7 +1278,8 @@ fn find_non_trait_impl(trait_impl: &SyntaxNode) -> Option { let impl_type = Some(impl_type_name(&as_impl)?); let sibblings = trait_impl.parent()?.children(); - sibblings.filter_map(ast::Impl::cast) + sibblings + .filter_map(ast::Impl::cast) .find(|s| impl_type_name(s) == impl_type && !is_trait_impl(s)) } From 8ad4a1d1187326e66a0de73133ea7197992c3837 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 11:45:52 +0100 Subject: [PATCH 0540/2442] Update sysroot crates --- crates/project-model/src/sysroot.rs | 27 ++++++---- crates/project-model/src/tests.rs | 79 +++++++---------------------- 2 files changed, 35 insertions(+), 71 deletions(-) diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index fa8d76f3f452..f6c09a27c9d7 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -128,14 +128,18 @@ impl Sysroot { } if let Some(alloc) = sysroot.by_name("alloc") { - if let Some(core) = sysroot.by_name("core") { - sysroot.crates[alloc].deps.push(core); + for dep in ALLOC_DEPS.trim().lines() { + if let Some(dep) = sysroot.by_name(dep) { + sysroot.crates[alloc].deps.push(dep) + } } } if let Some(proc_macro) = sysroot.by_name("proc_macro") { - if let Some(std) = sysroot.by_name("std") { - sysroot.crates[proc_macro].deps.push(std); + for dep in PROC_MACRO_DEPS.trim().lines() { + if let Some(dep) = sysroot.by_name(dep) { + sysroot.crates[proc_macro].deps.push(dep) + } } } @@ -239,6 +243,7 @@ fn get_rust_src(sysroot_path: &AbsPath) -> Option { const SYSROOT_CRATES: &str = " alloc +backtrace core panic_abort panic_unwind @@ -246,17 +251,19 @@ proc_macro profiler_builtins std stdarch/crates/std_detect -term test unwind"; +const ALLOC_DEPS: &str = "core"; + const STD_DEPS: &str = " alloc -core -panic_abort panic_unwind +panic_abort +core profiler_builtins +unwind std_detect -term -test -unwind"; +test"; + +const PROC_MACRO_DEPS: &str = "std"; diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index e2444e24974a..a1cb438bddc4 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -1566,10 +1566,10 @@ fn rust_project_hello_world_project_model() { }, Dependency { crate_id: CrateId( - 1, + 3, ), name: CrateName( - "core", + "panic_unwind", ), prelude: true, }, @@ -1584,10 +1584,10 @@ fn rust_project_hello_world_project_model() { }, Dependency { crate_id: CrateId( - 3, + 1, ), name: CrateName( - "panic_unwind", + "core", ), prelude: true, }, @@ -1600,6 +1600,15 @@ fn rust_project_hello_world_project_model() { ), prelude: true, }, + Dependency { + crate_id: CrateId( + 9, + ), + name: CrateName( + "unwind", + ), + prelude: true, + }, Dependency { crate_id: CrateId( 7, @@ -1613,29 +1622,11 @@ fn rust_project_hello_world_project_model() { crate_id: CrateId( 8, ), - name: CrateName( - "term", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 9, - ), name: CrateName( "test", ), prelude: true, }, - Dependency { - crate_id: CrateId( - 10, - ), - name: CrateName( - "unwind", - ), - prelude: true, - }, ], proc_macro: Err( "no proc macro loaded for sysroot crate", @@ -1687,40 +1678,6 @@ fn rust_project_hello_world_project_model() { ), edition: Edition2018, version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "term", - ), - canonical_name: "term", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 9, - ): CrateData { - root_file_id: FileId( - 10, - ), - edition: Edition2018, - version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( @@ -1748,10 +1705,10 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 10, + 9, ): CrateData { root_file_id: FileId( - 11, + 10, ), edition: Edition2018, version: None, @@ -1782,10 +1739,10 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 11, + 10, ): CrateData { root_file_id: FileId( - 12, + 11, ), edition: Edition2018, version: None, @@ -1836,7 +1793,7 @@ fn rust_project_hello_world_project_model() { }, Dependency { crate_id: CrateId( - 9, + 8, ), name: CrateName( "test", From 180b4cedec730d0c0127d0d41714abe4176d5365 Mon Sep 17 00:00:00 2001 From: Noritada Kobayashi Date: Mon, 7 Nov 2022 19:25:07 +0900 Subject: [PATCH 0541/2442] Fix the length displayed for byte string literals with escaped newlines The length of byte strings containing escaped newlines is displayed two bytes longer when the first escaped character is a newline. This is due to a small bug in handling the first escaped newline in string literals. Closes #13567 --- crates/syntax/src/ast/token_ext.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index ba72e64425b2..22ad6db9aef3 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -209,17 +209,19 @@ impl ast::String { let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; let mut buf = String::new(); - let mut text_iter = text.chars(); + let mut prev = 0; let mut has_error = false; unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match ( unescaped_char, buf.capacity() == 0, ) { (Ok(c), false) => buf.push(c), - (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (), + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev => { + prev = char_range.end + } (Ok(c), true) => { buf.reserve_exact(text.len()); - buf.push_str(&text[..char_range.start]); + buf.push_str(&text[..prev]); buf.push(c); } (Err(_), _) => has_error = true, @@ -252,17 +254,19 @@ impl ast::ByteString { let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; let mut buf: Vec = Vec::new(); - let mut text_iter = text.chars(); + let mut prev = 0; let mut has_error = false; unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match ( unescaped_char, buf.capacity() == 0, ) { (Ok(c), false) => buf.push(c as u8), - (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (), + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev => { + prev = char_range.end + } (Ok(c), true) => { buf.reserve_exact(text.len()); - buf.extend_from_slice(text[..char_range.start].as_bytes()); + buf.extend_from_slice(text[..prev].as_bytes()); buf.push(c as u8); } (Err(_), _) => has_error = true, @@ -445,6 +449,12 @@ mod tests { check_string_value(r"\foobar", None); check_string_value(r"\nfoobar", "\nfoobar"); check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\"); + check_string_value(r"\x61bcde", "a\x62cde"); + check_string_value( + r"a\ +bcde", "a\ +bcde", + ); } #[test] From ee2dd934caeeb2fb044ac1cacd3e65c3b033bc8b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 12:49:52 +0100 Subject: [PATCH 0542/2442] Don't trigger adjustment hints in all inlay hint tests --- crates/ide/src/inlay_hints.rs | 37 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 50934a27f89e..325e609054dc 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -861,23 +861,23 @@ fn binding_mode_hints( tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), }); }); - // match pat { - // ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => { - // let bm = sema.binding_mode_of_pat(pat)?; - // let bm = match bm { - // hir::BindingMode::Move => return None, - // hir::BindingMode::Ref(Mutability::Mut) => "ref mut", - // hir::BindingMode::Ref(Mutability::Shared) => "ref", - // }; - // acc.push(InlayHint { - // range, - // kind: InlayKind::BindingModeHint, - // label: bm.to_string().into(), - // tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), - // }); - // } - // _ => (), - // } + match pat { + ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => { + let bm = sema.binding_mode_of_pat(pat)?; + let bm = match bm { + hir::BindingMode::Move => return None, + hir::BindingMode::Ref(Mutability::Mut) => "ref mut", + hir::BindingMode::Ref(Mutability::Shared) => "ref", + }; + acc.push(InlayHint { + range, + kind: InlayKind::BindingModeHint, + label: bm.to_string().into(), + tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), + }); + } + _ => (), + } Some(()) } @@ -1306,7 +1306,7 @@ mod tests { chaining_hints: false, lifetime_elision_hints: LifetimeElisionHints::Never, closure_return_type_hints: ClosureReturnTypeHints::Never, - adjustment_hints: AdjustmentHints::Always, + adjustment_hints: AdjustmentHints::Never, binding_mode_hints: false, hide_named_constructor_hints: false, hide_closure_initialization_hints: false, @@ -1318,7 +1318,6 @@ mod tests { type_hints: true, parameter_hints: true, chaining_hints: true, - adjustment_hints: AdjustmentHints::Always, closure_return_type_hints: ClosureReturnTypeHints::WithBlock, binding_mode_hints: true, lifetime_elision_hints: LifetimeElisionHints::Always, From ffd7bf8bf9c99d115e7e0c4e6d1cffe60ea3ff84 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 12:59:51 +0100 Subject: [PATCH 0543/2442] Bump Cargo rust-version fields to latest stable --- crates/base-db/Cargo.toml | 2 +- crates/cfg/Cargo.toml | 2 +- crates/flycheck/Cargo.toml | 2 +- crates/hir-def/Cargo.toml | 2 +- crates/hir-expand/Cargo.toml | 2 +- crates/hir-ty/Cargo.toml | 2 +- crates/hir/Cargo.toml | 2 +- crates/ide-assists/Cargo.toml | 2 +- crates/ide-completion/Cargo.toml | 2 +- crates/ide-db/Cargo.toml | 2 +- crates/ide-diagnostics/Cargo.toml | 2 +- crates/ide-ssr/Cargo.toml | 2 +- crates/ide/Cargo.toml | 2 +- crates/limit/Cargo.toml | 2 +- crates/mbe/Cargo.toml | 2 +- crates/parser/Cargo.toml | 2 +- crates/paths/Cargo.toml | 2 +- crates/proc-macro-api/Cargo.toml | 2 +- crates/proc-macro-srv-cli/Cargo.toml | 2 +- crates/proc-macro-srv/Cargo.toml | 2 +- crates/proc-macro-test/Cargo.toml | 2 +- crates/proc-macro-test/imp/Cargo.toml | 2 +- crates/profile/Cargo.toml | 2 +- crates/project-model/Cargo.toml | 2 +- crates/rust-analyzer/Cargo.toml | 2 +- crates/sourcegen/Cargo.toml | 2 +- crates/stdx/Cargo.toml | 2 +- crates/syntax/Cargo.toml | 2 +- crates/syntax/fuzz/Cargo.toml | 2 +- crates/test-utils/Cargo.toml | 2 +- crates/text-edit/Cargo.toml | 2 +- crates/toolchain/Cargo.toml | 2 +- crates/tt/Cargo.toml | 2 +- crates/vfs-notify/Cargo.toml | 2 +- crates/vfs/Cargo.toml | 2 +- xtask/Cargo.toml | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/crates/base-db/Cargo.toml b/crates/base-db/Cargo.toml index f02a51ab6c47..a484ecec6825 100644 --- a/crates/base-db/Cargo.toml +++ b/crates/base-db/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml index ee1ad677a95f..2857420c285a 100644 --- a/crates/cfg/Cargo.toml +++ b/crates/cfg/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index 6871f90015fe..514d567fcce7 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index 4ad8e75970b5..22f98ea7cd45 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/hir-expand/Cargo.toml b/crates/hir-expand/Cargo.toml index 3359c99b3961..77eb1fd45043 100644 --- a/crates/hir-expand/Cargo.toml +++ b/crates/hir-expand/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index ed13275bab8f..a1d6835bfaed 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index e1418de3cdc2..f780e3f53c85 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/ide-assists/Cargo.toml b/crates/ide-assists/Cargo.toml index 57a41f3d9a93..e781c0a016d5 100644 --- a/crates/ide-assists/Cargo.toml +++ b/crates/ide-assists/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/ide-completion/Cargo.toml b/crates/ide-completion/Cargo.toml index 75835bce95da..11310e2f1291 100644 --- a/crates/ide-completion/Cargo.toml +++ b/crates/ide-completion/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index cf0bcd5c96b2..f48cce58c6e7 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/ide-diagnostics/Cargo.toml b/crates/ide-diagnostics/Cargo.toml index e1d146f4ee56..7e9a1125d751 100644 --- a/crates/ide-diagnostics/Cargo.toml +++ b/crates/ide-diagnostics/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/ide-ssr/Cargo.toml b/crates/ide-ssr/Cargo.toml index 4baf786c4555..7be62a8d9ffe 100644 --- a/crates/ide-ssr/Cargo.toml +++ b/crates/ide-ssr/Cargo.toml @@ -5,7 +5,7 @@ description = "Structural search and replace of Rust code" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust-analyzer" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index 712459a7ee9c..73f202630f15 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/limit/Cargo.toml b/crates/limit/Cargo.toml index 893db436d8b7..3536f73da73e 100644 --- a/crates/limit/Cargo.toml +++ b/crates/limit/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [features] tracking = [] diff --git a/crates/mbe/Cargo.toml b/crates/mbe/Cargo.toml index 13cd8901031d..bce2fc9a70e8 100644 --- a/crates/mbe/Cargo.toml +++ b/crates/mbe/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index a286a6bcddde..d1420de8937a 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/paths/Cargo.toml b/crates/paths/Cargo.toml index 5e83de7d994e..d23a63d2a973 100644 --- a/crates/paths/Cargo.toml +++ b/crates/paths/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/proc-macro-api/Cargo.toml b/crates/proc-macro-api/Cargo.toml index 54879c1870c0..f261f3def45d 100644 --- a/crates/proc-macro-api/Cargo.toml +++ b/crates/proc-macro-api/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/proc-macro-srv-cli/Cargo.toml b/crates/proc-macro-srv-cli/Cargo.toml index 9d0da5dee9c1..7991e125ab83 100644 --- a/crates/proc-macro-srv-cli/Cargo.toml +++ b/crates/proc-macro-srv-cli/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [dependencies] proc-macro-srv = { version = "0.0.0", path = "../proc-macro-srv" } diff --git a/crates/proc-macro-srv/Cargo.toml b/crates/proc-macro-srv/Cargo.toml index e39026ac70bf..a136abc12b75 100644 --- a/crates/proc-macro-srv/Cargo.toml +++ b/crates/proc-macro-srv/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/proc-macro-test/Cargo.toml b/crates/proc-macro-test/Cargo.toml index 684477191b27..d2a79f91074a 100644 --- a/crates/proc-macro-test/Cargo.toml +++ b/crates/proc-macro-test/Cargo.toml @@ -3,7 +3,7 @@ name = "proc-macro-test" version = "0.0.0" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" publish = false [lib] diff --git a/crates/proc-macro-test/imp/Cargo.toml b/crates/proc-macro-test/imp/Cargo.toml index 2d1fc3c5c7a3..1bd14070e90d 100644 --- a/crates/proc-macro-test/imp/Cargo.toml +++ b/crates/proc-macro-test/imp/Cargo.toml @@ -3,7 +3,7 @@ name = "proc-macro-test-impl" version = "0.0.0" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" publish = false [lib] diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index 5697aea964f7..01d1735bf784 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml index cf9868740cb0..39902a53214d 100644 --- a/crates/project-model/Cargo.toml +++ b/crates/project-model/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 7ae5324ab051..56f14fe18749 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -8,7 +8,7 @@ documentation = "https://rust-analyzer.github.io/manual.html" license = "MIT OR Apache-2.0" autobins = false edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/sourcegen/Cargo.toml b/crates/sourcegen/Cargo.toml index e75867e2d81c..593dc4e55b21 100644 --- a/crates/sourcegen/Cargo.toml +++ b/crates/sourcegen/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml index e0657ab0f6d1..957d16c036fa 100644 --- a/crates/stdx/Cargo.toml +++ b/crates/stdx/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 1ef903371cf8..00743cca5593 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -5,7 +5,7 @@ description = "Comment and whitespace preserving parser for the Rust language" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust-analyzer" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/syntax/fuzz/Cargo.toml b/crates/syntax/fuzz/Cargo.toml index ba2f515b0bc1..f295c40065db 100644 --- a/crates/syntax/fuzz/Cargo.toml +++ b/crates/syntax/fuzz/Cargo.toml @@ -4,7 +4,7 @@ name = "syntax-fuzz" version = "0.0.1" publish = false edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [package.metadata] cargo-fuzz = true diff --git a/crates/test-utils/Cargo.toml b/crates/test-utils/Cargo.toml index cceafe04e377..1047373b1c75 100644 --- a/crates/test-utils/Cargo.toml +++ b/crates/test-utils/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/text-edit/Cargo.toml b/crates/text-edit/Cargo.toml index 7a90d64a98ba..8df7e1af6116 100644 --- a/crates/text-edit/Cargo.toml +++ b/crates/text-edit/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/toolchain/Cargo.toml b/crates/toolchain/Cargo.toml index 3e0f31f19c50..a6a3ae742aeb 100644 --- a/crates/toolchain/Cargo.toml +++ b/crates/toolchain/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/tt/Cargo.toml b/crates/tt/Cargo.toml index 52dfb8608041..4f2103f3a97f 100644 --- a/crates/tt/Cargo.toml +++ b/crates/tt/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/vfs-notify/Cargo.toml b/crates/vfs-notify/Cargo.toml index df5dc24e2cd1..061f3c157a88 100644 --- a/crates/vfs-notify/Cargo.toml +++ b/crates/vfs-notify/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml index d7549a284153..e55bf6f293c4 100644 --- a/crates/vfs/Cargo.toml +++ b/crates/vfs/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 0be0bf920de9..95e27beab5dc 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" publish = false license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [dependencies] anyhow = "1.0.62" From bdf854701375c0692f9014db71a097520fddd41f Mon Sep 17 00:00:00 2001 From: Noritada Kobayashi Date: Mon, 7 Nov 2022 22:51:29 +0900 Subject: [PATCH 0544/2442] Clarify the intent Thanks to Lukas Wirth for a suggestion. --- crates/syntax/src/ast/token_ext.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index 22ad6db9aef3..32dd2db405c8 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -209,19 +209,19 @@ impl ast::String { let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; let mut buf = String::new(); - let mut prev = 0; + let mut prev_end = 0; let mut has_error = false; unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match ( unescaped_char, buf.capacity() == 0, ) { (Ok(c), false) => buf.push(c), - (Ok(_), true) if char_range.len() == 1 && char_range.start == prev => { - prev = char_range.end + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { + prev_end = char_range.end } (Ok(c), true) => { buf.reserve_exact(text.len()); - buf.push_str(&text[..prev]); + buf.push_str(&text[..prev_end]); buf.push(c); } (Err(_), _) => has_error = true, @@ -254,19 +254,19 @@ impl ast::ByteString { let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; let mut buf: Vec = Vec::new(); - let mut prev = 0; + let mut prev_end = 0; let mut has_error = false; unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match ( unescaped_char, buf.capacity() == 0, ) { (Ok(c), false) => buf.push(c as u8), - (Ok(_), true) if char_range.len() == 1 && char_range.start == prev => { - prev = char_range.end + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { + prev_end = char_range.end } (Ok(c), true) => { buf.reserve_exact(text.len()); - buf.extend_from_slice(text[..prev].as_bytes()); + buf.extend_from_slice(text[..prev_end].as_bytes()); buf.push(c as u8); } (Err(_), _) => has_error = true, @@ -449,11 +449,10 @@ mod tests { check_string_value(r"\foobar", None); check_string_value(r"\nfoobar", "\nfoobar"); check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\"); - check_string_value(r"\x61bcde", "a\x62cde"); + check_string_value(r"\x61bcde", "abcde"); check_string_value( r"a\ -bcde", "a\ -bcde", +bcde", "abcde", ); } From 2340d7059e3b89a5233b0c91cf3c36fa94adfe6e Mon Sep 17 00:00:00 2001 From: Noritada Kobayashi Date: Mon, 7 Nov 2022 23:39:02 +0900 Subject: [PATCH 0545/2442] Add test code for unescaping byte strings --- crates/syntax/src/ast/token_ext.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index 32dd2db405c8..8990f7a7d4e8 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -456,6 +456,31 @@ bcde", "abcde", ); } + fn check_byte_string_value<'a, const N: usize>( + lit: &str, + expected: impl Into>, + ) { + assert_eq!( + ast::ByteString { syntax: make::tokens::literal(&format!("b\"{}\"", lit)) } + .value() + .as_deref(), + expected.into().map(|value| &value[..]) + ); + } + + #[test] + fn test_byte_string_escape() { + check_byte_string_value(r"foobar", b"foobar"); + check_byte_string_value(r"\foobar", None::<&[u8; 0]>); + check_byte_string_value(r"\nfoobar", b"\nfoobar"); + check_byte_string_value(r"C:\\Windows\\System32\\", b"C:\\Windows\\System32\\"); + check_byte_string_value(r"\x61bcde", b"abcde"); + check_byte_string_value( + r"a\ +bcde", b"abcde", + ); + } + #[test] fn test_value_underscores() { check_float_value("3.141592653589793_f64", 3.141592653589793_f64); From b169e1e5decbbda7ad09a8fa07fb32ca83ec7a50 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 15:49:26 +0100 Subject: [PATCH 0546/2442] Remove code duplication --- crates/ide/src/moniker.rs | 20 ++++---------------- crates/ide/src/static_index.rs | 5 +++-- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 07d117aff10b..fcbf6d8e58c4 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -1,9 +1,9 @@ //! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports) //! for LSIF and LSP. -use hir::{db::DefDatabase, AsAssocItem, AssocItemContainer, Crate, Name, Semantics}; +use hir::{AsAssocItem, AssocItemContainer, Crate, Name, Semantics}; use ide_db::{ - base_db::{CrateOrigin, FileId, FileLoader, FilePosition, LangCrateOrigin}, + base_db::{CrateOrigin, FilePosition, LangCrateOrigin}, defs::{Definition, IdentClass}, helpers::pick_best_token, RootDatabase, @@ -11,7 +11,7 @@ use ide_db::{ use itertools::Itertools; use syntax::{AstNode, SyntaxKind::*, T}; -use crate::{doc_links::token_as_doc_comment, RangeInfo}; +use crate::{doc_links::token_as_doc_comment, parent_module::crates_for, RangeInfo}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum MonikerDescriptorKind { @@ -77,25 +77,13 @@ pub struct PackageInformation { pub version: Option, } -pub(crate) fn crate_for_file(db: &RootDatabase, file_id: FileId) -> Option { - for &krate in db.relevant_crates(file_id).iter() { - let crate_def_map = db.crate_def_map(krate); - for (_, data) in crate_def_map.modules() { - if data.origin.file_id() == Some(file_id) { - return Some(krate.into()); - } - } - } - None -} - pub(crate) fn moniker( db: &RootDatabase, FilePosition { file_id, offset }: FilePosition, ) -> Option>> { let sema = &Semantics::new(db); let file = sema.parse(file_id).syntax().clone(); - let current_crate = crate_for_file(db, file_id)?; + let current_crate: hir::Crate = crates_for(db, file_id).pop()?.into(); let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { IDENT | INT_NUMBER diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 27ad1a948d13..954d3b018afa 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -13,7 +13,8 @@ use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T}; use crate::{ hover::hover_for_definition, - moniker::{crate_for_file, def_to_moniker, MonikerResult}, + moniker::{def_to_moniker, MonikerResult}, + parent_module::crates_for, Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult, InlayHint, InlayHintsConfig, TryToNav, }; @@ -99,7 +100,7 @@ fn all_modules(db: &dyn HirDatabase) -> Vec { impl StaticIndex<'_> { fn add_file(&mut self, file_id: FileId) { - let current_crate = crate_for_file(self.db, file_id); + let current_crate = crates_for(self.db, file_id).pop().map(Into::into); let folds = self.analysis.folding_ranges(file_id).unwrap(); let inlay_hints = self .analysis From 6a06f6f724d385c61e428ef46e6bf9e13e1c37ce Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 16:48:50 +0100 Subject: [PATCH 0547/2442] Deduplicate reference search results --- crates/ide/src/references.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index e942413c1105..0f758cfa2d34 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -16,6 +16,7 @@ use ide_db::{ search::{ReferenceCategory, SearchScope, UsageSearchResult}, RootDatabase, }; +use itertools::Itertools; use stdx::hash::NoHashHashMap; use syntax::{ algo::find_node_at_offset, @@ -86,6 +87,7 @@ pub(crate) fn find_all_refs( file_id, refs.into_iter() .map(|file_ref| (file_ref.range, file_ref.category)) + .unique() .collect(), ) }) From fa70b0a86ec89ea53c0855caba42d121cbcc5697 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 17:21:37 +0100 Subject: [PATCH 0548/2442] internal: Use Cancellable in favor of Result for clarity --- crates/ide/src/inlay_hints.rs | 10 ++--- crates/ide/src/lib.rs | 2 +- crates/rust-analyzer/src/cargo_target_spec.rs | 10 ++--- crates/rust-analyzer/src/handlers.rs | 19 +++++----- crates/rust-analyzer/src/mem_docs.rs | 8 +++- crates/rust-analyzer/src/to_proto.rs | 38 +++++++++---------- 6 files changed, 44 insertions(+), 43 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 34d8bf67a301..8ef122528b4a 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -180,7 +180,7 @@ impl fmt::Debug for InlayHintLabelPart { pub(crate) fn inlay_hints( db: &RootDatabase, file_id: FileId, - range_limit: Option, + range_limit: Option, config: &InlayHintsConfig, ) -> Vec { let _p = profile::span("inlay_hints"); @@ -195,7 +195,7 @@ pub(crate) fn inlay_hints( let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node); match range_limit { - Some(FileRange { range, .. }) => match file.covering_element(range) { + Some(range) => match file.covering_element(range) { NodeOrToken::Token(_) => return acc, NodeOrToken::Node(n) => n .descendants() @@ -1213,7 +1213,6 @@ fn get_callable( #[cfg(test)] mod tests { use expect_test::{expect, Expect}; - use ide_db::base_db::FileRange; use itertools::Itertools; use syntax::{TextRange, TextSize}; use test_utils::extract_annotations; @@ -1838,10 +1837,7 @@ fn main() { .inlay_hints( &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, file_id, - Some(FileRange { - file_id, - range: TextRange::new(TextSize::from(500), TextSize::from(600)), - }), + Some(TextRange::new(TextSize::from(500), TextSize::from(600))), ) .unwrap(); let actual = diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 416817ca0b42..841a5832c541 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -367,7 +367,7 @@ impl Analysis { &self, config: &InlayHintsConfig, file_id: FileId, - range: Option, + range: Option, ) -> Cancellable> { self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config)) } diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 6ede194babc2..cf51cf15a0e1 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs @@ -3,11 +3,11 @@ use std::mem; use cfg::{CfgAtom, CfgExpr}; -use ide::{FileId, RunnableKind, TestId}; +use ide::{Cancellable, FileId, RunnableKind, TestId}; use project_model::{self, CargoFeatures, ManifestPath, TargetKind}; use vfs::AbsPathBuf; -use crate::{global_state::GlobalStateSnapshot, Result}; +use crate::global_state::GlobalStateSnapshot; /// Abstract representation of Cargo target. /// @@ -29,7 +29,7 @@ impl CargoTargetSpec { spec: Option, kind: &RunnableKind, cfg: &Option, - ) -> Result<(Vec, Vec)> { + ) -> (Vec, Vec) { let mut args = Vec::new(); let mut extra_args = Vec::new(); @@ -111,13 +111,13 @@ impl CargoTargetSpec { } } } - Ok((args, extra_args)) + (args, extra_args) } pub(crate) fn for_file( global_state_snapshot: &GlobalStateSnapshot, file_id: FileId, - ) -> Result> { + ) -> Cancellable> { let crate_id = match &*global_state_snapshot.analysis.crates_for(file_id)? { &[crate_id, ..] => crate_id, _ => return Ok(None), diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 34795a8eb40a..d190a9f4e2ca 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -9,9 +9,9 @@ use std::{ use anyhow::Context; use ide::{ - AnnotationConfig, AssistKind, AssistResolveStrategy, FileId, FilePosition, FileRange, - HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind, - SingleResolve, SourceChange, TextEdit, + AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FileId, FilePosition, + FileRange, HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, + RunnableKind, SingleResolve, SourceChange, TextEdit, }; use ide_db::SymbolKind; use lsp_server::ErrorCode; @@ -556,7 +556,7 @@ pub(crate) fn handle_will_rename_files( if source_change.source_file_edits.is_empty() { Ok(None) } else { - to_proto::workspace_edit(&snap, source_change).map(Some) + Ok(Some(to_proto::workspace_edit(&snap, source_change)?)) } } @@ -1313,7 +1313,7 @@ pub(crate) fn handle_ssr( position, selections, )??; - to_proto::workspace_edit(&snap, source_change) + to_proto::workspace_edit(&snap, source_change).map_err(Into::into) } pub(crate) fn publish_diagnostics( @@ -1354,13 +1354,12 @@ pub(crate) fn handle_inlay_hints( ) -> Result>> { let _p = profile::span("handle_inlay_hints"); let document_uri = ¶ms.text_document.uri; - let file_id = from_proto::file_id(&snap, document_uri)?; - let line_index = snap.file_line_index(file_id)?; - let range = from_proto::file_range( + let FileRange { file_id, range } = from_proto::file_range( &snap, TextDocumentIdentifier::new(document_uri.to_owned()), params.range, )?; + let line_index = snap.file_line_index(file_id)?; let inlay_hints_config = snap.config.inlay_hints(); Ok(Some( snap.analysis @@ -1369,7 +1368,7 @@ pub(crate) fn handle_inlay_hints( .map(|it| { to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it) }) - .collect::>>()?, + .collect::>>()?, )) } @@ -1426,7 +1425,7 @@ pub(crate) fn handle_call_hierarchy_prepare( .into_iter() .filter(|it| it.kind == Some(SymbolKind::Function)) .map(|it| to_proto::call_hierarchy_item(&snap, it)) - .collect::>>()?; + .collect::>>()?; Ok(Some(res)) } diff --git a/crates/rust-analyzer/src/mem_docs.rs b/crates/rust-analyzer/src/mem_docs.rs index f86a0f66ad8d..45a1dab9772f 100644 --- a/crates/rust-analyzer/src/mem_docs.rs +++ b/crates/rust-analyzer/src/mem_docs.rs @@ -7,7 +7,7 @@ use vfs::VfsPath; /// Holds the set of in-memory documents. /// -/// For these document, there true contents is maintained by the client. It +/// For these document, their true contents is maintained by the client. It /// might be different from what's on disk. #[derive(Default, Clone)] pub(crate) struct MemDocs { @@ -19,6 +19,7 @@ impl MemDocs { pub(crate) fn contains(&self, path: &VfsPath) -> bool { self.mem_docs.contains_key(path) } + pub(crate) fn insert(&mut self, path: VfsPath, data: DocumentData) -> Result<(), ()> { self.added_or_removed = true; match self.mem_docs.insert(path, data) { @@ -26,6 +27,7 @@ impl MemDocs { None => Ok(()), } } + pub(crate) fn remove(&mut self, path: &VfsPath) -> Result<(), ()> { self.added_or_removed = true; match self.mem_docs.remove(path) { @@ -33,17 +35,21 @@ impl MemDocs { None => Err(()), } } + pub(crate) fn get(&self, path: &VfsPath) -> Option<&DocumentData> { self.mem_docs.get(path) } + pub(crate) fn get_mut(&mut self, path: &VfsPath) -> Option<&mut DocumentData> { // NB: don't set `self.added_or_removed` here, as that purposefully only // tracks changes to the key set. self.mem_docs.get_mut(path) } + pub(crate) fn iter(&self) -> impl Iterator { self.mem_docs.keys() } + pub(crate) fn take_changes(&mut self) -> bool { mem::replace(&mut self.added_or_removed, false) } diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 6c84a2069cd5..830b071b9416 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -24,7 +24,7 @@ use crate::{ line_index::{LineEndings, LineIndex, PositionEncoding}, lsp_ext, lsp_utils::invalid_params_error, - semantic_tokens, Result, + semantic_tokens, }; pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { @@ -429,7 +429,7 @@ pub(crate) fn inlay_hint( line_index: &LineIndex, render_colons: bool, mut inlay_hint: InlayHint, -) -> Result { +) -> Cancellable { match inlay_hint.kind { InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"), InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "), @@ -518,7 +518,7 @@ pub(crate) fn inlay_hint( fn inlay_hint_label( snap: &GlobalStateSnapshot, label: InlayHintLabel, -) -> Result { +) -> Cancellable { Ok(match label.as_simple_str() { Some(s) => lsp_types::InlayHintLabel::String(s.into()), None => lsp_types::InlayHintLabel::LabelParts( @@ -536,7 +536,7 @@ fn inlay_hint_label( command: None, }) }) - .collect::>>()?, + .collect::>>()?, ), }) } @@ -794,7 +794,7 @@ pub(crate) fn optional_versioned_text_document_identifier( pub(crate) fn location( snap: &GlobalStateSnapshot, frange: FileRange, -) -> Result { +) -> Cancellable { let url = url(snap, frange.file_id); let line_index = snap.file_line_index(frange.file_id)?; let range = range(&line_index, frange.range); @@ -806,7 +806,7 @@ pub(crate) fn location( pub(crate) fn location_from_nav( snap: &GlobalStateSnapshot, nav: NavigationTarget, -) -> Result { +) -> Cancellable { let url = url(snap, nav.file_id); let line_index = snap.file_line_index(nav.file_id)?; let range = range(&line_index, nav.full_range); @@ -818,7 +818,7 @@ pub(crate) fn location_link( snap: &GlobalStateSnapshot, src: Option, target: NavigationTarget, -) -> Result { +) -> Cancellable { let origin_selection_range = match src { Some(src) => { let line_index = snap.file_line_index(src.file_id)?; @@ -840,7 +840,7 @@ pub(crate) fn location_link( fn location_info( snap: &GlobalStateSnapshot, target: NavigationTarget, -) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { +) -> Cancellable<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { let line_index = snap.file_line_index(target.file_id)?; let target_uri = url(snap, target.file_id); @@ -854,12 +854,12 @@ pub(crate) fn goto_definition_response( snap: &GlobalStateSnapshot, src: Option, targets: Vec, -) -> Result { +) -> Cancellable { if snap.config.location_link() { let links = targets .into_iter() .map(|nav| location_link(snap, src, nav)) - .collect::>>()?; + .collect::>>()?; Ok(links.into()) } else { let locations = targets @@ -867,7 +867,7 @@ pub(crate) fn goto_definition_response( .map(|nav| { location(snap, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) }) - .collect::>>()?; + .collect::>>()?; Ok(locations.into()) } } @@ -881,7 +881,7 @@ pub(crate) fn snippet_text_document_edit( is_snippet: bool, file_id: FileId, edit: TextEdit, -) -> Result { +) -> Cancellable { let text_document = optional_versioned_text_document_identifier(snap, file_id); let line_index = snap.file_line_index(file_id)?; let mut edits: Vec<_> = @@ -958,7 +958,7 @@ pub(crate) fn snippet_text_document_ops( pub(crate) fn snippet_workspace_edit( snap: &GlobalStateSnapshot, source_change: SourceChange, -) -> Result { +) -> Cancellable { let mut document_changes: Vec = Vec::new(); for op in source_change.file_system_edits { @@ -995,7 +995,7 @@ pub(crate) fn snippet_workspace_edit( pub(crate) fn workspace_edit( snap: &GlobalStateSnapshot, source_change: SourceChange, -) -> Result { +) -> Cancellable { assert!(!source_change.is_snippet); snippet_workspace_edit(snap, source_change).map(|it| it.into()) } @@ -1048,7 +1048,7 @@ impl From pub(crate) fn call_hierarchy_item( snap: &GlobalStateSnapshot, target: NavigationTarget, -) -> Result { +) -> Cancellable { let name = target.name.to_string(); let detail = target.description.clone(); let kind = target.kind.map(symbol_kind).unwrap_or(lsp_types::SymbolKind::FUNCTION); @@ -1080,7 +1080,7 @@ pub(crate) fn code_action( snap: &GlobalStateSnapshot, assist: Assist, resolve_data: Option<(usize, lsp_types::CodeActionParams)>, -) -> Result { +) -> Cancellable { let mut res = lsp_ext::CodeAction { title: assist.label.to_string(), group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0), @@ -1113,13 +1113,13 @@ pub(crate) fn code_action( pub(crate) fn runnable( snap: &GlobalStateSnapshot, runnable: Runnable, -) -> Result { +) -> Cancellable { let config = snap.config.runnables(); let spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id)?; let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone()); let target = spec.as_ref().map(|s| s.target.clone()); let (cargo_args, executable_args) = - CargoTargetSpec::runnable_args(snap, spec, &runnable.kind, &runnable.cfg)?; + CargoTargetSpec::runnable_args(snap, spec, &runnable.kind, &runnable.cfg); let label = runnable.label(target); let location = location_link(snap, None, runnable.nav)?; @@ -1142,7 +1142,7 @@ pub(crate) fn code_lens( acc: &mut Vec, snap: &GlobalStateSnapshot, annotation: Annotation, -) -> Result<()> { +) -> Cancellable<()> { let client_commands_config = snap.config.client_commands(); match annotation.kind { AnnotationKind::Runnable(run) => { From 1cb6ab89eebb76953864b3d7fae8ed068fddc5a0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 17:43:22 +0100 Subject: [PATCH 0549/2442] internal: error instead of panic on invalid file range --- crates/rust-analyzer/src/from_proto.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index 936957bab488..dd433b0f4d31 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs @@ -42,8 +42,10 @@ pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> R pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Result { let start = offset(line_index, range.start)?; let end = offset(line_index, range.end)?; - let text_range = TextRange::new(start, end); - Ok(text_range) + match end < start { + true => Err(format_err!("Invalid Range").into()), + false => Ok(TextRange::new(start, end)), + } } pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result { From 90e2db81269f285cd1a0232e35cfd4519e8ce5f3 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 8 Nov 2022 08:37:45 +0100 Subject: [PATCH 0550/2442] fix: Fix item completions not working properly after unit structs and outline modules --- crates/ide-completion/src/context/analysis.rs | 8 +++-- crates/ide-completion/src/tests/item_list.rs | 32 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 04111ec7efaa..c142a7305f9e 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -681,9 +681,13 @@ fn classify_name_ref( ast::Item::ExternBlock(it) => it.extern_item_list().is_none(), ast::Item::Fn(it) => it.body().is_none(), ast::Item::Impl(it) => it.assoc_item_list().is_none(), - ast::Item::Module(it) => it.item_list().is_none(), + ast::Item::Module(it) => { + it.item_list().is_none() && it.semicolon_token().is_none() + } ast::Item::Static(it) => it.body().is_none(), - ast::Item::Struct(it) => it.field_list().is_none(), + ast::Item::Struct(it) => { + it.field_list().is_none() && it.semicolon_token().is_none() + } ast::Item::Trait(it) => it.assoc_item_list().is_none(), ast::Item::TypeAlias(it) => it.ty().is_none(), ast::Item::Union(it) => it.record_field_list().is_none(), diff --git a/crates/ide-completion/src/tests/item_list.rs b/crates/ide-completion/src/tests/item_list.rs index 5076c6e86cae..8ed6cb3cf867 100644 --- a/crates/ide-completion/src/tests/item_list.rs +++ b/crates/ide-completion/src/tests/item_list.rs @@ -245,3 +245,35 @@ impl Test for () { "#]], ); } + +#[test] +fn after_unit_struct() { + check( + r#"struct S; f$0"#, + expect![[r#" + ma makro!(…) macro_rules! makro + md module + kw const + kw crate:: + kw enum + kw extern + kw fn + kw impl + kw mod + kw pub + kw pub(crate) + kw pub(super) + kw self:: + kw static + kw struct + kw trait + kw type + kw union + kw unsafe + kw use + sn macro_rules + sn tfn (Test function) + sn tmod (Test module) + "#]], + ); +} From 4403dde711dd947670b1cf52e39c25a91edd9f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 8 Nov 2022 09:57:05 +0200 Subject: [PATCH 0551/2442] Nest Cargo.lock under Cargo.toml in Code --- editors/code/package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/editors/code/package.json b/editors/code/package.json index 4357dc73067f..9c9f120efa3d 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1276,6 +1276,11 @@ "$generated-end": {} } }, + "configurationDefaults": { + "explorer.fileNesting.patterns": { + "Cargo.toml": "Cargo.lock" + } + }, "problemPatterns": [ { "name": "rustc", From 9be0615bde83a4a67c8319bce31f5929239d2fd9 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 8 Nov 2022 18:05:07 +0100 Subject: [PATCH 0552/2442] Don't canonicalize self type when querying FnOnce signature --- crates/hir-ty/src/lib.rs | 48 +++++++++++++++----------------- crates/hir/src/lib.rs | 3 +- crates/ide/src/signature_help.rs | 31 +++++++++++++++++++++ 3 files changed, 54 insertions(+), 28 deletions(-) diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index ad33053ad095..39514fc44e6c 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -523,7 +523,7 @@ where } pub fn callable_sig_from_fnonce( - self_ty: &Canonical, + self_ty: &Ty, env: Arc, db: &dyn HirDatabase, ) -> Option { @@ -531,27 +531,28 @@ pub fn callable_sig_from_fnonce( let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; - let mut kinds = self_ty.binders.interned().to_vec(); let b = TyBuilder::trait_ref(db, fn_once_trait); if b.remaining() != 2 { return None; } - let fn_once = b - .push(self_ty.value.clone()) - .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) - .build(); - kinds.extend(fn_once.substitution.iter(Interner).skip(1).map(|x| { - let vk = match x.data(Interner) { - chalk_ir::GenericArgData::Ty(_) => { - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) - } - chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime, - chalk_ir::GenericArgData::Const(c) => { - chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()) - } - }; - chalk_ir::WithKind::new(vk, UniverseIndex::ROOT) - })); + let fn_once = b.push(self_ty.clone()).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build(); + let kinds = fn_once + .substitution + .iter(Interner) + .skip(1) + .map(|x| { + let vk = match x.data(Interner) { + chalk_ir::GenericArgData::Ty(_) => { + chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) + } + chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime, + chalk_ir::GenericArgData::Const(c) => { + chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()) + } + }; + chalk_ir::WithKind::new(vk, UniverseIndex::ROOT) + }) + .collect::>(); // FIXME: chalk refuses to solve `>::Output == ^0.1`, so we first solve // `>` and then replace `^0.0` with the concrete argument tuple. @@ -563,21 +564,16 @@ pub fn callable_sig_from_fnonce( Some(Solution::Unique(vars)) => vars.value.subst, _ => return None, }; - let args = subst.at(Interner, self_ty.binders.interned().len()).ty(Interner)?; + let args = subst.at(Interner, 0).ty(Interner)?; let params = match args.kind(Interner) { chalk_ir::TyKind::Tuple(_, subst) => { subst.iter(Interner).filter_map(|arg| arg.ty(Interner).cloned()).collect::>() } _ => return None, }; - if params.iter().any(|ty| ty.is_unknown()) { - return None; - } - let fn_once = TyBuilder::trait_ref(db, fn_once_trait) - .push(self_ty.value.clone()) - .push(args.clone()) - .build(); + let fn_once = + TyBuilder::trait_ref(db, fn_once_trait).push(self_ty.clone()).push(args.clone()).build(); let projection = TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution.clone())) .build(); diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 9d77f343bc57..cbbcaebb4285 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2997,8 +2997,7 @@ impl Type { TyKind::Function(_) => Callee::FnPtr, TyKind::FnDef(..) => Callee::Def(self.ty.callable_def(db)?), _ => { - let ty = hir_ty::replace_errors_with_variables(&self.ty); - let sig = hir_ty::callable_sig_from_fnonce(&ty, self.env.clone(), db)?; + let sig = hir_ty::callable_sig_from_fnonce(&self.ty, self.env.clone(), db)?; return Some(Callable { ty: self.clone(), sig, diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index 7486b20293a6..e7412d27faf4 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -1345,5 +1345,36 @@ fn f i32>(f: F) { ^^ --- "#]], ); + check( + r#" +fn f &T>(f: F) { + f($0) +} +"#, + expect![[r#" + (&T, u16) -> &T + ^^ --- + "#]], + ); + } + + #[test] + fn regression_13579() { + check( + r#" +fn f() { + take(2)($0); +} + +fn take( + count: C +) -> impl Fn() -> C { + move || count +} +"#, + expect![[r#" + () -> i32 + "#]], + ); } } From 3c35d44f55d0af18116a8403533f83c2ebb9bf6f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 9 Nov 2022 20:50:18 +0100 Subject: [PATCH 0553/2442] Add proc-macro dependency to rustc_private crates --- crates/project-model/src/workspace.rs | 77 ++++++++++++++++----------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 2780c62ed118..4a2f468de725 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -509,14 +509,14 @@ impl ProjectWorkspace { build_scripts, toolchain: _, } => cargo_to_crate_graph( - rustc_cfg.clone(), - cfg_overrides, load_proc_macro, load, - cargo, - build_scripts, - sysroot.as_ref(), rustc, + cargo, + sysroot.as_ref(), + rustc_cfg.clone(), + cfg_overrides, + build_scripts, ), ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) @@ -602,7 +602,7 @@ fn project_json_to_crate_graph( for (from, krate) in project.crates() { if let Some(&from) = crates.get(&from) { if let Some((public_deps, libproc_macro)) = &sysroot_deps { - public_deps.add(from, &mut crate_graph); + public_deps.add_to_crate_graph(&mut crate_graph, from); if krate.is_proc_macro { if let Some(proc_macro) = libproc_macro { add_dep( @@ -626,14 +626,14 @@ fn project_json_to_crate_graph( } fn cargo_to_crate_graph( - rustc_cfg: Vec, - override_cfg: &CfgOverrides, load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, - cargo: &CargoWorkspace, - build_scripts: &WorkspaceBuildScripts, - sysroot: Option<&Sysroot>, rustc: &Option, + cargo: &CargoWorkspace, + sysroot: Option<&Sysroot>, + rustc_cfg: Vec, + override_cfg: &CfgOverrides, + build_scripts: &WorkspaceBuildScripts, ) -> CrateGraph { let _p = profile::span("cargo_to_crate_graph"); let mut crate_graph = CrateGraph::default(); @@ -642,13 +642,15 @@ fn cargo_to_crate_graph( None => (SysrootPublicDeps::default(), None), }; - let mut cfg_options = CfgOptions::default(); - cfg_options.extend(rustc_cfg); + let cfg_options = { + let mut cfg_options = CfgOptions::default(); + cfg_options.extend(rustc_cfg); + cfg_options.insert_atom("debug_assertions".into()); + cfg_options + }; let mut pkg_to_lib_crate = FxHashMap::default(); - cfg_options.insert_atom("debug_assertions".into()); - let mut pkg_crates = FxHashMap::default(); // Does any crate signal to rust-analyzer that they need the rustc_private crates? let mut has_private = false; @@ -723,7 +725,7 @@ fn cargo_to_crate_graph( // Set deps to the core, std and to the lib target of the current package for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() { // Add sysroot deps first so that a lib target named `core` etc. can overwrite them. - public_deps.add(from, &mut crate_graph); + public_deps.add_to_crate_graph(&mut crate_graph, from); if let Some((to, name)) = lib_tgt.clone() { if to != from && kind != TargetKind::BuildScript { @@ -767,15 +769,16 @@ fn cargo_to_crate_graph( if let Some(rustc_workspace) = rustc { handle_rustc_crates( &mut crate_graph, - rustc_workspace, + &mut pkg_to_lib_crate, load, + load_proc_macro, + rustc_workspace, + cargo, + &public_deps, + libproc_macro, + &pkg_crates, &cfg_options, override_cfg, - load_proc_macro, - &mut pkg_to_lib_crate, - &public_deps, - cargo, - &pkg_crates, build_scripts, ); } @@ -825,28 +828,29 @@ fn detached_files_to_crate_graph( }, ); - public_deps.add(detached_file_crate, &mut crate_graph); + public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate); } crate_graph } fn handle_rustc_crates( crate_graph: &mut CrateGraph, - rustc_workspace: &CargoWorkspace, + pkg_to_lib_crate: &mut FxHashMap, load: &mut dyn FnMut(&AbsPath) -> Option, + load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, + rustc_workspace: &CargoWorkspace, + cargo: &CargoWorkspace, + public_deps: &SysrootPublicDeps, + libproc_macro: Option, + pkg_crates: &FxHashMap>, cfg_options: &CfgOptions, override_cfg: &CfgOverrides, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, - pkg_to_lib_crate: &mut FxHashMap, - public_deps: &SysrootPublicDeps, - cargo: &CargoWorkspace, - pkg_crates: &FxHashMap>, build_scripts: &WorkspaceBuildScripts, ) { let mut rustc_pkg_crates = FxHashMap::default(); // The root package of the rustc-dev component is rustc_driver, so we match that let root_pkg = - rustc_workspace.packages().find(|package| rustc_workspace[*package].name == "rustc_driver"); + rustc_workspace.packages().find(|&package| rustc_workspace[package].name == "rustc_driver"); // The rustc workspace might be incomplete (such as if rustc-dev is not // installed for the current toolchain) and `rustc_source` is set to discover. if let Some(root_pkg) = root_pkg { @@ -901,7 +905,16 @@ fn handle_rustc_crates( ); pkg_to_lib_crate.insert(pkg, crate_id); // Add dependencies on core / std / alloc for this crate - public_deps.add(crate_id, crate_graph); + public_deps.add_to_crate_graph(crate_graph, crate_id); + if let Some(proc_macro) = libproc_macro { + add_dep_with_prelude( + crate_graph, + crate_id, + CrateName::new("proc_macro").unwrap(), + proc_macro, + rustc_workspace[tgt].is_proc_macro, + ); + } rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); } } @@ -1009,7 +1022,7 @@ struct SysrootPublicDeps { impl SysrootPublicDeps { /// Makes `from` depend on the public sysroot crates. - fn add(&self, from: CrateId, crate_graph: &mut CrateGraph) { + fn add_to_crate_graph(&self, crate_graph: &mut CrateGraph, from: CrateId) { for (name, krate, prelude) in &self.deps { add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude); } From 4f415fc3489d5a8e910a035455d7d33f15928ed7 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 10 Nov 2022 19:22:20 +0900 Subject: [PATCH 0554/2442] Ignore outermost non-delimited `Subtree` when reversing fixups --- crates/hir-expand/src/fixup.rs | 42 ++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index 00b4cb3f9641..aab36f640efa 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -4,6 +4,7 @@ use std::mem; use mbe::{SyntheticToken, SyntheticTokenId, TokenMap}; use rustc_hash::FxHashMap; +use smallvec::SmallVec; use syntax::{ ast::{self, AstNode, HasLoopBody}, match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, @@ -292,21 +293,34 @@ pub(crate) fn reverse_fixups( token_map: &TokenMap, undo_info: &SyntaxFixupUndoInfo, ) { - tt.token_trees.retain(|tt| match tt { - tt::TokenTree::Leaf(leaf) => token_map.synthetic_token_id(leaf.id()) != Some(EMPTY_ID), - tt::TokenTree::Subtree(st) => { - st.delimiter.map_or(true, |d| token_map.synthetic_token_id(d.id) != Some(EMPTY_ID)) - } - }); - tt.token_trees.iter_mut().for_each(|tt| match tt { - tt::TokenTree::Subtree(tt) => reverse_fixups(tt, token_map, undo_info), - tt::TokenTree::Leaf(leaf) => { - if let Some(id) = token_map.synthetic_token_id(leaf.id()) { - let original = &undo_info.original[id.0 as usize]; - *tt = tt::TokenTree::Subtree(original.clone()); + let tts = std::mem::take(&mut tt.token_trees); + tt.token_trees = tts + .into_iter() + .filter(|tt| match tt { + tt::TokenTree::Leaf(leaf) => token_map.synthetic_token_id(leaf.id()) != Some(EMPTY_ID), + tt::TokenTree::Subtree(st) => { + st.delimiter.map_or(true, |d| token_map.synthetic_token_id(d.id) != Some(EMPTY_ID)) } - } - }); + }) + .flat_map(|tt| match tt { + tt::TokenTree::Subtree(mut tt) => { + reverse_fixups(&mut tt, token_map, undo_info); + SmallVec::from_const([tt.into()]) + } + tt::TokenTree::Leaf(leaf) => { + if let Some(id) = token_map.synthetic_token_id(leaf.id()) { + let original = undo_info.original[id.0 as usize].clone(); + if original.delimiter.is_none() { + original.token_trees.into() + } else { + SmallVec::from_const([original.into()]) + } + } else { + SmallVec::from_const([leaf.into()]) + } + } + }) + .collect(); } #[cfg(test)] From 5b070610118a98d96869af4cad79575d4edc5941 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 10 Nov 2022 19:24:01 +0900 Subject: [PATCH 0555/2442] Test `TokenTree`s' equality modulo `Punct`s' spacing --- crates/hir-expand/src/fixup.rs | 41 +++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index aab36f640efa..a4abe75626e6 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -329,6 +329,31 @@ mod tests { use super::reverse_fixups; + // The following three functions are only meant to check partial structural equivalence of + // `TokenTree`s, see the last assertion in `check()`. + fn check_leaf_eq(a: &tt::Leaf, b: &tt::Leaf) -> bool { + match (a, b) { + (tt::Leaf::Literal(a), tt::Leaf::Literal(b)) => a.text == b.text, + (tt::Leaf::Punct(a), tt::Leaf::Punct(b)) => a.char == b.char, + (tt::Leaf::Ident(a), tt::Leaf::Ident(b)) => a.text == b.text, + _ => false, + } + } + + fn check_subtree_eq(a: &tt::Subtree, b: &tt::Subtree) -> bool { + a.delimiter.map(|it| it.kind) == b.delimiter.map(|it| it.kind) + && a.token_trees.len() == b.token_trees.len() + && a.token_trees.iter().zip(&b.token_trees).all(|(a, b)| check_tt_eq(a, b)) + } + + fn check_tt_eq(a: &tt::TokenTree, b: &tt::TokenTree) -> bool { + match (a, b) { + (tt::TokenTree::Leaf(a), tt::TokenTree::Leaf(b)) => check_leaf_eq(a, b), + (tt::TokenTree::Subtree(a), tt::TokenTree::Subtree(b)) => check_subtree_eq(a, b), + _ => false, + } + } + #[track_caller] fn check(ra_fixture: &str, mut expect: Expect) { let parsed = syntax::SourceFile::parse(ra_fixture); @@ -341,8 +366,7 @@ mod tests { fixups.append, ); - let mut actual = tt.to_string(); - actual.push('\n'); + let actual = format!("{}\n", tt); expect.indent(false); expect.assert_eq(&actual); @@ -358,9 +382,12 @@ mod tests { reverse_fixups(&mut tt, &tmap, &fixups.undo_info); // the fixed-up + reversed version should be equivalent to the original input - // (but token IDs don't matter) + // modulo token IDs and `Punct`s' spacing. let (original_as_tt, _) = mbe::syntax_node_to_token_tree(&parsed.syntax_node()); - assert_eq!(tt.to_string(), original_as_tt.to_string()); + assert!( + check_subtree_eq(&tt, &original_as_tt), + "different token tree: {tt:?}, {original_as_tt:?}" + ); } #[test] @@ -483,7 +510,6 @@ fn foo () {a . __ra_fixup} } #[test] - #[ignore] fn incomplete_field_expr_2() { check( r#" @@ -492,13 +518,12 @@ fn foo() { } "#, expect![[r#" -fn foo () {a .__ra_fixup ;} +fn foo () {a . __ra_fixup ;} "#]], ) } #[test] - #[ignore] fn incomplete_field_expr_3() { check( r#" @@ -508,7 +533,7 @@ fn foo() { } "#, expect![[r#" -fn foo () {a .__ra_fixup ; bar () ;} +fn foo () {a . __ra_fixup ; bar () ;} "#]], ) } From dea49d082644cb3dbc7755849b6e3c325a6f32d9 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 11 Nov 2022 19:50:26 +0900 Subject: [PATCH 0556/2442] fix: check visibility of each segment in path resolution --- crates/hir-def/src/nameres/collector.rs | 4 +++ crates/hir-def/src/nameres/path_resolution.rs | 7 +++++ crates/hir-def/src/nameres/tests/globs.rs | 30 +++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 9ffc218818ca..b0dd01f9dbea 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -212,6 +212,7 @@ impl Import { #[derive(Debug, Eq, PartialEq)] struct ImportDirective { + /// The module this import directive is in. module_id: LocalModuleId, import: Import, status: PartialResolvedImport, @@ -963,8 +964,10 @@ impl DefCollector<'_> { fn update( &mut self, + // The module for which `resolutions` have been resolve module_id: LocalModuleId, resolutions: &[(Option, PerNs)], + // Visibility this import will have vis: Visibility, import_type: ImportType, ) { @@ -974,6 +977,7 @@ impl DefCollector<'_> { fn update_recursive( &mut self, + // The module for which `resolutions` have been resolve module_id: LocalModuleId, resolutions: &[(Option, PerNs)], // All resolutions are imported with this visibility; the visibilities in diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 8dfda6df64e7..20d39ec6cb92 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -73,7 +73,10 @@ impl DefMap { pub(crate) fn resolve_visibility( &self, db: &dyn DefDatabase, + // module to import to original_module: LocalModuleId, + // pub(path) + // ^^^^ this visibility: &RawVisibility, ) -> Option { let mut vis = match visibility { @@ -115,6 +118,7 @@ impl DefMap { &self, db: &dyn DefDatabase, mode: ResolveMode, + // module to import to mut original_module: LocalModuleId, path: &ModPath, shadow: BuiltinShadowMode, @@ -361,6 +365,9 @@ impl DefMap { ); } }; + + curr_per_ns = curr_per_ns + .filter_visibility(|vis| vis.is_visible_from_def_map(db, self, original_module)); } ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate)) diff --git a/crates/hir-def/src/nameres/tests/globs.rs b/crates/hir-def/src/nameres/tests/globs.rs index b2a6a592cf38..84d14e3b926b 100644 --- a/crates/hir-def/src/nameres/tests/globs.rs +++ b/crates/hir-def/src/nameres/tests/globs.rs @@ -336,3 +336,33 @@ mod d { "#]], ); } + +#[test] +fn glob_name_collision_check_visibility() { + check( + r#" +mod event { + mod serenity { + pub fn Event() {} + } + use serenity::*; + + pub struct Event {} +} + +use event::Event; + "#, + expect![[r#" + crate + Event: t + event: t + + crate::event + Event: t v + serenity: t + + crate::event::serenity + Event: v + "#]], + ); +} From e75afebeb243538ac85e4cb965bd40582f4c7b59 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 11 Nov 2022 19:56:47 +0900 Subject: [PATCH 0557/2442] Resolve invisible defs in `fix_visibility` assist --- .../src/handlers/fix_visibility.rs | 20 +++++++++++-------- crates/ide-assists/src/tests/generated.rs | 4 ++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/crates/ide-assists/src/handlers/fix_visibility.rs b/crates/ide-assists/src/handlers/fix_visibility.rs index 876454302870..d9e00435ecf5 100644 --- a/crates/ide-assists/src/handlers/fix_visibility.rs +++ b/crates/ide-assists/src/handlers/fix_visibility.rs @@ -1,4 +1,4 @@ -use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; +use hir::{db::HirDatabase, HasSource, HasVisibility, ModuleDef, PathResolution, ScopeDef}; use ide_db::base_db::FileId; use syntax::{ ast::{self, HasVisibility as _}, @@ -18,7 +18,7 @@ use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; // fn frobnicate() {} // } // fn main() { -// m::frobnicate$0() {} +// m::frobnicate$0(); // } // ``` // -> @@ -27,7 +27,7 @@ use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; // $0pub(crate) fn frobnicate() {} // } // fn main() { -// m::frobnicate() {} +// m::frobnicate(); // } // ``` pub(crate) fn fix_visibility(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { @@ -37,11 +37,15 @@ pub(crate) fn fix_visibility(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let path: ast::Path = ctx.find_node_at_offset()?; - let path_res = ctx.sema.resolve_path(&path)?; - let def = match path_res { - PathResolution::Def(def) => def, - _ => return None, - }; + let qualifier = path.qualifier()?; + let name_ref = path.segment()?.name_ref()?; + let qualifier_res = ctx.sema.resolve_path(&qualifier)?; + let PathResolution::Def(ModuleDef::Module(module)) = qualifier_res else { return None; }; + let (_, def) = module + .scope(ctx.db(), None) + .into_iter() + .find(|(name, _)| name.to_smol_str() == name_ref.text().as_str())?; + let ScopeDef::ModuleDef(def) = def else { return None; }; let current_module = ctx.sema.scope(path.syntax())?.module(); let target_module = def.module(ctx.db())?; diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 029d169899bb..c09317572acf 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -741,7 +741,7 @@ mod m { fn frobnicate() {} } fn main() { - m::frobnicate$0() {} + m::frobnicate$0(); } "#####, r#####" @@ -749,7 +749,7 @@ mod m { $0pub(crate) fn frobnicate() {} } fn main() { - m::frobnicate() {} + m::frobnicate(); } "#####, ) From 19306c070d5deb8afa6e9da21fcf22e5b7e24a11 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 11 Nov 2022 19:59:52 +0900 Subject: [PATCH 0558/2442] Fix tests that depended on loose visibility restriction --- crates/hir-def/src/nameres/tests.rs | 6 +-- crates/hir-def/src/nameres/tests/globs.rs | 3 +- .../src/nameres/tests/mod_resolution.rs | 2 +- crates/hir-ty/src/tests/method_resolution.rs | 40 +++++++++---------- crates/hir-ty/src/tests/simple.rs | 18 ++++----- crates/hir-ty/src/tests/traits.rs | 36 ++++++++--------- .../src/handlers/add_missing_impl_members.rs | 28 ++++++------- .../src/handlers/generate_enum_variant.rs | 12 +++--- .../src/handlers/generate_function.rs | 4 +- .../src/handlers/no_such_field.rs | 4 +- .../src/handlers/useless_braces.rs | 20 +++++----- crates/ide/src/goto_definition.rs | 6 +-- 12 files changed, 90 insertions(+), 89 deletions(-) diff --git a/crates/hir-def/src/nameres/tests.rs b/crates/hir-def/src/nameres/tests.rs index 70dd2eb3ade6..0d90047c28f6 100644 --- a/crates/hir-def/src/nameres/tests.rs +++ b/crates/hir-def/src/nameres/tests.rs @@ -58,9 +58,9 @@ extern { "#, expect![[r#" crate - E: t + E: _ S: t v - V: t v + V: _ foo: t crate::foo @@ -307,7 +307,7 @@ pub struct FromLib; Bar: t v crate::foo - Bar: t v + Bar: _ FromLib: t v "#]], ); diff --git a/crates/hir-def/src/nameres/tests/globs.rs b/crates/hir-def/src/nameres/tests/globs.rs index 84d14e3b926b..88a3c76393f0 100644 --- a/crates/hir-def/src/nameres/tests/globs.rs +++ b/crates/hir-def/src/nameres/tests/globs.rs @@ -119,7 +119,7 @@ use foo::*; use foo::bar::*; //- /foo/mod.rs -mod bar; +pub mod bar; fn Foo() {}; pub struct Foo {}; @@ -132,6 +132,7 @@ pub(crate) struct PubCrateStruct; crate Foo: t PubCrateStruct: t v + bar: t foo: t crate::foo diff --git a/crates/hir-def/src/nameres/tests/mod_resolution.rs b/crates/hir-def/src/nameres/tests/mod_resolution.rs index ba3bf8b5a5cf..c575bf7cac25 100644 --- a/crates/hir-def/src/nameres/tests/mod_resolution.rs +++ b/crates/hir-def/src/nameres/tests/mod_resolution.rs @@ -580,7 +580,7 @@ fn module_resolution_decl_inside_inline_module_in_crate_root() { //- /main.rs mod foo { #[path = "baz.rs"] - mod bar; + pub mod bar; } use self::foo::bar::Baz; diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs index ac8edb841a58..5d76d185ffc0 100644 --- a/crates/hir-ty/src/tests/method_resolution.rs +++ b/crates/hir-ty/src/tests/method_resolution.rs @@ -164,16 +164,16 @@ fn infer_associated_method_with_modules() { check_infer( r#" mod a { - struct A; + pub struct A; impl A { pub fn thing() -> A { A {} }} } mod b { - struct B; + pub struct B; impl B { pub fn thing() -> u32 { 99 }} - mod c { - struct C; + pub mod c { + pub struct C; impl C { pub fn thing() -> C { C {} }} } } @@ -186,22 +186,22 @@ fn infer_associated_method_with_modules() { } "#, expect![[r#" - 55..63 '{ A {} }': A - 57..61 'A {}': A - 125..131 '{ 99 }': u32 - 127..129 '99': u32 - 201..209 '{ C {} }': C - 203..207 'C {}': C - 240..324 '{ ...g(); }': () - 250..251 'x': A - 254..265 'a::A::thing': fn thing() -> A - 254..267 'a::A::thing()': A - 277..278 'y': u32 - 281..292 'b::B::thing': fn thing() -> u32 - 281..294 'b::B::thing()': u32 - 304..305 'z': C - 308..319 'c::C::thing': fn thing() -> C - 308..321 'c::C::thing()': C + 59..67 '{ A {} }': A + 61..65 'A {}': A + 133..139 '{ 99 }': u32 + 135..137 '99': u32 + 217..225 '{ C {} }': C + 219..223 'C {}': C + 256..340 '{ ...g(); }': () + 266..267 'x': A + 270..281 'a::A::thing': fn thing() -> A + 270..283 'a::A::thing()': A + 293..294 'y': u32 + 297..308 'b::B::thing': fn thing() -> u32 + 297..310 'b::B::thing()': u32 + 320..321 'z': C + 324..335 'c::C::thing': fn thing() -> C + 324..337 'c::C::thing()': C "#]], ); } diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index 080e2ac1b8e1..d7431443b83d 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -214,7 +214,7 @@ fn infer_paths() { fn a() -> u32 { 1 } mod b { - fn c() -> u32 { 1 } + pub fn c() -> u32 { 1 } } fn test() { @@ -225,13 +225,13 @@ fn test() { expect![[r#" 14..19 '{ 1 }': u32 16..17 '1': u32 - 47..52 '{ 1 }': u32 - 49..50 '1': u32 - 66..90 '{ ...c(); }': () - 72..73 'a': fn a() -> u32 - 72..75 'a()': u32 - 81..85 'b::c': fn c() -> u32 - 81..87 'b::c()': u32 + 51..56 '{ 1 }': u32 + 53..54 '1': u32 + 70..94 '{ ...c(); }': () + 76..77 'a': fn a() -> u32 + 76..79 'a()': u32 + 85..89 'b::c': fn c() -> u32 + 85..91 'b::c()': u32 "#]], ); } @@ -1856,7 +1856,7 @@ fn not_shadowing_module_by_primitive() { check_types( r#" //- /str.rs -fn foo() -> u32 {0} +pub fn foo() -> u32 {0} //- /main.rs mod str; diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 7d42b8b9bc8d..3d7194b6f446 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -1706,7 +1706,7 @@ fn where_clause_trait_in_scope_for_method_resolution() { check_types( r#" mod foo { - trait Trait { + pub trait Trait { fn foo(&self) -> u32 { 0 } } } @@ -1723,7 +1723,7 @@ fn super_trait_method_resolution() { check_infer( r#" mod foo { - trait SuperTrait { + pub trait SuperTrait { fn foo(&self) -> u32 {} } } @@ -1735,15 +1735,15 @@ fn test(x: T, y: U) { y.foo(); }"#, expect![[r#" - 49..53 'self': &Self - 62..64 '{}': u32 - 181..182 'x': T - 187..188 'y': U - 193..222 '{ ...o(); }': () - 199..200 'x': T - 199..206 'x.foo()': u32 - 212..213 'y': U - 212..219 'y.foo()': u32 + 53..57 'self': &Self + 66..68 '{}': u32 + 185..186 'x': T + 191..192 'y': U + 197..226 '{ ...o(); }': () + 203..204 'x': T + 203..210 'x.foo()': u32 + 216..217 'y': U + 216..223 'y.foo()': u32 "#]], ); } @@ -1754,7 +1754,7 @@ fn super_trait_impl_trait_method_resolution() { r#" //- minicore: sized mod foo { - trait SuperTrait { + pub trait SuperTrait { fn foo(&self) -> u32 {} } } @@ -1764,12 +1764,12 @@ fn test(x: &impl Trait1) { x.foo(); }"#, expect![[r#" - 49..53 'self': &Self - 62..64 '{}': u32 - 115..116 'x': &impl Trait1 - 132..148 '{ ...o(); }': () - 138..139 'x': &impl Trait1 - 138..145 'x.foo()': u32 + 53..57 'self': &Self + 66..68 '{}': u32 + 119..120 'x': &impl Trait1 + 136..152 '{ ...o(); }': () + 142..143 'x': &impl Trait1 + 142..149 'x.foo()': u32 "#]], ); } diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 62cf5ab4f37a..722302f991e2 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -379,14 +379,14 @@ impl Foo for S { r#" mod foo { pub struct Bar; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { $0 }"#, r#" mod foo { pub struct Bar; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { @@ -439,14 +439,14 @@ impl bar::Foo for S { r#" mod foo { pub struct Bar; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { $0 }"#, r#" mod foo { pub struct Bar; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { @@ -464,14 +464,14 @@ impl foo::Foo for S { r#" mod foo { pub struct Bar; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { $0 }"#, r#" mod foo { pub struct Bar; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { @@ -489,7 +489,7 @@ impl foo::Foo for S { add_missing_impl_members, r#" mod foo { - trait Foo { fn foo(&self, bar: T); } + pub trait Foo { fn foo(&self, bar: T); } pub struct Param; } struct Param; @@ -497,7 +497,7 @@ struct S; impl foo::Foo for S { $0 }"#, r#" mod foo { - trait Foo { fn foo(&self, bar: T); } + pub trait Foo { fn foo(&self, bar: T); } pub struct Param; } struct Param; @@ -518,7 +518,7 @@ impl foo::Foo for S { mod foo { pub struct Bar; impl Bar { type Assoc = u32; } - trait Foo { fn foo(&self, bar: Bar::Assoc); } + pub trait Foo { fn foo(&self, bar: Bar::Assoc); } } struct S; impl foo::Foo for S { $0 }"#, @@ -526,7 +526,7 @@ impl foo::Foo for S { $0 }"#, mod foo { pub struct Bar; impl Bar { type Assoc = u32; } - trait Foo { fn foo(&self, bar: Bar::Assoc); } + pub trait Foo { fn foo(&self, bar: Bar::Assoc); } } struct S; impl foo::Foo for S { @@ -545,7 +545,7 @@ impl foo::Foo for S { mod foo { pub struct Bar; pub struct Baz; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { $0 }"#, @@ -553,7 +553,7 @@ impl foo::Foo for S { $0 }"#, mod foo { pub struct Bar; pub struct Baz; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { @@ -571,14 +571,14 @@ impl foo::Foo for S { r#" mod foo { pub trait Fn { type Output; } - trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } + pub trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } } struct S; impl foo::Foo for S { $0 }"#, r#" mod foo { pub trait Fn { type Output; } - trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } + pub trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } } struct S; impl foo::Foo for S { diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index 35cd42908af2..0bcb5728311b 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -261,12 +261,12 @@ fn main() { } //- /foo.rs -enum Foo { +pub enum Foo { Bar, } ", r" -enum Foo { +pub enum Foo { Bar, Baz, } @@ -310,7 +310,7 @@ fn main() { generate_enum_variant, r" mod m { - enum Foo { + pub enum Foo { Bar, } } @@ -320,7 +320,7 @@ fn main() { ", r" mod m { - enum Foo { + pub enum Foo { Bar, Baz, } @@ -516,10 +516,10 @@ mod foo; use foo::Foo::Bar$0; //- /foo.rs -enum Foo {} +pub enum Foo {} ", r" -enum Foo { +pub enum Foo { Bar, } ", diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index c229127e48ff..57f198748cb7 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -1324,7 +1324,7 @@ fn foo() { generate_function, r" mod bar { - mod baz {} + pub mod baz {} } fn foo() { @@ -1333,7 +1333,7 @@ fn foo() { ", r" mod bar { - mod baz { + pub mod baz { pub(crate) fn my_fn() { ${0:todo!()} } diff --git a/crates/ide-diagnostics/src/handlers/no_such_field.rs b/crates/ide-diagnostics/src/handlers/no_such_field.rs index a80299106bd3..d8f2a9de9818 100644 --- a/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -268,12 +268,12 @@ fn main() { foo::Foo { bar: 3, $0baz: false}; } //- /foo.rs -struct Foo { +pub struct Foo { bar: i32 } "#, r#" -struct Foo { +pub struct Foo { bar: i32, pub(crate) baz: bool } diff --git a/crates/ide-diagnostics/src/handlers/useless_braces.rs b/crates/ide-diagnostics/src/handlers/useless_braces.rs index 8b9330e04013..289ed0458c67 100644 --- a/crates/ide-diagnostics/src/handlers/useless_braces.rs +++ b/crates/ide-diagnostics/src/handlers/useless_braces.rs @@ -71,9 +71,9 @@ use a; use a::{c, d::e}; mod a { - mod c {} - mod d { - mod e {} + pub mod c {} + pub mod d { + pub mod e {} } } "#, @@ -87,9 +87,9 @@ use a::{ }; mod a { - mod c {} - mod d { - mod e {} + pub mod c {} + pub mod d { + pub mod e {} } } "#, @@ -116,11 +116,11 @@ use b; ); check_fix( r#" -mod a { mod c {} } +mod a { pub mod c {} } use a::{c$0}; "#, r#" -mod a { mod c {} } +mod a { pub mod c {} } use a::c; "#, ); @@ -136,11 +136,11 @@ use a; ); check_fix( r#" -mod a { mod c {} mod d { mod e {} } } +mod a { pub mod c {} pub mod d { pub mod e {} } } use a::{c, d::{e$0}}; "#, r#" -mod a { mod c {} mod d { mod e {} } } +mod a { pub mod c {} pub mod d { pub mod e {} } } use a::{c, d::e}; "#, ); diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index f97c67b144ac..43f7a529bc29 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -289,10 +289,10 @@ mod b; enum E { X(Foo$0) } //- /a.rs -struct Foo; - //^^^ +pub struct Foo; + //^^^ //- /b.rs -struct Foo; +pub struct Foo; "#, ); } From e35836eb811a99872fdf63f1f0f1046ee651eeb0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 11 Nov 2022 13:00:22 +0100 Subject: [PATCH 0559/2442] Send status notification if there are no found workspaces --- crates/rust-analyzer/src/reload.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index e1f651786dee..407416d9f40f 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -106,6 +106,14 @@ impl GlobalState { status.health = lsp_ext::Health::Error; status.message = Some(error) } + + if self.config.linked_projects().is_empty() + && self.config.detached_files().is_empty() + && self.config.notifications().cargo_toml_not_found + { + status.health = lsp_ext::Health::Warning; + status.message = Some("Workspace reload required".to_string()) + } status } @@ -427,9 +435,14 @@ impl GlobalState { fn fetch_workspace_error(&self) -> Result<(), String> { let mut buf = String::new(); - for ws in self.fetch_workspaces_queue.last_op_result() { - if let Err(err) = ws { - stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err); + let last_op_result = self.fetch_workspaces_queue.last_op_result(); + if last_op_result.is_empty() { + stdx::format_to!(buf, "rust-analyzer failed to discover workspace"); + } else { + for ws in last_op_result { + if let Err(err) = ws { + stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err); + } } } From e50712cf2c115a1c287080b351f584edce49485b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 11 Nov 2022 13:38:07 +0100 Subject: [PATCH 0560/2442] fix: Fix hover in attributed items not preferring similar kinded tokens --- crates/ide/src/hover.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 3687b597fc64..838fb18c3d59 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -119,7 +119,14 @@ pub(crate) fn hover( }); } - let in_attr = matches!(original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind()))); + let in_attr = original_token + .parent_ancestors() + .filter_map(ast::Item::cast) + .any(|item| sema.is_attr_macro_call(&item)) + && !matches!( + original_token.parent().and_then(ast::TokenTree::cast), + Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind())) + ); // prefer descending the same token kind in attribute expansions, in normal macros text // equivalency is more important let descended = if in_attr { From c6c932d3f3b57b6e5e04321398e67326ebd1ce58 Mon Sep 17 00:00:00 2001 From: "Alexis (Poliorcetics) Bourget" Date: Sun, 25 Sep 2022 01:23:20 +0200 Subject: [PATCH 0561/2442] chore: Align config property --- crates/rust-analyzer/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index d642cd9b928e..25e341391a8f 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -120,7 +120,7 @@ config_data! { /// Compilation target override (target triple). cargo_target: Option = "null", /// Unsets `#[cfg(test)]` for the specified crates. - cargo_unsetTest: Vec = "[\"core\"]", + cargo_unsetTest: Vec = "[\"core\"]", /// Check all targets and tests (`--all-targets`). checkOnSave_allTargets: bool = "true", From 0d4737adb68704a9db802614f6ac9ba933d81f65 Mon Sep 17 00:00:00 2001 From: "Alexis (Poliorcetics) Bourget" Date: Sun, 25 Sep 2022 01:22:27 +0200 Subject: [PATCH 0562/2442] feat: Support passing multiple targets to cargo (for Rust 1.64.0+) --- crates/flycheck/src/lib.rs | 6 +-- crates/project-model/src/build_scripts.rs | 2 +- crates/project-model/src/cargo_workspace.rs | 52 +++++++++++++++------ crates/rust-analyzer/src/config.rs | 35 ++++++++++---- docs/user/generated_config.adoc | 10 ++-- editors/code/package.json | 17 +++++-- 6 files changed, 87 insertions(+), 35 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index ff507a52d550..8f93dad06e3f 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -40,7 +40,7 @@ pub enum InvocationLocation { pub enum FlycheckConfig { CargoCommand { command: String, - target_triple: Option, + target_triples: Vec, all_targets: bool, no_default_features: bool, all_features: bool, @@ -286,7 +286,7 @@ impl FlycheckActor { let (mut cmd, args) = match &self.config { FlycheckConfig::CargoCommand { command, - target_triple, + target_triples, no_default_features, all_targets, all_features, @@ -300,7 +300,7 @@ impl FlycheckActor { cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]) .arg(self.root.join("Cargo.toml").as_os_str()); - if let Some(target) = target_triple { + for target in target_triples { cmd.args(&["--target", target.as_str()]); } if *all_targets { diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index a26a7c57acfc..ae2b41f27d58 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -69,7 +69,7 @@ impl WorkspaceBuildScripts { cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]); // --all-targets includes tests, benches and examples in addition to the - // default lib and bins. This is an independent concept from the --targets + // default lib and bins. This is an independent concept from the --target // flag below. cmd.arg("--all-targets"); diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index b4c2ba436772..02ec7a4f6f99 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -270,11 +270,7 @@ impl CargoWorkspace { config: &CargoConfig, progress: &dyn Fn(String), ) -> Result { - let target = config - .target - .clone() - .or_else(|| cargo_config_build_target(cargo_toml, &config.extra_env)) - .or_else(|| rustc_discover_host_triple(cargo_toml, &config.extra_env)); + let targets = find_list_of_build_targets(config, cargo_toml); let mut meta = MetadataCommand::new(); meta.cargo_path(toolchain::cargo()); @@ -294,8 +290,12 @@ impl CargoWorkspace { } meta.current_dir(current_dir.as_os_str()); - if let Some(target) = target { - meta.other_options(vec![String::from("--filter-platform"), target]); + if !targets.is_empty() { + let other_options: Vec<_> = targets + .into_iter() + .flat_map(|target| ["--filter-platform".to_string(), target]) + .collect(); + meta.other_options(other_options); } // FIXME: Fetching metadata is a slow process, as it might require @@ -469,6 +469,19 @@ impl CargoWorkspace { } } +fn find_list_of_build_targets(config: &CargoConfig, cargo_toml: &ManifestPath) -> Vec { + if let Some(target) = &config.target { + return [target.into()].to_vec(); + } + + let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env); + if !build_targets.is_empty() { + return build_targets; + } + + rustc_discover_host_triple(cargo_toml, &config.extra_env).into_iter().collect() +} + fn rustc_discover_host_triple( cargo_toml: &ManifestPath, extra_env: &FxHashMap, @@ -499,7 +512,7 @@ fn rustc_discover_host_triple( fn cargo_config_build_target( cargo_toml: &ManifestPath, extra_env: &FxHashMap, -) -> Option { +) -> Vec { let mut cargo_config = Command::new(toolchain::cargo()); cargo_config.envs(extra_env); cargo_config @@ -507,12 +520,21 @@ fn cargo_config_build_target( .args(&["-Z", "unstable-options", "config", "get", "build.target"]) .env("RUSTC_BOOTSTRAP", "1"); // if successful we receive `build.target = "target-triple"` + // or `build.target = ["", ..]` tracing::debug!("Discovering cargo config target by {:?}", cargo_config); - match utf8_stdout(cargo_config) { - Ok(stdout) => stdout - .strip_prefix("build.target = \"") - .and_then(|stdout| stdout.strip_suffix('"')) - .map(ToOwned::to_owned), - Err(_) => None, - } + utf8_stdout(cargo_config).map(parse_output_cargo_config_build_target).unwrap_or_default() +} + +fn parse_output_cargo_config_build_target(stdout: String) -> Vec { + let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"'); + + if !trimmed.starts_with('[') { + return [trimmed.to_string()].to_vec(); + } + + let res = serde_json::from_str(trimmed); + if let Err(e) = &res { + tracing::warn!("Failed to parse `build.target` as an array of target: {}`", e); + } + res.unwrap_or_default() } diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 25e341391a8f..6b2f22faa717 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -118,6 +118,8 @@ config_data! { /// This option does not take effect until rust-analyzer is restarted. cargo_sysroot: Option = "\"discover\"", /// Compilation target override (target triple). + // FIXME(@poliorcetics): move to multiple targets here too, but this will need more work + // than `checkOnSave_target` cargo_target: Option = "null", /// Unsets `#[cfg(test)]` for the specified crates. cargo_unsetTest: Vec = "[\"core\"]", @@ -174,9 +176,13 @@ config_data! { /// ``` /// . checkOnSave_overrideCommand: Option> = "null", - /// Check for a specific target. Defaults to - /// `#rust-analyzer.cargo.target#`. - checkOnSave_target: Option = "null", + /// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. + /// + /// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. + /// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`. + /// + /// Aliased as `"checkOnSave.targets"`. + checkOnSave_target | checkOnSave_targets: CheckOnSaveTargets = "[]", /// Toggles the additional completions that automatically add imports when completed. /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. @@ -1147,11 +1153,10 @@ impl Config { } Some(_) | None => FlycheckConfig::CargoCommand { command: self.data.checkOnSave_command.clone(), - target_triple: self - .data - .checkOnSave_target - .clone() - .or_else(|| self.data.cargo_target.clone()), + target_triples: match &self.data.checkOnSave_target.0[..] { + [] => self.data.cargo_target.clone().into_iter().collect(), + targets => targets.into(), + }, all_targets: self.data.checkOnSave_allTargets, no_default_features: self .data @@ -1657,6 +1662,9 @@ enum InvocationStrategy { PerWorkspace, } +#[derive(Deserialize, Debug, Clone)] +struct CheckOnSaveTargets(#[serde(deserialize_with = "single_or_array")] Vec); + #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "snake_case")] enum InvocationLocation { @@ -2118,6 +2126,17 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json "The command will be executed in the project root." ], }, + "CheckOnSaveTargets" => set! { + "anyOf": [ + { + "type": "string", + }, + { + "type": "array", + "items": { "type": "string" } + }, + ], + }, _ => panic!("missing entry for {}: {}", ty, default), } diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index da8e62980789..57f950034cbb 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -190,11 +190,15 @@ cargo check --workspace --message-format=json --all-targets ``` . -- -[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `null`):: +[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `[]`):: + -- -Check for a specific target. Defaults to -`#rust-analyzer.cargo.target#`. +Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. + +Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. +`["aarch64-apple-darwin", "x86_64-apple-darwin"]`. + +Aliased as `"checkOnSave.targets"`. -- [[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`):: + diff --git a/editors/code/package.json b/editors/code/package.json index 0c7816596042..762726842f95 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -634,11 +634,18 @@ } }, "rust-analyzer.checkOnSave.target": { - "markdownDescription": "Check for a specific target. Defaults to\n`#rust-analyzer.cargo.target#`.", - "default": null, - "type": [ - "null", - "string" + "markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.", + "default": [], + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } ] }, "rust-analyzer.completion.autoimport.enable": { From a143ff0248320bfd234aad0d93f2a59baf78216f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 11 Nov 2022 14:36:27 +0100 Subject: [PATCH 0563/2442] fix: Fix r-a eagerly showing no discovered workspace errors --- crates/rust-analyzer/src/global_state.rs | 2 +- crates/rust-analyzer/src/main_loop.rs | 2 +- crates/rust-analyzer/src/reload.rs | 11 ++++------- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 74277ff2e576..4e8bc8d6462c 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -100,7 +100,7 @@ pub(crate) struct GlobalState { /// the user just adds comments or whitespace to Cargo.toml, we do not want /// to invalidate any salsa caches. pub(crate) workspaces: Arc>, - pub(crate) fetch_workspaces_queue: OpQueue>>, + pub(crate) fetch_workspaces_queue: OpQueue>>>, pub(crate) fetch_build_data_queue: OpQueue<(Arc>, Vec>)>, diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 6e5da58fe372..274588ce0e07 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -451,7 +451,7 @@ impl GlobalState { ProjectWorkspaceProgress::Begin => (Progress::Begin, None), ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)), ProjectWorkspaceProgress::End(workspaces) => { - self.fetch_workspaces_queue.op_completed(workspaces); + self.fetch_workspaces_queue.op_completed(Some(workspaces)); let old = Arc::clone(&self.workspaces); self.switch_workspaces("fetched workspace".to_string()); diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 407416d9f40f..aa0510a4ea6a 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -206,12 +206,9 @@ impl GlobalState { self.show_and_log_error("failed to run build scripts".to_string(), Some(error)); } - let workspaces = self - .fetch_workspaces_queue - .last_op_result() - .iter() - .filter_map(|res| res.as_ref().ok().cloned()) - .collect::>(); + let Some(workspaces) = self.fetch_workspaces_queue.last_op_result() else { return; }; + let workspaces = + workspaces.iter().filter_map(|res| res.as_ref().ok().cloned()).collect::>(); fn eq_ignore_build_data<'a>( left: &'a ProjectWorkspace, @@ -435,7 +432,7 @@ impl GlobalState { fn fetch_workspace_error(&self) -> Result<(), String> { let mut buf = String::new(); - let last_op_result = self.fetch_workspaces_queue.last_op_result(); + let Some(last_op_result) = self.fetch_workspaces_queue.last_op_result() else { return Ok(()) }; if last_op_result.is_empty() { stdx::format_to!(buf, "rust-analyzer failed to discover workspace"); } else { From 6674bd898ed0e85fd61dba2b018144477ef6347c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 11 Nov 2022 15:25:15 +0100 Subject: [PATCH 0564/2442] fix: Add trait alias grammar to rust.ungram --- crates/hir-def/src/data.rs | 18 +++++++++++++----- crates/hir-def/src/item_tree.rs | 3 ++- crates/hir-def/src/item_tree/lower.rs | 10 +--------- crates/hir-def/src/item_tree/pretty.rs | 19 ++++++++++++++----- crates/syntax/rust.ungram | 7 +++++-- crates/syntax/src/ast/generated/nodes.rs | 2 ++ 6 files changed, 37 insertions(+), 22 deletions(-) diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 2dc69b00ace0..9c7696908648 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -236,11 +236,19 @@ impl TraitData { .by_key("rustc_skip_array_during_method_dispatch") .exists(); - let mut collector = - AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr)); - collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items); - let (items, attribute_calls, diagnostics) = collector.finish(); - + let (items, attribute_calls, diagnostics) = match &tr_def.items { + Some(items) => { + let mut collector = AssocItemCollector::new( + db, + module_id, + tree_id.file_id(), + ItemContainerId::TraitId(tr), + ); + collector.collect(&item_tree, tree_id.tree_id(), items); + collector.finish() + } + None => Default::default(), + }; ( Arc::new(TraitData { name, diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 570344596def..0aa531eff71f 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -666,7 +666,8 @@ pub struct Trait { pub generic_params: Interned, pub is_auto: bool, pub is_unsafe: bool, - pub items: Box<[AssocItem]>, + /// This is [`None`] if this Trait is a trait alias. + pub items: Option>, pub ast_id: FileAstId, } diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 79249757d9e9..b25274bccc9a 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -451,15 +451,7 @@ impl<'a> Ctx<'a> { .collect() }); let ast_id = self.source_ast_id_map.ast_id(trait_def); - let res = Trait { - name, - visibility, - generic_params, - is_auto, - is_unsafe, - items: items.unwrap_or_default(), - ast_id, - }; + let res = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id }; Some(id(self.data().traits.alloc(res))) } diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index da1643152c2f..48c40df22ff5 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -375,12 +375,21 @@ impl<'a> Printer<'a> { } w!(self, "trait {}", name); self.print_generic_params(generic_params); - self.print_where_clause_and_opening_brace(generic_params); - self.indented(|this| { - for item in &**items { - this.print_mod_item((*item).into()); + match items { + Some(items) => { + self.print_where_clause_and_opening_brace(generic_params); + self.indented(|this| { + for item in &**items { + this.print_mod_item((*item).into()); + } + }); } - }); + None => { + w!(self, " = "); + // FIXME: Print the aliased traits + self.print_where_clause_and_opening_brace(generic_params); + } + } wln!(self, "}}"); } ModItem::Impl(it) => { diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 5379732ac6c3..0a0cb0290d6c 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -239,8 +239,11 @@ Static = Trait = Attr* Visibility? 'unsafe'? 'auto'? - 'trait' Name GenericParamList? (':' TypeBoundList?)? WhereClause? - AssocItemList + 'trait' Name GenericParamList? + ( + (':' TypeBoundList?)? WhereClause? AssocItemList + | '=' TypeBoundList? WhereClause? ';' + ) AssocItemList = '{' Attr* AssocItem* '}' diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 6cfb98d92fcf..2ea715f47fb2 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -407,6 +407,8 @@ impl Trait { pub fn auto_token(&self) -> Option { support::token(&self.syntax, T![auto]) } pub fn trait_token(&self) -> Option { support::token(&self.syntax, T![trait]) } pub fn assoc_item_list(&self) -> Option { support::child(&self.syntax) } + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] From 6b4b7d81e461b758a5785e2f8ac6eea0ed71e6f2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 11 Nov 2022 16:57:05 +0100 Subject: [PATCH 0565/2442] internal: Add version info to unsupported proc macro abi error --- crates/proc-macro-srv/src/abis/mod.rs | 2 +- crates/proc-macro-srv/src/dylib.rs | 4 ++-- crates/proc-macro-srv/src/lib.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/proc-macro-srv/src/abis/mod.rs b/crates/proc-macro-srv/src/abis/mod.rs index 2f854bc15954..0ce099ae0bab 100644 --- a/crates/proc-macro-srv/src/abis/mod.rs +++ b/crates/proc-macro-srv/src/abis/mod.rs @@ -117,7 +117,7 @@ impl Abi { let inner = unsafe { Abi_1_63::from_lib(lib, symbol_name) }?; Ok(Abi::Abi1_63(inner)) } - _ => Err(LoadProcMacroDylibError::UnsupportedABI), + _ => Err(LoadProcMacroDylibError::UnsupportedABI(info.version_string.clone())), } } diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs index 7aba74e5396d..0722cd89d729 100644 --- a/crates/proc-macro-srv/src/dylib.rs +++ b/crates/proc-macro-srv/src/dylib.rs @@ -80,14 +80,14 @@ fn load_library(file: &Path) -> Result { pub enum LoadProcMacroDylibError { Io(io::Error), LibLoading(libloading::Error), - UnsupportedABI, + UnsupportedABI(String), } impl fmt::Display for LoadProcMacroDylibError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Io(e) => e.fmt(f), - Self::UnsupportedABI => write!(f, "unsupported ABI version"), + Self::UnsupportedABI(v) => write!(f, "unsupported ABI `{v}`"), Self::LibLoading(e) => e.fmt(f), } } diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index 72a2dfe72d37..b4f5ebd157f3 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -113,12 +113,12 @@ impl ProcMacroSrv { fn expander(&mut self, path: &Path) -> Result<&dylib::Expander, String> { let time = fs::metadata(path).and_then(|it| it.modified()).map_err(|err| { - format!("Failed to get file metadata for {}: {:?}", path.display(), err) + format!("Failed to get file metadata for {}: {}", path.display(), err) })?; Ok(match self.expanders.entry((path.to_path_buf(), time)) { Entry::Vacant(v) => v.insert(dylib::Expander::new(path).map_err(|err| { - format!("Cannot create expander for {}: {:?}", path.display(), err) + format!("Cannot create expander for {}: {}", path.display(), err) })?), Entry::Occupied(e) => e.into_mut(), }) From f26d5484d89bd41e4fe89367fc4d13463d498d8b Mon Sep 17 00:00:00 2001 From: yue4u Date: Sat, 12 Nov 2022 22:33:40 +0900 Subject: [PATCH 0566/2442] fix: filter unnecessary completions after colon --- crates/ide-completion/src/context.rs | 42 ++++++++- crates/ide-completion/src/lib.rs | 1 - crates/ide-completion/src/tests/attribute.rs | 24 +++++ crates/ide-completion/src/tests/special.rs | 97 +++++++++++++++++++- crates/rust-analyzer/src/handlers.rs | 14 +-- 5 files changed, 162 insertions(+), 16 deletions(-) diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 9850813a0ce1..27f6745d2417 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -19,7 +19,7 @@ use syntax::{ ast::{self, AttrKind, NameOrNameRef}, AstNode, SyntaxKind::{self, *}, - SyntaxToken, TextRange, TextSize, + SyntaxToken, TextRange, TextSize, T, }; use text_edit::Indel; @@ -569,6 +569,28 @@ impl<'a> CompletionContext<'a> { // completing on let original_token = original_file.syntax().token_at_offset(offset).left_biased()?; + // try to skip completions on path with qinvalid colons + // this approach works in normal path and inside token tree + match original_token.kind() { + T![:] => { + // return if no prev token before colon + let prev_token = original_token.prev_token()?; + + // only has a single colon + if prev_token.kind() != T![:] { + return None; + } + + if !is_prev_token_valid_path_start_or_segment(&prev_token) { + return None; + } + } + T![::] if !is_prev_token_valid_path_start_or_segment(&original_token) => { + return None; + } + _ => {} + } + let AnalysisResult { analysis, expected: (expected_type, expected_name), @@ -618,6 +640,24 @@ impl<'a> CompletionContext<'a> { } } +fn is_prev_token_valid_path_start_or_segment(token: &SyntaxToken) -> bool { + if let Some(prev_token) = token.prev_token() { + // token before coloncolon is invalid + if !matches!( + prev_token.kind(), + // trival + WHITESPACE | COMMENT + // PathIdentSegment + | IDENT | T![super] | T![self] | T![Self] | T![crate] + // QualifiedPath + | T![>] + ) { + return false; + } + } + true +} + const OP_TRAIT_LANG_NAMES: &[&str] = &[ "add_assign", "add", diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs index 9d0044e55f59..4b48ec6bc339 100644 --- a/crates/ide-completion/src/lib.rs +++ b/crates/ide-completion/src/lib.rs @@ -164,7 +164,6 @@ pub fn completions( completions::vis::complete_vis_path(&mut completions, ctx, path_ctx, has_in_token); } } - // prevent `(` from triggering unwanted completion noise return Some(completions.into()); } diff --git a/crates/ide-completion/src/tests/attribute.rs b/crates/ide-completion/src/tests/attribute.rs index 1578ba2c3771..4e60820dd6d6 100644 --- a/crates/ide-completion/src/tests/attribute.rs +++ b/crates/ide-completion/src/tests/attribute.rs @@ -607,6 +607,30 @@ fn attr_in_source_file_end() { ); } +#[test] +fn invalid_path() { + check( + r#" +//- proc_macros: identity +#[proc_macros:::$0] +struct Foo; +"#, + expect![[r#""#]], + ); + + check( + r#" +//- minicore: derive, copy +mod foo { + pub use Copy as Bar; +} +#[derive(foo:::::$0)] +struct Foo; +"#, + expect![""], + ); +} + mod cfg { use super::*; diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index 033dc99c26cf..1aea5d89b4a0 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -2,13 +2,22 @@ use expect_test::{expect, Expect}; -use crate::tests::{check_edit, completion_list_no_kw}; +use crate::tests::{check_edit, completion_list_no_kw, completion_list_with_trigger_character}; fn check(ra_fixture: &str, expect: Expect) { let actual = completion_list_no_kw(ra_fixture); expect.assert_eq(&actual) } +pub(crate) fn check_with_trigger_character( + ra_fixture: &str, + trigger_character: Option, + expect: Expect, +) { + let actual = completion_list_with_trigger_character(ra_fixture, trigger_character); + expect.assert_eq(&actual) +} + #[test] fn completes_if_prefix_is_keyword() { check_edit( @@ -893,3 +902,89 @@ fn f() { "#]], ); } + +#[test] +fn completes_after_colon_with_trigger() { + check_with_trigger_character( + r#" +//- minicore: option +fn foo { ::$0 } +"#, + Some(':'), + expect![[r#" + md core + "#]], + ); + check_with_trigger_character( + r#" +//- minicore: option +fn foo { /* test */::$0 } +"#, + Some(':'), + expect![[r#" + md core + "#]], + ); + + check_with_trigger_character( + r#" +fn foo { crate::$0 } +"#, + Some(':'), + expect![[r#" + fn foo() fn() + "#]], + ); + + check_with_trigger_character( + r#" +fn foo { crate:$0 } +"#, + Some(':'), + expect![""], + ); +} + +#[test] +fn completes_after_colon_without_trigger() { + check_with_trigger_character( + r#" +fn foo { crate::$0 } +"#, + None, + expect![[r#" + fn foo() fn() + "#]], + ); + + check_with_trigger_character( + r#" +fn foo { crate:$0 } +"#, + None, + expect![""], + ); +} + +#[test] +fn no_completions_in_invalid_path() { + check( + r#" +fn foo { crate:::$0 } +"#, + expect![""], + ); + check( + r#" +fn foo { crate::::$0 } +"#, + expect![""], + ); + + check( + r#" +fn foo { crate:::::$0 } +"#, + expect![""], + ); +} diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index d190a9f4e2ca..4f318f39de5f 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -28,7 +28,7 @@ use lsp_types::{ use project_model::{ManifestPath, ProjectWorkspace, TargetKind}; use serde_json::json; use stdx::{format_to, never}; -use syntax::{algo, ast, AstNode, TextRange, TextSize, T}; +use syntax::{algo, ast, AstNode, TextRange, TextSize}; use vfs::AbsPathBuf; use crate::{ @@ -812,18 +812,6 @@ pub(crate) fn handle_completion( let completion_trigger_character = params.context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next()); - if Some(':') == completion_trigger_character { - let source_file = snap.analysis.parse(position.file_id)?; - let left_token = source_file.syntax().token_at_offset(position.offset).left_biased(); - let completion_triggered_after_single_colon = match left_token { - Some(left_token) => left_token.kind() == T![:], - None => true, - }; - if completion_triggered_after_single_colon { - return Ok(None); - } - } - let completion_config = &snap.config.completion(); let items = match snap.analysis.completions( completion_config, From 46417add8ddc623f8abb8e96861dba721044f656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sun, 13 Nov 2022 22:23:56 +0100 Subject: [PATCH 0567/2442] Update several crates to bring support for the new Tier 3 Windows targets --- Cargo.lock | 92 ++++++++++++++++++++++++------------------ crates/stdx/Cargo.toml | 2 +- 2 files changed, 54 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c04906c45383..41c5d36671de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -310,7 +310,7 @@ dependencies = [ "hashbrown", "lock_api", "once_cell", - "parking_lot_core 0.9.3", + "parking_lot_core 0.9.4", ] [[package]] @@ -369,14 +369,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" +checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -974,11 +974,11 @@ dependencies = [ [[package]] name = "miow" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7377f7792b3afb6a3cba68daa54ca23c032137010460d667fda53a8d66be00e" +checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123" dependencies = [ - "windows-sys 0.28.0", + "windows-sys 0.42.0", ] [[package]] @@ -1061,7 +1061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.3", + "parking_lot_core 0.9.4", ] [[package]] @@ -1080,15 +1080,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -2003,19 +2003,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6" -dependencies = [ - "windows_aarch64_msvc 0.28.0", - "windows_i686_gnu 0.28.0", - "windows_i686_msvc 0.28.0", - "windows_x86_64_gnu 0.28.0", - "windows_x86_64_msvc 0.28.0", -] - [[package]] name = "windows-sys" version = "0.36.1" @@ -2030,10 +2017,25 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_msvc" -version = "0.28.0" +name = "windows-sys" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" [[package]] name = "windows_aarch64_msvc" @@ -2042,10 +2044,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] -name = "windows_i686_gnu" -version = "0.28.0" +name = "windows_aarch64_msvc" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" [[package]] name = "windows_i686_gnu" @@ -2054,10 +2056,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] -name = "windows_i686_msvc" -version = "0.28.0" +name = "windows_i686_gnu" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" [[package]] name = "windows_i686_msvc" @@ -2066,10 +2068,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] -name = "windows_x86_64_gnu" -version = "0.28.0" +name = "windows_i686_msvc" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" [[package]] name = "windows_x86_64_gnu" @@ -2078,10 +2080,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] -name = "windows_x86_64_msvc" -version = "0.28.0" +name = "windows_x86_64_gnu" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" [[package]] name = "windows_x86_64_msvc" @@ -2089,6 +2097,12 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + [[package]] name = "write-json" version = "0.1.2" diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml index 957d16c036fa..f7b7d09640ff 100644 --- a/crates/stdx/Cargo.toml +++ b/crates/stdx/Cargo.toml @@ -16,7 +16,7 @@ always-assert = { version = "0.1.2", features = ["log"] } # Think twice before adding anything here [target.'cfg(windows)'.dependencies] -miow = "0.4.0" +miow = "0.5.0" winapi = { version = "0.3.9", features = ["winerror"] } [features] From 15dfeabb96b370e9fab1ddbb8b39a9dcefc3764b Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 15 Nov 2022 12:05:11 +0100 Subject: [PATCH 0568/2442] Fix GAT completion not including generic parameters --- .../src/completions/item_list/trait_impl.rs | 77 +++++++++++++++---- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs index e82cbfdcb840..b612cdc4a174 100644 --- a/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -157,7 +157,7 @@ fn complete_trait_impl( add_function_impl(acc, ctx, replacement_range, func, hir_impl) } (hir::AssocItem::TypeAlias(type_alias), All | TypeAlias) => { - add_type_alias_impl(acc, ctx, replacement_range, type_alias) + add_type_alias_impl(acc, ctx, replacement_range, type_alias, hir_impl) } (hir::AssocItem::Const(const_), All | Const) => { add_const_impl(acc, ctx, replacement_range, const_, hir_impl) @@ -247,24 +247,50 @@ fn add_type_alias_impl( ctx: &CompletionContext<'_>, replacement_range: TextRange, type_alias: hir::TypeAlias, + impl_def: hir::Impl, ) { - let alias_name = type_alias.name(ctx.db); - let (alias_name, escaped_name) = - (alias_name.unescaped().to_smol_str(), alias_name.to_smol_str()); + let alias_name = type_alias.name(ctx.db).unescaped().to_smol_str(); let label = format!("type {} =", alias_name); - let replacement = format!("type {} = ", escaped_name); let mut item = CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label); item.lookup_by(format!("type {}", alias_name)) .set_documentation(type_alias.docs(ctx.db)) .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); - match ctx.config.snippet_cap { - Some(cap) => item - .snippet_edit(cap, TextEdit::replace(replacement_range, format!("{}$0;", replacement))), - None => item.text_edit(TextEdit::replace(replacement_range, replacement)), - }; - item.add_to(acc); + + if let Some(source) = ctx.sema.source(type_alias) { + let assoc_item = ast::AssocItem::TypeAlias(source.value); + if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { + let transformed_ty = match transformed_item { + ast::AssocItem::TypeAlias(ty) => ty, + _ => unreachable!(), + }; + + let start = transformed_ty.syntax().text_range().start(); + let Some(end) = transformed_ty + .eq_token() + .map(|tok| tok.text_range().start()) + .or(transformed_ty.semicolon_token().map(|tok| tok.text_range().start())) else { return }; + + let len = end - start; + let mut decl = transformed_ty.syntax().text().slice(..len).to_string(); + if !decl.ends_with(' ') { + decl.push(' '); + } + decl.push_str("= "); + + match ctx.config.snippet_cap { + Some(cap) => { + let snippet = format!("{}$0;", decl); + item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet)); + } + None => { + item.text_edit(TextEdit::replace(replacement_range, decl)); + } + }; + item.add_to(acc); + } + } } fn add_const_impl( @@ -350,9 +376,7 @@ fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String { .map_or(end, |f| f.text_range().start()); let len = end - start; - let range = TextRange::new(0.into(), len); - - let syntax = node.text().slice(range).to_string(); + let syntax = node.text().slice(..len).to_string(); syntax.trim_end().to_owned() } @@ -1160,6 +1184,31 @@ impl Foo for Test { $0 } } +"#, + ); + } + + #[test] + fn includes_gat_generics() { + check_edit( + "type Ty", + r#" +trait Tr<'b> { + type Ty<'a: 'b, T: Copy, const C: usize>; +} + +impl<'b> Tr<'b> for () { + $0 +} +"#, + r#" +trait Tr<'b> { + type Ty<'a: 'b, T: Copy, const C: usize>; +} + +impl<'b> Tr<'b> for () { + type Ty<'a: 'b, T: Copy, const C: usize> = $0; +} "#, ); } From 7e77d4e310fa36c9ede7905be5971776a075be16 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 15 Nov 2022 12:41:39 +0100 Subject: [PATCH 0569/2442] Strip comments and attributes off of all trait item completions --- .../src/completions/item_list/trait_impl.rs | 82 +++++++++++++++++-- 1 file changed, 76 insertions(+), 6 deletions(-) diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs index b612cdc4a174..7384a3f2d80b 100644 --- a/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -236,9 +236,7 @@ fn get_transformed_assoc_item( ); transform.apply(assoc_item.syntax()); - if let ast::AssocItem::Fn(func) = &assoc_item { - func.remove_attrs_and_docs(); - } + assoc_item.remove_attrs_and_docs(); Some(assoc_item) } @@ -335,7 +333,6 @@ fn add_const_impl( } fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> String { - const_.remove_attrs_and_docs(); let const_ = if needs_whitespace { insert_whitespace_into_node::insert_ws_into(const_.syntax().clone()) } else { @@ -359,8 +356,6 @@ fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> Strin } fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String { - node.remove_attrs_and_docs(); - let node = if needs_whitespace { insert_whitespace_into_node::insert_ws_into(node.syntax().clone()) } else { @@ -1209,6 +1204,81 @@ trait Tr<'b> { impl<'b> Tr<'b> for () { type Ty<'a: 'b, T: Copy, const C: usize> = $0; } +"#, + ); + } + + #[test] + fn strips_comments() { + check_edit( + "fn func", + r#" +trait Tr { + /// docs + #[attr] + fn func(); +} +impl Tr for () { + $0 +} +"#, + r#" +trait Tr { + /// docs + #[attr] + fn func(); +} +impl Tr for () { + fn func() { + $0 +} +} +"#, + ); + check_edit( + "const C", + r#" +trait Tr { + /// docs + #[attr] + const C: usize; +} +impl Tr for () { + $0 +} +"#, + r#" +trait Tr { + /// docs + #[attr] + const C: usize; +} +impl Tr for () { + const C: usize = $0; +} +"#, + ); + check_edit( + "type Item", + r#" +trait Tr { + /// docs + #[attr] + type Item; +} +impl Tr for () { + $0 +} +"#, + r#" +trait Tr { + /// docs + #[attr] + type Item; +} +impl Tr for () { + type Item = $0; +} "#, ); } From 1ad11b53661979624ba1bfcf4520d5e2b9edbc01 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Wed, 16 Nov 2022 19:54:07 +0900 Subject: [PATCH 0570/2442] fix: resolve inference variable before applying adjustments --- crates/hir-ty/src/method_resolution.rs | 2 +- crates/hir-ty/src/tests/regression.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index b1178ba0d2af..20bed7bf3cc4 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -541,7 +541,7 @@ pub struct ReceiverAdjustments { impl ReceiverAdjustments { pub(crate) fn apply(&self, table: &mut InferenceTable<'_>, ty: Ty) -> (Ty, Vec) { - let mut ty = ty; + let mut ty = table.resolve_ty_shallow(&ty); let mut adjust = Vec::new(); for _ in 0..self.autoderefs { match autoderef::autoderef_step(table, ty.clone()) { diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index a155adcec6c3..4e46397459d5 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -1707,3 +1707,19 @@ impl Trait for [T; N] { "#, ); } + +#[test] +fn unsize_array_with_inference_variable() { + check_types( + r#" +//- minicore: try, slice +use core::ops::ControlFlow; +fn foo() -> ControlFlow<(), [usize; 1]> { loop {} } +fn bar() -> ControlFlow<(), ()> { + let a = foo()?.len(); + //^ usize + ControlFlow::Continue(()) +} +"#, + ); +} From 7577c44c65321b20b165445e417329619a9bc506 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 17 Nov 2022 01:42:56 +0900 Subject: [PATCH 0571/2442] Update proc-macro-srv tests --- crates/proc-macro-srv/src/tests/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/proc-macro-srv/src/tests/mod.rs b/crates/proc-macro-srv/src/tests/mod.rs index b46cdddcf6b1..cc0fc91fe989 100644 --- a/crates/proc-macro-srv/src/tests/mod.rs +++ b/crates/proc-macro-srv/src/tests/mod.rs @@ -19,7 +19,7 @@ fn test_derive_error() { expect![[r##" SUBTREE $ IDENT compile_error 4294967295 - PUNCH ! [joint] 4294967295 + PUNCH ! [alone] 4294967295 SUBTREE () 4294967295 LITERAL "#[derive(DeriveError)] struct S ;" 4294967295 PUNCH ; [alone] 4294967295"##]], @@ -109,7 +109,7 @@ fn test_fn_like_macro_clone_literals() { PUNCH , [alone] 4294967295 LITERAL 2_u32 4294967295 PUNCH , [alone] 4294967295 - PUNCH - [joint] 4294967295 + PUNCH - [alone] 4294967295 LITERAL 4i64 4294967295 PUNCH , [alone] 4294967295 LITERAL 3.14f32 4294967295 @@ -130,7 +130,7 @@ fn test_attr_macro() { expect![[r##" SUBTREE $ IDENT compile_error 4294967295 - PUNCH ! [joint] 4294967295 + PUNCH ! [alone] 4294967295 SUBTREE () 4294967295 LITERAL "#[attr_error(some arguments)] mod m {}" 4294967295 PUNCH ; [alone] 4294967295"##]], From cd6459e7b389f1127200e83f99da45fc96b01589 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 17 Nov 2022 17:39:31 +0100 Subject: [PATCH 0572/2442] Make "Remove dbg!()" assist work on selections --- crates/ide-assists/src/handlers/remove_dbg.rs | 63 ++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/crates/ide-assists/src/handlers/remove_dbg.rs b/crates/ide-assists/src/handlers/remove_dbg.rs index 3d9cbff177ba..99ae60e07bcf 100644 --- a/crates/ide-assists/src/handlers/remove_dbg.rs +++ b/crates/ide-assists/src/handlers/remove_dbg.rs @@ -1,7 +1,7 @@ use itertools::Itertools; use syntax::{ ast::{self, AstNode, AstToken}, - match_ast, NodeOrToken, SyntaxElement, TextSize, T, + match_ast, NodeOrToken, SyntaxElement, TextRange, TextSize, T, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -22,7 +22,36 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // } // ``` pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let macro_call = ctx.find_node_at_offset::()?; + let macro_calls = if ctx.has_empty_selection() { + vec![ctx.find_node_at_offset::()?] + } else { + ctx.covering_element() + .as_node()? + .descendants() + .filter(|node| ctx.selection_trimmed().contains_range(node.text_range())) + .filter_map(ast::MacroCall::cast) + .collect() + }; + + let replacements = + macro_calls.into_iter().filter_map(compute_dbg_replacement).collect::>(); + if replacements.is_empty() { + return None; + } + + acc.add( + AssistId("remove_dbg", AssistKind::Refactor), + "Remove dbg!()", + ctx.selection_trimmed(), + |builder| { + for (range, text) in replacements { + builder.replace(range, text); + } + }, + ) +} + +fn compute_dbg_replacement(macro_call: ast::MacroCall) -> Option<(TextRange, String)> { let tt = macro_call.token_tree()?; let r_delim = NodeOrToken::Token(tt.right_delimiter_token()?); if macro_call.path()?.segment()?.name_ref()?.text() != "dbg" @@ -41,7 +70,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( let macro_expr = ast::MacroExpr::cast(macro_call.syntax().parent()?)?; let parent = macro_expr.syntax().parent()?; - let (range, text) = match &*input_expressions { + Some(match &*input_expressions { // dbg!() [] => { match_ast! { @@ -107,10 +136,6 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( } // dbg!(expr0, expr1, ...) exprs => (macro_call.syntax().text_range(), format!("({})", exprs.iter().format(", "))), - }; - - acc.add(AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", range, |builder| { - builder.replace(range, text); }) } @@ -238,4 +263,28 @@ fn foo() { check(r#"$0dbg!(0, 1)"#, r#"(0, 1)"#); check(r#"$0dbg!(0, (1, 2))"#, r#"(0, (1, 2))"#); } + + #[test] + fn test_range() { + check( + r#" +fn f() { + dbg!(0) + $0dbg!(1); + dbg!(())$0 +} +"#, + r#" +fn f() { + dbg!(0) + 1; + () +} +"#, + ); + } + + #[test] + fn test_range_partial() { + check_assist_not_applicable(remove_dbg, r#"$0dbg$0!(0)"#); + check_assist_not_applicable(remove_dbg, r#"$0dbg!(0$0)"#); + } } From 656d886ca8a37ac4b0df60f48d699584d3abca46 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 18 Nov 2022 11:31:12 +0100 Subject: [PATCH 0573/2442] Make it more obvious which SCIP features we do not yet emit in code --- crates/rust-analyzer/src/cli/scip.rs | 113 ++++++++++++++++----------- 1 file changed, 67 insertions(+), 46 deletions(-) diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs index ca7ba896b67c..9edd045ab071 100644 --- a/crates/rust-analyzer/src/cli/scip.rs +++ b/crates/rust-analyzer/src/cli/scip.rs @@ -47,30 +47,27 @@ impl flags::Scip { let si = StaticIndex::compute(&analysis); - let mut index = scip_types::Index { - metadata: Some(scip_types::Metadata { - version: scip_types::ProtocolVersion::UnspecifiedProtocolVersion.into(), - tool_info: Some(scip_types::ToolInfo { - name: "rust-analyzer".to_owned(), - version: "0.1".to_owned(), - arguments: vec![], - ..Default::default() - }) - .into(), - project_root: format!( - "file://{}", - path.normalize() - .as_os_str() - .to_str() - .ok_or(anyhow::anyhow!("Unable to normalize project_root path"))? - .to_string() - ), - text_document_encoding: scip_types::TextEncoding::UTF8.into(), - ..Default::default() + let metadata = scip_types::Metadata { + version: scip_types::ProtocolVersion::UnspecifiedProtocolVersion.into(), + tool_info: Some(scip_types::ToolInfo { + name: "rust-analyzer".to_owned(), + version: "0.1".to_owned(), + arguments: vec![], + special_fields: Default::default(), }) .into(), - ..Default::default() + project_root: format!( + "file://{}", + path.normalize() + .as_os_str() + .to_str() + .ok_or(anyhow::anyhow!("Unable to normalize project_root path"))? + .to_string() + ), + text_document_encoding: scip_types::TextEncoding::UTF8.into(), + special_fields: Default::default(), }; + let mut documents = Vec::new(); let mut symbols_emitted: HashSet = HashSet::default(); let mut tokens_to_symbol: HashMap = HashMap::new(); @@ -95,18 +92,14 @@ impl flags::Scip { endings: LineEndings::Unix, }; - let mut doc = scip_types::Document { - relative_path, - language: "rust".to_string(), - ..Default::default() - }; + let mut occurrences = Vec::new(); + let mut symbols = Vec::new(); - tokens.into_iter().for_each(|(range, id)| { + tokens.into_iter().for_each(|(text_range, id)| { let token = si.tokens.get(id).unwrap(); - let mut occurrence = scip_types::Occurrence::default(); - occurrence.range = text_range_to_scip_range(&line_index, range); - occurrence.symbol = tokens_to_symbol + let range = text_range_to_scip_range(&line_index, text_range); + let symbol = tokens_to_symbol .entry(id) .or_insert_with(|| { let symbol = token_to_symbol(&token).unwrap_or_else(&mut new_local_symbol); @@ -114,34 +107,62 @@ impl flags::Scip { }) .clone(); + let mut symbol_roles = Default::default(); + if let Some(def) = token.definition { - if def.range == range { - occurrence.symbol_roles |= scip_types::SymbolRole::Definition as i32; + if def.range == text_range { + symbol_roles |= scip_types::SymbolRole::Definition as i32; } if symbols_emitted.insert(id) { - let mut symbol_info = scip_types::SymbolInformation::default(); - symbol_info.symbol = occurrence.symbol.clone(); - if let Some(hover) = &token.hover { - if !hover.markup.as_str().is_empty() { - symbol_info.documentation = vec![hover.markup.as_str().to_string()]; - } - } + let documentation = token + .hover + .as_ref() + .map(|hover| hover.markup.as_str()) + .filter(|it| !it.is_empty()) + .map(|it| vec![it.to_owned()]); + let symbol_info = scip_types::SymbolInformation { + symbol: symbol.clone(), + documentation: documentation.unwrap_or_default(), + relationships: Vec::new(), + special_fields: Default::default(), + }; - doc.symbols.push(symbol_info) + symbols.push(symbol_info) } } - doc.occurrences.push(occurrence); + occurrences.push(scip_types::Occurrence { + range, + symbol, + symbol_roles, + override_documentation: Vec::new(), + syntax_kind: Default::default(), + diagnostics: Vec::new(), + special_fields: Default::default(), + }); }); - if doc.occurrences.is_empty() { + if occurrences.is_empty() { continue; } - index.documents.push(doc); + documents.push(scip_types::Document { + relative_path, + language: "rust".to_string(), + occurrences, + symbols, + special_fields: Default::default(), + }); } + let index = scip_types::Index { + metadata: Some(metadata).into(), + documents, + external_symbols: Vec::new(), + special_fields: Default::default(), + }; + scip::write_message_to_file("index.scip", index) .map_err(|err| anyhow::anyhow!("Failed to write scip to file: {}", err))?; @@ -181,7 +202,7 @@ fn new_descriptor_str( name: name.to_string(), disambiguator: "".to_string(), suffix: suffix.into(), - ..Default::default() + special_fields: Default::default(), } } @@ -232,11 +253,11 @@ fn token_to_symbol(token: &TokenStaticData) -> Option { manager: "cargo".to_string(), name: package_name, version: version.unwrap_or_else(|| ".".to_string()), - ..Default::default() + special_fields: Default::default(), }) .into(), descriptors, - ..Default::default() + special_fields: Default::default(), }) } From 073a63b93ec39b51cb412119c38716c1af5db871 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 18 Nov 2022 19:47:45 +0100 Subject: [PATCH 0574/2442] feat: Allow viewing the full compiler diagnostic in a readonly textview --- .../rust-analyzer/src/diagnostics/to_proto.rs | 19 +++++---- editors/code/package.json | 5 +++ editors/code/src/client.ts | 42 ++++++++++++++++++- editors/code/src/config.ts | 3 ++ editors/code/src/ctx.ts | 3 +- editors/code/src/main.ts | 24 +++++++++++ 6 files changed, 84 insertions(+), 12 deletions(-) diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index 189ac2fbf533..35f37c740b80 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -359,14 +359,15 @@ pub(crate) fn map_rust_diagnostic_to_lsp( .iter() .flat_map(|primary_span| { let primary_location = primary_location(config, workspace_root, primary_span, snap); - - let mut message = message.clone(); - if needs_primary_span_label { - if let Some(primary_span_label) = &primary_span.label { - format_to!(message, "\n{}", primary_span_label); + let message = { + let mut message = message.clone(); + if needs_primary_span_label { + if let Some(primary_span_label) = &primary_span.label { + format_to!(message, "\n{}", primary_span_label); + } } - } - + message + }; // Each primary diagnostic span may result in multiple LSP diagnostics. let mut diagnostics = Vec::new(); @@ -417,7 +418,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( message: message.clone(), related_information: Some(information_for_additional_diagnostic), tags: if tags.is_empty() { None } else { Some(tags.clone()) }, - data: None, + data: Some(serde_json::json!({ "rendered": rd.rendered })), }; diagnostics.push(MappedRustDiagnostic { url: secondary_location.uri, @@ -449,7 +450,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( } }, tags: if tags.is_empty() { None } else { Some(tags.clone()) }, - data: None, + data: Some(serde_json::json!({ "rendered": rd.rendered })), }, fix: None, }); diff --git a/editors/code/package.json b/editors/code/package.json index 0c7816596042..b1c3473b825d 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -396,6 +396,11 @@ "default": true, "type": "boolean" }, + "rust-analyzer.diagnostics.previewRustcOutput": { + "markdownDescription": "Whether to show the main part of the rendered rustc output of a diagnostic message.", + "default": false, + "type": "boolean" + }, "$generated-start": {}, "rust-analyzer.assist.emitMustUse": { "markdownDescription": "Whether to insert #[must_use] when generating `as_` methods\nfor enum variants.", diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index fb667619c86b..23e039722ee3 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -4,7 +4,7 @@ import * as ra from "../src/lsp_ext"; import * as Is from "vscode-languageclient/lib/common/utils/is"; import { assert } from "./util"; import { WorkspaceEdit } from "vscode"; -import { substituteVSCodeVariables } from "./config"; +import { Config, substituteVSCodeVariables } from "./config"; import { randomUUID } from "crypto"; export interface Env { @@ -66,7 +66,8 @@ export async function createClient( traceOutputChannel: vscode.OutputChannel, outputChannel: vscode.OutputChannel, initializationOptions: vscode.WorkspaceConfiguration, - serverOptions: lc.ServerOptions + serverOptions: lc.ServerOptions, + config: Config ): Promise { const clientOptions: lc.LanguageClientOptions = { documentSelector: [{ scheme: "file", language: "rust" }], @@ -99,6 +100,43 @@ export async function createClient( } }, }, + async handleDiagnostics( + uri: vscode.Uri, + diagnostics: vscode.Diagnostic[], + next: lc.HandleDiagnosticsSignature + ) { + const preview = config.previewRustcOutput; + diagnostics.forEach((diag, idx) => { + // Abuse the fact that VSCode leaks the LSP diagnostics data field through the + // Diagnostic class, if they ever break this we are out of luck and have to go + // back to the worst diagnostics experience ever:) + + // We encode the rendered output of a rustc diagnostic in the rendered field of + // the data payload of the lsp diagnostic. If that field exists, overwrite the + // diagnostic code such that clicking it opens the diagnostic in a readonly + // text editor for easy inspection + const rendered = (diag as unknown as { data?: { rendered?: string } }).data + ?.rendered; + if (rendered) { + if (preview) { + const index = rendered.match(/^(note|help):/m)?.index || 0; + diag.message = rendered + .substring(0, index) + .replace(/^ -->[^\n]+\n/m, ""); + } + diag.code = { + target: vscode.Uri.from({ + scheme: "rust-analyzer-diagnostics-view", + path: "/diagnostic message", + fragment: uri.toString(), + query: idx.toString(), + }), + value: "Click for full compiler diagnostic", + }; + } + }); + return next(uri, diagnostics); + }, async provideHover( document: vscode.TextDocument, position: vscode.Position, diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 632a7d86faa3..d8dbd1df16df 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -238,6 +238,9 @@ export class Config { gotoTypeDef: this.get("hover.actions.gotoTypeDef.enable"), }; } + get previewRustcOutput() { + return this.get("diagnostics.previewRustcOutput"); + } } const VarRegex = new RegExp(/\$\{(.+?)\}/g); diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 3e366525ee29..d6cee5c8fc61 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -179,7 +179,8 @@ export class Ctx { this.traceOutputChannel, this.outputChannel, initializationOptions, - serverOptions + serverOptions, + this.config ); this.pushClientCleanup( this._client.onNotification(ra.serverStatus, (params) => diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index e76b657c1bfb..25f1e83d109c 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -48,6 +48,30 @@ async function activateServer(ctx: Ctx): Promise { ctx.pushExtCleanup(activateTaskProvider(ctx.config)); } + ctx.pushExtCleanup( + vscode.workspace.registerTextDocumentContentProvider( + "rust-analyzer-diagnostics-view", + new (class implements vscode.TextDocumentContentProvider { + async provideTextDocumentContent(uri: vscode.Uri): Promise { + const diags = ctx.client?.diagnostics?.get( + vscode.Uri.parse(uri.fragment, true) + ); + if (!diags) { + return "Unable to find original rustc diagnostic"; + } + + const diag = diags[parseInt(uri.query)]; + if (!diag) { + return "Unable to find original rustc diagnostic"; + } + const rendered = (diag as unknown as { data?: { rendered?: string } }).data + ?.rendered; + return rendered ?? "Unable to find original rustc diagnostic"; + } + })() + ) + ); + vscode.workspace.onDidChangeWorkspaceFolders( async (_) => ctx.onWorkspaceFolderChanges(), null, From 8452844c2674584064d8d459e41a3a809648a62f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 18 Nov 2022 20:11:48 +0100 Subject: [PATCH 0575/2442] Fix tests checking the data value --- crates/rust-analyzer/src/diagnostics/to_proto.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index 35f37c740b80..beb23c54c9f0 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -535,7 +535,8 @@ mod tests { Config::new(workspace_root.to_path_buf(), ClientCapabilities::default()), ); let snap = state.snapshot(); - let actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root, &snap); + let mut actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root, &snap); + actual.iter_mut().for_each(|diag| diag.diagnostic.data = None); expect.assert_debug_eq(&actual) } From 52bc15fc1fe763f5e7a91cb70c71a00997bb52ab Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 18 Nov 2022 23:32:26 +0100 Subject: [PATCH 0576/2442] fix: Fix proc-macro-srv search paths for Arch Linux --- crates/project-model/src/workspace.rs | 15 +++++++++ crates/rust-analyzer/src/cli/load_cargo.rs | 22 +++---------- crates/rust-analyzer/src/reload.rs | 36 +++------------------- 3 files changed, 25 insertions(+), 48 deletions(-) diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 4a2f468de725..3d199ed24afe 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -377,6 +377,21 @@ impl ProjectWorkspace { } } + pub fn find_sysroot_proc_macro_srv(&self) -> Option { + match self { + ProjectWorkspace::Cargo { sysroot: Some(sysroot), .. } + | ProjectWorkspace::Json { sysroot: Some(sysroot), .. } => { + let standalone_server_name = + format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX); + ["libexec", "lib"] + .into_iter() + .map(|segment| sysroot.root().join(segment).join(&standalone_server_name)) + .find(|server_path| std::fs::metadata(&server_path).is_ok()) + } + _ => None, + } + } + /// Returns the roots for the current `ProjectWorkspace` /// The return type contains the path and whether or not /// the root is a member of the current workspace diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 5dba545b8718..762d7d3a18e8 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -60,24 +60,12 @@ pub fn load_workspace( }; let proc_macro_client = if load_config.with_proc_macro { - let mut path = AbsPathBuf::assert(std::env::current_exe()?); - let mut args = vec!["proc-macro"]; + let (server_path, args): (_, &[_]) = match ws.find_sysroot_proc_macro_srv() { + Some(server_path) => (server_path, &[]), + None => (AbsPathBuf::assert(std::env::current_exe()?), &["proc-macro"]), + }; - if let ProjectWorkspace::Cargo { sysroot, .. } | ProjectWorkspace::Json { sysroot, .. } = - &ws - { - if let Some(sysroot) = sysroot.as_ref() { - let standalone_server_name = - format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX); - let server_path = sysroot.root().join("libexec").join(&standalone_server_name); - if std::fs::metadata(&server_path).is_ok() { - path = server_path; - args = vec![]; - } - } - } - - ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|e| e.to_string()) + ProcMacroServer::spawn(server_path, args).map_err(|e| e.to_string()) } else { Err("proc macro server disabled".to_owned()) }; diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index aa0510a4ea6a..fcfe4be0b8ce 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -305,9 +305,6 @@ impl GlobalState { let files_config = self.config.files(); let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude); - let standalone_server_name = - format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX); - if self.proc_macro_clients.is_empty() { if let Some((path, path_manually_set)) = self.config.proc_macro_srv() { tracing::info!("Spawning proc-macro servers"); @@ -315,40 +312,17 @@ impl GlobalState { .workspaces .iter() .map(|ws| { - let (path, args) = if path_manually_set { + let (path, args): (_, &[_]) = if path_manually_set { tracing::debug!( "Pro-macro server path explicitly set: {}", path.display() ); - (path.clone(), vec![]) + (path.clone(), &[]) } else { - let mut sysroot_server = None; - if let ProjectWorkspace::Cargo { sysroot, .. } - | ProjectWorkspace::Json { sysroot, .. } = ws - { - if let Some(sysroot) = sysroot.as_ref() { - let server_path = sysroot - .root() - .join("libexec") - .join(&standalone_server_name); - if std::fs::metadata(&server_path).is_ok() { - tracing::debug!( - "Sysroot proc-macro server exists at {}", - server_path.display() - ); - sysroot_server = Some(server_path); - } else { - tracing::debug!( - "Sysroot proc-macro server does not exist at {}", - server_path.display() - ); - } - } + match ws.find_sysroot_proc_macro_srv() { + Some(server_path) => (server_path, &[]), + None => (path.clone(), &["proc-macro"]), } - sysroot_server.map_or_else( - || (path.clone(), vec!["proc-macro".to_owned()]), - |path| (path, vec![]), - ) }; tracing::info!(?args, "Using proc-macro server at {}", path.display(),); From 0ffb361eb943cdfaa6c21b761a7906161fd3b041 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sat, 19 Nov 2022 11:10:47 +0530 Subject: [PATCH 0577/2442] feat: adds hover hint to ".." in record pattern currently only works with struct pattern --- crates/ide/src/hover.rs | 7 +++-- crates/ide/src/hover/render.rs | 54 +++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 838fb18c3d59..966daad1358d 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -87,7 +87,7 @@ pub struct HoverResult { // Shows additional information, like the type of an expression or the documentation for a definition when "focusing" code. // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. // -// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[] +// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif pub(crate) fn hover( db: &RootDatabase, FileRange { file_id, range }: FileRange, @@ -268,7 +268,10 @@ fn hover_type_fallback( } }; - let res = render::type_info(sema, config, &expr_or_pat)?; + let res = + render::type_info(sema, config, &expr_or_pat) + .or_else(|| render::struct_rest_pat(sema, config, &expr_or_pat))?; + let range = sema .original_range_opt(&node) .map(|frange| frange.range) diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index d109c0769194..3b561f65da97 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -14,7 +14,7 @@ use ide_db::{ use itertools::Itertools; use stdx::format_to; use syntax::{ - algo, ast, match_ast, AstNode, Direction, + algo, ast::{self, RecordPat}, match_ast, AstNode, Direction, SyntaxKind::{LET_EXPR, LET_STMT}, SyntaxToken, T, }; @@ -250,6 +250,58 @@ pub(super) fn keyword( Some(HoverResult { markup, actions }) } +pub(super) fn struct_rest_pat( + sema: &Semantics<'_, RootDatabase>, + config: &HoverConfig, + expr_or_pat: &Either, +) -> Option { + let pat = expr_or_pat.as_ref().right()?; + + let mut ancestors = sema.ancestors_with_macros(pat.syntax().clone()); + let _record_pat_field_list = ancestors.next()?; + let record_pat = ancestors.next()?; + let pattern = sema + .find_nodes_at_offset_with_descend::( + &record_pat, + record_pat.text_range().start()) + .next()?; + + let missing_fields = sema.record_pattern_missing_fields(&pattern); + + // if there are no missing fields, the end result is a hover that shows ".." + // should be left in to indicate that there are no more fields in the pattern + // example, S {a: 1, b: 2, ..} when struct S {a: u32, b: u32} + + let mut res = HoverResult::default(); + let mut targets: Vec = Vec::new(); + let mut push_new_def = |item: hir::ModuleDef| { + if !targets.contains(&item) { + targets.push(item); + } + }; + for (_, t) in &missing_fields { + walk_and_push_ty(sema.db, &t, &mut push_new_def); + } + + res.markup = { + let mut s = String::from(".., "); + for (f, _) in &missing_fields { + s += f.display(sema.db).to_string().as_ref(); + s += ", "; + } + // get rid of trailing comma + if s.len() > 0 {s.truncate(s.len() - 2);} + + if config.markdown() { + Markup::fenced_block(&s) + } else { + s.into() + } + }; + res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + Some(res) +} + pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option { let (path, tt) = attr.as_simple_call()?; if !tt.syntax().text_range().contains(token.text_range().start()) { From a778203db9d23d2c6dbbd1bd038d6ef2d5368b94 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sat, 19 Nov 2022 11:17:43 +0530 Subject: [PATCH 0578/2442] simplify ancestor climbing to not consider macros --- crates/ide/src/hover/render.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 3b561f65da97..b5320c6b6b21 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -257,7 +257,7 @@ pub(super) fn struct_rest_pat( ) -> Option { let pat = expr_or_pat.as_ref().right()?; - let mut ancestors = sema.ancestors_with_macros(pat.syntax().clone()); + let mut ancestors = pat.syntax().ancestors(); let _record_pat_field_list = ancestors.next()?; let record_pat = ancestors.next()?; let pattern = sema From 8b176810588734bdba3b5ea3374d39046f184f45 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sat, 19 Nov 2022 11:34:49 +0530 Subject: [PATCH 0579/2442] fix formatting and remove unnecessary check --- crates/ide/src/hover.rs | 3 +-- crates/ide/src/hover/render.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 966daad1358d..cc64b0c3db39 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -268,8 +268,7 @@ fn hover_type_fallback( } }; - let res = - render::type_info(sema, config, &expr_or_pat) + let res = render::type_info(sema, config, &expr_or_pat) .or_else(|| render::struct_rest_pat(sema, config, &expr_or_pat))?; let range = sema diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index b5320c6b6b21..b66c029257dd 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -14,7 +14,9 @@ use ide_db::{ use itertools::Itertools; use stdx::format_to; use syntax::{ - algo, ast::{self, RecordPat}, match_ast, AstNode, Direction, + algo, + ast::{self, RecordPat}, + match_ast, AstNode, Direction, SyntaxKind::{LET_EXPR, LET_STMT}, SyntaxToken, T, }; @@ -263,7 +265,8 @@ pub(super) fn struct_rest_pat( let pattern = sema .find_nodes_at_offset_with_descend::( &record_pat, - record_pat.text_range().start()) + record_pat.text_range().start(), + ) .next()?; let missing_fields = sema.record_pattern_missing_fields(&pattern); @@ -290,7 +293,7 @@ pub(super) fn struct_rest_pat( s += ", "; } // get rid of trailing comma - if s.len() > 0 {s.truncate(s.len() - 2);} + s.truncate(s.len() - 2); if config.markdown() { Markup::fenced_block(&s) From a3f8fd71df0e09b6cd161a7e7df78c67bb47d329 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sat, 19 Nov 2022 15:00:25 +0530 Subject: [PATCH 0580/2442] fix: format expression parsing edge-cases handle positional arg with formatting handle indexed positional args --- .../src/handlers/move_format_string_arg.rs | 6 +- .../src/syntax_helpers/format_string_exprs.rs | 62 +++++++++---------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/crates/ide-assists/src/handlers/move_format_string_arg.rs b/crates/ide-assists/src/handlers/move_format_string_arg.rs index aa710d2ce651..11db6ae7f7b8 100644 --- a/crates/ide-assists/src/handlers/move_format_string_arg.rs +++ b/crates/ide-assists/src/handlers/move_format_string_arg.rs @@ -92,7 +92,7 @@ pub(crate) fn move_format_string_arg(acc: &mut Assists, ctx: &AssistContext<'_>) NodeOrToken::Node(n) => { format_to!(current_arg, "{n}"); }, - NodeOrToken::Token(t) if t.kind() == COMMA=> { + NodeOrToken::Token(t) if t.kind() == COMMA => { existing_args.push(current_arg.trim().into()); current_arg.clear(); }, @@ -238,14 +238,14 @@ fn main() { &add_macro_decl( r#" fn main() { - print!("{} {x + 1:b} {Struct(1, 2)}$0", 1); + print!("{:b} {x + 1:b} {Struct(1, 2)}$0", 1); } "#, ), &add_macro_decl( r#" fn main() { - print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2)); + print!("{:b} {:b} {}"$0, 1, x + 1, Struct(1, 2)); } "#, ), diff --git a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs index ac6c6e8feeea..c3b7bb27d88b 100644 --- a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs +++ b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs @@ -103,7 +103,12 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { output.push(chr); extracted_expressions.push(Arg::Placeholder); state = State::NotArg; - } + }, + (State::MaybeArg, ':') => { + output.push(chr); + extracted_expressions.push(Arg::Placeholder); + state = State::FormatOpts; + }, (State::MaybeArg, _) => { if matches!(chr, '\\' | '$') { current_expr.push('\\'); @@ -117,49 +122,40 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { } else { state = State::Expr; } - } - (State::Ident | State::Expr, '}') => { - if inexpr_open_count == 0 { - output.push(chr); - - if matches!(state, State::Expr) { - extracted_expressions.push(Arg::Expr(current_expr.trim().into())); - } else { - extracted_expressions.push(Arg::Ident(current_expr.trim().into())); - } - - current_expr = String::new(); - state = State::NotArg; - } else { - // We're closing one brace met before inside of the expression. - current_expr.push(chr); - inexpr_open_count -= 1; - } - } + }, (State::Ident | State::Expr, ':') if matches!(chars.peek(), Some(':')) => { // path separator state = State::Expr; current_expr.push_str("::"); chars.next(); - } - (State::Ident | State::Expr, ':') => { + }, + (State::Ident | State::Expr, ':' | '}') => { if inexpr_open_count == 0 { - // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}" - output.push(chr); + let trimmed = current_expr.trim(); - if matches!(state, State::Expr) { - extracted_expressions.push(Arg::Expr(current_expr.trim().into())); + // if the expression consists of a single number, like "0" or "12", it can refer to + // format args in the order they are specified. + // see: https://doc.rust-lang.org/std/fmt/#positional-parameters + if trimmed.chars().fold(true, |only_num, c| c.is_ascii_digit() && only_num) { + output.push_str(trimmed); + } else if matches!(state, State::Expr) { + extracted_expressions.push(Arg::Expr(trimmed.into())); } else { - extracted_expressions.push(Arg::Ident(current_expr.trim().into())); + extracted_expressions.push(Arg::Ident(trimmed.into())); } - current_expr = String::new(); - state = State::FormatOpts; - } else { + output.push(chr); + current_expr.clear(); + state = if chr == ':' {State::FormatOpts} else if chr == '}' {State::NotArg} else {unreachable!()}; + } else if chr == '}' { + // We're closing one brace met before inside of the expression. + current_expr.push(chr); + inexpr_open_count -= 1; + } else if chr == ':' { // We're inside of braced expression, assume that it's a struct field name/value delimiter. current_expr.push(chr); } - } + }, (State::Ident | State::Expr, '{') => { state = State::Expr; current_expr.push(chr); @@ -219,6 +215,10 @@ mod tests { ("{expr} is {2 + 2}", expect![["{} is {}; expr, 2 + 2"]]), ("{expr:?}", expect![["{:?}; expr"]]), ("{expr:1$}", expect![[r"{:1\$}; expr"]]), + ("{:1$}", expect![[r"{:1\$}; $1"]]), + ("{:>padding$}", expect![[r"{:>padding\$}; $1"]]), + ("{}, {}, {0}", expect![[r"{}, {}, {0}; $1, $2"]]), + ("{}, {}, {0:b}", expect![[r"{}, {}, {0:b}; $1, $2"]]), ("{$0}", expect![[r"{}; \$0"]]), ("{malformed", expect![["-"]]), ("malformed}", expect![["-"]]), From dc8254c6abdfcd273cb49475e798048558dcf4db Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 19 Nov 2022 10:32:32 +0100 Subject: [PATCH 0581/2442] fix: Fix nested macro diagnostics pointing at macro expansion files --- .../src/handlers/macro_error.rs | 5 +---- .../src/handlers/unresolved_macro_call.rs | 5 +---- .../src/handlers/unresolved_proc_macro.rs | 12 +--------- crates/ide-diagnostics/src/lib.rs | 22 +++++++++++++++++++ 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/crates/ide-diagnostics/src/handlers/macro_error.rs b/crates/ide-diagnostics/src/handlers/macro_error.rs index 43ff4ed5a6c8..870c78d1f1eb 100644 --- a/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -5,10 +5,7 @@ use crate::{Diagnostic, DiagnosticsContext}; // This diagnostic is shown for macro expansion errors. pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { // Use more accurate position if available. - let display_range = d - .precise_location - .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone()).range); - + let display_range = ctx.resolve_precise_location(&d.node, d.precise_location); Diagnostic::new("macro-error", d.message.clone(), display_range).experimental() } diff --git a/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs index 4b43124757f0..87531f4acfb7 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs @@ -9,10 +9,7 @@ pub(crate) fn unresolved_macro_call( d: &hir::UnresolvedMacroCall, ) -> Diagnostic { // Use more accurate position if available. - let display_range = d - .precise_location - .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.macro_call.clone()).range); - + let display_range = ctx.resolve_precise_location(&d.macro_call, d.precise_location); let bang = if d.is_bang { "!" } else { "" }; Diagnostic::new( "unresolved-macro-call", diff --git a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs index 760f51f90498..23818d883f73 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs @@ -1,5 +1,4 @@ use hir::db::DefDatabase; -use syntax::NodeOrToken; use crate::{Diagnostic, DiagnosticsContext, Severity}; @@ -19,16 +18,7 @@ pub(crate) fn unresolved_proc_macro( proc_attr_macros_enabled: bool, ) -> Diagnostic { // Use more accurate position if available. - let display_range = (|| { - let precise_location = d.precise_location?; - let root = ctx.sema.parse_or_expand(d.node.file_id)?; - match root.covering_element(precise_location) { - NodeOrToken::Node(it) => Some(ctx.sema.original_range(&it)), - NodeOrToken::Token(it) => d.node.with_value(it).original_file_range_opt(ctx.sema.db), - } - })() - .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone())) - .range; + let display_range = ctx.resolve_precise_location(&d.node, d.precise_location); let config_enabled = match d.kind { hir::MacroKind::Attr => proc_macros_enabled && proc_attr_macros_enabled, diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index ae299f058414..d81e36a1f863 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -182,6 +182,28 @@ struct DiagnosticsContext<'a> { resolve: &'a AssistResolveStrategy, } +impl<'a> DiagnosticsContext<'a> { + fn resolve_precise_location( + &self, + node: &InFile, + precise_location: Option, + ) -> TextRange { + let sema = &self.sema; + (|| { + let precise_location = precise_location?; + let root = sema.parse_or_expand(node.file_id)?; + match root.covering_element(precise_location) { + syntax::NodeOrToken::Node(it) => Some(sema.original_range(&it)), + syntax::NodeOrToken::Token(it) => { + node.with_value(it).original_file_range_opt(sema.db) + } + } + })() + .unwrap_or_else(|| sema.diagnostics_display_range(node.clone())) + .range + } +} + pub fn diagnostics( db: &RootDatabase, config: &DiagnosticsConfig, From 6d4b2b4b17841cdb29e99bf7e7e71b57dbaa2dc1 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sat, 19 Nov 2022 15:08:32 +0530 Subject: [PATCH 0582/2442] run cargo fmt --- .../src/syntax_helpers/format_string_exprs.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs index c3b7bb27d88b..313346ee1315 100644 --- a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs +++ b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs @@ -103,12 +103,12 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { output.push(chr); extracted_expressions.push(Arg::Placeholder); state = State::NotArg; - }, + } (State::MaybeArg, ':') => { output.push(chr); extracted_expressions.push(Arg::Placeholder); state = State::FormatOpts; - }, + } (State::MaybeArg, _) => { if matches!(chr, '\\' | '$') { current_expr.push('\\'); @@ -122,13 +122,13 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { } else { state = State::Expr; } - }, + } (State::Ident | State::Expr, ':') if matches!(chars.peek(), Some(':')) => { // path separator state = State::Expr; current_expr.push_str("::"); chars.next(); - }, + } (State::Ident | State::Expr, ':' | '}') => { if inexpr_open_count == 0 { let trimmed = current_expr.trim(); @@ -146,7 +146,13 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { output.push(chr); current_expr.clear(); - state = if chr == ':' {State::FormatOpts} else if chr == '}' {State::NotArg} else {unreachable!()}; + state = if chr == ':' { + State::FormatOpts + } else if chr == '}' { + State::NotArg + } else { + unreachable!() + }; } else if chr == '}' { // We're closing one brace met before inside of the expression. current_expr.push(chr); @@ -155,7 +161,7 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { // We're inside of braced expression, assume that it's a struct field name/value delimiter. current_expr.push(chr); } - }, + } (State::Ident | State::Expr, '{') => { state = State::Expr; current_expr.push(chr); From a4f071afd5ebe8a1fc537136f9e823349cdee526 Mon Sep 17 00:00:00 2001 From: bvanjoi Date: Sat, 19 Nov 2022 19:38:53 +0800 Subject: [PATCH 0583/2442] fix(assists): remove `item_const` which had default value when implement missing members` --- .../src/handlers/add_missing_impl_members.rs | 10 ++++++++-- .../src/handlers/replace_derive_with_manual_impl.rs | 2 -- crates/ide-assists/src/utils.rs | 4 ++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 722302f991e2..2b3793659cf7 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -196,6 +196,7 @@ trait Foo { type Output; const CONST: usize = 42; + const CONST_2: i32; fn foo(&self); fn bar(&self); @@ -213,6 +214,7 @@ trait Foo { type Output; const CONST: usize = 42; + const CONST_2: i32; fn foo(&self); fn bar(&self); @@ -226,7 +228,7 @@ impl Foo for S { $0type Output; - const CONST: usize = 42; + const CONST_2: i32; fn foo(&self) { todo!() @@ -658,6 +660,7 @@ trait Foo { type Output; const CONST: usize = 42; + const CONST_2: i32; fn valid(some: u32) -> bool { false } fn foo(some: u32) -> bool; @@ -669,13 +672,16 @@ trait Foo { type Output; const CONST: usize = 42; + const CONST_2: i32; fn valid(some: u32) -> bool { false } fn foo(some: u32) -> bool; } struct S; impl Foo for S { - $0fn valid(some: u32) -> bool { false } + $0const CONST: usize = 42; + + fn valid(some: u32) -> bool { false } }"#, ) } diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index f9ba289ee175..6fa15b28e4ef 100644 --- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -1019,8 +1019,6 @@ struct Foo { impl foo::Bar for Foo { $0type Qux; - const Baz: usize = 42; - const Fez: usize; fn foo() { diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index 307e67927056..68c31b4f8e92 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -119,6 +119,10 @@ pub fn filter_assoc_items( (default_methods, def.body()), (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None) ), + ast::AssocItem::Const(def) => matches!( + (default_methods, def.body()), + (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None) + ), _ => default_methods == DefaultMethods::No, }) .collect::>() From 87658c81731cd99b80bcd32d2188890f2ca22291 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sat, 19 Nov 2022 21:22:10 +0530 Subject: [PATCH 0584/2442] refactor hover change struct_rest_pat to guarentee a HoverResult Move token and node matching out of struct_rest_pat into hover --- crates/ide/src/hover.rs | 104 +++++++++++++++++++-------------- crates/ide/src/hover/render.rs | 23 +++----- 2 files changed, 66 insertions(+), 61 deletions(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index cc64b0c3db39..1e07e7dbac9c 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -127,6 +127,7 @@ pub(crate) fn hover( original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind())) ); + // prefer descending the same token kind in attribute expansions, in normal macros text // equivalency is more important let descended = if in_attr { @@ -135,54 +136,68 @@ pub(crate) fn hover( sema.descend_into_macros_with_same_text(original_token.clone()) }; - // FIXME: Definition should include known lints and the like instead of having this special case here - let hovered_lint = descended.iter().find_map(|token| { - let attr = token.parent_ancestors().find_map(ast::Attr::cast)?; - render::try_for_lint(&attr, token) - }); - if let Some(res) = hovered_lint { - return Some(RangeInfo::new(original_token.text_range(), res)); - } - + // try lint hover let result = descended .iter() - .filter_map(|token| { - let node = token.parent()?; - let class = IdentClass::classify_token(sema, token)?; - if let IdentClass::Operator(OperatorClass::Await(_)) = class { - // It's better for us to fall back to the keyword hover here, - // rendering poll is very confusing - return None; - } - Some(class.definitions().into_iter().zip(iter::once(node).cycle())) + .find_map(|token| { + // FIXME: Definition should include known lints and the like instead of having this special case here + let attr = token.parent_ancestors().find_map(ast::Attr::cast)?; + render::try_for_lint(&attr, token) }) - .flatten() - .unique_by(|&(def, _)| def) - .filter_map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config)) - .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| { - acc.actions.extend(actions); - acc.markup = Markup::from(format!("{}\n---\n{}", acc.markup, markup)); - acc + // try item definitions + .or_else(|| { + descended + .iter() + .filter_map(|token| { + let node = token.parent()?; + let class = IdentClass::classify_token(sema, token)?; + if let IdentClass::Operator(OperatorClass::Await(_)) = class { + // It's better for us to fall back to the keyword hover here, + // rendering poll is very confusing + return None; + } + Some(class.definitions().into_iter().zip(iter::once(node).cycle())) + }) + .flatten() + .unique_by(|&(def, _)| def) + .filter_map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config)) + .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| { + acc.actions.extend(actions); + acc.markup = Markup::from(format!("{}\n---\n{}", acc.markup, markup)); + acc + }) + }) + // try keywords + .or_else(|| { + descended.iter().find_map(|token| render::keyword(sema, config, token)) + }) + // try rest item hover + .or_else(|| { + descended.iter().find_map(|token| { + if token.kind() != DOT2 { + return None; + } + + let record_pat_field_list = + token.parent_ancestors().find_map(ast::RecordPatFieldList::cast)?; + + let record_pat = + record_pat_field_list.syntax().parent().and_then(ast::RecordPat::cast)?; + + Some(render::struct_rest_pat(sema, config, &record_pat)) + }) }); - if result.is_none() { - // fallbacks, show keywords or types - - let res = descended.iter().find_map(|token| render::keyword(sema, config, token)); - if let Some(res) = res { - return Some(RangeInfo::new(original_token.text_range(), res)); - } - let res = descended - .iter() - .find_map(|token| hover_type_fallback(sema, config, token, &original_token)); - if let Some(_) = res { - return res; - } - } - result.map(|mut res: HoverResult| { - res.actions = dedupe_or_merge_hover_actions(res.actions); - RangeInfo::new(original_token.text_range(), res) - }) + result + .map(|mut res: HoverResult| { + res.actions = dedupe_or_merge_hover_actions(res.actions); + RangeInfo::new(original_token.text_range(), res) + }) + // fallback to type hover if there aren't any other suggestions + // this finds its own range instead of using the closest token's range + .or_else(|| { + descended.iter().find_map(|token| hover_type_fallback(sema, config, token, &token)) + }) } pub(crate) fn hover_for_definition( @@ -268,8 +283,7 @@ fn hover_type_fallback( } }; - let res = render::type_info(sema, config, &expr_or_pat) - .or_else(|| render::struct_rest_pat(sema, config, &expr_or_pat))?; + let res = render::type_info(sema, config, &expr_or_pat)?; let range = sema .original_range_opt(&node) diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index b66c029257dd..fb00a40f9619 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -252,24 +252,15 @@ pub(super) fn keyword( Some(HoverResult { markup, actions }) } +/// Returns missing types in a record pattern. +/// Only makes sense when there's a rest pattern in the record pattern. +/// i.e. `let S {a, ..} = S {a: 1, b: 2}` pub(super) fn struct_rest_pat( sema: &Semantics<'_, RootDatabase>, config: &HoverConfig, - expr_or_pat: &Either, -) -> Option { - let pat = expr_or_pat.as_ref().right()?; - - let mut ancestors = pat.syntax().ancestors(); - let _record_pat_field_list = ancestors.next()?; - let record_pat = ancestors.next()?; - let pattern = sema - .find_nodes_at_offset_with_descend::( - &record_pat, - record_pat.text_range().start(), - ) - .next()?; - - let missing_fields = sema.record_pattern_missing_fields(&pattern); + pattern: &RecordPat, +) -> HoverResult { + let missing_fields = sema.record_pattern_missing_fields(pattern); // if there are no missing fields, the end result is a hover that shows ".." // should be left in to indicate that there are no more fields in the pattern @@ -302,7 +293,7 @@ pub(super) fn struct_rest_pat( } }; res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); - Some(res) + res } pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option { From 29951f9766dc8ffc2b661b78cdff44ceafef3d57 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sat, 19 Nov 2022 21:23:33 +0530 Subject: [PATCH 0585/2442] fix formatting --- crates/ide/src/hover.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 1e07e7dbac9c..9751dc11db6b 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -127,7 +127,7 @@ pub(crate) fn hover( original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind())) ); - + // prefer descending the same token kind in attribute expansions, in normal macros text // equivalency is more important let descended = if in_attr { @@ -168,9 +168,7 @@ pub(crate) fn hover( }) }) // try keywords - .or_else(|| { - descended.iter().find_map(|token| render::keyword(sema, config, token)) - }) + .or_else(|| descended.iter().find_map(|token| render::keyword(sema, config, token))) // try rest item hover .or_else(|| { descended.iter().find_map(|token| { From a6d0e342a3eff8494f49966ca58f858a0ff5cc85 Mon Sep 17 00:00:00 2001 From: yue Date: Sun, 20 Nov 2022 00:58:59 +0900 Subject: [PATCH 0586/2442] Update crates/ide-completion/src/context.rs Co-authored-by: Lukas Wirth --- crates/ide-completion/src/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 27f6745d2417..1201854ff4f9 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -569,7 +569,7 @@ impl<'a> CompletionContext<'a> { // completing on let original_token = original_file.syntax().token_at_offset(offset).left_biased()?; - // try to skip completions on path with qinvalid colons + // try to skip completions on path with invalid colons // this approach works in normal path and inside token tree match original_token.kind() { T![:] => { From 7a568f7f9571c2c93fd8e60712878736d942c787 Mon Sep 17 00:00:00 2001 From: yue4u Date: Sun, 20 Nov 2022 01:29:02 +0900 Subject: [PATCH 0587/2442] fix: remove insufficient check for coloncolon --- crates/ide-completion/src/context.rs | 3 --- crates/ide-completion/src/tests/special.rs | 7 ------- 2 files changed, 10 deletions(-) diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 1201854ff4f9..a0e1153f08b8 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -585,9 +585,6 @@ impl<'a> CompletionContext<'a> { return None; } } - T![::] if !is_prev_token_valid_path_start_or_segment(&original_token) => { - return None; - } _ => {} } diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index 1aea5d89b4a0..6cfa72d6539b 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -977,13 +977,6 @@ fn foo { crate:::$0 } check( r#" fn foo { crate::::$0 } -"#, - expect![""], - ); - - check( - r#" -fn foo { crate:::::$0 } "#, expect![""], ); From 23cfe0702de3a7144be6842bf54d94091b0cde6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nyikos=20Zolt=C3=A1n?= Date: Sat, 19 Nov 2022 20:08:01 +0100 Subject: [PATCH 0588/2442] fix: tuple to named struct inside macros seems to fix #13634 --- .../convert_tuple_struct_to_named_struct.rs | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index 92e091fca126..b0383291e737 100644 --- a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -168,7 +168,7 @@ fn edit_struct_references( let arg_list = call_expr.syntax().descendants().find_map(ast::ArgList::cast)?; edit.replace( - call_expr.syntax().text_range(), + ctx.sema.original_range(&node).range, ast::make::record_expr( path, ast::make::record_expr_field_list(arg_list.args().zip(names).map( @@ -249,6 +249,24 @@ mod tests { ); check_assist_not_applicable(convert_tuple_struct_to_named_struct, r#"struct Foo$0;"#); } + #[test] + fn convert_in_macro_args() { + check_assist( + convert_tuple_struct_to_named_struct, + r#" +macro_rules! foo {($i:expr) => {$i} } +struct T$0(u8); +fn test() { + foo!(T(1)); +}"#, + r#" +macro_rules! foo {($i:expr) => {$i} } +struct T { field1: u8 } +fn test() { + foo!(T { field1: 1 }); +}"#, + ); + } #[test] fn convert_simple_struct() { @@ -554,6 +572,29 @@ where ); } + #[test] + fn convert_variant_in_macro_args() { + check_assist( + convert_tuple_struct_to_named_struct, + r#" +macro_rules! foo {($i:expr) => {$i} } +enum T { + V$0(u8) +} +fn test() { + foo!(T::V(1)); +}"#, + r#" +macro_rules! foo {($i:expr) => {$i} } +enum T { + V { field1: u8 } +} +fn test() { + foo!(T::V { field1: 1 }); +}"#, + ); + } + #[test] fn convert_simple_variant() { check_assist( From e39d90a8e6723cbd9937aca273d1f58a9beee2c9 Mon Sep 17 00:00:00 2001 From: ZZzzaaKK <66885975+ZZzzaaKK@users.noreply.github.com> Date: Sun, 20 Nov 2022 01:58:16 +0100 Subject: [PATCH 0589/2442] Improve grammar of architecture.md --- docs/dev/architecture.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index e3a4fdfda90c..a07cf036e060 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md @@ -481,7 +481,7 @@ It is not cheap enough to enable in prod, and this is a bug which should be fixe rust-analyzer strives to be as configurable as possible while offering reasonable defaults where no configuration exists yet. The rule of thumb is to enable most features by default unless they are buggy or degrade performance too much. There will always be features that some people find more annoying than helpful, so giving the users the ability to tweak or disable these is a big part of offering a good user experience. -Enabling them by default is a matter of discoverability, as many users end up don't know about some features even though they are presented in the manual. +Enabling them by default is a matter of discoverability, as many users don't know about some features even though they are presented in the manual. Mind the code--architecture gap: at the moment, we are using fewer feature flags than we really should. ### Serialization @@ -492,8 +492,8 @@ If a type is serializable, then it is a part of some IPC boundary. You often don't control the other side of this boundary, so changing serializable types is hard. For this reason, the types in `ide`, `base_db` and below are not serializable by design. -If such types need to cross an IPC boundary, then the client of rust-analyzer needs to provide custom, client-specific serialization format. +If such types need to cross an IPC boundary, then the client of rust-analyzer needs to provide a custom, client-specific serialization format. This isolates backwards compatibility and migration concerns to a specific client. -For example, `rust-project.json` is it's own format -- it doesn't include `CrateGraph` as is. +For example, `rust-project.json` is its own format -- it doesn't include `CrateGraph` as is. Instead, it creates a `CrateGraph` by calling appropriate constructing functions. From 427b63b676c89dc6be407181f25f74ddc9950ea1 Mon Sep 17 00:00:00 2001 From: Jake Heinz Date: Sun, 20 Nov 2022 08:48:27 +0000 Subject: [PATCH 0590/2442] hir-expand: fix compile_error! expansion not unquoting strings --- .../src/macro_expansion_tests/builtin_fn_macro.rs | 6 ++++-- crates/hir-expand/src/builtin_fn_macro.rs | 13 ++++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index c04cd1651926..bb45266725c6 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -163,7 +163,8 @@ macro_rules! compile_error { } // This expands to nothing (since it's in item position), but emits an error. -compile_error!("error!"); +compile_error!("error, with an escaped quote: \""); +compile_error!(r"this is a raw string"); "#, expect![[r##" #[rustc_builtin_macro] @@ -172,7 +173,8 @@ macro_rules! compile_error { ($msg:expr,) => ({ /* compiler built-in */ }) } -/* error: error! */ +/* error: error, with an escaped quote: " */ +/* error: this is a raw string */ "##]], ); } diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index 7b19518e25a8..985954d44e46 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -379,15 +379,10 @@ fn compile_error_expand( tt: &tt::Subtree, ) -> ExpandResult { let err = match &*tt.token_trees { - [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => { - let text = it.text.as_str(); - if text.starts_with('"') && text.ends_with('"') { - // FIXME: does not handle raw strings - ExpandError::Other(text[1..text.len() - 1].into()) - } else { - ExpandError::Other("`compile_error!` argument must be a string".into()) - } - } + [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => match unquote_str(it) { + Some(unquoted) => ExpandError::Other(unquoted.into()), + None => ExpandError::Other("`compile_error!` argument must be a string".into()), + }, _ => ExpandError::Other("`compile_error!` argument must be a string".into()), }; From ebbc5492f586601a9a369ace53397864bc39b71a Mon Sep 17 00:00:00 2001 From: Max Gautier Date: Sun, 20 Nov 2022 12:47:28 +0100 Subject: [PATCH 0591/2442] Fix typo on 'configuration' anchor https://rust-analyzer.github.io/manual.html#_configuration lands you at the start of the page, while https://rust-analyzer.github.io/manual.html#configuration correctly puts you at the correct anchor --- docs/user/manual.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 49500e390a50..1a4c70575b03 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -367,7 +367,7 @@ if executable('rust-analyzer') endif ---- -There is no dedicated UI for the server configuration, so you would need to send any options as a value of the `initialization_options` field, as described in the <<_configuration,Configuration>> section. +There is no dedicated UI for the server configuration, so you would need to send any options as a value of the `initialization_options` field, as described in the <> section. Here is an example of how to enable the proc-macro support: [source,vim] From 95b4a7487b4055d951b59967caffcdc92a733c84 Mon Sep 17 00:00:00 2001 From: Bben01 <52465698+Bben01@users.noreply.github.com> Date: Mon, 7 Nov 2022 22:31:43 +0200 Subject: [PATCH 0592/2442] Suppress "Implement default members" inside contained items --- .../src/handlers/add_missing_impl_members.rs | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 62cf5ab4f37a..2394e4341afb 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -107,6 +107,14 @@ fn add_missing_impl_members_inner( ) -> Option<()> { let _p = profile::span("add_missing_impl_members_inner"); let impl_def = ctx.find_node_at_offset::()?; + + if ctx.token_at_offset().all(|t| { + t.parent_ancestors() + .any(|s| ast::BlockExpr::can_cast(s.kind()) || ast::ParamList::can_cast(s.kind())) + }) { + return None; + } + let target_scope = ctx.sema.scope(impl_def.syntax())?; let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?; @@ -1337,4 +1345,95 @@ impl PartialEq for SomeStruct { "#, ); } + + #[test] + fn test_ignore_function_body() { + check_assist_not_applicable( + add_missing_default_members, + r#" +trait Trait { + type X; + fn foo(&self); + fn bar(&self) {} +} + +impl Trait for () { + type X = u8; + fn foo(&self) {$0 + let x = 5; + } +}"#, + ) + } + + #[test] + fn test_ignore_param_list() { + check_assist_not_applicable( + add_missing_impl_members, + r#" +trait Trait { + type X; + fn foo(&self); + fn bar(&self); +} + +impl Trait for () { + type X = u8; + fn foo(&self$0) { + let x = 5; + } +}"#, + ) + } + + #[test] + fn test_ignore_scope_inside_function() { + check_assist_not_applicable( + add_missing_impl_members, + r#" +trait Trait { + type X; + fn foo(&self); + fn bar(&self); +} + +impl Trait for () { + type X = u8; + fn foo(&self) { + let x = async {$0 5 }; + } +}"#, + ) + } + + #[test] + fn test_apply_outside_function() { + check_assist( + add_missing_default_members, + r#" +trait Trait { + type X; + fn foo(&self); + fn bar(&self) {} +} + +impl Trait for () { + type X = u8; + fn foo(&self)$0 {} +}"#, + r#" +trait Trait { + type X; + fn foo(&self); + fn bar(&self) {} +} + +impl Trait for () { + type X = u8; + fn foo(&self) {} + + $0fn bar(&self) {} +}"#, + ) + } } From ecb15ca7173a6d416c9f74af06f71cf003cdd597 Mon Sep 17 00:00:00 2001 From: Mihail Mihov Date: Wed, 9 Nov 2022 23:43:07 +0200 Subject: [PATCH 0593/2442] Add assist to generate trait impl's --- .../src/handlers/generate_trait_impl.rs | 226 ++++++++++++++++++ crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 21 ++ 3 files changed, 249 insertions(+) create mode 100644 crates/ide-assists/src/handlers/generate_trait_impl.rs diff --git a/crates/ide-assists/src/handlers/generate_trait_impl.rs b/crates/ide-assists/src/handlers/generate_trait_impl.rs new file mode 100644 index 000000000000..7b1ee5b5c310 --- /dev/null +++ b/crates/ide-assists/src/handlers/generate_trait_impl.rs @@ -0,0 +1,226 @@ +use syntax::ast::{self, AstNode, HasName}; + +use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists}; + +// Assist: generate_trait_impl +// +// Adds a new trait impl for a type. +// +// ``` +// struct $0Ctx { +// data: T, +// } +// ``` +// -> +// ``` +// struct Ctx { +// data: T, +// } +// +// impl $0 for Ctx { +// +// } +// ``` +pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let nominal = ctx.find_node_at_offset::()?; + let name = nominal.name()?; + let target = nominal.syntax().text_range(); + + if let Some(_) = ctx.find_node_at_offset::() { + return None; + } + + acc.add( + AssistId("generate_trait_impl", AssistKind::Generate), + format!("Generate trait impl for `{name}`"), + target, + |edit| { + let start_offset = nominal.syntax().text_range().end(); + match ctx.config.snippet_cap { + Some(cap) => { + let snippet = generate_trait_impl_text(&nominal, "$0", ""); + edit.insert_snippet(cap, start_offset, snippet); + } + None => { + let text = generate_trait_impl_text(&nominal, "", ""); + edit.insert(start_offset, text); + } + } + }, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_target}; + + use super::*; + + #[test] + fn test_add_trait_impl() { + check_assist( + generate_trait_impl, + r#" + struct Foo$0 {} + "#, + r#" + struct Foo {} + + impl $0 for Foo { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_generics() { + check_assist( + generate_trait_impl, + r#" + struct Foo$0 {} + "#, + r#" + struct Foo {} + + impl $0 for Foo { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_generics_and_lifetime_parameters() { + check_assist( + generate_trait_impl, + r#" + struct Foo<'a, T: Foo<'a>>$0 {} + "#, + r#" + struct Foo<'a, T: Foo<'a>> {} + + impl<'a, T: Foo<'a>> $0 for Foo<'a, T> { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_attributes() { + check_assist( + generate_trait_impl, + r#" + #[cfg(feature = "foo")] + struct Foo<'a, T: Foo$0<'a>> {} + "#, + r#" + #[cfg(feature = "foo")] + struct Foo<'a, T: Foo<'a>> {} + + #[cfg(feature = "foo")] + impl<'a, T: Foo<'a>> $0 for Foo<'a, T> { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_default_generic() { + check_assist( + generate_trait_impl, + r#" + struct Defaulted$0 {} + "#, + r#" + struct Defaulted {} + + impl $0 for Defaulted { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_constrained_default_generic() { + check_assist( + generate_trait_impl, + r#" + struct Defaulted$0<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} + "#, + r#" + struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} + + impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> $0 for Defaulted<'a, 'b, T, S> { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_const_defaulted_generic() { + check_assist( + generate_trait_impl, + r#" + struct Defaulted$0 {} + "#, + r#" + struct Defaulted {} + + impl $0 for Defaulted { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_trait_constraint() { + check_assist( + generate_trait_impl, + r#" + pub trait Trait {} + struct Struct$0 + where + T: Trait, + { + inner: T, + } + "#, + r#" + pub trait Trait {} + struct Struct + where + T: Trait, + { + inner: T, + } + + impl $0 for Struct + where + T: Trait, + { + + } + "#, + ); + } + + #[test] + fn add_trait_impl_target() { + check_assist_target( + generate_trait_impl, + r#" + struct SomeThingIrrelevant; + /// Has a lifetime parameter + struct Foo$0<'a, T: Foo<'a>> {} + struct EvenMoreIrrelevant; + "#, + "/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}", + ); + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 387cc6314282..e3c483cf0a96 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -152,6 +152,7 @@ mod handlers { mod generate_function; mod generate_getter; mod generate_impl; + mod generate_trait_impl; mod generate_is_empty_from_len; mod generate_new; mod generate_setter; @@ -247,6 +248,7 @@ mod handlers { generate_from_impl_for_enum::generate_from_impl_for_enum, generate_function::generate_function, generate_impl::generate_impl, + generate_trait_impl::generate_trait_impl, generate_is_empty_from_len::generate_is_empty_from_len, generate_new::generate_new, inline_call::inline_call, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index c09317572acf..67657b61bb52 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1341,6 +1341,27 @@ impl Person { ) } +#[test] +fn doctest_generate_trait_impl() { + check_doc_test( + "generate_trait_impl", + r#####" +struct $0Ctx { + data: T, +} +"#####, + r#####" +struct Ctx { + data: T, +} + +impl $0 for Ctx { + +} +"#####, + ) +} + #[test] fn doctest_inline_call() { check_doc_test( From 0bd11f817136f372b30a328ccf71c0bb0c68ef21 Mon Sep 17 00:00:00 2001 From: Mihail Mihov Date: Thu, 10 Nov 2022 00:01:29 +0200 Subject: [PATCH 0594/2442] Reduce trigger range of `generate_impl` assist and update tests --- .../ide-assists/src/handlers/generate_impl.rs | 280 ++++++++++-------- crates/ide-assists/src/tests/generated.rs | 4 +- 2 files changed, 160 insertions(+), 124 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_impl.rs b/crates/ide-assists/src/handlers/generate_impl.rs index 9af26c04eb45..1bea220f3893 100644 --- a/crates/ide-assists/src/handlers/generate_impl.rs +++ b/crates/ide-assists/src/handlers/generate_impl.rs @@ -7,8 +7,8 @@ use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assi // Adds a new inherent impl for a type. // // ``` -// struct Ctx { -// data: T,$0 +// struct Ctx$0 { +// data: T, // } // ``` // -> @@ -26,6 +26,10 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio let name = nominal.name()?; let target = nominal.syntax().text_range(); + if let Some(_) = ctx.find_node_at_offset::() { + return None; + } + acc.add( AssistId("generate_impl", AssistKind::Generate), format!("Generate impl for `{name}`"), @@ -52,139 +56,171 @@ mod tests { use super::*; - // FIXME: break up into separate test fns #[test] fn test_add_impl() { - check_assist( - generate_impl, - "struct Foo {$0}\n", - "struct Foo {}\n\nimpl Foo {\n $0\n}\n", - ); - check_assist( - generate_impl, - "struct Foo {$0}", - "struct Foo {}\n\nimpl Foo {\n $0\n}", - ); - check_assist( - generate_impl, - "struct Foo<'a, T: Foo<'a>> {$0}", - "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}", - ); check_assist( generate_impl, r#" - struct MyOwnArray {}$0"#, + struct Foo$0 {} + "#, r#" - struct MyOwnArray {} + struct Foo {} - impl MyOwnArray { - $0 - }"#, - ); - check_assist( - generate_impl, - r#" - #[cfg(feature = "foo")] - struct Foo<'a, T: Foo<'a>> {$0}"#, - r#" - #[cfg(feature = "foo")] - struct Foo<'a, T: Foo<'a>> {} - - #[cfg(feature = "foo")] - impl<'a, T: Foo<'a>> Foo<'a, T> { - $0 - }"#, - ); - - check_assist( - generate_impl, - r#" - #[cfg(not(feature = "foo"))] - struct Foo<'a, T: Foo<'a>> {$0}"#, - r#" - #[cfg(not(feature = "foo"))] - struct Foo<'a, T: Foo<'a>> {} - - #[cfg(not(feature = "foo"))] - impl<'a, T: Foo<'a>> Foo<'a, T> { - $0 - }"#, - ); - - check_assist( - generate_impl, - r#" - struct Defaulted {}$0"#, - r#" - struct Defaulted {} - - impl Defaulted { - $0 - }"#, - ); - - check_assist( - generate_impl, - r#" - struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}$0"#, - r#" - struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} - - impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> Defaulted<'a, 'b, T, S> { - $0 - }"#, - ); - - check_assist( - generate_impl, - r#" - struct Defaulted {}$0"#, - r#" - struct Defaulted {} - - impl Defaulted { - $0 - }"#, - ); - - check_assist( - generate_impl, - r#"pub trait Trait {} -struct Struct$0 -where - T: Trait, -{ - inner: T, -}"#, - r#"pub trait Trait {} -struct Struct -where - T: Trait, -{ - inner: T, -} - -impl Struct -where - T: Trait, -{ - $0 -}"#, + impl Foo { + $0 + } + "#, ); } #[test] - fn add_impl_target() { + fn test_add_impl_with_generics() { + check_assist( + generate_impl, + r#" + struct Foo$0 {} + "#, + r#" + struct Foo {} + + impl Foo { + $0 + } + "#, + ); + } + + #[test] + fn test_add_impl_with_generics_and_lifetime_parameters() { + check_assist( + generate_impl, + r#" + struct Foo<'a, T: Foo<'a>>$0 {} + "#, + r#" + struct Foo<'a, T: Foo<'a>> {} + + impl<'a, T: Foo<'a>> Foo<'a, T> { + $0 + } + "#, + ); + } + + #[test] + fn test_add_impl_with_attributes() { + check_assist( + generate_impl, + r#" + #[cfg(feature = "foo")] + struct Foo<'a, T: Foo$0<'a>> {} + "#, + r#" + #[cfg(feature = "foo")] + struct Foo<'a, T: Foo<'a>> {} + + #[cfg(feature = "foo")] + impl<'a, T: Foo<'a>> Foo<'a, T> { + $0 + } + "#, + ); + } + + #[test] + fn test_add_impl_with_default_generic() { + check_assist( + generate_impl, + r#" + struct Defaulted$0 {} + "#, + r#" + struct Defaulted {} + + impl Defaulted { + $0 + } + "#, + ); + } + + #[test] + fn test_add_impl_with_constrained_default_generic() { + check_assist( + generate_impl, + r#" + struct Defaulted$0<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} + "#, + r#" + struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} + + impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> Defaulted<'a, 'b, T, S> { + $0 + } + "#, + ); + } + + #[test] + fn test_add_impl_with_const_defaulted_generic() { + check_assist( + generate_impl, + r#" + struct Defaulted$0 {} + "#, + r#" + struct Defaulted {} + + impl Defaulted { + $0 + } + "#, + ); + } + + #[test] + fn test_add_impl_with_trait_constraint() { + check_assist( + generate_impl, + r#" + pub trait Trait {} + struct Struct$0 + where + T: Trait, + { + inner: T, + } + "#, + r#" + pub trait Trait {} + struct Struct + where + T: Trait, + { + inner: T, + } + + impl Struct + where + T: Trait, + { + $0 + } + "#, + ); + } + + #[test] + fn add_trait_impl_target() { check_assist_target( generate_impl, - " -struct SomeThingIrrelevant; -/// Has a lifetime parameter -struct Foo<'a, T: Foo<'a>> {$0} -struct EvenMoreIrrelevant; -", - "/// Has a lifetime parameter -struct Foo<'a, T: Foo<'a>> {}", + r#" + struct SomeThingIrrelevant; + /// Has a lifetime parameter + struct Foo$0<'a, T: Foo<'a>> {} + struct EvenMoreIrrelevant; + "#, + "/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}", ); } } diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 67657b61bb52..d797f077672d 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1249,8 +1249,8 @@ fn doctest_generate_impl() { check_doc_test( "generate_impl", r#####" -struct Ctx { - data: T,$0 +struct Ctx$0 { + data: T, } "#####, r#####" From 469f620b064d2935c741222927dc955da395532b Mon Sep 17 00:00:00 2001 From: Mihail Mihov Date: Mon, 21 Nov 2022 22:58:01 +0200 Subject: [PATCH 0595/2442] Combine `generate_impl` and `generate_trait_impl` into a single file --- .../ide-assists/src/handlers/generate_impl.rs | 223 ++++++++++++++++- .../src/handlers/generate_trait_impl.rs | 226 ------------------ crates/ide-assists/src/lib.rs | 3 +- 3 files changed, 222 insertions(+), 230 deletions(-) delete mode 100644 crates/ide-assists/src/handlers/generate_trait_impl.rs diff --git a/crates/ide-assists/src/handlers/generate_impl.rs b/crates/ide-assists/src/handlers/generate_impl.rs index 1bea220f3893..690c97e26d8c 100644 --- a/crates/ide-assists/src/handlers/generate_impl.rs +++ b/crates/ide-assists/src/handlers/generate_impl.rs @@ -1,6 +1,9 @@ use syntax::ast::{self, AstNode, HasName}; -use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assists}; +use crate::{ + utils::{generate_impl_text, generate_trait_impl_text}, + AssistContext, AssistId, AssistKind, Assists, +}; // Assist: generate_impl // @@ -50,6 +53,54 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio ) } +// Assist: generate_trait_impl +// +// Adds a new trait impl for a type. +// +// ``` +// struct $0Ctx { +// data: T, +// } +// ``` +// -> +// ``` +// struct Ctx { +// data: T, +// } +// +// impl $0 for Ctx { +// +// } +// ``` +pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let nominal = ctx.find_node_at_offset::()?; + let name = nominal.name()?; + let target = nominal.syntax().text_range(); + + if let Some(_) = ctx.find_node_at_offset::() { + return None; + } + + acc.add( + AssistId("generate_trait_impl", AssistKind::Generate), + format!("Generate trait impl for `{name}`"), + target, + |edit| { + let start_offset = nominal.syntax().text_range().end(); + match ctx.config.snippet_cap { + Some(cap) => { + let snippet = generate_trait_impl_text(&nominal, "$0", ""); + edit.insert_snippet(cap, start_offset, snippet); + } + None => { + let text = generate_trait_impl_text(&nominal, "", ""); + edit.insert(start_offset, text); + } + } + }, + ) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_target}; @@ -211,7 +262,7 @@ mod tests { } #[test] - fn add_trait_impl_target() { + fn add_impl_target() { check_assist_target( generate_impl, r#" @@ -223,4 +274,172 @@ mod tests { "/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}", ); } + + #[test] + fn test_add_trait_impl() { + check_assist( + generate_trait_impl, + r#" + struct Foo$0 {} + "#, + r#" + struct Foo {} + + impl $0 for Foo { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_generics() { + check_assist( + generate_trait_impl, + r#" + struct Foo$0 {} + "#, + r#" + struct Foo {} + + impl $0 for Foo { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_generics_and_lifetime_parameters() { + check_assist( + generate_trait_impl, + r#" + struct Foo<'a, T: Foo<'a>>$0 {} + "#, + r#" + struct Foo<'a, T: Foo<'a>> {} + + impl<'a, T: Foo<'a>> $0 for Foo<'a, T> { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_attributes() { + check_assist( + generate_trait_impl, + r#" + #[cfg(feature = "foo")] + struct Foo<'a, T: Foo$0<'a>> {} + "#, + r#" + #[cfg(feature = "foo")] + struct Foo<'a, T: Foo<'a>> {} + + #[cfg(feature = "foo")] + impl<'a, T: Foo<'a>> $0 for Foo<'a, T> { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_default_generic() { + check_assist( + generate_trait_impl, + r#" + struct Defaulted$0 {} + "#, + r#" + struct Defaulted {} + + impl $0 for Defaulted { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_constrained_default_generic() { + check_assist( + generate_trait_impl, + r#" + struct Defaulted$0<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} + "#, + r#" + struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} + + impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> $0 for Defaulted<'a, 'b, T, S> { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_const_defaulted_generic() { + check_assist( + generate_trait_impl, + r#" + struct Defaulted$0 {} + "#, + r#" + struct Defaulted {} + + impl $0 for Defaulted { + + } + "#, + ); + } + + #[test] + fn test_add_trait_impl_with_trait_constraint() { + check_assist( + generate_trait_impl, + r#" + pub trait Trait {} + struct Struct$0 + where + T: Trait, + { + inner: T, + } + "#, + r#" + pub trait Trait {} + struct Struct + where + T: Trait, + { + inner: T, + } + + impl $0 for Struct + where + T: Trait, + { + + } + "#, + ); + } + + #[test] + fn add_trait_impl_target() { + check_assist_target( + generate_trait_impl, + r#" + struct SomeThingIrrelevant; + /// Has a lifetime parameter + struct Foo$0<'a, T: Foo<'a>> {} + struct EvenMoreIrrelevant; + "#, + "/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}", + ); + } } diff --git a/crates/ide-assists/src/handlers/generate_trait_impl.rs b/crates/ide-assists/src/handlers/generate_trait_impl.rs deleted file mode 100644 index 7b1ee5b5c310..000000000000 --- a/crates/ide-assists/src/handlers/generate_trait_impl.rs +++ /dev/null @@ -1,226 +0,0 @@ -use syntax::ast::{self, AstNode, HasName}; - -use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists}; - -// Assist: generate_trait_impl -// -// Adds a new trait impl for a type. -// -// ``` -// struct $0Ctx { -// data: T, -// } -// ``` -// -> -// ``` -// struct Ctx { -// data: T, -// } -// -// impl $0 for Ctx { -// -// } -// ``` -pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let nominal = ctx.find_node_at_offset::()?; - let name = nominal.name()?; - let target = nominal.syntax().text_range(); - - if let Some(_) = ctx.find_node_at_offset::() { - return None; - } - - acc.add( - AssistId("generate_trait_impl", AssistKind::Generate), - format!("Generate trait impl for `{name}`"), - target, - |edit| { - let start_offset = nominal.syntax().text_range().end(); - match ctx.config.snippet_cap { - Some(cap) => { - let snippet = generate_trait_impl_text(&nominal, "$0", ""); - edit.insert_snippet(cap, start_offset, snippet); - } - None => { - let text = generate_trait_impl_text(&nominal, "", ""); - edit.insert(start_offset, text); - } - } - }, - ) -} - -#[cfg(test)] -mod tests { - use crate::tests::{check_assist, check_assist_target}; - - use super::*; - - #[test] - fn test_add_trait_impl() { - check_assist( - generate_trait_impl, - r#" - struct Foo$0 {} - "#, - r#" - struct Foo {} - - impl $0 for Foo { - - } - "#, - ); - } - - #[test] - fn test_add_trait_impl_with_generics() { - check_assist( - generate_trait_impl, - r#" - struct Foo$0 {} - "#, - r#" - struct Foo {} - - impl $0 for Foo { - - } - "#, - ); - } - - #[test] - fn test_add_trait_impl_with_generics_and_lifetime_parameters() { - check_assist( - generate_trait_impl, - r#" - struct Foo<'a, T: Foo<'a>>$0 {} - "#, - r#" - struct Foo<'a, T: Foo<'a>> {} - - impl<'a, T: Foo<'a>> $0 for Foo<'a, T> { - - } - "#, - ); - } - - #[test] - fn test_add_trait_impl_with_attributes() { - check_assist( - generate_trait_impl, - r#" - #[cfg(feature = "foo")] - struct Foo<'a, T: Foo$0<'a>> {} - "#, - r#" - #[cfg(feature = "foo")] - struct Foo<'a, T: Foo<'a>> {} - - #[cfg(feature = "foo")] - impl<'a, T: Foo<'a>> $0 for Foo<'a, T> { - - } - "#, - ); - } - - #[test] - fn test_add_trait_impl_with_default_generic() { - check_assist( - generate_trait_impl, - r#" - struct Defaulted$0 {} - "#, - r#" - struct Defaulted {} - - impl $0 for Defaulted { - - } - "#, - ); - } - - #[test] - fn test_add_trait_impl_with_constrained_default_generic() { - check_assist( - generate_trait_impl, - r#" - struct Defaulted$0<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} - "#, - r#" - struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} - - impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> $0 for Defaulted<'a, 'b, T, S> { - - } - "#, - ); - } - - #[test] - fn test_add_trait_impl_with_const_defaulted_generic() { - check_assist( - generate_trait_impl, - r#" - struct Defaulted$0 {} - "#, - r#" - struct Defaulted {} - - impl $0 for Defaulted { - - } - "#, - ); - } - - #[test] - fn test_add_trait_impl_with_trait_constraint() { - check_assist( - generate_trait_impl, - r#" - pub trait Trait {} - struct Struct$0 - where - T: Trait, - { - inner: T, - } - "#, - r#" - pub trait Trait {} - struct Struct - where - T: Trait, - { - inner: T, - } - - impl $0 for Struct - where - T: Trait, - { - - } - "#, - ); - } - - #[test] - fn add_trait_impl_target() { - check_assist_target( - generate_trait_impl, - r#" - struct SomeThingIrrelevant; - /// Has a lifetime parameter - struct Foo$0<'a, T: Foo<'a>> {} - struct EvenMoreIrrelevant; - "#, - "/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}", - ); - } -} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index e3c483cf0a96..b12f99cc5329 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -152,7 +152,6 @@ mod handlers { mod generate_function; mod generate_getter; mod generate_impl; - mod generate_trait_impl; mod generate_is_empty_from_len; mod generate_new; mod generate_setter; @@ -248,7 +247,7 @@ mod handlers { generate_from_impl_for_enum::generate_from_impl_for_enum, generate_function::generate_function, generate_impl::generate_impl, - generate_trait_impl::generate_trait_impl, + generate_impl::generate_trait_impl, generate_is_empty_from_len::generate_is_empty_from_len, generate_new::generate_new, inline_call::inline_call, From b116fe9be0812ce3052d7c96359e87cfe7aca558 Mon Sep 17 00:00:00 2001 From: Isobel Redelmeier Date: Mon, 21 Nov 2022 16:40:32 -0500 Subject: [PATCH 0596/2442] Fix: Handle empty `checkOnSave/target` values This fixes a regression introduced by #13290, in which failing to set `checkOnSave/target` (or `checkOnSave/targets`) would lead to an invalid config. --- crates/rust-analyzer/src/config.rs | 20 ++++++++++++++------ docs/user/generated_config.adoc | 2 +- editors/code/package.json | 5 ++++- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 6b2f22faa717..6c0d712a4f47 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -182,7 +182,7 @@ config_data! { /// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`. /// /// Aliased as `"checkOnSave.targets"`. - checkOnSave_target | checkOnSave_targets: CheckOnSaveTargets = "[]", + checkOnSave_target | checkOnSave_targets: Option = "null", /// Toggles the additional completions that automatically add imports when completed. /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. @@ -1153,10 +1153,15 @@ impl Config { } Some(_) | None => FlycheckConfig::CargoCommand { command: self.data.checkOnSave_command.clone(), - target_triples: match &self.data.checkOnSave_target.0[..] { - [] => self.data.cargo_target.clone().into_iter().collect(), - targets => targets.into(), - }, + target_triples: self + .data + .checkOnSave_target + .clone() + .and_then(|targets| match &targets.0[..] { + [] => None, + targets => Some(targets.into()), + }) + .unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()), all_targets: self.data.checkOnSave_allTargets, no_default_features: self .data @@ -2126,8 +2131,11 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json "The command will be executed in the project root." ], }, - "CheckOnSaveTargets" => set! { + "Option" => set! { "anyOf": [ + { + "type": "null" + }, { "type": "string", }, diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 57f950034cbb..db41c7bf109e 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -190,7 +190,7 @@ cargo check --workspace --message-format=json --all-targets ``` . -- -[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `[]`):: +[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `null`):: + -- Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. diff --git a/editors/code/package.json b/editors/code/package.json index c4d4e428ea07..a3385a3868b6 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -640,8 +640,11 @@ }, "rust-analyzer.checkOnSave.target": { "markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.", - "default": [], + "default": null, "anyOf": [ + { + "type": "null" + }, { "type": "string" }, From 2300c9de83d0dbff1f27546a04f12a1ebe59c9e3 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 24 Nov 2022 10:21:19 +0100 Subject: [PATCH 0597/2442] Handle sysroot config in detached-files workspaces --- crates/project-model/src/workspace.rs | 58 ++++++++++++++++++--------- crates/rust-analyzer/src/reload.rs | 6 ++- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 4a2f468de725..d263912328fe 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -93,7 +93,7 @@ pub enum ProjectWorkspace { // // /// Project with a set of disjoint files, not belonging to any particular workspace. /// Backed by basic sysroot crates for basic completion and highlighting. - DetachedFiles { files: Vec, sysroot: Sysroot, rustc_cfg: Vec }, + DetachedFiles { files: Vec, sysroot: Option, rustc_cfg: Vec }, } impl fmt::Debug for ProjectWorkspace { @@ -133,7 +133,7 @@ impl fmt::Debug for ProjectWorkspace { ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f .debug_struct("DetachedFiles") .field("n_files", &files.len()) - .field("n_sysroot_crates", &sysroot.crates().len()) + .field("sysroot", &sysroot.is_some()) .field("n_rustc_cfg", &rustc_cfg.len()) .finish(), } @@ -191,10 +191,7 @@ impl ProjectWorkspace { let sysroot = match &config.sysroot { Some(RustcSource::Path(path)) => { Some(Sysroot::with_sysroot_dir(path.clone()).with_context(|| { - format!( - "Failed to find sysroot for Cargo.toml file {}.", - cargo_toml.display() - ) + format!("Failed to find sysroot at {}.", path.display()) })?) } Some(RustcSource::Discover) => Some( @@ -291,14 +288,29 @@ impl ProjectWorkspace { Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) } - pub fn load_detached_files(detached_files: Vec) -> Result { - let sysroot = Sysroot::discover( - detached_files - .first() - .and_then(|it| it.parent()) - .ok_or_else(|| format_err!("No detached files to load"))?, - &Default::default(), - )?; + pub fn load_detached_files( + detached_files: Vec, + config: &CargoConfig, + ) -> Result { + let sysroot = match &config.sysroot { + Some(RustcSource::Path(path)) => Some( + Sysroot::with_sysroot_dir(path.clone()) + .with_context(|| format!("Failed to find sysroot at {}.", path.display()))?, + ), + Some(RustcSource::Discover) => { + let dir = &detached_files + .first() + .and_then(|it| it.parent()) + .ok_or_else(|| format_err!("No detached files to load"))?; + Some(Sysroot::discover(dir, &config.extra_env).with_context(|| { + format!("Failed to find sysroot in {}. Is rust-src installed?", dir.display()) + })?) + } + None => None, + }; + if let Some(sysroot) = &sysroot { + tracing::info!(src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot"); + } let rustc_cfg = rustc_cfg::get(None, None, &Default::default()); Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg }) } @@ -464,21 +476,25 @@ impl ProjectWorkspace { include: vec![detached_file.clone()], exclude: Vec::new(), }) - .chain(mk_sysroot(Some(sysroot))) + .chain(mk_sysroot(sysroot.as_ref())) .collect(), } } pub fn n_packages(&self) -> usize { match self { - ProjectWorkspace::Json { project, .. } => project.n_crates(), + ProjectWorkspace::Json { project, sysroot, .. } => { + let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len()); + sysroot_package_len + project.n_crates() + } ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => { let rustc_package_len = rustc.as_ref().map_or(0, |it| it.packages().len()); let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len()); cargo.packages().len() + sysroot_package_len + rustc_package_len } ProjectWorkspace::DetachedFiles { sysroot, files, .. } => { - sysroot.crates().len() + files.len() + let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len()); + sysroot_package_len + files.len() } } } @@ -790,12 +806,14 @@ fn detached_files_to_crate_graph( rustc_cfg: Vec, load: &mut dyn FnMut(&AbsPath) -> Option, detached_files: &[AbsPathBuf], - sysroot: &Sysroot, + sysroot: &Option, ) -> CrateGraph { let _p = profile::span("detached_files_to_crate_graph"); let mut crate_graph = CrateGraph::default(); - let (public_deps, _libproc_macro) = - sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load); + let (public_deps, _libproc_macro) = match sysroot { + Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load), + None => (SysrootPublicDeps::default(), None), + }; let mut cfg_options = CfgOptions::default(); cfg_options.extend(rustc_cfg); diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index aa0510a4ea6a..0306b6640b20 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -158,8 +158,10 @@ impl GlobalState { .collect::>(); if !detached_files.is_empty() { - workspaces - .push(project_model::ProjectWorkspace::load_detached_files(detached_files)); + workspaces.push(project_model::ProjectWorkspace::load_detached_files( + detached_files, + &cargo_config, + )); } tracing::info!("did fetch workspaces {:?}", workspaces); From c8b6fef70fd77e412a665ea8a1e45b0122e68544 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 24 Nov 2022 21:30:15 +0100 Subject: [PATCH 0598/2442] Properly implement Drop for JodGroupChild --- crates/flycheck/src/lib.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 8f93dad06e3f..f13088cd90ef 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -360,13 +360,20 @@ impl FlycheckActor { } } -struct JodChild(GroupChild); +struct JodGroupChild(GroupChild); + +impl Drop for JodGroupChild { + fn drop(&mut self) { + _ = self.0.kill(); + _ = self.0.wait(); + } +} /// A handle to a cargo process used for fly-checking. struct CargoHandle { /// The handle to the actual cargo process. As we cannot cancel directly from with /// a read syscall dropping and therefore terminating the process is our best option. - child: JodChild, + child: JodGroupChild, thread: jod_thread::JoinHandle>, receiver: Receiver, } @@ -374,7 +381,7 @@ struct CargoHandle { impl CargoHandle { fn spawn(mut command: Command) -> std::io::Result { command.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null()); - let mut child = command.group_spawn().map(JodChild)?; + let mut child = command.group_spawn().map(JodGroupChild)?; let stdout = child.0.inner().stdout.take().unwrap(); let stderr = child.0.inner().stderr.take().unwrap(); From 9fba39f0c02e43a0503a64b1ed4b36a05d8a1658 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 24 Nov 2022 22:26:05 +0100 Subject: [PATCH 0599/2442] Add deriveHelper to semanticTokenTypes section of package.json --- editors/code/package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/editors/code/package.json b/editors/code/package.json index c4d4e428ea07..eb4f25812081 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1493,6 +1493,11 @@ "description": "Style for derives", "superType": "attribute" }, + { + "id": "deriveHelper", + "description": "Style for derive helpers", + "superType": "attribute" + }, { "id": "dot", "description": "Style for .", From f64feeb11ac78db9c634339465d973ceb9cb3c97 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Thu, 24 Nov 2022 22:32:15 -0800 Subject: [PATCH 0600/2442] Correct node traversal to look at parent instead Co-authored-by: Lukas Wirth --- crates/ide/src/hover.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 9751dc11db6b..5e812a1569cd 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -176,8 +176,8 @@ pub(crate) fn hover( return None; } - let record_pat_field_list = - token.parent_ancestors().find_map(ast::RecordPatFieldList::cast)?; + let rest_pat = token.syntax().parent().and_then(ast::RestPat::cast)?; + let record_pat_field_list = rest_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast)?; let record_pat = record_pat_field_list.syntax().parent().and_then(ast::RecordPat::cast)?; From 132d5ffc7d86e77ee80a45545b8e9f503b59a8c4 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Fri, 25 Nov 2022 12:03:49 +0530 Subject: [PATCH 0601/2442] add back [] in hover documentation --- crates/ide/src/hover.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 5e812a1569cd..cbf61efba059 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -87,7 +87,7 @@ pub struct HoverResult { // Shows additional information, like the type of an expression or the documentation for a definition when "focusing" code. // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. // -// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif +// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[] pub(crate) fn hover( db: &RootDatabase, FileRange { file_id, range }: FileRange, From e86d451484bf06a452a330af4b1b0c00de286715 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Fri, 25 Nov 2022 12:20:34 +0530 Subject: [PATCH 0602/2442] fix token method call --- crates/ide/src/hover.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index cbf61efba059..016567311c82 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -176,7 +176,7 @@ pub(crate) fn hover( return None; } - let rest_pat = token.syntax().parent().and_then(ast::RestPat::cast)?; + let rest_pat = token.parent().and_then(ast::RestPat::cast)?; let record_pat_field_list = rest_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast)?; let record_pat = From 91e7624de01fc28e4abe2400a6f945b430ab0ab1 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Fri, 25 Nov 2022 12:20:38 +0530 Subject: [PATCH 0603/2442] add hover tests --- crates/ide/src/hover/tests.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index eb997e6fef83..f8be4cfb04c2 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -5307,3 +5307,38 @@ fn main() { $0V; } "#]], ); } + +#[test] +fn hover_rest_pat() { + check( + r#" +struct Struct {a: u32, b: u32, c: u8, d: u16}; + +fn main() { + let Struct {a, c, .$0.} = Struct {a: 1, b: 2, c: 3, d: 4}; +} +"#, + expect![[r#" + *..* + ```rust + .., b: u32, d: u16 + ``` + "#]], + ); + + check( + r#" +struct Struct {a: u32, b: u32, c: u8, d: u16}; + +fn main() { + let Struct {a, b, c, d, .$0.} = Struct {a: 1, b: 2, c: 3, d: 4}; +} +"#, + expect![[r#" + *..* + ```rust + .. + ``` + "#]], + ); +} From a26aef9055e116d790ea63c37118aefcf93d3d0f Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Fri, 25 Nov 2022 12:22:06 +0530 Subject: [PATCH 0604/2442] fix formatting --- crates/ide/src/hover.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 016567311c82..9cbfed4763b0 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -177,7 +177,8 @@ pub(crate) fn hover( } let rest_pat = token.parent().and_then(ast::RestPat::cast)?; - let record_pat_field_list = rest_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast)?; + let record_pat_field_list = + rest_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast)?; let record_pat = record_pat_field_list.syntax().parent().and_then(ast::RecordPat::cast)?; From 3c794a34da24398bfc3783966f14e21c59026cb6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 25 Nov 2022 10:27:49 +0100 Subject: [PATCH 0605/2442] Go to declaration goes to assoc items of trait declarations --- crates/ide/src/goto_declaration.rs | 90 +++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 8 deletions(-) diff --git a/crates/ide/src/goto_declaration.rs b/crates/ide/src/goto_declaration.rs index 926292c9b3ce..5c17b7f41586 100644 --- a/crates/ide/src/goto_declaration.rs +++ b/crates/ide/src/goto_declaration.rs @@ -1,18 +1,22 @@ -use hir::Semantics; +use hir::{AsAssocItem, Semantics}; use ide_db::{ defs::{Definition, NameClass, NameRefClass}, RootDatabase, }; use syntax::{ast, match_ast, AstNode, SyntaxKind::*, T}; -use crate::{FilePosition, NavigationTarget, RangeInfo}; +use crate::{ + goto_definition::goto_definition, navigation_target::TryToNav, FilePosition, NavigationTarget, + RangeInfo, +}; // Feature: Go to Declaration // // Navigates to the declaration of an identifier. // -// This is currently the same as `Go to Definition` with the exception of outline modules where it -// will navigate to the `mod name;` item declaration. +// This is the same as `Go to Definition` with the following exceptions: +// - outline modules will navigate to the `mod name;` item declaration +// - trait assoc items will navigate to the assoc item of the trait declaration opposed to the trait impl pub(crate) fn goto_declaration( db: &RootDatabase, position: FilePosition, @@ -41,16 +45,28 @@ pub(crate) fn goto_declaration( _ => None } }; - match def? { + let assoc = match def? { Definition::Module(module) => { - Some(NavigationTarget::from_module_to_decl(db, module)) + return Some(NavigationTarget::from_module_to_decl(db, module)) } + Definition::Const(c) => c.as_assoc_item(db), + Definition::TypeAlias(ta) => ta.as_assoc_item(db), + Definition::Function(f) => f.as_assoc_item(db), _ => None, - } + }?; + + let trait_ = assoc.containing_trait_impl(db)?; + let name = Some(assoc.name(db)?); + let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?; + item.try_to_nav(db) }) .collect(); - Some(RangeInfo::new(range, info)) + if info.is_empty() { + goto_definition(db, position) + } else { + Some(RangeInfo::new(range, info)) + } } #[cfg(test)] @@ -109,4 +125,62 @@ mod foo { "#, ) } + + #[test] + fn goto_decl_goto_def_fallback() { + check( + r#" +struct Foo; + // ^^^ +impl Foo$0 {} +"#, + ); + } + + #[test] + fn goto_decl_assoc_item_no_impl_item() { + check( + r#" +trait Trait { + const C: () = (); + // ^ +} +impl Trait for () {} + +fn main() { + <()>::C$0; +} +"#, + ); + } + + #[test] + fn goto_decl_assoc_item() { + check( + r#" +trait Trait { + const C: () = (); + // ^ +} +impl Trait for () { + const C: () = (); +} + +fn main() { + <()>::C$0; +} +"#, + ); + check( + r#" +trait Trait { + const C: () = (); + // ^ +} +impl Trait for () { + const C$0: () = (); +} +"#, + ); + } } From ae0bdffcc9b9e25412f118dfe788cf112fb7e2ef Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 25 Nov 2022 00:03:48 +0100 Subject: [PATCH 0606/2442] Go to declaration goes to field declaration in pattern and expression shorthands --- crates/ide/src/goto_declaration.rs | 33 +++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/crates/ide/src/goto_declaration.rs b/crates/ide/src/goto_declaration.rs index 5c17b7f41586..c7130a2a4bb0 100644 --- a/crates/ide/src/goto_declaration.rs +++ b/crates/ide/src/goto_declaration.rs @@ -36,11 +36,11 @@ pub(crate) fn goto_declaration( match parent { ast::NameRef(name_ref) => match NameRefClass::classify(&sema, &name_ref)? { NameRefClass::Definition(it) => Some(it), - _ => None + NameRefClass::FieldShorthand { field_ref, .. } => return field_ref.try_to_nav(db), }, ast::Name(name) => match NameClass::classify(&sema, &name)? { - NameClass::Definition(it) => Some(it), - _ => None + NameClass::Definition(it) | NameClass::ConstReference(it) => Some(it), + NameClass::PatFieldShorthand { field_ref, .. } => return field_ref.try_to_nav(db), }, _ => None } @@ -180,6 +180,33 @@ trait Trait { impl Trait for () { const C$0: () = (); } +"#, + ); + } + + #[test] + fn goto_decl_field_pat_shorthand() { + check( + r#" +struct Foo { field: u32 } + //^^^^^ +fn main() { + let Foo { field$0 }; +} +"#, + ); + } + + #[test] + fn goto_decl_constructor_shorthand() { + check( + r#" +struct Foo { field: u32 } + //^^^^^ +fn main() { + let field = 0; + Foo { field$0 }; +} "#, ); } From 7bf2a25dfe8337fe46a2698756cdfab46556ef88 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 25 Nov 2022 23:17:21 +0100 Subject: [PATCH 0607/2442] Encode the variants of `HirFileId` in a u32 with MSB as the tag --- crates/hir-expand/src/db.rs | 2 +- crates/hir-expand/src/hygiene.rs | 8 +- crates/hir-expand/src/lib.rs | 227 +++++++++--------- .../test_symbol_index_collection.txt | 134 ++--------- 4 files changed, 145 insertions(+), 226 deletions(-) diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 87e4db03984a..0096649be146 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -240,7 +240,7 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc { } fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option { - match file_id.0 { + match file_id.repr() { HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), HirFileIdRepr::MacroFile(macro_file) => { // FIXME: Note how we convert from `Parse` to `SyntaxNode` here, diff --git a/crates/hir-expand/src/hygiene.rs b/crates/hir-expand/src/hygiene.rs index d60734372c0c..df1e20256ca3 100644 --- a/crates/hir-expand/src/hygiene.rs +++ b/crates/hir-expand/src/hygiene.rs @@ -17,7 +17,7 @@ use crate::{ db::{self, AstDatabase}, fixup, name::{AsName, Name}, - HirFileId, HirFileIdRepr, InFile, MacroCallKind, MacroCallLoc, MacroDefKind, MacroFile, + HirFileId, InFile, MacroCallKind, MacroCallLoc, MacroDefKind, MacroFile, }; #[derive(Clone, Debug)] @@ -216,9 +216,9 @@ fn make_hygiene_info( impl HygieneFrame { pub(crate) fn new(db: &dyn AstDatabase, file_id: HirFileId) -> HygieneFrame { - let (info, krate, local_inner) = match file_id.0 { - HirFileIdRepr::FileId(_) => (None, None, false), - HirFileIdRepr::MacroFile(macro_file) => { + let (info, krate, local_inner) = match file_id.macro_file() { + None => (None, None, false), + Some(macro_file) => { let loc = db.lookup_intern_macro_call(macro_file.macro_call_id); let info = make_hygiene_info(db, macro_file, &loc).map(|info| (loc.kind.file_id(), info)); diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 7352b003a491..bc5f9f3b8afd 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -23,7 +23,11 @@ pub use mbe::{Origin, ValueResult}; use std::{fmt, hash::Hash, iter, sync::Arc}; -use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange, ProcMacroKind}; +use base_db::{ + impl_intern_key, + salsa::{self, InternId}, + CrateId, FileId, FileRange, ProcMacroKind, +}; use either::Either; use syntax::{ algo::{self, skip_trivia_token}, @@ -79,26 +83,12 @@ impl fmt::Display for ExpandError { /// finite (because everything bottoms out at the real `FileId`) and small /// (`MacroCallId` uses the location interning. You can check details here: /// ). +/// +/// The two variants are encoded in a single u32 which are differentiated by the MSB. +/// If the MSB is 0, the value represents a `FileId`, otherwise the remaining 31 bits represent a +/// `MacroCallId`. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct HirFileId(HirFileIdRepr); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -enum HirFileIdRepr { - FileId(FileId), - MacroFile(MacroFile), -} - -impl From for HirFileId { - fn from(id: FileId) -> Self { - HirFileId(HirFileIdRepr::FileId(id)) - } -} - -impl From for HirFileId { - fn from(id: MacroFile) -> Self { - HirFileId(HirFileIdRepr::MacroFile(id)) - } -} +pub struct HirFileId(u32); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroFile { @@ -172,13 +162,37 @@ pub enum MacroCallKind { }, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +enum HirFileIdRepr { + FileId(FileId), + MacroFile(MacroFile), +} + +impl From for HirFileId { + fn from(FileId(id): FileId) -> Self { + assert!(id < Self::MAX_FILE_ID); + HirFileId(id) + } +} + +impl From for HirFileId { + fn from(MacroFile { macro_call_id: MacroCallId(id) }: MacroFile) -> Self { + let id = id.as_u32(); + assert!(id < Self::MAX_FILE_ID); + HirFileId(id | Self::MACRO_FILE_TAG_MASK) + } +} + impl HirFileId { + const MAX_FILE_ID: u32 = u32::MAX ^ Self::MACRO_FILE_TAG_MASK; + const MACRO_FILE_TAG_MASK: u32 = 1 << 31; + /// For macro-expansion files, returns the file original source file the /// expansion originated from. pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId { let mut file_id = self; loop { - match file_id.0 { + match file_id.repr() { HirFileIdRepr::FileId(id) => break id, HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_call_id); @@ -194,7 +208,7 @@ impl HirFileId { pub fn expansion_level(self, db: &dyn db::AstDatabase) -> u32 { let mut level = 0; let mut curr = self; - while let HirFileIdRepr::MacroFile(macro_file) = curr.0 { + while let Some(macro_file) = curr.macro_file() { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); level += 1; @@ -205,25 +219,17 @@ impl HirFileId { /// If this is a macro call, returns the syntax node of the call. pub fn call_node(self, db: &dyn db::AstDatabase) -> Option> { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(macro_file) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - Some(loc.kind.to_node(db)) - } - } + let macro_file = self.macro_file()?; + let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); + Some(loc.kind.to_node(db)) } /// If this is a macro call, returns the syntax node of the very first macro call this file resides in. pub fn original_call_node(self, db: &dyn db::AstDatabase) -> Option<(FileId, SyntaxNode)> { - let mut call = match self.0 { - HirFileIdRepr::FileId(_) => return None, - HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => { - db.lookup_intern_macro_call(macro_call_id).kind.to_node(db) - } - }; + let mut call = + db.lookup_intern_macro_call(self.macro_file()?.macro_call_id).kind.to_node(db); loop { - match call.file_id.0 { + match call.file_id.repr() { HirFileIdRepr::FileId(file_id) => break Some((file_id, call.value)), HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => { call = db.lookup_intern_macro_call(macro_call_id).kind.to_node(db); @@ -234,84 +240,74 @@ impl HirFileId { /// Return expansion information if it is a macro-expansion file pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(macro_file) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); + let macro_file = self.macro_file()?; + let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - let arg_tt = loc.kind.arg(db)?; + let arg_tt = loc.kind.arg(db)?; - let macro_def = db.macro_def(loc.def).ok()?; - let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?; - let macro_arg = db.macro_arg(macro_file.macro_call_id)?; + let macro_def = db.macro_def(loc.def).ok()?; + let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?; + let macro_arg = db.macro_arg(macro_file.macro_call_id)?; - let def = loc.def.ast_id().left().and_then(|id| { - let def_tt = match id.to_node(db) { - ast::Macro::MacroRules(mac) => mac.token_tree()?, - ast::Macro::MacroDef(_) - if matches!(*macro_def, TokenExpander::BuiltinAttr(_)) => - { - return None - } - ast::Macro::MacroDef(mac) => mac.body()?, - }; - Some(InFile::new(id.file_id, def_tt)) - }); - let attr_input_or_mac_def = def.or_else(|| match loc.kind { - MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => { - let tt = ast_id - .to_node(db) - .doc_comments_and_attrs() - .nth(invoc_attr_index as usize) - .and_then(Either::left)? - .token_tree()?; - Some(InFile::new(ast_id.file_id, tt)) - } - _ => None, - }); - - Some(ExpansionInfo { - expanded: InFile::new(self, parse.syntax_node()), - arg: InFile::new(loc.kind.file_id(), arg_tt), - attr_input_or_mac_def, - macro_arg_shift: mbe::Shift::new(¯o_arg.0), - macro_arg, - macro_def, - exp_map, - }) + let def = loc.def.ast_id().left().and_then(|id| { + let def_tt = match id.to_node(db) { + ast::Macro::MacroRules(mac) => mac.token_tree()?, + ast::Macro::MacroDef(_) if matches!(*macro_def, TokenExpander::BuiltinAttr(_)) => { + return None + } + ast::Macro::MacroDef(mac) => mac.body()?, + }; + Some(InFile::new(id.file_id, def_tt)) + }); + let attr_input_or_mac_def = def.or_else(|| match loc.kind { + MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => { + let tt = ast_id + .to_node(db) + .doc_comments_and_attrs() + .nth(invoc_attr_index as usize) + .and_then(Either::left)? + .token_tree()?; + Some(InFile::new(ast_id.file_id, tt)) } - } + _ => None, + }); + + Some(ExpansionInfo { + expanded: InFile::new(self, parse.syntax_node()), + arg: InFile::new(loc.kind.file_id(), arg_tt), + attr_input_or_mac_def, + macro_arg_shift: mbe::Shift::new(¯o_arg.0), + macro_arg, + macro_def, + exp_map, + }) } /// Indicate it is macro file generated for builtin derive pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option> { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(macro_file) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - let attr = match loc.def.kind { - MacroDefKind::BuiltInDerive(..) => loc.kind.to_node(db), - _ => return None, - }; - Some(attr.with_value(ast::Attr::cast(attr.value.clone())?)) - } - } + let macro_file = self.macro_file()?; + let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); + let attr = match loc.def.kind { + MacroDefKind::BuiltInDerive(..) => loc.kind.to_node(db), + _ => return None, + }; + Some(attr.with_value(ast::Attr::cast(attr.value.clone())?)) } pub fn is_custom_derive(&self, db: &dyn db::AstDatabase) -> bool { - match self.0 { - HirFileIdRepr::FileId(_) => false, - HirFileIdRepr::MacroFile(macro_file) => { + match self.macro_file() { + Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); matches!(loc.def.kind, MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _)) } + None => false, } } /// Return whether this file is an include macro pub fn is_include_macro(&self, db: &dyn db::AstDatabase) -> bool { - match self.0 { - HirFileIdRepr::MacroFile(macro_file) => { + match self.macro_file() { + Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); matches!(loc.eager, Some(EagerCallInfo { included_file: Some(_), .. })) } @@ -321,8 +317,8 @@ impl HirFileId { /// Return whether this file is an attr macro pub fn is_attr_macro(&self, db: &dyn db::AstDatabase) -> bool { - match self.0 { - HirFileIdRepr::MacroFile(macro_file) => { + match self.macro_file() { + Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); matches!(loc.kind, MacroCallKind::Attr { .. }) } @@ -333,23 +329,36 @@ impl HirFileId { /// Return whether this file is the pseudo expansion of the derive attribute. /// See [`crate::builtin_attr_macro::derive_attr_expand`]. pub fn is_derive_attr_pseudo_expansion(&self, db: &dyn db::AstDatabase) -> bool { - match self.0 { - HirFileIdRepr::MacroFile(macro_file) => { + match self.macro_file() { + Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); matches!(loc.kind, MacroCallKind::Attr { is_derive: true, .. }) } - _ => false, + None => false, } } + #[inline] pub fn is_macro(self) -> bool { - matches!(self.0, HirFileIdRepr::MacroFile(_)) + self.0 & Self::MACRO_FILE_TAG_MASK != 0 } + #[inline] pub fn macro_file(self) -> Option { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(m) => Some(m), + match self.0 & Self::MACRO_FILE_TAG_MASK { + 0 => None, + _ => Some(MacroFile { + macro_call_id: MacroCallId(InternId::from(self.0 ^ Self::MACRO_FILE_TAG_MASK)), + }), + } + } + + fn repr(self) -> HirFileIdRepr { + match self.0 & Self::MACRO_FILE_TAG_MASK { + 0 => HirFileIdRepr::FileId(FileId(self.0)), + _ => HirFileIdRepr::MacroFile(MacroFile { + macro_call_id: MacroCallId(InternId::from(self.0 ^ Self::MACRO_FILE_TAG_MASK)), + }), } } } @@ -442,7 +451,7 @@ impl MacroCallKind { pub fn original_call_range_with_body(self, db: &dyn db::AstDatabase) -> FileRange { let mut kind = self; let file_id = loop { - match kind.file_id().0 { + match kind.file_id().repr() { HirFileIdRepr::MacroFile(file) => { kind = db.lookup_intern_macro_call(file.macro_call_id).kind; } @@ -467,7 +476,7 @@ impl MacroCallKind { pub fn original_call_range(self, db: &dyn db::AstDatabase) -> FileRange { let mut kind = self; let file_id = loop { - match kind.file_id().0 { + match kind.file_id().repr() { HirFileIdRepr::MacroFile(file) => { kind = db.lookup_intern_macro_call(file.macro_call_id).kind; } @@ -779,7 +788,7 @@ impl<'a> InFile<&'a SyntaxNode> { /// For attributes and derives, this will point back to the attribute only. /// For the entire item `InFile::use original_file_range_full`. pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange { - match self.file_id.0 { + match self.file_id.repr() { HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() }, HirFileIdRepr::MacroFile(mac_file) => { if let Some(res) = self.original_file_range_opt(db) { @@ -846,7 +855,7 @@ impl InFile { /// Falls back to the macro call range if the node cannot be mapped up fully. pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange { - match self.file_id.0 { + match self.file_id.repr() { HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() }, HirFileIdRepr::MacroFile(mac_file) => { if let Some(res) = self.original_file_range_opt(db) { @@ -861,7 +870,7 @@ impl InFile { /// Attempts to map the syntax node back up its macro calls. pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option { - match self.file_id.0 { + match self.file_id.repr() { HirFileIdRepr::FileId(file_id) => { Some(FileRange { file_id, range: self.value.text_range() }) } diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt index 2f531ca0c709..8c11408dec5d 100644 --- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -14,11 +14,7 @@ name: "Alias", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: TYPE_ALIAS, @@ -36,11 +32,7 @@ name: "CONST", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: CONST, @@ -58,11 +50,7 @@ name: "CONST_WITH_INNER", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: CONST, @@ -80,11 +68,7 @@ name: "Enum", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: ENUM, @@ -102,11 +86,7 @@ name: "Macro", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: MACRO_DEF, @@ -124,11 +104,7 @@ name: "STATIC", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: STATIC, @@ -146,11 +122,7 @@ name: "Struct", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -168,13 +140,7 @@ name: "StructFromMacro", loc: DeclarationLocation { hir_file_id: HirFileId( - MacroFile( - MacroFile { - macro_call_id: MacroCallId( - 0, - ), - }, - ), + 2147483648, ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -192,11 +158,7 @@ name: "StructInFn", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -216,11 +178,7 @@ name: "StructInNamedConst", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -240,11 +198,7 @@ name: "StructInUnnamedConst", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -262,11 +216,7 @@ name: "Trait", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: TRAIT, @@ -284,11 +234,7 @@ name: "Union", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: UNION, @@ -306,11 +252,7 @@ name: "a_mod", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: MODULE, @@ -328,11 +270,7 @@ name: "b_mod", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: MODULE, @@ -350,11 +288,7 @@ name: "define_struct", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: MACRO_RULES, @@ -372,11 +306,7 @@ name: "impl_fn", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: FN, @@ -394,11 +324,7 @@ name: "macro_rules_macro", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: MACRO_RULES, @@ -416,11 +342,7 @@ name: "main", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: FN, @@ -438,11 +360,7 @@ name: "trait_fn", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: FN, @@ -475,11 +393,7 @@ name: "StructInModA", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 0, - ), - ), + 0, ), ptr: SyntaxNodePtr { kind: STRUCT, @@ -510,11 +424,7 @@ name: "StructInModB", loc: DeclarationLocation { hir_file_id: HirFileId( - FileId( - FileId( - 1, - ), - ), + 1, ), ptr: SyntaxNodePtr { kind: STRUCT, From 822c61f559dc522dbd28f2886d20989a55613fc0 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Sat, 26 Nov 2022 23:51:57 +0900 Subject: [PATCH 0608/2442] refactor: remove unnecessary stuff --- crates/ide-assists/src/handlers/extract_function.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index c1e2f19ab18b..10a3a33226bb 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -265,7 +265,7 @@ enum ParamKind { MutRef, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug)] enum FunType { Unit, Single(hir::Type), @@ -1368,7 +1368,7 @@ impl FlowHandler { None => FlowHandler::None, Some(flow_kind) => { let action = flow_kind.clone(); - if *ret_ty == FunType::Unit { + if let FunType::Unit = ret_ty { match flow_kind { FlowKind::Return(None) | FlowKind::Break(_, None) @@ -1946,7 +1946,7 @@ fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) { if nested_scope.is_none() { if let Some(expr) = ast::Expr::cast(e.clone()) { match expr { - ast::Expr::ReturnExpr(return_expr) if nested_scope.is_none() => { + ast::Expr::ReturnExpr(return_expr) => { let expr = return_expr.expr(); if let Some(replacement) = make_rewritten_flow(handler, expr) { ted::replace(return_expr.syntax(), replacement.syntax()) From 8e03f18e37d2782189391955bc56d3aebead81f5 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Sat, 26 Nov 2022 23:51:22 +0900 Subject: [PATCH 0609/2442] fix: check if range contains tail expression --- .../src/handlers/extract_function.rs | 204 ++++++++++++++++-- 1 file changed, 183 insertions(+), 21 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 10a3a33226bb..0483cfdc6466 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -11,7 +11,9 @@ use ide_db::{ helpers::mod_path_to_ast, imports::insert_use::{insert_use, ImportScope}, search::{FileReference, ReferenceCategory, SearchScope}, - syntax_helpers::node_ext::{preorder_expr, walk_expr, walk_pat, walk_patterns_in_expr}, + syntax_helpers::node_ext::{ + for_each_tail_expr, preorder_expr, walk_expr, walk_pat, walk_patterns_in_expr, + }, FxIndexSet, RootDatabase, }; use itertools::Itertools; @@ -78,7 +80,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op }; let body = extraction_target(&node, range)?; - let container_info = body.analyze_container(&ctx.sema)?; + let (container_info, contains_tail_expr) = body.analyze_container(&ctx.sema)?; let (locals_used, self_param) = body.analyze(&ctx.sema); @@ -119,6 +121,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op ret_ty, body, outliving_locals, + contains_tail_expr, mods: container_info, }; @@ -245,6 +248,8 @@ struct Function { ret_ty: RetType, body: FunctionBody, outliving_locals: Vec, + /// Whether at least one of the container's tail expr is contained in the range we're extracting. + contains_tail_expr: bool, mods: ContainerInfo, } @@ -294,7 +299,6 @@ struct ControlFlow { #[derive(Clone, Debug)] struct ContainerInfo { is_const: bool, - is_in_tail: bool, parent_loop: Option, /// The function's return type, const's type etc. ret_type: Option, @@ -743,7 +747,10 @@ impl FunctionBody { (res, self_param) } - fn analyze_container(&self, sema: &Semantics<'_, RootDatabase>) -> Option { + fn analyze_container( + &self, + sema: &Semantics<'_, RootDatabase>, + ) -> Option<(ContainerInfo, bool)> { let mut ancestors = self.parent()?.ancestors(); let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted); let mut parent_loop = None; @@ -815,28 +822,36 @@ impl FunctionBody { } }; }; - let container_tail = match expr? { - ast::Expr::BlockExpr(block) => block.tail_expr(), - expr => Some(expr), - }; - let is_in_tail = - container_tail.zip(self.tail_expr()).map_or(false, |(container_tail, body_tail)| { - container_tail.syntax().text_range().contains_range(body_tail.syntax().text_range()) + + let expr = expr?; + let contains_tail_expr = if let Some(body_tail) = self.tail_expr() { + let mut contains_tail_expr = false; + let tail_expr_range = body_tail.syntax().text_range(); + for_each_tail_expr(&expr, &mut |e| { + if tail_expr_range.contains_range(e.syntax().text_range()) { + contains_tail_expr = true; + } }); + contains_tail_expr + } else { + false + }; let parent = self.parent()?; let parents = generic_parents(&parent); let generic_param_lists = parents.iter().filter_map(|it| it.generic_param_list()).collect(); let where_clauses = parents.iter().filter_map(|it| it.where_clause()).collect(); - Some(ContainerInfo { - is_in_tail, - is_const, - parent_loop, - ret_type: ty, - generic_param_lists, - where_clauses, - }) + Some(( + ContainerInfo { + is_const, + parent_loop, + ret_type: ty, + generic_param_lists, + where_clauses, + }, + contains_tail_expr, + )) } fn return_ty(&self, ctx: &AssistContext<'_>) -> Option { @@ -1633,7 +1648,7 @@ impl Function { fn make_ret_ty(&self, ctx: &AssistContext<'_>, module: hir::Module) -> Option { let fun_ty = self.return_type(ctx); - let handler = if self.mods.is_in_tail { + let handler = if self.contains_tail_expr { FlowHandler::None } else { FlowHandler::from_ret_ty(self, &fun_ty) @@ -1707,7 +1722,7 @@ fn make_body( fun: &Function, ) -> ast::BlockExpr { let ret_ty = fun.return_type(ctx); - let handler = if fun.mods.is_in_tail { + let handler = if fun.contains_tail_expr { FlowHandler::None } else { FlowHandler::from_ret_ty(fun, &ret_ty) @@ -5582,6 +5597,153 @@ impl Struct where T: Into + Copy, U: Debug { fn $0fun_name(t: T, v: V) -> i32 where T: Into + Copy, V: Into { t.into() + v.into() } +"#, + ); + } + + #[test] + fn non_tail_expr_of_tail_expr_loop() { + check_assist( + extract_function, + r#" +pub fn f() { + loop { + $0if true { + continue; + }$0 + + if false { + break; + } + } +} +"#, + r#" +pub fn f() { + loop { + if let ControlFlow::Break(_) = fun_name() { + continue; + } + + if false { + break; + } + } +} + +fn $0fun_name() -> ControlFlow<()> { + if true { + return ControlFlow::Break(()); + } + ControlFlow::Continue(()) +} +"#, + ); + } + + #[test] + fn non_tail_expr_of_tail_if_block() { + // FIXME: double semicolon + check_assist( + extract_function, + r#" +//- minicore: option, try +impl core::ops::Try for Option { + type Output = T; + type Residual = Option; +} +impl core::ops::FromResidual for Option {} + +fn f() -> Option<()> { + if true { + let a = $0if true { + Some(())? + } else { + () + }$0; + Some(a) + } else { + None + } +} +"#, + r#" +impl core::ops::Try for Option { + type Output = T; + type Residual = Option; +} +impl core::ops::FromResidual for Option {} + +fn f() -> Option<()> { + if true { + let a = fun_name()?;; + Some(a) + } else { + None + } +} + +fn $0fun_name() -> Option<()> { + Some(if true { + Some(())? + } else { + () + }) +} +"#, + ); + } + + #[test] + fn tail_expr_of_tail_block_nested() { + check_assist( + extract_function, + r#" +//- minicore: option, try +impl core::ops::Try for Option { + type Output = T; + type Residual = Option; +} +impl core::ops::FromResidual for Option {} + +fn f() -> Option<()> { + if true { + $0{ + let a = if true { + Some(())? + } else { + () + }; + Some(a) + }$0 + } else { + None + } +} +"#, + r#" +impl core::ops::Try for Option { + type Output = T; + type Residual = Option; +} +impl core::ops::FromResidual for Option {} + +fn f() -> Option<()> { + if true { + fun_name()? + } else { + None + } +} + +fn $0fun_name() -> Option<()> { + let a = if true { + Some(())? + } else { + () + }; + Some(a) +} "#, ); } From e1de04d60ceff530295f57ae47a65e9c05716bbf Mon Sep 17 00:00:00 2001 From: yue4u Date: Sun, 27 Nov 2022 01:53:45 +0900 Subject: [PATCH 0610/2442] fix: only special casing 3 colon in a row --- crates/ide-completion/src/context.rs | 22 +++------------------- crates/ide-completion/src/tests/special.rs | 8 +------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index a0e1153f08b8..0e3b677f2d67 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -581,7 +581,9 @@ impl<'a> CompletionContext<'a> { return None; } - if !is_prev_token_valid_path_start_or_segment(&prev_token) { + // has 3 colon in a row + // special casing this as per discussion in https://github.com/rust-lang/rust-analyzer/pull/13611#discussion_r1031845205 + if prev_token.prev_token().map(|t| t.kind() == T![:]).unwrap_or(false) { return None; } } @@ -637,24 +639,6 @@ impl<'a> CompletionContext<'a> { } } -fn is_prev_token_valid_path_start_or_segment(token: &SyntaxToken) -> bool { - if let Some(prev_token) = token.prev_token() { - // token before coloncolon is invalid - if !matches!( - prev_token.kind(), - // trival - WHITESPACE | COMMENT - // PathIdentSegment - | IDENT | T![super] | T![self] | T![Self] | T![crate] - // QualifiedPath - | T![>] - ) { - return false; - } - } - true -} - const OP_TRAIT_LANG_NAMES: &[&str] = &[ "add_assign", "add", diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index 6cfa72d6539b..0e59f4ec5416 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -967,16 +967,10 @@ fn foo { crate:$0 } } #[test] -fn no_completions_in_invalid_path() { +fn no_completions_in_after_tripple_colon() { check( r#" fn foo { crate:::$0 } -"#, - expect![""], - ); - check( - r#" -fn foo { crate::::$0 } "#, expect![""], ); From 1ca5cb7ed9928fad4222cb26727da41ff9ac148f Mon Sep 17 00:00:00 2001 From: yue4u Date: Sun, 27 Nov 2022 02:39:38 +0900 Subject: [PATCH 0611/2442] fix: also exclude 2 coloncolon in a row --- crates/ide-completion/src/context.rs | 9 +++++++-- crates/ide-completion/src/tests/special.rs | 8 +++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 0e3b677f2d67..aa77f449530e 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -581,9 +581,14 @@ impl<'a> CompletionContext<'a> { return None; } - // has 3 colon in a row + // has 3 colon or 2 coloncolon in a row // special casing this as per discussion in https://github.com/rust-lang/rust-analyzer/pull/13611#discussion_r1031845205 - if prev_token.prev_token().map(|t| t.kind() == T![:]).unwrap_or(false) { + // and https://github.com/rust-lang/rust-analyzer/pull/13611#discussion_r1032812751 + if prev_token + .prev_token() + .map(|t| t.kind() == T![:] || t.kind() == T![::]) + .unwrap_or(false) + { return None; } } diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index 0e59f4ec5416..cad4af4937de 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -967,11 +967,17 @@ fn foo { crate:$0 } } #[test] -fn no_completions_in_after_tripple_colon() { +fn no_completions_in_invalid_path() { check( r#" fn foo { crate:::$0 } "#, expect![""], ); + check( + r#" +fn foo { crate::::$0 } +"#, + expect![""], + ) } From 8661740626ae7f608051e1309d802c408b1e20e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maria=20Jos=C3=A9=20Solano?= Date: Sun, 27 Nov 2022 09:46:37 -0800 Subject: [PATCH 0612/2442] Use typed notification method --- editors/code/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 25f1e83d109c..01a1a2db7fdf 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -79,7 +79,7 @@ async function activateServer(ctx: Ctx): Promise { ); vscode.workspace.onDidChangeConfiguration( async (_) => { - await ctx.client?.sendNotification("workspace/didChangeConfiguration", { + await ctx.client?.sendNotification(lc.DidChangeConfigurationNotification.type, { settings: "", }); }, From 2174aca8f8601a0135827377ebf349838e1123db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maria=20Jos=C3=A9=20Solano?= Date: Sun, 27 Nov 2022 10:07:09 -0800 Subject: [PATCH 0613/2442] Check for workspace root in runnable codelens --- crates/rust-analyzer/src/to_proto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 81cc1952ba5c..fcc4d7be24d2 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -1164,7 +1164,7 @@ pub(crate) fn code_lens( let r = runnable(snap, run)?; let lens_config = snap.config.lens(); - if lens_config.run && client_commands_config.run_single { + if lens_config.run && client_commands_config.run_single && r.args.workspace_root.is_some() { let command = command::run_single(&r, &title); acc.push(lsp_types::CodeLens { range: annotation_range, From b3bd5a471e314841fb1d2d94fdc50ef3c8d8548f Mon Sep 17 00:00:00 2001 From: Crauzer Date: Tue, 29 Nov 2022 00:32:13 +0100 Subject: [PATCH 0614/2442] implement vararg type collection from function params --- crates/hir-expand/src/name.rs | 1 + crates/hir-ty/src/infer.rs | 19 ++++++++++++++++++- crates/hir-ty/src/tests/patterns.rs | 12 ++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 2679a1c36026..259fe1327f88 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -419,6 +419,7 @@ pub mod known { shr, sub_assign, sub, + va_list ); // self/Self cannot be used as an identifier diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 0b3c23f5747a..112eb5bd84cd 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -537,8 +537,20 @@ impl<'a> InferenceContext<'a> { let data = self.db.function_data(func); let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) .with_impl_trait_mode(ImplTraitLoweringMode::Param); - let param_tys = + let mut param_tys = data.params.iter().map(|(_, type_ref)| ctx.lower_ty(type_ref)).collect::>(); + // Check if function contains a va_list, if it does then we append it to the parameter types + // that are collected from the function data + if data.is_varargs() { + let va_list_ty = match self.resolve_va_list() { + Some(va_list) => TyBuilder::adt(self.db, va_list) + .fill_with_defaults(self.db, || self.table.new_type_var()) + .build(), + None => self.err_ty(), + }; + + param_tys.push(va_list_ty) + } for (ty, pat) in param_tys.into_iter().zip(self.body.params.iter()) { let ty = self.insert_type_vars(ty); let ty = self.normalize_associated_types_in(ty); @@ -983,6 +995,11 @@ impl<'a> InferenceContext<'a> { let trait_ = self.resolve_ops_index()?; self.db.trait_data(trait_).associated_type_by_name(&name![Output]) } + + fn resolve_va_list(&self) -> Option { + let struct_ = self.resolve_lang_item(name![va_list])?.as_struct()?; + Some(struct_.into()) + } } /// When inferring an expression, we propagate downward whatever type hint we diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs index 74de33117ee7..9333e2693522 100644 --- a/crates/hir-ty/src/tests/patterns.rs +++ b/crates/hir-ty/src/tests/patterns.rs @@ -1080,3 +1080,15 @@ fn my_fn(#[cfg(feature = "feature")] u8: u8, u32: u32) {} "#, ); } + +#[test] +fn var_args() { + check_types( + r#" +#[lang = "va_list"] +pub struct VaListImpl<'f>; +fn my_fn(foo: ...) {} + //^^^ VaListImpl +"#, + ); +} From 9914d30450ffbd64c2acbfa44d22add033df2a5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maria=20Jos=C3=A9=20Solano?= Date: Mon, 28 Nov 2022 19:10:16 -0800 Subject: [PATCH 0615/2442] Fix formatting --- crates/rust-analyzer/src/to_proto.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index fcc4d7be24d2..d1f805af1d46 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -1164,7 +1164,10 @@ pub(crate) fn code_lens( let r = runnable(snap, run)?; let lens_config = snap.config.lens(); - if lens_config.run && client_commands_config.run_single && r.args.workspace_root.is_some() { + if lens_config.run + && client_commands_config.run_single + && r.args.workspace_root.is_some() + { let command = command::run_single(&r, &title); acc.push(lsp_types::CodeLens { range: annotation_range, From 16bf32fcdd1398d7adeccfbd9e11cd8e2d3b4c11 Mon Sep 17 00:00:00 2001 From: Wilco Kusee Date: Tue, 29 Nov 2022 15:25:09 +0100 Subject: [PATCH 0616/2442] Update Chalk to version 87 --- Cargo.lock | 16 ++++++++-------- crates/hir-ty/Cargo.toml | 8 ++++---- crates/hir-ty/src/chalk_db.rs | 2 ++ crates/hir-ty/src/display.rs | 1 - 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41c5d36671de..84dda206db2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -171,9 +171,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chalk-derive" -version = "0.86.0" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5499d415d855b5094366a824815341893ad3de0ecb6048c430118bdae6d27402" +checksum = "d552b2fa341f5fc35c6b917b1d289d3c3a34d0b74e579390ea6192d6152a8cdb" dependencies = [ "proc-macro2", "quote", @@ -183,9 +183,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.86.0" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3800118c76a48507b0eece3a01f3a429b5c478d203c493096e6040c67ab960e1" +checksum = "43aa55deff4e7fbdb09fa014543372f2c95a06835ac487b9ce57b5099b950838" dependencies = [ "bitflags", "chalk-derive", @@ -194,9 +194,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.86.0" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1baf60628fd73104d1f8562586a52d48f37f1e84435aab2e62674b1fd935b8c8" +checksum = "80179569cdc8b618b02e2b91b3314802778f4d73b75cd6fd2a451171df9d5611" dependencies = [ "chalk-derive", "chalk-ir", @@ -207,9 +207,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.86.0" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e9c3c068f9358786348e58a1b94ef0a5cf90a9810fc1f10fda896f0b5d80185" +checksum = "61213deefc36ba265ad01c4d997e18bcddf7922862a4594a47ca4575afb3dab4" dependencies = [ "chalk-derive", "chalk-ir", diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index a1d6835bfaed..802face85243 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -18,10 +18,10 @@ ena = "0.14.0" tracing = "0.1.35" rustc-hash = "1.1.0" scoped-tls = "1.0.0" -chalk-solve = { version = "0.86.0", default-features = false } -chalk-ir = "0.86.0" -chalk-recursive = { version = "0.86.0", default-features = false } -chalk-derive = "0.86.0" +chalk-solve = { version = "0.87.0", default-features = false } +chalk-ir = "0.87.0" +chalk-recursive = { version = "0.87.0", default-features = false } +chalk-derive = "0.87.0" la-arena = { version = "0.3.0", path = "../../lib/la-arena" } once_cell = "1.15.0" typed-arena = "2.0.1" diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index 43c3451cab37..1c2b8de7f784 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -568,6 +568,7 @@ fn well_known_trait_from_lang_attr(name: &str) -> Option { "sized" => WellKnownTrait::Sized, "unpin" => WellKnownTrait::Unpin, "unsize" => WellKnownTrait::Unsize, + "tuple_trait" => WellKnownTrait::Tuple, _ => return None, }) } @@ -585,6 +586,7 @@ fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str { WellKnownTrait::FnOnce => "fn_once", WellKnownTrait::Generator => "generator", WellKnownTrait::Sized => "sized", + WellKnownTrait::Tuple => "tuple_trait", WellKnownTrait::Unpin => "unpin", WellKnownTrait::Unsize => "unsize", } diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index a22a4b170f61..9d453eef7168 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -1098,7 +1098,6 @@ impl HirDisplay for LifetimeData { write!(f, "{}", param_data.name) } LifetimeData::Static => write!(f, "'static"), - LifetimeData::Empty(_) => Ok(()), LifetimeData::Erased => Ok(()), LifetimeData::Phantom(_, _) => Ok(()), } From b65b02fd976d0174312e71ac8735ed8fecdfc74e Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 29 Nov 2022 18:50:21 +0100 Subject: [PATCH 0617/2442] Fix signature help not showing up when cursor is between `))` or `>>` --- crates/ide/src/signature_help.rs | 58 +++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index e7412d27faf4..6045a787ecc2 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -74,20 +74,28 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio ast::ArgList(arg_list) => { let cursor_outside = arg_list.r_paren_token().as_ref() == Some(&token); if cursor_outside { - return None; + continue; } - return signature_help_for_call(&sema, token); + return signature_help_for_call(&sema, arg_list, token); }, ast::GenericArgList(garg_list) => { let cursor_outside = garg_list.r_angle_token().as_ref() == Some(&token); if cursor_outside { - return None; + continue; } - return signature_help_for_generics(&sema, token); + return signature_help_for_generics(&sema, garg_list, token); }, _ => (), } } + + // Stop at multi-line expressions, since the signature of the outer call is not very + // helpful inside them. + if let Some(expr) = ast::Expr::cast(node.clone()) { + if expr.syntax().text().contains_char('\n') { + return None; + } + } } None @@ -95,10 +103,11 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio fn signature_help_for_call( sema: &Semantics<'_, RootDatabase>, + arg_list: ast::ArgList, token: SyntaxToken, ) -> Option { // Find the calling expression and its NameRef - let mut node = token.parent()?; + let mut node = arg_list.syntax().parent()?; let calling_node = loop { if let Some(callable) = ast::CallableExpr::cast(node.clone()) { if callable @@ -109,14 +118,6 @@ fn signature_help_for_call( } } - // Stop at multi-line expressions, since the signature of the outer call is not very - // helpful inside them. - if let Some(expr) = ast::Expr::cast(node.clone()) { - if expr.syntax().text().contains_char('\n') { - return None; - } - } - node = node.parent()?; }; @@ -200,10 +201,11 @@ fn signature_help_for_call( fn signature_help_for_generics( sema: &Semantics<'_, RootDatabase>, + garg_list: ast::GenericArgList, token: SyntaxToken, ) -> Option { - let parent = token.parent()?; - let arg_list = parent + let arg_list = garg_list + .syntax() .ancestors() .filter_map(ast::GenericArgList::cast) .find(|list| list.syntax().text_range().contains(token.text_range().start()))?; @@ -770,6 +772,32 @@ fn f() { "#, expect![[]], ); + check( + r#" +fn foo(a: u8) -> u8 {a} +fn bar(a: u8) -> u8 {a} +fn f() { + foo(bar(123)$0) +} +"#, + expect![[r#" + fn foo(a: u8) -> u8 + ^^^^^ + "#]], + ); + check( + r#" +struct Vec(T); +struct Vec2(T); +fn f() { + let _: Vec2$0> +} +"#, + expect![[r#" + struct Vec2 + ^ + "#]], + ); } #[test] From 335cb2605010b29426a87c7ba15244f580fd92f7 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 29 Nov 2022 19:20:32 +0100 Subject: [PATCH 0618/2442] Version the inlay hint resolve data --- crates/rust-analyzer/src/from_proto.rs | 10 +++++++++- crates/rust-analyzer/src/handlers.rs | 22 ++++++++++++++++++++-- crates/rust-analyzer/src/lsp_ext.rs | 4 ++-- crates/rust-analyzer/src/to_proto.rs | 10 ++++++++-- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index dd433b0f4d31..4e7095b3ce3b 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs @@ -67,7 +67,15 @@ pub(crate) fn file_range( text_document_identifier: lsp_types::TextDocumentIdentifier, range: lsp_types::Range, ) -> Result { - let file_id = file_id(snap, &text_document_identifier.uri)?; + file_range_uri(snap, &text_document_identifier.uri, range) +} + +pub(crate) fn file_range_uri( + snap: &GlobalStateSnapshot, + document: &lsp_types::Url, + range: lsp_types::Range, +) -> Result { + let file_id = file_id(snap, document)?; let line_index = snap.file_line_index(file_id)?; let range = text_range(&line_index, range)?; Ok(FileRange { file_id, range }) diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 4f318f39de5f..1604a02fb135 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -29,6 +29,7 @@ use project_model::{ManifestPath, ProjectWorkspace, TargetKind}; use serde_json::json; use stdx::{format_to, never}; use syntax::{algo, ast, AstNode, TextRange, TextSize}; +use tracing::error; use vfs::AbsPathBuf; use crate::{ @@ -1372,9 +1373,26 @@ pub(crate) fn handle_inlay_hints_resolve( let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?; - let file_range = from_proto::file_range( + match snap.url_file_version(&resolve_data.text_document.uri) { + Some(version) if version == resolve_data.text_document.version => {} + Some(version) => { + error!( + "attempted inlayHints/resolve of '{}' at version {} while server version is {}", + resolve_data.text_document.uri, resolve_data.text_document.version, version, + ); + return Ok(hint); + } + None => { + error!( + "attempted inlayHints/resolve of unknown file '{}' at version {}", + resolve_data.text_document.uri, resolve_data.text_document.version, + ); + return Ok(hint); + } + } + let file_range = from_proto::file_range_uri( &snap, - resolve_data.text_document, + &resolve_data.text_document.uri, match resolve_data.position { PositionOrRange::Position(pos) => Range::new(pos, pos), PositionOrRange::Range(range) => range, diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 8cc5648f3ce0..a1df0b6d7dd5 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -3,11 +3,11 @@ use std::{collections::HashMap, path::PathBuf}; use lsp_types::request::Request; -use lsp_types::PositionEncodingKind; use lsp_types::{ notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams, PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams, }; +use lsp_types::{PositionEncodingKind, VersionedTextDocumentIdentifier}; use serde::{Deserialize, Serialize}; pub enum AnalyzerStatus {} @@ -550,7 +550,7 @@ pub struct CompletionResolveData { #[derive(Debug, Serialize, Deserialize)] pub struct InlayHintResolveData { - pub text_document: TextDocumentIdentifier, + pub text_document: VersionedTextDocumentIdentifier, pub position: PositionOrRange, } diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index d1f805af1d46..3ce24bdd14fd 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -492,7 +492,10 @@ pub(crate) fn inlay_hint( let uri = url(snap, file_id); let line_index = snap.file_line_index(file_id).ok()?; - let text_document = lsp_types::TextDocumentIdentifier { uri }; + let text_document = lsp_types::VersionedTextDocumentIdentifier { + version: snap.url_file_version(&uri)?, + uri, + }; to_value(lsp_ext::InlayHintResolveData { text_document, position: lsp_ext::PositionOrRange::Position(position(&line_index, offset)), @@ -501,7 +504,10 @@ pub(crate) fn inlay_hint( } Some(ide::InlayTooltip::HoverRanged(file_id, text_range)) => { let uri = url(snap, file_id); - let text_document = lsp_types::TextDocumentIdentifier { uri }; + let text_document = lsp_types::VersionedTextDocumentIdentifier { + version: snap.url_file_version(&uri)?, + uri, + }; let line_index = snap.file_line_index(file_id).ok()?; to_value(lsp_ext::InlayHintResolveData { text_document, From 32f59cf01de639d0b23753687f5fb5b08c0758c0 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 29 Nov 2022 19:33:16 +0100 Subject: [PATCH 0619/2442] Update hash --- docs/dev/lsp-extensions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index fe316fcae9b8..5aced035d526 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ [^\n]+\n/m, ""); } + let value; + if (errorCode) { + if (typeof diag.code === "string" || typeof diag.code === "number") { + value = diag.code; + } else { + value = diag.code?.value; + } + } diag.code = { target: vscode.Uri.from({ scheme: "rust-analyzer-diagnostics-view", @@ -131,7 +141,7 @@ export async function createClient( fragment: uri.toString(), query: idx.toString(), }), - value: "Click for full compiler diagnostic", + value: value ?? "Click for full compiler diagnostic", }; } }); diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index d8dbd1df16df..eb4f965291fe 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -241,6 +241,10 @@ export class Config { get previewRustcOutput() { return this.get("diagnostics.previewRustcOutput"); } + + get useRustcErrorCode() { + return this.get("diagnostics.useRustcErrorCode"); + } } const VarRegex = new RegExp(/\$\{(.+?)\}/g); From b996a54cd845ae315a7b089437b43bf1b79a5e65 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 3 Jan 2023 11:58:31 +0100 Subject: [PATCH 0757/2442] Skip lifetime elision on fn pointers and fn trait types --- crates/hir-ty/src/infer/expr.rs | 1 + .../src/handlers/add_explicit_type.rs | 5 +- .../src/handlers/extract_type_alias.rs | 130 +++++++++--------- crates/ide-db/src/syntax_helpers/node_ext.rs | 9 +- crates/ide/src/inlay_hints/fn_lifetime_fn.rs | 30 +++- 5 files changed, 105 insertions(+), 70 deletions(-) diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 2e5c4244109f..a015f67024fd 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -334,6 +334,7 @@ impl<'a> InferenceContext<'a> { let (param_tys, ret_ty) = match res { Some(res) => { let adjustments = auto_deref_adjust_steps(&derefs); + // FIXME: Handle call adjustments for Fn/FnMut self.write_expr_adj(*callee, adjustments); res } diff --git a/crates/ide-assists/src/handlers/add_explicit_type.rs b/crates/ide-assists/src/handlers/add_explicit_type.rs index b5f99726fe1c..0057f439f1af 100644 --- a/crates/ide-assists/src/handlers/add_explicit_type.rs +++ b/crates/ide-assists/src/handlers/add_explicit_type.rs @@ -47,7 +47,10 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> O // Don't enable the assist if there is a type ascription without any placeholders if let Some(ty) = &ascribed_ty { let mut contains_infer_ty = false; - walk_ty(ty, &mut |ty| contains_infer_ty |= matches!(ty, ast::Type::InferType(_))); + walk_ty(ty, &mut |ty| { + contains_infer_ty |= matches!(ty, ast::Type::InferType(_)); + false + }); if !contains_infer_ty { cov_mark::hit!(add_explicit_type_not_applicable_if_ty_already_specified); return None; diff --git a/crates/ide-assists/src/handlers/extract_type_alias.rs b/crates/ide-assists/src/handlers/extract_type_alias.rs index 3116935fc5e7..0505f5784f81 100644 --- a/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -108,76 +108,80 @@ fn collect_used_generics<'gp>( } let mut generics = Vec::new(); - walk_ty(ty, &mut |ty| match ty { - ast::Type::PathType(ty) => { - if let Some(path) = ty.path() { - if let Some(name_ref) = path.as_single_name_ref() { - if let Some(param) = known_generics.iter().find(|gp| { - match gp { - ast::GenericParam::ConstParam(cp) => cp.name(), - ast::GenericParam::TypeParam(tp) => tp.name(), - _ => None, - } - .map_or(false, |n| n.text() == name_ref.text()) - }) { - generics.push(param); - } - } - generics.extend( - path.segments() - .filter_map(|seg| seg.generic_arg_list()) - .flat_map(|it| it.generic_args()) - .filter_map(|it| match it { - ast::GenericArg::LifetimeArg(lt) => { - let lt = lt.lifetime()?; - known_generics.iter().find(find_lifetime(<.text())) + walk_ty(ty, &mut |ty| { + match ty { + ast::Type::PathType(ty) => { + if let Some(path) = ty.path() { + if let Some(name_ref) = path.as_single_name_ref() { + if let Some(param) = known_generics.iter().find(|gp| { + match gp { + ast::GenericParam::ConstParam(cp) => cp.name(), + ast::GenericParam::TypeParam(tp) => tp.name(), + _ => None, } - _ => None, - }), - ); - } - } - ast::Type::ImplTraitType(impl_ty) => { - if let Some(it) = impl_ty.type_bound_list() { - generics.extend( - it.bounds() - .filter_map(|it| it.lifetime()) - .filter_map(|lt| known_generics.iter().find(find_lifetime(<.text()))), - ); - } - } - ast::Type::DynTraitType(dyn_ty) => { - if let Some(it) = dyn_ty.type_bound_list() { - generics.extend( - it.bounds() - .filter_map(|it| it.lifetime()) - .filter_map(|lt| known_generics.iter().find(find_lifetime(<.text()))), - ); - } - } - ast::Type::RefType(ref_) => generics.extend( - ref_.lifetime().and_then(|lt| known_generics.iter().find(find_lifetime(<.text()))), - ), - ast::Type::ArrayType(ar) => { - if let Some(expr) = ar.expr() { - if let ast::Expr::PathExpr(p) = expr { - if let Some(path) = p.path() { - if let Some(name_ref) = path.as_single_name_ref() { - if let Some(param) = known_generics.iter().find(|gp| { - if let ast::GenericParam::ConstParam(cp) = gp { - cp.name().map_or(false, |n| n.text() == name_ref.text()) - } else { - false + .map_or(false, |n| n.text() == name_ref.text()) + }) { + generics.push(param); + } + } + generics.extend( + path.segments() + .filter_map(|seg| seg.generic_arg_list()) + .flat_map(|it| it.generic_args()) + .filter_map(|it| match it { + ast::GenericArg::LifetimeArg(lt) => { + let lt = lt.lifetime()?; + known_generics.iter().find(find_lifetime(<.text())) + } + _ => None, + }), + ); + } + } + ast::Type::ImplTraitType(impl_ty) => { + if let Some(it) = impl_ty.type_bound_list() { + generics.extend( + it.bounds() + .filter_map(|it| it.lifetime()) + .filter_map(|lt| known_generics.iter().find(find_lifetime(<.text()))), + ); + } + } + ast::Type::DynTraitType(dyn_ty) => { + if let Some(it) = dyn_ty.type_bound_list() { + generics.extend( + it.bounds() + .filter_map(|it| it.lifetime()) + .filter_map(|lt| known_generics.iter().find(find_lifetime(<.text()))), + ); + } + } + ast::Type::RefType(ref_) => generics.extend( + ref_.lifetime() + .and_then(|lt| known_generics.iter().find(find_lifetime(<.text()))), + ), + ast::Type::ArrayType(ar) => { + if let Some(expr) = ar.expr() { + if let ast::Expr::PathExpr(p) = expr { + if let Some(path) = p.path() { + if let Some(name_ref) = path.as_single_name_ref() { + if let Some(param) = known_generics.iter().find(|gp| { + if let ast::GenericParam::ConstParam(cp) = gp { + cp.name().map_or(false, |n| n.text() == name_ref.text()) + } else { + false + } + }) { + generics.push(param); } - }) { - generics.push(param); } } } } } - } - _ => (), + _ => (), + }; + false }); // stable resort to lifetime, type, const generics.sort_by_key(|gp| match gp { diff --git a/crates/ide-db/src/syntax_helpers/node_ext.rs b/crates/ide-db/src/syntax_helpers/node_ext.rs index b72003ff3633..aa03478599d6 100644 --- a/crates/ide-db/src/syntax_helpers/node_ext.rs +++ b/crates/ide-db/src/syntax_helpers/node_ext.rs @@ -173,7 +173,8 @@ pub fn walk_pat(pat: &ast::Pat, cb: &mut dyn FnMut(ast::Pat)) { } /// Preorder walk all the type's sub types. -pub fn walk_ty(ty: &ast::Type, cb: &mut dyn FnMut(ast::Type)) { +// FIXME: Make the control flow more proper +pub fn walk_ty(ty: &ast::Type, cb: &mut dyn FnMut(ast::Type) -> bool) { let mut preorder = ty.syntax().preorder(); while let Some(event) = preorder.next() { let node = match event { @@ -184,10 +185,12 @@ pub fn walk_ty(ty: &ast::Type, cb: &mut dyn FnMut(ast::Type)) { match ast::Type::cast(node) { Some(ty @ ast::Type::MacroType(_)) => { preorder.skip_subtree(); - cb(ty) + cb(ty); } Some(ty) => { - cb(ty); + if cb(ty) { + preorder.skip_subtree(); + } } // skip const args None if ast::ConstArg::can_cast(kind) => { diff --git a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs index 1f5bcea63a20..2aa5e3dc734f 100644 --- a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs +++ b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs @@ -59,9 +59,14 @@ pub(super) fn hints( r.amp_token(), lifetime, is_elided, - )) + )); + false } - _ => (), + ast::Type::FnPtrType(_) => true, + ast::Type::PathType(t) => { + t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some() + } + _ => false, }) }); acc @@ -146,8 +151,13 @@ pub(super) fn hints( is_trivial = false; acc.push(mk_lt_hint(amp, output_lt.to_string())); } + false } - _ => (), + ast::Type::FnPtrType(_) => true, + ast::Type::PathType(t) => { + t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some() + } + _ => false, }) } } @@ -295,6 +305,20 @@ impl () { // ^^^<'0, '1> // ^'0 ^'1 ^'0 } +"#, + ); + } + + #[test] + fn hints_lifetimes_skip_fn_likes() { + check_with_config( + InlayHintsConfig { + lifetime_elision_hints: LifetimeElisionHints::Always, + ..TEST_CONFIG + }, + r#" +fn fn_ptr(a: fn(&()) -> &()) {} +fn fn_trait<>(a: impl Fn(&()) -> &()) {} "#, ); } From c4d8cf1dad9e2ad5710c56533c42979e91520c78 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 3 Jan 2023 12:32:38 +0100 Subject: [PATCH 0758/2442] Use ZWNJ to prevent VSCode from forming ligatures between hints and code --- editors/code/src/client.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 1470c1f581d4..e6595340aae9 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -100,6 +100,24 @@ export async function createClient( } }, }, + async provideInlayHints(document, viewPort, token, next) { + const inlays = await next(document, viewPort, token); + if (!inlays) { + return inlays; + } + // U+200C is a zero-width non-joiner to prevent the editor from forming a ligature + // between code and hints + for (const inlay of inlays) { + if (typeof inlay.label === "string") { + inlay.label = `\u{200c}${inlay.label}\u{200c}`; + } else if (Array.isArray(inlay.label)) { + for (const it of inlay.label) { + it.value = `\u{200c}${it.value}\u{200c}`; + } + } + } + return inlays; + }, async handleDiagnostics( uri: vscode.Uri, diagnostics: vscode.Diagnostic[], From b6bb1e9ae777d54da910885cc1437f7660d987a4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 3 Jan 2023 15:46:08 +0100 Subject: [PATCH 0759/2442] Only set machine-applicable rustc diagnostics as preferred --- crates/rust-analyzer/src/diagnostics/to_proto.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index d1ee99af3ec6..80be43fe80a4 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -191,6 +191,7 @@ fn map_rust_child_diagnostic( let mut edit_map: HashMap> = HashMap::new(); let mut suggested_replacements = Vec::new(); + let mut is_preferred = true; for &span in &spans { if let Some(suggested_replacement) = &span.suggested_replacement { if !suggested_replacement.is_empty() { @@ -209,6 +210,8 @@ fn map_rust_child_diagnostic( ) { edit_map.entry(location.uri).or_default().push(edit); } + is_preferred &= + matches!(span.suggestion_applicability, Some(Applicability::MachineApplicable)); } } @@ -251,7 +254,7 @@ fn map_rust_child_diagnostic( document_changes: None, change_annotations: None, }), - is_preferred: Some(true), + is_preferred: Some(is_preferred), data: None, command: None, }, From 21ea0048cd879342cbec67152dbacec6e38b56bb Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Wed, 4 Jan 2023 18:20:15 +0900 Subject: [PATCH 0760/2442] fix: unescape inline module names in module resolution --- crates/hir-def/src/nameres/mod_resolution.rs | 2 +- .../src/nameres/tests/mod_resolution.rs | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/crates/hir-def/src/nameres/mod_resolution.rs b/crates/hir-def/src/nameres/mod_resolution.rs index 11d20d3db39a..4c263846d27d 100644 --- a/crates/hir-def/src/nameres/mod_resolution.rs +++ b/crates/hir-def/src/nameres/mod_resolution.rs @@ -34,7 +34,7 @@ impl ModDir { let path = match attr_path.map(SmolStr::as_str) { None => { let mut path = self.dir_path.clone(); - path.push(&name.to_smol_str()); + path.push(&name.unescaped().to_smol_str()); path } Some(attr_path) => { diff --git a/crates/hir-def/src/nameres/tests/mod_resolution.rs b/crates/hir-def/src/nameres/tests/mod_resolution.rs index c575bf7cac25..a01931288478 100644 --- a/crates/hir-def/src/nameres/tests/mod_resolution.rs +++ b/crates/hir-def/src/nameres/tests/mod_resolution.rs @@ -156,6 +156,43 @@ pub struct Baz; ); } +#[test] +fn module_resolution_works_for_inline_raw_modules() { + check( + r#" +//- /lib.rs +mod r#async { + pub mod a; + pub mod r#async; +} +use self::r#async::a::Foo; +use self::r#async::r#async::Bar; + +//- /async/a.rs +pub struct Foo; + +//- /async/async.rs +pub struct Bar; +"#, + expect![[r#" + crate + Bar: t v + Foo: t v + r#async: t + + crate::r#async + a: t + r#async: t + + crate::r#async::a + Foo: t v + + crate::r#async::r#async + Bar: t v + "#]], + ); +} + #[test] fn module_resolution_decl_path() { check( From ae73628f6bf0ee3ac6f571b447972f4f37a39103 Mon Sep 17 00:00:00 2001 From: bvanjoi Date: Wed, 4 Jan 2023 22:10:17 +0800 Subject: [PATCH 0761/2442] fix: keep whitespace in extract function handler --- .../src/handlers/extract_function.rs | 9 +++++---- crates/syntax/src/ast/make.rs | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 4ee9d4638bbd..94614360c729 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -1799,7 +1799,8 @@ fn make_body( }) .collect::>(); let tail_expr = tail_expr.map(|expr| expr.dedent(old_indent).indent(body_indent)); - make::hacky_block_expr_with_comments(elements, tail_expr) + + make::hacky_block_expr(elements, tail_expr) } }; @@ -1881,7 +1882,7 @@ fn with_tail_expr(block: ast::BlockExpr, tail_expr: ast::Expr) -> ast::BlockExpr elements.push(syntax::NodeOrToken::Node(stmt_tail.syntax().clone())); } - make::hacky_block_expr_with_comments(elements, Some(tail_expr)) + make::hacky_block_expr(elements, Some(tail_expr)) } fn format_type(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> String { @@ -4978,9 +4979,8 @@ fn $0fun_name() { ); } - // FIXME: we do want to preserve whitespace #[test] - fn extract_function_does_not_preserve_whitespace() { + fn extract_function_does_preserve_whitespace() { check_assist( extract_function, r#" @@ -4999,6 +4999,7 @@ fn func() { fn $0fun_name() { let a = 0; + let x = 0; } "#, diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 8c26009add2b..f17b7d8557df 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -339,10 +339,10 @@ pub fn tail_only_block_expr(tail_expr: ast::Expr) -> ast::BlockExpr { } /// Ideally this function wouldn't exist since it involves manual indenting. -/// It differs from `make::block_expr` by also supporting comments. +/// It differs from `make::block_expr` by also supporting comments and whitespace. /// /// FIXME: replace usages of this with the mutable syntax tree API -pub fn hacky_block_expr_with_comments( +pub fn hacky_block_expr( elements: impl IntoIterator, tail_expr: Option, ) -> ast::BlockExpr { @@ -350,10 +350,17 @@ pub fn hacky_block_expr_with_comments( for node_or_token in elements.into_iter() { match node_or_token { rowan::NodeOrToken::Node(n) => format_to!(buf, " {n}\n"), - rowan::NodeOrToken::Token(t) if t.kind() == SyntaxKind::COMMENT => { - format_to!(buf, " {t}\n") + rowan::NodeOrToken::Token(t) => { + let kind = t.kind(); + if kind == SyntaxKind::COMMENT { + format_to!(buf, " {t}\n") + } else if kind == SyntaxKind::WHITESPACE { + let content = t.text().trim_matches(|c| c != '\n'); + if content.len() >= 1 { + format_to!(buf, "{}", &content[1..]) + } + } } - _ => (), } } if let Some(tail_expr) = tail_expr { From 150da92b5c6e4a8dc3c27f24864de471c2b2c380 Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Wed, 4 Jan 2023 12:55:05 -0500 Subject: [PATCH 0762/2442] return immediately from `render_record_lit` if `snippet_cap` is None this is the record literal version of #13805, which handled the same issue for tuple literals --- .../ide-completion/src/completions/record.rs | 31 ++++++++++++++++++- crates/ide-completion/src/render/variant.rs | 3 ++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs index 6743ec897f00..0521e735dedf 100644 --- a/crates/ide-completion/src/completions/record.rs +++ b/crates/ide-completion/src/completions/record.rs @@ -159,8 +159,9 @@ fn baz() { #[test] fn enum_variant_no_snippets() { let conf = CompletionConfig { snippet_cap: SnippetCap::new(false), ..TEST_CONFIG }; + // tuple variant check_edit_with_config( - conf, + conf.clone(), "Variant()", r#" enum Enum { @@ -178,6 +179,34 @@ enum Enum { Variant(usize), } +impl Enum { + fn new(u: usize) -> Self { + Self::Variant + } +} +"#, + ); + + // record variant + check_edit_with_config( + conf, + "Variant{}", + r#" +enum Enum { + Variant{u: usize}, +} + +impl Enum { + fn new(u: usize) -> Self { + Self::Va$0 + } +} +"#, + r#" +enum Enum { + Variant{u: usize}, +} + impl Enum { fn new(u: usize) -> Self { Self::Variant diff --git a/crates/ide-completion/src/render/variant.rs b/crates/ide-completion/src/render/variant.rs index f3e88489f46d..55c55725be4f 100644 --- a/crates/ide-completion/src/render/variant.rs +++ b/crates/ide-completion/src/render/variant.rs @@ -22,6 +22,9 @@ pub(crate) fn render_record_lit( fields: &[hir::Field], path: &str, ) -> RenderedLiteral { + if snippet_cap.is_none() { + return RenderedLiteral { literal: path.to_string(), detail: path.to_string() }; + } let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| { if snippet_cap.is_some() { f(&format_args!("{}: ${{{}:()}}", field.name(db), idx + 1)) From 1bfc732b78aa1664245009c1d40d47d9ac149e94 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 5 Jan 2023 20:06:49 +0900 Subject: [PATCH 0763/2442] Store diverging flag for type variables as bitflags --- Cargo.lock | 1 + crates/hir-ty/Cargo.toml | 1 + crates/hir-ty/src/infer/unify.rs | 32 +++++++++++++++++--------------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c255b12b7f1..59cd66756cd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -557,6 +557,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", + "bitflags", "chalk-derive", "chalk-ir", "chalk-recursive", diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index c72199c37fe7..ae837ac6dce8 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -13,6 +13,7 @@ doctest = false cov-mark = "2.0.0-pre.1" itertools = "0.10.5" arrayvec = "0.7.2" +bitflags = "1.3.2" smallvec = "1.10.0" ena = "0.14.0" tracing = "0.1.35" diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 12f45f00f9c4..c4488d6d91ea 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -1,6 +1,6 @@ //! Unification and canonicalization logic. -use std::{fmt, mem, sync::Arc}; +use std::{fmt, iter, mem, sync::Arc}; use chalk_ir::{ cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy, @@ -128,9 +128,11 @@ pub(crate) fn unify( )) } -#[derive(Copy, Clone, Debug)] -pub(crate) struct TypeVariableData { - diverging: bool, +bitflags::bitflags! { + #[derive(Default)] + pub(crate) struct TypeVariableFlags: u8 { + const DIVERGING = 1 << 0; + } } type ChalkInferenceTable = chalk_solve::infer::InferenceTable; @@ -140,14 +142,14 @@ pub(crate) struct InferenceTable<'a> { pub(crate) db: &'a dyn HirDatabase, pub(crate) trait_env: Arc, var_unification_table: ChalkInferenceTable, - type_variable_table: Vec, + type_variable_table: Vec, pending_obligations: Vec>>, } pub(crate) struct InferenceTableSnapshot { var_table_snapshot: chalk_solve::infer::InferenceSnapshot, pending_obligations: Vec>>, - type_variable_table_snapshot: Vec, + type_variable_table_snapshot: Vec, } impl<'a> InferenceTable<'a> { @@ -169,19 +171,19 @@ impl<'a> InferenceTable<'a> { /// result. pub(super) fn propagate_diverging_flag(&mut self) { for i in 0..self.type_variable_table.len() { - if !self.type_variable_table[i].diverging { + if !self.type_variable_table[i].contains(TypeVariableFlags::DIVERGING) { continue; } let v = InferenceVar::from(i as u32); let root = self.var_unification_table.inference_var_root(v); if let Some(data) = self.type_variable_table.get_mut(root.index() as usize) { - data.diverging = true; + *data |= TypeVariableFlags::DIVERGING; } } } pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) { - self.type_variable_table[iv.index() as usize].diverging = diverging; + self.type_variable_table[iv.index() as usize].set(TypeVariableFlags::DIVERGING, diverging); } fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { @@ -189,7 +191,7 @@ impl<'a> InferenceTable<'a> { _ if self .type_variable_table .get(iv.index() as usize) - .map_or(false, |data| data.diverging) => + .map_or(false, |data| data.contains(TypeVariableFlags::DIVERGING)) => { TyKind::Never } @@ -247,10 +249,8 @@ impl<'a> InferenceTable<'a> { } fn extend_type_variable_table(&mut self, to_index: usize) { - self.type_variable_table.extend( - (0..1 + to_index - self.type_variable_table.len()) - .map(|_| TypeVariableData { diverging: false }), - ); + let count = to_index - self.type_variable_table.len() + 1; + self.type_variable_table.extend(iter::repeat(TypeVariableFlags::default()).take(count)); } fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty { @@ -258,7 +258,9 @@ impl<'a> InferenceTable<'a> { // Chalk might have created some type variables for its own purposes that we don't know about... self.extend_type_variable_table(var.index() as usize); assert_eq!(var.index() as usize, self.type_variable_table.len() - 1); - self.type_variable_table[var.index() as usize].diverging = diverging; + if diverging { + self.type_variable_table[var.index() as usize] |= TypeVariableFlags::DIVERGING; + } var.to_ty_with_kind(Interner, kind) } From b183612610c6383861f9c983a10588124800bac7 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 5 Jan 2023 20:19:46 +0900 Subject: [PATCH 0764/2442] Add `INTEGER` and `FLOAT` flags for type variables --- crates/hir-ty/src/infer/unify.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index c4488d6d91ea..a1fef48f25a8 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -132,6 +132,8 @@ bitflags::bitflags! { #[derive(Default)] pub(crate) struct TypeVariableFlags: u8 { const DIVERGING = 1 << 0; + const INTEGER = 1 << 1; + const FLOAT = 1 << 2; } } @@ -258,8 +260,14 @@ impl<'a> InferenceTable<'a> { // Chalk might have created some type variables for its own purposes that we don't know about... self.extend_type_variable_table(var.index() as usize); assert_eq!(var.index() as usize, self.type_variable_table.len() - 1); + let flags = self.type_variable_table.get_mut(var.index() as usize).unwrap(); if diverging { - self.type_variable_table[var.index() as usize] |= TypeVariableFlags::DIVERGING; + *flags |= TypeVariableFlags::DIVERGING; + } + if matches!(kind, TyVariableKind::Integer) { + *flags |= TypeVariableFlags::INTEGER; + } else if matches!(kind, TyVariableKind::Float) { + *flags |= TypeVariableFlags::FLOAT; } var.to_ty_with_kind(Interner, kind) } From d01630c8f39e88aa175db9dbe92a9e2a188007ab Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 5 Jan 2023 21:31:10 +0900 Subject: [PATCH 0765/2442] Apply fallback to scalar type variables before final obligation resolution --- crates/hir-ty/src/infer.rs | 2 + crates/hir-ty/src/infer/unify.rs | 45 +++++++++++++++++++++ crates/hir-ty/src/tests/traits.rs | 65 +++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 7b54886d53f8..6b59f1c20daa 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -512,6 +512,8 @@ impl<'a> InferenceContext<'a> { fn resolve_all(self) -> InferenceResult { let InferenceContext { mut table, mut result, .. } = self; + table.fallback_if_possible(); + // FIXME resolve obligations as well (use Guidance if necessary) table.resolve_obligations_as_possible(); diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index a1fef48f25a8..e7ddd1591fe8 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -350,6 +350,51 @@ impl<'a> InferenceTable<'a> { self.resolve_with_fallback(t, &|_, _, d, _| d) } + /// Apply a fallback to unresolved scalar types. Integer type variables and float type + /// variables are replaced with i32 and f64, respectively. + /// + /// This method is only intended to be called just before returning inference results (i.e. in + /// `InferenceContext::resolve_all()`). + /// + /// FIXME: This method currently doesn't apply fallback to unconstrained general type variables + /// whereas rustc replaces them with `()` or `!`. + pub(super) fn fallback_if_possible(&mut self) { + let int_fallback = TyKind::Scalar(Scalar::Int(IntTy::I32)).intern(Interner); + let float_fallback = TyKind::Scalar(Scalar::Float(FloatTy::F64)).intern(Interner); + + let scalar_vars: Vec<_> = self + .type_variable_table + .iter() + .enumerate() + .filter_map(|(index, flags)| { + let kind = if flags.contains(TypeVariableFlags::INTEGER) { + TyVariableKind::Integer + } else if flags.contains(TypeVariableFlags::FLOAT) { + TyVariableKind::Float + } else { + return None; + }; + + // FIXME: This is not really the nicest way to get `InferenceVar`s. Can we get them + // without directly constructing them from `index`? + let var = InferenceVar::from(index as u32).to_ty(Interner, kind); + Some(var) + }) + .collect(); + + for var in scalar_vars { + let maybe_resolved = self.resolve_ty_shallow(&var); + if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) { + let fallback = match kind { + TyVariableKind::Integer => &int_fallback, + TyVariableKind::Float => &float_fallback, + TyVariableKind::General => unreachable!(), + }; + self.unify(&var, fallback); + } + } + } + /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that. pub(crate) fn unify>(&mut self, ty1: &T, ty2: &T) -> bool { let result = match self.try_unify(ty1, ty2) { diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index a9fd01ee011d..d01fe0632859 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -4100,3 +4100,68 @@ where "#, ); } + +#[test] +fn bin_op_with_scalar_fallback() { + // Extra impls are significant so that chalk doesn't give us definite guidances. + check_types( + r#" +//- minicore: add +use core::ops::Add; + +struct Vec2(T, T); + +impl Add for Vec2 { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { loop {} } +} +impl Add for Vec2 { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { loop {} } +} +impl Add for Vec2 { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { loop {} } +} +impl Add for Vec2 { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { loop {} } +} + +fn test() { + let a = Vec2(1, 2); + let b = Vec2(3, 4); + let c = a + b; + //^ Vec2 + let a = Vec2(1., 2.); + let b = Vec2(3., 4.); + let c = a + b; + //^ Vec2 +} +"#, + ); +} + +#[test] +fn trait_method_with_scalar_fallback() { + check_types( + r#" +trait Trait { + type Output; + fn foo(&self) -> Self::Output; +} +impl Trait for T { + type Output = T; + fn foo(&self) -> Self::Output { loop {} } +} +fn test() { + let a = 42; + let b = a.foo(); + //^ i32 + let a = 3.14; + let b = a.foo(); + //^ f64 +} +"#, + ); +} From 9f6567f20c90adc5451b0a3b87b29997131906d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Fri, 6 Jan 2023 16:00:23 +0200 Subject: [PATCH 0766/2442] Fix option_env expansion --- crates/hir-expand/src/builtin_fn_macro.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index 985954d44e46..eed71d88e28e 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -671,7 +671,7 @@ fn option_env_expand( let expanded = match get_env_inner(db, arg_id, &key) { None => quote! { #DOLLAR_CRATE::option::Option::None::<&str> }, - Some(s) => quote! { #DOLLAR_CRATE::option::Some(#s) }, + Some(s) => quote! { #DOLLAR_CRATE::option::Option::Some(#s) }, }; ExpandResult::ok(ExpandedEager::new(expanded)) From 41d290d671c48dfae282abfe43b1435803d6d053 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Jan 2023 19:20:08 +0000 Subject: [PATCH 0767/2442] Bump d3-color and d3-graphviz in /editors/code Bumps [d3-color](https://github.com/d3/d3-color) to 3.1.0 and updates ancestor dependency [d3-graphviz](https://github.com/magjac/d3-graphviz). These dependencies need to be updated together. Updates `d3-color` from 2.0.0 to 3.1.0 - [Release notes](https://github.com/d3/d3-color/releases) - [Commits](https://github.com/d3/d3-color/compare/v2.0.0...v3.1.0) Updates `d3-graphviz` from 4.1.1 to 5.0.2 - [Release notes](https://github.com/magjac/d3-graphviz/releases) - [Changelog](https://github.com/magjac/d3-graphviz/blob/master/CHANGELOG.md) - [Commits](https://github.com/magjac/d3-graphviz/compare/v4.1.1...v5.0.2) --- updated-dependencies: - dependency-name: d3-color dependency-type: indirect - dependency-name: d3-graphviz dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- editors/code/package-lock.json | 339 ++++++++------------------------- editors/code/package.json | 2 +- 2 files changed, 79 insertions(+), 262 deletions(-) diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 0b25564e28d3..ee69d2247604 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT OR Apache-2.0", "dependencies": { "d3": "^7.6.1", - "d3-graphviz": "^4.1.1", + "d3-graphviz": "^5.0.2", "vscode-languageclient": "^8.0.2" }, "devDependencies": { @@ -54,14 +54,14 @@ } }, "node_modules/@hpcc-js/wasm": { - "version": "1.12.8", - "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-1.12.8.tgz", - "integrity": "sha512-n4q9ARKco2hpCLsuVaW6Az3cDVaua7B3DSONHkc49WtEzgY/btvcDG5Zr1P6PZDv0sQ7oPnAi9Y+W2DI++MgcQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-2.5.0.tgz", + "integrity": "sha512-G26BamgaHW46f6P8bmkygapgNcy+tTDMwIvCzmMzdp39sxUS1u4gaT/vR2SSDc4x3SfL5RE4B2B8ef/wd429Hg==", "dependencies": { - "yargs": "^17.3.1" + "yargs": "17.6.2" }, "bin": { - "dot-wasm": "bin/cli.js" + "dot-wasm": "bin/dot-wasm.js" } }, "node_modules/@humanwhocodes/config-array": { @@ -698,13 +698,16 @@ "dev": true }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/color-convert": { @@ -876,14 +879,6 @@ "node": ">=12" } }, - "node_modules/d3-brush/node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "engines": { - "node": ">=12" - } - }, "node_modules/d3-chord": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", @@ -945,14 +940,6 @@ "node": ">=12" } }, - "node_modules/d3-drag/node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "engines": { - "node": ">=12" - } - }, "node_modules/d3-dsv": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", @@ -1029,95 +1016,24 @@ } }, "node_modules/d3-graphviz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-4.1.1.tgz", - "integrity": "sha512-s0IVbKf8rs4eJI2xo5Umr7nXDX/LEZw/x2WtKxmlyQxR0qUY49UiLhBNOX7VDHZywMle43NKEXnU6fn22fpJvQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-5.0.2.tgz", + "integrity": "sha512-EVRow9rnFgm/L1trbbnu2PGOND11IcSEdWXbrDbz9hH0/Kj3YM2AqMkkTN/EAWgawD5/zryyCy+3Vm05oSJ1Kg==", "dependencies": { - "@hpcc-js/wasm": "1.12.8", - "d3-dispatch": "^2.0.0", - "d3-format": "^2.0.0", - "d3-interpolate": "^2.0.1", - "d3-path": "^2.0.0", - "d3-timer": "^2.0.0", - "d3-transition": "^2.0.0", - "d3-zoom": "^2.0.0" + "@hpcc-js/wasm": "2.5.0", + "d3-dispatch": "^3.0.1", + "d3-format": "^3.1.0", + "d3-interpolate": "^3.0.1", + "d3-path": "^3.1.0", + "d3-timer": "^3.0.1", + "d3-transition": "^3.0.1", + "d3-zoom": "^3.0.0" + }, + "engines": { + "node": ">=14" }, "peerDependencies": { - "d3-selection": "^2.0.0" - } - }, - "node_modules/d3-graphviz/node_modules/d3-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", - "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" - }, - "node_modules/d3-graphviz/node_modules/d3-dispatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", - "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==" - }, - "node_modules/d3-graphviz/node_modules/d3-drag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz", - "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==", - "dependencies": { - "d3-dispatch": "1 - 2", - "d3-selection": "2" - } - }, - "node_modules/d3-graphviz/node_modules/d3-ease": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz", - "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==" - }, - "node_modules/d3-graphviz/node_modules/d3-format": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", - "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" - }, - "node_modules/d3-graphviz/node_modules/d3-interpolate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", - "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", - "dependencies": { - "d3-color": "1 - 2" - } - }, - "node_modules/d3-graphviz/node_modules/d3-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz", - "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==" - }, - "node_modules/d3-graphviz/node_modules/d3-timer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", - "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" - }, - "node_modules/d3-graphviz/node_modules/d3-transition": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz", - "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==", - "dependencies": { - "d3-color": "1 - 2", - "d3-dispatch": "1 - 2", - "d3-ease": "1 - 2", - "d3-interpolate": "1 - 2", - "d3-timer": "1 - 2" - }, - "peerDependencies": { - "d3-selection": "2" - } - }, - "node_modules/d3-graphviz/node_modules/d3-zoom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz", - "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==", - "dependencies": { - "d3-dispatch": "1 - 2", - "d3-drag": "2", - "d3-interpolate": "1 - 2", - "d3-selection": "2", - "d3-transition": "2" + "d3-selection": "^3.0.0" } }, "node_modules/d3-hierarchy": { @@ -1140,9 +1056,9 @@ } }, "node_modules/d3-path": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", - "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", "engines": { "node": ">=12" } @@ -1199,9 +1115,12 @@ } }, "node_modules/d3-selection": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", - "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } }, "node_modules/d3-shape": { "version": "3.1.0", @@ -1277,14 +1196,6 @@ "node": ">=12" } }, - "node_modules/d3/node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "engines": { - "node": ">=12" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -3907,26 +3818,26 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" + "yargs-parser": "^21.1.1" }, "engines": { "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "engines": { "node": ">=12" } @@ -3970,11 +3881,11 @@ } }, "@hpcc-js/wasm": { - "version": "1.12.8", - "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-1.12.8.tgz", - "integrity": "sha512-n4q9ARKco2hpCLsuVaW6Az3cDVaua7B3DSONHkc49WtEzgY/btvcDG5Zr1P6PZDv0sQ7oPnAi9Y+W2DI++MgcQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-2.5.0.tgz", + "integrity": "sha512-G26BamgaHW46f6P8bmkygapgNcy+tTDMwIvCzmMzdp39sxUS1u4gaT/vR2SSDc4x3SfL5RE4B2B8ef/wd429Hg==", "requires": { - "yargs": "^17.3.1" + "yargs": "17.6.2" } }, "@humanwhocodes/config-array": { @@ -4406,12 +4317,12 @@ "dev": true }, "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, @@ -4518,13 +4429,6 @@ "d3-timer": "3", "d3-transition": "3", "d3-zoom": "3" - }, - "dependencies": { - "d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" - } } }, "d3-array": { @@ -4550,13 +4454,6 @@ "d3-interpolate": "1 - 3", "d3-selection": "3", "d3-transition": "3" - }, - "dependencies": { - "d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" - } } }, "d3-chord": { @@ -4600,13 +4497,6 @@ "requires": { "d3-dispatch": "1 - 3", "d3-selection": "3" - }, - "dependencies": { - "d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" - } } }, "d3-dsv": { @@ -4656,91 +4546,18 @@ } }, "d3-graphviz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-4.1.1.tgz", - "integrity": "sha512-s0IVbKf8rs4eJI2xo5Umr7nXDX/LEZw/x2WtKxmlyQxR0qUY49UiLhBNOX7VDHZywMle43NKEXnU6fn22fpJvQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-5.0.2.tgz", + "integrity": "sha512-EVRow9rnFgm/L1trbbnu2PGOND11IcSEdWXbrDbz9hH0/Kj3YM2AqMkkTN/EAWgawD5/zryyCy+3Vm05oSJ1Kg==", "requires": { - "@hpcc-js/wasm": "1.12.8", - "d3-dispatch": "^2.0.0", - "d3-format": "^2.0.0", - "d3-interpolate": "^2.0.1", - "d3-path": "^2.0.0", - "d3-timer": "^2.0.0", - "d3-transition": "^2.0.0", - "d3-zoom": "^2.0.0" - }, - "dependencies": { - "d3-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", - "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" - }, - "d3-dispatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", - "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==" - }, - "d3-drag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz", - "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==", - "requires": { - "d3-dispatch": "1 - 2", - "d3-selection": "2" - } - }, - "d3-ease": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz", - "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==" - }, - "d3-format": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", - "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" - }, - "d3-interpolate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", - "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", - "requires": { - "d3-color": "1 - 2" - } - }, - "d3-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz", - "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==" - }, - "d3-timer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", - "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" - }, - "d3-transition": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz", - "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==", - "requires": { - "d3-color": "1 - 2", - "d3-dispatch": "1 - 2", - "d3-ease": "1 - 2", - "d3-interpolate": "1 - 2", - "d3-timer": "1 - 2" - } - }, - "d3-zoom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz", - "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==", - "requires": { - "d3-dispatch": "1 - 2", - "d3-drag": "2", - "d3-interpolate": "1 - 2", - "d3-selection": "2", - "d3-transition": "2" - } - } + "@hpcc-js/wasm": "2.5.0", + "d3-dispatch": "^3.0.1", + "d3-format": "^3.1.0", + "d3-interpolate": "^3.0.1", + "d3-path": "^3.1.0", + "d3-timer": "^3.0.1", + "d3-transition": "^3.0.1", + "d3-zoom": "^3.0.0" } }, "d3-hierarchy": { @@ -4757,9 +4574,9 @@ } }, "d3-path": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", - "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==" }, "d3-polygon": { "version": "3.0.1", @@ -4798,9 +4615,9 @@ } }, "d3-selection": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", - "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" }, "d3-shape": { "version": "3.1.0", @@ -6720,23 +6537,23 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" + "yargs-parser": "^21.1.1" } }, "yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==" + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" }, "yauzl": { "version": "2.10.0", diff --git a/editors/code/package.json b/editors/code/package.json index 89ff64fca738..454b95a63b21 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "d3": "^7.6.1", - "d3-graphviz": "^4.1.1", + "d3-graphviz": "^5.0.2", "vscode-languageclient": "^8.0.2" }, "devDependencies": { From 0dd26821783ccc809fb0995f178fd6c53f6eebd7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 9 Jan 2023 11:59:09 +0100 Subject: [PATCH 0768/2442] Refactor replace_arith assists into one module --- .../src/handlers/replace_arith_op.rs | 226 ++++++++++++++++++ .../handlers/replace_arith_with_checked.rs | 45 ---- .../handlers/replace_arith_with_saturating.rs | 48 ---- .../handlers/replace_arith_with_wrapping.rs | 48 ---- crates/ide-assists/src/lib.rs | 10 +- crates/ide-assists/src/utils.rs | 124 +--------- 6 files changed, 234 insertions(+), 267 deletions(-) create mode 100644 crates/ide-assists/src/handlers/replace_arith_op.rs delete mode 100644 crates/ide-assists/src/handlers/replace_arith_with_checked.rs delete mode 100644 crates/ide-assists/src/handlers/replace_arith_with_saturating.rs delete mode 100644 crates/ide-assists/src/handlers/replace_arith_with_wrapping.rs diff --git a/crates/ide-assists/src/handlers/replace_arith_op.rs b/crates/ide-assists/src/handlers/replace_arith_op.rs new file mode 100644 index 000000000000..f1ca35cafc3a --- /dev/null +++ b/crates/ide-assists/src/handlers/replace_arith_op.rs @@ -0,0 +1,226 @@ +use ide_db::assists::{AssistId, AssistKind, GroupLabel}; +use syntax::{ + ast::{self, ArithOp, BinaryOp}, + AstNode, TextRange, +}; + +use crate::assist_context::{AssistContext, Assists}; + +// Assist: replace_arith_with_checked +// +// Replaces arithmetic on integers with the `checked_*` equivalent. +// +// ``` +// fn main() { +// let x = 1 $0+ 2; +// } +// ``` +// -> +// ``` +// fn main() { +// let x = 1.checked_add(2); +// } +// ``` +pub(crate) fn replace_arith_with_checked(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + replace_arith(acc, ctx, ArithKind::Checked) +} + +// Assist: replace_arith_with_saturating +// +// Replaces arithmetic on integers with the `saturating_*` equivalent. +// +// ``` +// fn main() { +// let x = 1 $0+ 2; +// } +// ``` +// -> +// ``` +// fn main() { +// let x = 1.saturating_add(2); +// } +// ``` +pub(crate) fn replace_arith_with_saturating( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { + replace_arith(acc, ctx, ArithKind::Saturating) +} + +// Assist: replace_arith_with_wrapping +// +// Replaces arithmetic on integers with the `wrapping_*` equivalent. +// +// ``` +// fn main() { +// let x = 1 $0+ 2; +// } +// ``` +// -> +// ``` +// fn main() { +// let x = 1.wrapping_add(2); +// } +// ``` +pub(crate) fn replace_arith_with_wrapping( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { + replace_arith(acc, ctx, ArithKind::Wrapping) +} + +fn replace_arith(acc: &mut Assists, ctx: &AssistContext<'_>, kind: ArithKind) -> Option<()> { + let (lhs, op, rhs) = parse_binary_op(ctx)?; + + if !is_primitive_int(ctx, &lhs) || !is_primitive_int(ctx, &rhs) { + return None; + } + + let start = lhs.syntax().text_range().start(); + let end = rhs.syntax().text_range().end(); + let range = TextRange::new(start, end); + + acc.add_group( + &GroupLabel("replace_arith".into()), + kind.assist_id(), + kind.label(), + range, + |builder| { + let method_name = kind.method_name(op); + + builder.replace(range, format!("{lhs}.{method_name}({rhs})")) + }, + ) +} + +fn is_primitive_int(ctx: &AssistContext<'_>, expr: &ast::Expr) -> bool { + match ctx.sema.type_of_expr(expr) { + Some(ty) => ty.adjusted().is_int_or_uint(), + _ => false, + } +} + +/// Extract the operands of an arithmetic expression (e.g. `1 + 2` or `1.checked_add(2)`) +fn parse_binary_op(ctx: &AssistContext<'_>) -> Option<(ast::Expr, ArithOp, ast::Expr)> { + let expr = ctx.find_node_at_offset::()?; + + let op = match expr.op_kind() { + Some(BinaryOp::ArithOp(ArithOp::Add)) => ArithOp::Add, + Some(BinaryOp::ArithOp(ArithOp::Sub)) => ArithOp::Sub, + Some(BinaryOp::ArithOp(ArithOp::Mul)) => ArithOp::Mul, + Some(BinaryOp::ArithOp(ArithOp::Div)) => ArithOp::Div, + _ => return None, + }; + + let lhs = expr.lhs()?; + let rhs = expr.rhs()?; + + Some((lhs, op, rhs)) +} + +pub(crate) enum ArithKind { + Saturating, + Wrapping, + Checked, +} + +impl ArithKind { + fn assist_id(&self) -> AssistId { + let s = match self { + ArithKind::Saturating => "replace_arith_with_saturating", + ArithKind::Checked => "replace_arith_with_checked", + ArithKind::Wrapping => "replace_arith_with_wrapping", + }; + + AssistId(s, AssistKind::RefactorRewrite) + } + + fn label(&self) -> &'static str { + match self { + ArithKind::Saturating => "Replace arithmetic with call to saturating_*", + ArithKind::Checked => "Replace arithmetic with call to checked_*", + ArithKind::Wrapping => "Replace arithmetic with call to wrapping_*", + } + } + + fn method_name(&self, op: ArithOp) -> String { + let prefix = match self { + ArithKind::Checked => "checked_", + ArithKind::Wrapping => "wrapping_", + ArithKind::Saturating => "saturating_", + }; + + let suffix = match op { + ArithOp::Add => "add", + ArithOp::Sub => "sub", + ArithOp::Mul => "mul", + ArithOp::Div => "div", + _ => unreachable!("this function should only be called with +, -, / or *"), + }; + format!("{prefix}{suffix}") + } +} + +#[cfg(test)] +mod tests { + use crate::tests::check_assist; + + use super::*; + + #[test] + fn arith_kind_method_name() { + assert_eq!(ArithKind::Saturating.method_name(ArithOp::Add), "saturating_add"); + assert_eq!(ArithKind::Checked.method_name(ArithOp::Sub), "checked_sub"); + } + + #[test] + fn replace_arith_with_checked_add() { + check_assist( + replace_arith_with_checked, + r#" +fn main() { + let x = 1 $0+ 2; +} +"#, + r#" +fn main() { + let x = 1.checked_add(2); +} +"#, + ) + } + + #[test] + fn replace_arith_with_saturating_add() { + check_assist( + replace_arith_with_saturating, + r#" +fn main() { + let x = 1 $0+ 2; +} +"#, + r#" +fn main() { + let x = 1.saturating_add(2); +} +"#, + ) + } + + #[test] + fn replace_arith_with_wrapping_add() { + check_assist( + replace_arith_with_wrapping, + r#" +fn main() { + let x = 1 $0+ 2; +} +"#, + r#" +fn main() { + let x = 1.wrapping_add(2); +} +"#, + ) + } +} diff --git a/crates/ide-assists/src/handlers/replace_arith_with_checked.rs b/crates/ide-assists/src/handlers/replace_arith_with_checked.rs deleted file mode 100644 index ff1fba5818cc..000000000000 --- a/crates/ide-assists/src/handlers/replace_arith_with_checked.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::assist_context::{AssistContext, Assists}; -use crate::utils::{replace_arith, ArithKind}; - -// Assist: replace_arith_with_checked -// -// Replaces arithmetic on integers with the `checked_*` equivalent. -// -// ``` -// fn main() { -// let x = 1 $0+ 2; -// } -// ``` -// -> -// ``` -// fn main() { -// let x = 1.checked_add(2); -// } -// ``` -pub(crate) fn replace_arith_with_checked(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - replace_arith(acc, ctx, ArithKind::Checked) -} - -#[cfg(test)] -mod tests { - use crate::tests::check_assist; - - use super::*; - - #[test] - fn replace_arith_with_saturating_add() { - check_assist( - replace_arith_with_checked, - r#" -fn main() { - let x = 1 $0+ 2; -} -"#, - r#" -fn main() { - let x = 1.checked_add(2); -} -"#, - ) - } -} diff --git a/crates/ide-assists/src/handlers/replace_arith_with_saturating.rs b/crates/ide-assists/src/handlers/replace_arith_with_saturating.rs deleted file mode 100644 index 717875e84f03..000000000000 --- a/crates/ide-assists/src/handlers/replace_arith_with_saturating.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::assist_context::{AssistContext, Assists}; -use crate::utils::{replace_arith, ArithKind}; - -// Assist: replace_arith_with_saturating -// -// Replaces arithmetic on integers with the `saturating_*` equivalent. -// -// ``` -// fn main() { -// let x = 1 $0+ 2; -// } -// ``` -// -> -// ``` -// fn main() { -// let x = 1.saturating_add(2); -// } -// ``` -pub(crate) fn replace_arith_with_saturating( - acc: &mut Assists, - ctx: &AssistContext<'_>, -) -> Option<()> { - replace_arith(acc, ctx, ArithKind::Saturating) -} - -#[cfg(test)] -mod tests { - use crate::tests::check_assist; - - use super::*; - - #[test] - fn replace_arith_with_saturating_add() { - check_assist( - replace_arith_with_saturating, - r#" -fn main() { - let x = 1 $0+ 2; -} -"#, - r#" -fn main() { - let x = 1.saturating_add(2); -} -"#, - ) - } -} diff --git a/crates/ide-assists/src/handlers/replace_arith_with_wrapping.rs b/crates/ide-assists/src/handlers/replace_arith_with_wrapping.rs deleted file mode 100644 index e0a90292b194..000000000000 --- a/crates/ide-assists/src/handlers/replace_arith_with_wrapping.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::assist_context::{AssistContext, Assists}; -use crate::utils::{replace_arith, ArithKind}; - -// Assist: replace_arith_with_wrapping -// -// Replaces arithmetic on integers with the `wrapping_*` equivalent. -// -// ``` -// fn main() { -// let x = 1 $0+ 2; -// } -// ``` -// -> -// ``` -// fn main() { -// let x = 1.wrapping_add(2); -// } -// ``` -pub(crate) fn replace_arith_with_wrapping( - acc: &mut Assists, - ctx: &AssistContext<'_>, -) -> Option<()> { - replace_arith(acc, ctx, ArithKind::Wrapping) -} - -#[cfg(test)] -mod tests { - use crate::tests::check_assist; - - use super::*; - - #[test] - fn replace_arith_with_saturating_add() { - check_assist( - replace_arith_with_wrapping, - r#" -fn main() { - let x = 1 $0+ 2; -} -"#, - r#" -fn main() { - let x = 1.wrapping_add(2); -} -"#, - ) - } -} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 3938fa098353..0255ffdea3f2 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -183,9 +183,7 @@ mod handlers { mod replace_derive_with_manual_impl; mod replace_if_let_with_match; mod replace_or_with_or_else; - mod replace_arith_with_checked; - mod replace_arith_with_wrapping; - mod replace_arith_with_saturating; + mod replace_arith_op; mod introduce_named_generic; mod replace_let_with_if_let; mod replace_qualified_name_with_use; @@ -289,9 +287,9 @@ mod handlers { replace_or_with_or_else::replace_or_with_or_else, replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type, replace_qualified_name_with_use::replace_qualified_name_with_use, - replace_arith_with_wrapping::replace_arith_with_wrapping, - replace_arith_with_checked::replace_arith_with_checked, - replace_arith_with_saturating::replace_arith_with_saturating, + replace_arith_op::replace_arith_with_wrapping, + replace_arith_op::replace_arith_with_checked, + replace_arith_op::replace_arith_with_saturating, sort_items::sort_items, split_import::split_import, toggle_ignore::toggle_ignore, diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index 0227222c0896..db32e7182c44 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -4,27 +4,21 @@ use std::ops; pub(crate) use gen_trait_fn_body::gen_trait_fn_body; use hir::{db::HirDatabase, HirDisplay, Semantics}; -use ide_db::{ - assists::{AssistId, AssistKind}, - famous_defs::FamousDefs, - path_transform::PathTransform, - RootDatabase, SnippetCap, -}; +use ide_db::{famous_defs::FamousDefs, path_transform::PathTransform, RootDatabase, SnippetCap}; use stdx::format_to; use syntax::{ ast::{ self, edit::{self, AstNodeEdit}, edit_in_place::{AttrsOwnerEdit, Removable}, - make, ArithOp, BinExpr, BinaryOp, Expr, HasArgList, HasAttrs, HasGenericParams, HasName, - HasTypeBounds, Whitespace, + make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace, }, - ted, AstNode, AstToken, Direction, SmolStr, SourceFile, + ted, AstNode, AstToken, Direction, SourceFile, SyntaxKind::*, SyntaxNode, TextRange, TextSize, T, }; -use crate::assist_context::{AssistContext, Assists, SourceChangeBuilder}; +use crate::assist_context::{AssistContext, SourceChangeBuilder}; pub(crate) mod suggest_name; mod gen_trait_fn_body; @@ -711,113 +705,3 @@ pub(crate) fn convert_param_list_to_arg_list(list: ast::ParamList) -> ast::ArgLi } make::arg_list(args) } - -pub(crate) enum ArithKind { - Saturating, - Wrapping, - Checked, -} - -impl ArithKind { - fn assist_id(&self) -> AssistId { - let s = match self { - ArithKind::Saturating => "replace_arith_with_saturating", - ArithKind::Checked => "replace_arith_with_checked", - ArithKind::Wrapping => "replace_arith_with_wrapping", - }; - - AssistId(s, AssistKind::RefactorRewrite) - } - - fn label(&self) -> &'static str { - match self { - ArithKind::Saturating => "Replace arithmetic with call to saturating_*", - ArithKind::Checked => "Replace arithmetic with call to checked_*", - ArithKind::Wrapping => "Replace arithmetic with call to wrapping_*", - } - } - - fn method_name(&self, op: ArithOp) -> SmolStr { - // is this too much effort to avoid an allocation? is there a better way? - let mut bytes = [0u8; 14]; - let prefix = match self { - ArithKind::Checked => "checked_", - ArithKind::Wrapping => "wrapping_", - ArithKind::Saturating => "saturating_", - }; - - bytes[0..(prefix.len())].copy_from_slice(prefix.as_bytes()); - - let suffix = match op { - ArithOp::Add => "add", - ArithOp::Sub => "sub", - ArithOp::Mul => "mul", - ArithOp::Div => "div", - _ => unreachable!("this function should only be called with +, -, / or *"), - }; - - bytes[(prefix.len())..(prefix.len() + suffix.len())].copy_from_slice(suffix.as_bytes()); - - let len = prefix.len() + suffix.len(); - let s = core::str::from_utf8(&bytes[0..len]).unwrap(); - SmolStr::from(s) - } -} - -pub(crate) fn replace_arith( - acc: &mut Assists, - ctx: &AssistContext<'_>, - kind: ArithKind, -) -> Option<()> { - let (lhs, op, rhs) = parse_binary_op(ctx)?; - - if !is_primitive_int(ctx, &lhs) || !is_primitive_int(ctx, &rhs) { - return None; - } - - let start = lhs.syntax().text_range().start(); - let end = rhs.syntax().text_range().end(); - let range = TextRange::new(start, end); - - acc.add(kind.assist_id(), kind.label(), range, |builder| { - let method_name = kind.method_name(op); - - builder.replace(range, format!("{lhs}.{method_name}({rhs})")) - }) -} - -fn is_primitive_int(ctx: &AssistContext<'_>, expr: &Expr) -> bool { - match ctx.sema.type_of_expr(expr) { - Some(ty) => ty.adjusted().is_int_or_uint(), - _ => false, - } -} - -/// Extract the operands of an arithmetic expression (e.g. `1 + 2` or `1.checked_add(2)`) -fn parse_binary_op(ctx: &AssistContext<'_>) -> Option<(Expr, ArithOp, Expr)> { - let expr = ctx.find_node_at_offset::()?; - - let op = match expr.op_kind() { - Some(BinaryOp::ArithOp(ArithOp::Add)) => ArithOp::Add, - Some(BinaryOp::ArithOp(ArithOp::Sub)) => ArithOp::Sub, - Some(BinaryOp::ArithOp(ArithOp::Mul)) => ArithOp::Mul, - Some(BinaryOp::ArithOp(ArithOp::Div)) => ArithOp::Div, - _ => return None, - }; - - let lhs = expr.lhs()?; - let rhs = expr.rhs()?; - - Some((lhs, op, rhs)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn arith_kind_method_name() { - assert_eq!(ArithKind::Saturating.method_name(ArithOp::Add), "saturating_add"); - assert_eq!(ArithKind::Checked.method_name(ArithOp::Sub), "checked_sub"); - } -} From 9290399ec438c8ba6f3819bbd16212dfabbcb610 Mon Sep 17 00:00:00 2001 From: unvalley Date: Sat, 26 Nov 2022 23:00:03 +0900 Subject: [PATCH 0769/2442] fix: rename to extract_expressions_from_format_string --- ...extract_expressions_from_format_string.rs} | 21 ++++--- crates/ide-assists/src/lib.rs | 4 +- crates/ide-assists/src/tests/generated.rs | 62 +++++++++---------- 3 files changed, 45 insertions(+), 42 deletions(-) rename crates/ide-assists/src/handlers/{move_format_string_arg.rs => extract_expressions_from_format_string.rs} (93%) diff --git a/crates/ide-assists/src/handlers/move_format_string_arg.rs b/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs similarity index 93% rename from crates/ide-assists/src/handlers/move_format_string_arg.rs rename to crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs index 11db6ae7f7b8..b1bc2a9e6dbd 100644 --- a/crates/ide-assists/src/handlers/move_format_string_arg.rs +++ b/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs @@ -10,7 +10,7 @@ use itertools::Itertools; use stdx::format_to; use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange}; -// Assist: move_format_string_arg +// Assist: extract_expressions_from_format_string // // Move an expression out of a format string. // @@ -40,7 +40,10 @@ use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange}; // } // ``` -pub(crate) fn move_format_string_arg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { +pub(crate) fn extract_expressions_from_format_string( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { let fmt_string = ctx.find_token_at_offset::()?; let tt = fmt_string.syntax().parent().and_then(ast::TokenTree::cast)?; @@ -58,7 +61,7 @@ pub(crate) fn move_format_string_arg(acc: &mut Assists, ctx: &AssistContext<'_>) acc.add( AssistId( - "move_format_string_arg", + "extract_expressions_from_format_string", // if there aren't any expressions, then make the assist a RefactorExtract if extracted_args.iter().filter(|f| matches!(f, Arg::Expr(_))).count() == 0 { AssistKind::RefactorExtract @@ -171,7 +174,7 @@ macro_rules! print { #[test] fn multiple_middle_arg() { check_assist( - move_format_string_arg, + extract_expressions_from_format_string, &add_macro_decl( r#" fn main() { @@ -192,7 +195,7 @@ fn main() { #[test] fn single_arg() { check_assist( - move_format_string_arg, + extract_expressions_from_format_string, &add_macro_decl( r#" fn main() { @@ -213,7 +216,7 @@ fn main() { #[test] fn multiple_middle_placeholders_arg() { check_assist( - move_format_string_arg, + extract_expressions_from_format_string, &add_macro_decl( r#" fn main() { @@ -234,7 +237,7 @@ fn main() { #[test] fn multiple_trailing_args() { check_assist( - move_format_string_arg, + extract_expressions_from_format_string, &add_macro_decl( r#" fn main() { @@ -255,7 +258,7 @@ fn main() { #[test] fn improper_commas() { check_assist( - move_format_string_arg, + extract_expressions_from_format_string, &add_macro_decl( r#" fn main() { @@ -276,7 +279,7 @@ fn main() { #[test] fn nested_tt() { check_assist( - move_format_string_arg, + extract_expressions_from_format_string, &add_macro_decl( r#" fn main() { diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 8b1247c640a9..0bf502fdbcd9 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -138,7 +138,7 @@ mod handlers { mod flip_binexpr; mod flip_comma; mod flip_trait_bound; - mod move_format_string_arg; + mod extract_expressions_from_format_string; mod generate_constant; mod generate_default_from_enum_variant; mod generate_default_from_new; @@ -230,6 +230,7 @@ mod handlers { convert_while_to_loop::convert_while_to_loop, destructure_tuple_binding::destructure_tuple_binding, expand_glob_import::expand_glob_import, + extract_expressions_from_format_string::extract_expressions_from_format_string, extract_struct_from_enum_variant::extract_struct_from_enum_variant, extract_type_alias::extract_type_alias, fix_visibility::fix_visibility, @@ -264,7 +265,6 @@ mod handlers { merge_match_arms::merge_match_arms, move_bounds::move_bounds_to_where_clause, move_const_to_impl::move_const_to_impl, - move_format_string_arg::move_format_string_arg, move_guard::move_arm_cond_to_match_guard, move_guard::move_guard_to_arm_body, move_module_to_file::move_module_to_file, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 80b8c27c7c05..5e24de620777 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -624,6 +624,37 @@ fn qux(bar: Bar, baz: Baz) {} ) } +#[test] +fn doctest_extract_expressions_from_format_string() { + check_doc_test( + "extract_expressions_from_format_string", + r#####" +macro_rules! format_args { + ($lit:literal $(tt:tt)*) => { 0 }, +} +macro_rules! print { + ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*))); +} + +fn main() { + print!("{x + 1}$0"); +} +"#####, + r#####" +macro_rules! format_args { + ($lit:literal $(tt:tt)*) => { 0 }, +} +macro_rules! print { + ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*))); +} + +fn main() { + print!("{}"$0, x + 1); +} +"#####, + ) +} + #[test] fn doctest_extract_function() { check_doc_test( @@ -1703,37 +1734,6 @@ impl S { ) } -#[test] -fn doctest_move_format_string_arg() { - check_doc_test( - "move_format_string_arg", - r#####" -macro_rules! format_args { - ($lit:literal $(tt:tt)*) => { 0 }, -} -macro_rules! print { - ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*))); -} - -fn main() { - print!("{x + 1}$0"); -} -"#####, - r#####" -macro_rules! format_args { - ($lit:literal $(tt:tt)*) => { 0 }, -} -macro_rules! print { - ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*))); -} - -fn main() { - print!("{}"$0, x + 1); -} -"#####, - ) -} - #[test] fn doctest_move_from_mod_rs() { check_doc_test( From 796a1064122d7e85b509716d46beb6bb3d267811 Mon Sep 17 00:00:00 2001 From: unvalley Date: Sat, 26 Nov 2022 23:01:52 +0900 Subject: [PATCH 0770/2442] fix: ide assist handlers order --- crates/ide-assists/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 0bf502fdbcd9..cdb9c70f71be 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -128,6 +128,7 @@ mod handlers { mod convert_while_to_loop; mod destructure_tuple_binding; mod expand_glob_import; + mod extract_expressions_from_format_string; mod extract_function; mod extract_module; mod extract_struct_from_enum_variant; @@ -138,7 +139,6 @@ mod handlers { mod flip_binexpr; mod flip_comma; mod flip_trait_bound; - mod extract_expressions_from_format_string; mod generate_constant; mod generate_default_from_enum_variant; mod generate_default_from_new; From 13267adb12b6a62d69c5ca0cf872beba9413b6ec Mon Sep 17 00:00:00 2001 From: unvalley Date: Sun, 27 Nov 2022 14:44:32 +0900 Subject: [PATCH 0771/2442] fix: to leave Ident in parse_format_exprs --- .../src/syntax_helpers/format_string_exprs.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs index f5f03d70b013..6ff580c16761 100644 --- a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs +++ b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs @@ -140,8 +140,8 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { output.push_str(trimmed); } else if matches!(state, State::Expr) { extracted_expressions.push(Arg::Expr(trimmed.into())); - } else { - extracted_expressions.push(Arg::Ident(trimmed.into())); + } else if matches!(state, State::Ident) { + output.push_str(trimmed); } output.push(chr); @@ -218,9 +218,9 @@ mod tests { let test_vector = &[ ("no expressions", expect![["no expressions"]]), (r"no expressions with \$0$1", expect![r"no expressions with \\\$0\$1"]), - ("{expr} is {2 + 2}", expect![["{} is {}; expr, 2 + 2"]]), - ("{expr:?}", expect![["{:?}; expr"]]), - ("{expr:1$}", expect![[r"{:1\$}; expr"]]), + ("{expr} is {2 + 2}", expect![["{expr} is {}; 2 + 2"]]), + ("{expr:?}", expect![["{expr:?}"]]), + ("{expr:1$}", expect![[r"{expr:1\$}"]]), ("{:1$}", expect![[r"{:1\$}; $1"]]), ("{:>padding$}", expect![[r"{:>padding\$}; $1"]]), ("{}, {}, {0}", expect![[r"{}, {}, {0}; $1, $2"]]), @@ -230,8 +230,8 @@ mod tests { ("malformed}", expect![["-"]]), ("{{correct", expect![["{{correct"]]), ("correct}}", expect![["correct}}"]]), - ("{correct}}}", expect![["{}}}; correct"]]), - ("{correct}}}}}", expect![["{}}}}}; correct"]]), + ("{correct}}}", expect![["{correct}}}"]]), + ("{correct}}}}}", expect![["{correct}}}}}"]]), ("{incorrect}}", expect![["-"]]), ("placeholders {} {}", expect![["placeholders {} {}; $1, $2"]]), ("mixed {} {2 + 2} {}", expect![["mixed {} {} {}; $1, 2 + 2, $2"]]), @@ -239,7 +239,7 @@ mod tests { "{SomeStruct { val_a: 0, val_b: 1 }}", expect![["{}; SomeStruct { val_a: 0, val_b: 1 }"]], ), - ("{expr:?} is {2.32f64:.5}", expect![["{:?} is {:.5}; expr, 2.32f64"]]), + ("{expr:?} is {2.32f64:.5}", expect![["{expr:?} is {:.5}; 2.32f64"]]), ( "{SomeStruct { val_a: 0, val_b: 1 }:?}", expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]], From 29f3d7dee75e20eeec573065dc01070544d3d6e3 Mon Sep 17 00:00:00 2001 From: unvalley Date: Sun, 27 Nov 2022 14:49:30 +0900 Subject: [PATCH 0772/2442] test: fix arg_type test --- crates/ide-db/src/syntax_helpers/format_string_exprs.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs index 6ff580c16761..fcef71fb74e7 100644 --- a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs +++ b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs @@ -262,8 +262,6 @@ mod tests { .unwrap() .1, vec![ - Arg::Ident("_ident".to_owned()), - Arg::Ident("r#raw_ident".to_owned()), Arg::Expr("expr.obj".to_owned()), Arg::Expr("name {thing: 42}".to_owned()), Arg::Placeholder From 285f09cfa8dfb696b8bd20a1fac5db5fec1ae46d Mon Sep 17 00:00:00 2001 From: unvalley Date: Sun, 27 Nov 2022 15:36:26 +0900 Subject: [PATCH 0773/2442] feat: extract only expressions from format string --- .../extract_expressions_from_format_string.rs | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs b/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs index b1bc2a9e6dbd..6b947fe36416 100644 --- a/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs +++ b/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs @@ -121,15 +121,14 @@ pub(crate) fn extract_expressions_from_format_string( let mut placeholder_idx = 1; for extracted_args in extracted_args { - // remove expr from format string - args.push_str(", "); - match extracted_args { - Arg::Ident(s) | Arg::Expr(s) => { + Arg::Expr(s)=> { + args.push_str(", "); // insert arg args.push_str(&s); } Arg::Placeholder => { + args.push_str(", "); // try matching with existing argument match existing_args.next() { Some(ea) => { @@ -142,6 +141,7 @@ pub(crate) fn extract_expressions_from_format_string( } } } + Arg::Ident(_s) => (), } } @@ -292,6 +292,29 @@ fn main() { fn main() { print!("My name is {} {}"$0, stringify!(Paperino), x + x) } +"#, + ), + ); + } + + #[test] + fn extract_only_expressions() { + check_assist( + extract_expressions_from_format_string, + &add_macro_decl( + r#" +fn main() { + let var = 1 + 1; + print!("foobar {var} {var:?} {x$0 + x}") +} +"#, + ), + &add_macro_decl( + r#" +fn main() { + let var = 1 + 1; + print!("foobar {var} {var:?} {}"$0, x + x) +} "#, ), ); From 872df2f4131d1dc40a412d4b160cc031a2f30c03 Mon Sep 17 00:00:00 2001 From: unvalley Date: Sun, 27 Nov 2022 17:23:46 +0900 Subject: [PATCH 0774/2442] chore: update assist label name --- .../src/handlers/extract_expressions_from_format_string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs b/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs index 6b947fe36416..46d1d7b95530 100644 --- a/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs +++ b/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs @@ -69,7 +69,7 @@ pub(crate) fn extract_expressions_from_format_string( AssistKind::QuickFix }, ), - "Extract format args", + "Extract format expressions", tt.syntax().text_range(), |edit| { let fmt_range = fmt_string.syntax().text_range(); From a310fc0cd53ff8528ef31b5021c490fd944ab199 Mon Sep 17 00:00:00 2001 From: unvalley Date: Sun, 27 Nov 2022 18:24:43 +0900 Subject: [PATCH 0775/2442] docs: update assist comment --- .../src/handlers/extract_expressions_from_format_string.rs | 4 ++-- crates/ide-assists/src/tests/generated.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs b/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs index 46d1d7b95530..4f3b6e0c287c 100644 --- a/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs +++ b/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs @@ -23,7 +23,7 @@ use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange}; // } // // fn main() { -// print!("{x + 1}$0"); +// print!("{var} {x + 1}$0"); // } // ``` // -> @@ -36,7 +36,7 @@ use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange}; // } // // fn main() { -// print!("{}"$0, x + 1); +// print!("{var} {}"$0, x + 1); // } // ``` diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 5e24de620777..f7ff173bb014 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -637,7 +637,7 @@ macro_rules! print { } fn main() { - print!("{x + 1}$0"); + print!("{var} {x + 1}$0"); } "#####, r#####" @@ -649,7 +649,7 @@ macro_rules! print { } fn main() { - print!("{}"$0, x + 1); + print!("{var} {}"$0, x + 1); } "#####, ) From 9eabc2cde8e76d718de81b6cd4d0091c7a8d9690 Mon Sep 17 00:00:00 2001 From: unvalley Date: Tue, 29 Nov 2022 01:39:27 +0900 Subject: [PATCH 0776/2442] fix: add_format_like_completions to handle no exprs --- .../ide-completion/src/completions/postfix.rs | 4 +-- .../src/completions/postfix/format_like.rs | 25 ++++++++++++++++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs index 3db400604b02..f4f37d77d81f 100644 --- a/crates/ide-completion/src/completions/postfix.rs +++ b/crates/ide-completion/src/completions/postfix.rs @@ -595,12 +595,12 @@ fn main() { check_edit( "format", r#"fn main() { "{some_var:?}".$0 }"#, - r#"fn main() { format!("{:?}", some_var) }"#, + r#"fn main() { format!("{some_var:?}") }"#, ); check_edit( "panic", r#"fn main() { "Panic with {a}".$0 }"#, - r#"fn main() { panic!("Panic with {}", a) }"#, + r#"fn main() { panic!("Panic with {a}") }"#, ); check_edit( "println", diff --git a/crates/ide-completion/src/completions/postfix/format_like.rs b/crates/ide-completion/src/completions/postfix/format_like.rs index d64d6379a9cd..dfcc78e92308 100644 --- a/crates/ide-completion/src/completions/postfix/format_like.rs +++ b/crates/ide-completion/src/completions/postfix/format_like.rs @@ -54,7 +54,11 @@ pub(crate) fn add_format_like_completions( if let Ok((out, exprs)) = parse_format_exprs(receiver_text.text()) { let exprs = with_placeholders(exprs); for (label, macro_name) in KINDS { - let snippet = format!(r#"{macro_name}({out}, {})"#, exprs.join(", ")); + let snippet = if exprs.is_empty() { + format!(r#"{}({})"#, macro_name, out) + } else { + format!(r#"{}({}, {})"#, macro_name, out, exprs.join(", ")) + }; postfix_snippet(label, macro_name, &snippet).add_to(acc); } @@ -72,10 +76,9 @@ mod tests { ("eprintln!", "{}", r#"eprintln!("{}", $1)"#), ( "log::info!", - "{} {expr} {} {2 + 2}", - r#"log::info!("{} {} {} {}", $1, expr, $2, 2 + 2)"#, + "{} {ident} {} {2 + 2}", + r#"log::info!("{} {ident} {} {}", $1, $2, 2 + 2)"#, ), - ("format!", "{expr:?}", r#"format!("{:?}", expr)"#), ]; for (kind, input, output) in test_vector { @@ -85,4 +88,18 @@ mod tests { assert_eq!(&snippet, output); } } + + #[test] + fn test_into_suggestion_no_epxrs() { + let test_vector = &[ + ("println!", "{ident}", r#"println!("{ident}")"#), + ("format!", "{ident:?}", r#"format!("{ident:?}")"#), + ]; + + for (kind, input, output) in test_vector { + let (parsed_string, _exprs) = parse_format_exprs(input).unwrap(); + let snippet = format!(r#"{}("{}")"#, kind, parsed_string); + assert_eq!(&snippet, output); + } + } } From 87d57f51bcf07eb364fcf835f9be987006158961 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 20 Dec 2022 11:31:07 +0100 Subject: [PATCH 0777/2442] Rename checkOnSave settings to flycheck --- crates/rust-analyzer/src/config.rs | 180 +++++++------- .../src/config/patch_old_style.rs | 17 +- docs/user/generated_config.adoc | 176 +++++++------- editors/code/package.json | 224 +++++++++--------- 4 files changed, 302 insertions(+), 295 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 4ee92b3d4ed0..25bfa0c28edd 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -124,65 +124,8 @@ config_data! { /// Unsets `#[cfg(test)]` for the specified crates. cargo_unsetTest: Vec = "[\"core\"]", - /// Check all targets and tests (`--all-targets`). - checkOnSave_allTargets: bool = "true", - /// Cargo command to use for `cargo check`. - checkOnSave_command: String = "\"check\"", - /// Run specified `cargo check` command for diagnostics on save. - checkOnSave_enable: bool = "true", - /// Extra arguments for `cargo check`. - checkOnSave_extraArgs: Vec = "[]", - /// Extra environment variables that will be set when running `cargo check`. - /// Extends `#rust-analyzer.cargo.extraEnv#`. - checkOnSave_extraEnv: FxHashMap = "{}", - /// List of features to activate. Defaults to - /// `#rust-analyzer.cargo.features#`. - /// - /// Set to `"all"` to pass `--all-features` to Cargo. - checkOnSave_features: Option = "null", - /// Specifies the working directory for running checks. - /// - "workspace": run checks for workspaces in the corresponding workspaces' root directories. - // FIXME: Ideally we would support this in some way - /// This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`. - /// - "root": run checks in the project's root directory. - /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` - /// is set. - checkOnSave_invocationLocation: InvocationLocation = "\"workspace\"", - /// Specifies the invocation strategy to use when running the checkOnSave command. - /// If `per_workspace` is set, the command will be executed for each workspace. - /// If `once` is set, the command will be executed once. - /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` - /// is set. - checkOnSave_invocationStrategy: InvocationStrategy = "\"per_workspace\"", - /// Whether to pass `--no-default-features` to Cargo. Defaults to - /// `#rust-analyzer.cargo.noDefaultFeatures#`. - checkOnSave_noDefaultFeatures: Option = "null", - /// Override the command rust-analyzer uses instead of `cargo check` for - /// diagnostics on save. The command is required to output json and - /// should therefore include `--message-format=json` or a similar option. - /// - /// If you're changing this because you're using some tool wrapping - /// Cargo, you might also want to change - /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`. - /// - /// If there are multiple linked projects, this command is invoked for - /// each of them, with the working directory being the project root - /// (i.e., the folder containing the `Cargo.toml`). - /// - /// An example command would be: - /// - /// ```bash - /// cargo check --workspace --message-format=json --all-targets - /// ``` - /// . - checkOnSave_overrideCommand: Option> = "null", - /// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. - /// - /// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. - /// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`. - /// - /// Aliased as `"checkOnSave.targets"`. - checkOnSave_target | checkOnSave_targets: Option = "null", + /// Run the flycheck command for diagnostics on save. + checkOnSave | checkOnSave_enable: bool = "true", /// Toggles the additional completions that automatically add imports when completed. /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. @@ -268,6 +211,64 @@ config_data! { /// Controls file watching implementation. files_watcher: FilesWatcherDef = "\"client\"", + /// Check all targets and tests (`--all-targets`). + flycheck_allTargets | checkOnSave_allTargets: bool = "true", + /// Cargo command to use for `cargo check`. + flycheck_command | checkOnSave_command: String = "\"check\"", + /// Extra arguments for `cargo check`. + flycheck_extraArgs | checkOnSave_extraArgs: Vec = "[]", + /// Extra environment variables that will be set when running `cargo check`. + /// Extends `#rust-analyzer.cargo.extraEnv#`. + flycheck_extraEnv | checkOnSave_extraEnv: FxHashMap = "{}", + /// List of features to activate. Defaults to + /// `#rust-analyzer.cargo.features#`. + /// + /// Set to `"all"` to pass `--all-features` to Cargo. + flycheck_features | checkOnSave_features: Option = "null", + /// Specifies the working directory for running checks. + /// - "workspace": run checks for workspaces in the corresponding workspaces' root directories. + // FIXME: Ideally we would support this in some way + /// This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`. + /// - "root": run checks in the project's root directory. + /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` + /// is set. + flycheck_invocationLocation | checkOnSave_invocationLocation: InvocationLocation = "\"workspace\"", + /// Specifies the invocation strategy to use when running the checkOnSave command. + /// If `per_workspace` is set, the command will be executed for each workspace. + /// If `once` is set, the command will be executed once. + /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` + /// is set. + flycheck_invocationStrategy | checkOnSave_invocationStrategy: InvocationStrategy = "\"per_workspace\"", + /// Whether to pass `--no-default-features` to Cargo. Defaults to + /// `#rust-analyzer.cargo.noDefaultFeatures#`. + flycheck_noDefaultFeatures | checkOnSave_noDefaultFeatures: Option = "null", + /// Override the command rust-analyzer uses instead of `cargo check` for + /// diagnostics on save. The command is required to output json and + /// should therefore include `--message-format=json` or a similar option. + /// + /// If you're changing this because you're using some tool wrapping + /// Cargo, you might also want to change + /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`. + /// + /// If there are multiple linked projects, this command is invoked for + /// each of them, with the working directory being the project root + /// (i.e., the folder containing the `Cargo.toml`). + /// + /// An example command would be: + /// + /// ```bash + /// cargo check --workspace --message-format=json --all-targets + /// ``` + /// . + flycheck_overrideCommand | checkOnSave_overrideCommand: Option> = "null", + /// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. + /// + /// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. + /// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`. + /// + /// Aliased as `"checkOnSave.targets"`. + flycheck_targets | checkOnSave_targets | checkOnSave_target: Option = "null", + /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. highlightRelated_breakPoints_enable: bool = "true", /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`). @@ -786,9 +787,9 @@ impl Config { fn validate(&self, error_sink: &mut Vec<(String, serde_json::Error)>) { use serde::de::Error; - if self.data.checkOnSave_command.is_empty() { + if self.data.flycheck_command.is_empty() { error_sink.push(( - "/checkOnSave/command".to_string(), + "/flycheck/command".to_string(), serde_json::Error::custom("expected a non-empty string"), )); } @@ -1033,7 +1034,7 @@ impl Config { pub fn check_on_save_extra_env(&self) -> FxHashMap { let mut extra_env = self.data.cargo_extraEnv.clone(); - extra_env.extend(self.data.checkOnSave_extraEnv.clone()); + extra_env.extend(self.data.flycheck_extraEnv.clone()); extra_env } @@ -1145,7 +1146,7 @@ impl Config { } pub fn flycheck(&self) -> FlycheckConfig { - match &self.data.checkOnSave_overrideCommand { + match &self.data.flycheck_overrideCommand { Some(args) if !args.is_empty() => { let mut args = args.clone(); let command = args.remove(0); @@ -1153,13 +1154,13 @@ impl Config { command, args, extra_env: self.check_on_save_extra_env(), - invocation_strategy: match self.data.checkOnSave_invocationStrategy { + invocation_strategy: match self.data.flycheck_invocationStrategy { InvocationStrategy::Once => flycheck::InvocationStrategy::Once, InvocationStrategy::PerWorkspace => { flycheck::InvocationStrategy::PerWorkspace } }, - invocation_location: match self.data.checkOnSave_invocationLocation { + invocation_location: match self.data.flycheck_invocationLocation { InvocationLocation::Root => { flycheck::InvocationLocation::Root(self.root_path.clone()) } @@ -1168,42 +1169,42 @@ impl Config { } } Some(_) | None => FlycheckConfig::CargoCommand { - command: self.data.checkOnSave_command.clone(), + command: self.data.flycheck_command.clone(), target_triples: self .data - .checkOnSave_target + .flycheck_targets .clone() .and_then(|targets| match &targets.0[..] { [] => None, targets => Some(targets.into()), }) .unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()), - all_targets: self.data.checkOnSave_allTargets, + all_targets: self.data.flycheck_allTargets, no_default_features: self .data - .checkOnSave_noDefaultFeatures + .flycheck_noDefaultFeatures .unwrap_or(self.data.cargo_noDefaultFeatures), all_features: matches!( - self.data.checkOnSave_features.as_ref().unwrap_or(&self.data.cargo_features), + self.data.flycheck_features.as_ref().unwrap_or(&self.data.cargo_features), CargoFeaturesDef::All ), features: match self .data - .checkOnSave_features + .flycheck_features .clone() .unwrap_or_else(|| self.data.cargo_features.clone()) { CargoFeaturesDef::All => vec![], CargoFeaturesDef::Selected(it) => it, }, - extra_args: self.data.checkOnSave_extraArgs.clone(), + extra_args: self.data.flycheck_extraArgs.clone(), extra_env: self.check_on_save_extra_env(), }, } } pub fn check_on_save(&self) -> bool { - self.data.checkOnSave_enable + self.data.checkOnSave } pub fn runnables(&self) -> RunnablesConfig { @@ -1862,25 +1863,27 @@ fn get_field( alias: Option<&'static str>, default: &str, ) -> T { - let default = serde_json::from_str(default).unwrap(); // XXX: check alias first, to work-around the VS Code where it pre-fills the // defaults instead of sending an empty object. alias .into_iter() .chain(iter::once(field)) - .find_map(move |field| { + .filter_map(move |field| { let mut pointer = field.replace('_', "/"); pointer.insert(0, '/'); - json.pointer_mut(&pointer).and_then(|it| match serde_json::from_value(it.take()) { - Ok(it) => Some(it), - Err(e) => { - tracing::warn!("Failed to deserialize config field at {}: {:?}", pointer, e); - error_sink.push((pointer, e)); - None - } - }) + json.pointer_mut(&pointer) + .map(|it| serde_json::from_value(it.take()).map_err(|e| (e, pointer))) }) - .unwrap_or(default) + .find(Result::is_ok) + .and_then(|res| match res { + Ok(it) => Some(it), + Err((e, pointer)) => { + tracing::warn!("Failed to deserialize config field at {}: {:?}", pointer, e); + error_sink.push((pointer, e)); + None + } + }) + .unwrap_or_else(|| serde_json::from_str(default).unwrap()) } fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json::Value { @@ -1964,15 +1967,6 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json "type": ["null", "array"], "items": { "type": "string" }, }, - "MergeBehaviorDef" => set! { - "type": "string", - "enum": ["none", "crate", "module"], - "enumDescriptions": [ - "Do not merge imports at all.", - "Merge imports from the same crate into a single `use` statement.", - "Merge imports from the same module into a single `use` statement." - ], - }, "ExprFillDefaultDef" => set! { "type": "string", "enum": ["todo", "default"], diff --git a/crates/rust-analyzer/src/config/patch_old_style.rs b/crates/rust-analyzer/src/config/patch_old_style.rs index 3b174a719342..38b70219cb2e 100644 --- a/crates/rust-analyzer/src/config/patch_old_style.rs +++ b/crates/rust-analyzer/src/config/patch_old_style.rs @@ -4,6 +4,9 @@ use serde_json::{json, Value}; /// This function patches the json config to the new expected keys. /// That is we try to load old known config keys here and convert them to the new ones. /// See https://github.com/rust-lang/rust-analyzer/pull/12010 +/// +/// We already have an alias system for simple cases, but if we make structural changes +/// the alias infra fails down. pub(super) fn patch_json_for_outdated_configs(json: &mut Value) { let copy = json.clone(); @@ -105,9 +108,9 @@ pub(super) fn patch_json_for_outdated_configs(json: &mut Value) { merge(json, json!({ "cargo": { "features": "all" } })); } - // checkOnSave_allFeatures, checkOnSave_features -> checkOnSave_features + // checkOnSave_allFeatures, checkOnSave_features -> flycheck_features if let Some(Value::Bool(true)) = copy.pointer("/checkOnSave/allFeatures") { - merge(json, json!({ "checkOnSave": { "features": "all" } })); + merge(json, json!({ "flycheck": { "features": "all" } })); } // completion_addCallArgumentSnippets completion_addCallParenthesis -> completion_callable_snippets @@ -121,6 +124,16 @@ pub(super) fn patch_json_for_outdated_configs(json: &mut Value) { (_, _) => return, }; merge(json, json!({ "completion": { "callable": {"snippets": res }} })); + + // We need to do this due to the checkOnSave_enable -> checkOnSave change, as that key now can either be an object or a bool + // checkOnSave_* -> flycheck_* + if let Some(Value::Object(obj)) = copy.pointer("/checkOnSave") { + // checkOnSave_enable -> checkOnSave + if let Some(b @ Value::Bool(_)) = obj.get("enable") { + merge(json, json!({ "checkOnSave": b })); + } + merge(json, json!({ "flycheck": obj })); + } } fn merge(dst: &mut Value, src: Value) { diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 91f8e98449ec..e6da4f38ab4e 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -109,96 +109,10 @@ Compilation target override (target triple). -- Unsets `#[cfg(test)]` for the specified crates. -- -[[rust-analyzer.checkOnSave.allTargets]]rust-analyzer.checkOnSave.allTargets (default: `true`):: +[[rust-analyzer.checkOnSave]]rust-analyzer.checkOnSave (default: `true`):: + -- -Check all targets and tests (`--all-targets`). --- -[[rust-analyzer.checkOnSave.command]]rust-analyzer.checkOnSave.command (default: `"check"`):: -+ --- -Cargo command to use for `cargo check`. --- -[[rust-analyzer.checkOnSave.enable]]rust-analyzer.checkOnSave.enable (default: `true`):: -+ --- -Run specified `cargo check` command for diagnostics on save. --- -[[rust-analyzer.checkOnSave.extraArgs]]rust-analyzer.checkOnSave.extraArgs (default: `[]`):: -+ --- -Extra arguments for `cargo check`. --- -[[rust-analyzer.checkOnSave.extraEnv]]rust-analyzer.checkOnSave.extraEnv (default: `{}`):: -+ --- -Extra environment variables that will be set when running `cargo check`. -Extends `#rust-analyzer.cargo.extraEnv#`. --- -[[rust-analyzer.checkOnSave.features]]rust-analyzer.checkOnSave.features (default: `null`):: -+ --- -List of features to activate. Defaults to -`#rust-analyzer.cargo.features#`. - -Set to `"all"` to pass `--all-features` to Cargo. --- -[[rust-analyzer.checkOnSave.invocationLocation]]rust-analyzer.checkOnSave.invocationLocation (default: `"workspace"`):: -+ --- -Specifies the working directory for running checks. -- "workspace": run checks for workspaces in the corresponding workspaces' root directories. - This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`. -- "root": run checks in the project's root directory. -This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` -is set. --- -[[rust-analyzer.checkOnSave.invocationStrategy]]rust-analyzer.checkOnSave.invocationStrategy (default: `"per_workspace"`):: -+ --- -Specifies the invocation strategy to use when running the checkOnSave command. -If `per_workspace` is set, the command will be executed for each workspace. -If `once` is set, the command will be executed once. -This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` -is set. --- -[[rust-analyzer.checkOnSave.noDefaultFeatures]]rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`):: -+ --- -Whether to pass `--no-default-features` to Cargo. Defaults to -`#rust-analyzer.cargo.noDefaultFeatures#`. --- -[[rust-analyzer.checkOnSave.overrideCommand]]rust-analyzer.checkOnSave.overrideCommand (default: `null`):: -+ --- -Override the command rust-analyzer uses instead of `cargo check` for -diagnostics on save. The command is required to output json and -should therefore include `--message-format=json` or a similar option. - -If you're changing this because you're using some tool wrapping -Cargo, you might also want to change -`#rust-analyzer.cargo.buildScripts.overrideCommand#`. - -If there are multiple linked projects, this command is invoked for -each of them, with the working directory being the project root -(i.e., the folder containing the `Cargo.toml`). - -An example command would be: - -```bash -cargo check --workspace --message-format=json --all-targets -``` -. --- -[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `null`):: -+ --- -Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. - -Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. -`["aarch64-apple-darwin", "x86_64-apple-darwin"]`. - -Aliased as `"checkOnSave.targets"`. +Run the flycheck command for diagnostics on save. -- [[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`):: + @@ -327,6 +241,92 @@ also need to add the folders to Code's `files.watcherExclude`. -- Controls file watching implementation. -- +[[rust-analyzer.flycheck.allTargets]]rust-analyzer.flycheck.allTargets (default: `true`):: ++ +-- +Check all targets and tests (`--all-targets`). +-- +[[rust-analyzer.flycheck.command]]rust-analyzer.flycheck.command (default: `"check"`):: ++ +-- +Cargo command to use for `cargo check`. +-- +[[rust-analyzer.flycheck.extraArgs]]rust-analyzer.flycheck.extraArgs (default: `[]`):: ++ +-- +Extra arguments for `cargo check`. +-- +[[rust-analyzer.flycheck.extraEnv]]rust-analyzer.flycheck.extraEnv (default: `{}`):: ++ +-- +Extra environment variables that will be set when running `cargo check`. +Extends `#rust-analyzer.cargo.extraEnv#`. +-- +[[rust-analyzer.flycheck.features]]rust-analyzer.flycheck.features (default: `null`):: ++ +-- +List of features to activate. Defaults to +`#rust-analyzer.cargo.features#`. + +Set to `"all"` to pass `--all-features` to Cargo. +-- +[[rust-analyzer.flycheck.invocationLocation]]rust-analyzer.flycheck.invocationLocation (default: `"workspace"`):: ++ +-- +Specifies the working directory for running checks. +- "workspace": run checks for workspaces in the corresponding workspaces' root directories. + This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`. +- "root": run checks in the project's root directory. +This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` +is set. +-- +[[rust-analyzer.flycheck.invocationStrategy]]rust-analyzer.flycheck.invocationStrategy (default: `"per_workspace"`):: ++ +-- +Specifies the invocation strategy to use when running the checkOnSave command. +If `per_workspace` is set, the command will be executed for each workspace. +If `once` is set, the command will be executed once. +This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` +is set. +-- +[[rust-analyzer.flycheck.noDefaultFeatures]]rust-analyzer.flycheck.noDefaultFeatures (default: `null`):: ++ +-- +Whether to pass `--no-default-features` to Cargo. Defaults to +`#rust-analyzer.cargo.noDefaultFeatures#`. +-- +[[rust-analyzer.flycheck.overrideCommand]]rust-analyzer.flycheck.overrideCommand (default: `null`):: ++ +-- +Override the command rust-analyzer uses instead of `cargo check` for +diagnostics on save. The command is required to output json and +should therefore include `--message-format=json` or a similar option. + +If you're changing this because you're using some tool wrapping +Cargo, you might also want to change +`#rust-analyzer.cargo.buildScripts.overrideCommand#`. + +If there are multiple linked projects, this command is invoked for +each of them, with the working directory being the project root +(i.e., the folder containing the `Cargo.toml`). + +An example command would be: + +```bash +cargo check --workspace --message-format=json --all-targets +``` +. +-- +[[rust-analyzer.flycheck.targets]]rust-analyzer.flycheck.targets (default: `null`):: ++ +-- +Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. + +Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. +`["aarch64-apple-darwin", "x86_64-apple-darwin"]`. + +Aliased as `"checkOnSave.targets"`. +-- [[rust-analyzer.highlightRelated.breakPoints.enable]]rust-analyzer.highlightRelated.breakPoints.enable (default: `true`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index 454b95a63b21..4fe829382dd9 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -556,121 +556,11 @@ "type": "string" } }, - "rust-analyzer.checkOnSave.allTargets": { - "markdownDescription": "Check all targets and tests (`--all-targets`).", + "rust-analyzer.checkOnSave": { + "markdownDescription": "Run the flycheck command for diagnostics on save.", "default": true, "type": "boolean" }, - "rust-analyzer.checkOnSave.command": { - "markdownDescription": "Cargo command to use for `cargo check`.", - "default": "check", - "type": "string" - }, - "rust-analyzer.checkOnSave.enable": { - "markdownDescription": "Run specified `cargo check` command for diagnostics on save.", - "default": true, - "type": "boolean" - }, - "rust-analyzer.checkOnSave.extraArgs": { - "markdownDescription": "Extra arguments for `cargo check`.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "rust-analyzer.checkOnSave.extraEnv": { - "markdownDescription": "Extra environment variables that will be set when running `cargo check`.\nExtends `#rust-analyzer.cargo.extraEnv#`.", - "default": {}, - "type": "object" - }, - "rust-analyzer.checkOnSave.features": { - "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.", - "default": null, - "anyOf": [ - { - "type": "string", - "enum": [ - "all" - ], - "enumDescriptions": [ - "Pass `--all-features` to cargo" - ] - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "null" - } - ] - }, - "rust-analyzer.checkOnSave.invocationLocation": { - "markdownDescription": "Specifies the working directory for running checks.\n- \"workspace\": run checks for workspaces in the corresponding workspaces' root directories.\n This falls back to \"root\" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.\n- \"root\": run checks in the project's root directory.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.", - "default": "workspace", - "type": "string", - "enum": [ - "workspace", - "root" - ], - "enumDescriptions": [ - "The command will be executed in the corresponding workspace root.", - "The command will be executed in the project root." - ] - }, - "rust-analyzer.checkOnSave.invocationStrategy": { - "markdownDescription": "Specifies the invocation strategy to use when running the checkOnSave command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.", - "default": "per_workspace", - "type": "string", - "enum": [ - "per_workspace", - "once" - ], - "enumDescriptions": [ - "The command will be executed for each workspace.", - "The command will be executed once." - ] - }, - "rust-analyzer.checkOnSave.noDefaultFeatures": { - "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.", - "default": null, - "type": [ - "null", - "boolean" - ] - }, - "rust-analyzer.checkOnSave.overrideCommand": { - "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", - "default": null, - "type": [ - "null", - "array" - ], - "items": { - "type": "string" - } - }, - "rust-analyzer.checkOnSave.target": { - "markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.", - "default": null, - "anyOf": [ - { - "type": "null" - }, - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - }, "rust-analyzer.completion.autoimport.enable": { "markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.", "default": true, @@ -812,6 +702,116 @@ "Use server-side file watching" ] }, + "rust-analyzer.flycheck.allTargets": { + "markdownDescription": "Check all targets and tests (`--all-targets`).", + "default": true, + "type": "boolean" + }, + "rust-analyzer.flycheck.command": { + "markdownDescription": "Cargo command to use for `cargo check`.", + "default": "check", + "type": "string" + }, + "rust-analyzer.flycheck.extraArgs": { + "markdownDescription": "Extra arguments for `cargo check`.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "rust-analyzer.flycheck.extraEnv": { + "markdownDescription": "Extra environment variables that will be set when running `cargo check`.\nExtends `#rust-analyzer.cargo.extraEnv#`.", + "default": {}, + "type": "object" + }, + "rust-analyzer.flycheck.features": { + "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.", + "default": null, + "anyOf": [ + { + "type": "string", + "enum": [ + "all" + ], + "enumDescriptions": [ + "Pass `--all-features` to cargo" + ] + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ] + }, + "rust-analyzer.flycheck.invocationLocation": { + "markdownDescription": "Specifies the working directory for running checks.\n- \"workspace\": run checks for workspaces in the corresponding workspaces' root directories.\n This falls back to \"root\" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.\n- \"root\": run checks in the project's root directory.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.", + "default": "workspace", + "type": "string", + "enum": [ + "workspace", + "root" + ], + "enumDescriptions": [ + "The command will be executed in the corresponding workspace root.", + "The command will be executed in the project root." + ] + }, + "rust-analyzer.flycheck.invocationStrategy": { + "markdownDescription": "Specifies the invocation strategy to use when running the checkOnSave command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.", + "default": "per_workspace", + "type": "string", + "enum": [ + "per_workspace", + "once" + ], + "enumDescriptions": [ + "The command will be executed for each workspace.", + "The command will be executed once." + ] + }, + "rust-analyzer.flycheck.noDefaultFeatures": { + "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.", + "default": null, + "type": [ + "null", + "boolean" + ] + }, + "rust-analyzer.flycheck.overrideCommand": { + "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", + "default": null, + "type": [ + "null", + "array" + ], + "items": { + "type": "string" + } + }, + "rust-analyzer.flycheck.targets": { + "markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.", + "default": null, + "anyOf": [ + { + "type": "null" + }, + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, "rust-analyzer.highlightRelated.breakPoints.enable": { "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.", "default": true, From d2bb62b6a81d26f1e41712e04d4ac760f860d3b3 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 9 Jan 2023 14:15:13 +0100 Subject: [PATCH 0778/2442] Rename checkOnSave settings to check --- crates/rust-analyzer/src/config.rs | 151 ++++++------ .../src/config/patch_old_style.rs | 8 +- docs/user/generated_config.adoc | 174 +++++++------- editors/code/package.json | 222 +++++++++--------- 4 files changed, 274 insertions(+), 281 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 25bfa0c28edd..b97c8106be6a 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -124,9 +124,67 @@ config_data! { /// Unsets `#[cfg(test)]` for the specified crates. cargo_unsetTest: Vec = "[\"core\"]", - /// Run the flycheck command for diagnostics on save. + /// Run the check command for diagnostics on save. checkOnSave | checkOnSave_enable: bool = "true", + /// Check all targets and tests (`--all-targets`). + check_allTargets | checkOnSave_allTargets: bool = "true", + /// Cargo command to use for `cargo check`. + check_command | checkOnSave_command: String = "\"check\"", + /// Extra arguments for `cargo check`. + check_extraArgs | checkOnSave_extraArgs: Vec = "[]", + /// Extra environment variables that will be set when running `cargo check`. + /// Extends `#rust-analyzer.cargo.extraEnv#`. + check_extraEnv | checkOnSave_extraEnv: FxHashMap = "{}", + /// List of features to activate. Defaults to + /// `#rust-analyzer.cargo.features#`. + /// + /// Set to `"all"` to pass `--all-features` to Cargo. + check_features | checkOnSave_features: Option = "null", + /// Specifies the working directory for running checks. + /// - "workspace": run checks for workspaces in the corresponding workspaces' root directories. + // FIXME: Ideally we would support this in some way + /// This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`. + /// - "root": run checks in the project's root directory. + /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` + /// is set. + check_invocationLocation | checkOnSave_invocationLocation: InvocationLocation = "\"workspace\"", + /// Specifies the invocation strategy to use when running the checkOnSave command. + /// If `per_workspace` is set, the command will be executed for each workspace. + /// If `once` is set, the command will be executed once. + /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` + /// is set. + check_invocationStrategy | checkOnSave_invocationStrategy: InvocationStrategy = "\"per_workspace\"", + /// Whether to pass `--no-default-features` to Cargo. Defaults to + /// `#rust-analyzer.cargo.noDefaultFeatures#`. + check_noDefaultFeatures | checkOnSave_noDefaultFeatures: Option = "null", + /// Override the command rust-analyzer uses instead of `cargo check` for + /// diagnostics on save. The command is required to output json and + /// should therefore include `--message-format=json` or a similar option. + /// + /// If you're changing this because you're using some tool wrapping + /// Cargo, you might also want to change + /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`. + /// + /// If there are multiple linked projects, this command is invoked for + /// each of them, with the working directory being the project root + /// (i.e., the folder containing the `Cargo.toml`). + /// + /// An example command would be: + /// + /// ```bash + /// cargo check --workspace --message-format=json --all-targets + /// ``` + /// . + check_overrideCommand | checkOnSave_overrideCommand: Option> = "null", + /// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. + /// + /// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. + /// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`. + /// + /// Aliased as `"checkOnSave.targets"`. + check_targets | checkOnSave_targets | checkOnSave_target: Option = "null", + /// Toggles the additional completions that automatically add imports when completed. /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. completion_autoimport_enable: bool = "true", @@ -211,64 +269,6 @@ config_data! { /// Controls file watching implementation. files_watcher: FilesWatcherDef = "\"client\"", - /// Check all targets and tests (`--all-targets`). - flycheck_allTargets | checkOnSave_allTargets: bool = "true", - /// Cargo command to use for `cargo check`. - flycheck_command | checkOnSave_command: String = "\"check\"", - /// Extra arguments for `cargo check`. - flycheck_extraArgs | checkOnSave_extraArgs: Vec = "[]", - /// Extra environment variables that will be set when running `cargo check`. - /// Extends `#rust-analyzer.cargo.extraEnv#`. - flycheck_extraEnv | checkOnSave_extraEnv: FxHashMap = "{}", - /// List of features to activate. Defaults to - /// `#rust-analyzer.cargo.features#`. - /// - /// Set to `"all"` to pass `--all-features` to Cargo. - flycheck_features | checkOnSave_features: Option = "null", - /// Specifies the working directory for running checks. - /// - "workspace": run checks for workspaces in the corresponding workspaces' root directories. - // FIXME: Ideally we would support this in some way - /// This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`. - /// - "root": run checks in the project's root directory. - /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` - /// is set. - flycheck_invocationLocation | checkOnSave_invocationLocation: InvocationLocation = "\"workspace\"", - /// Specifies the invocation strategy to use when running the checkOnSave command. - /// If `per_workspace` is set, the command will be executed for each workspace. - /// If `once` is set, the command will be executed once. - /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` - /// is set. - flycheck_invocationStrategy | checkOnSave_invocationStrategy: InvocationStrategy = "\"per_workspace\"", - /// Whether to pass `--no-default-features` to Cargo. Defaults to - /// `#rust-analyzer.cargo.noDefaultFeatures#`. - flycheck_noDefaultFeatures | checkOnSave_noDefaultFeatures: Option = "null", - /// Override the command rust-analyzer uses instead of `cargo check` for - /// diagnostics on save. The command is required to output json and - /// should therefore include `--message-format=json` or a similar option. - /// - /// If you're changing this because you're using some tool wrapping - /// Cargo, you might also want to change - /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`. - /// - /// If there are multiple linked projects, this command is invoked for - /// each of them, with the working directory being the project root - /// (i.e., the folder containing the `Cargo.toml`). - /// - /// An example command would be: - /// - /// ```bash - /// cargo check --workspace --message-format=json --all-targets - /// ``` - /// . - flycheck_overrideCommand | checkOnSave_overrideCommand: Option> = "null", - /// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. - /// - /// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. - /// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`. - /// - /// Aliased as `"checkOnSave.targets"`. - flycheck_targets | checkOnSave_targets | checkOnSave_target: Option = "null", - /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. highlightRelated_breakPoints_enable: bool = "true", /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`). @@ -787,9 +787,9 @@ impl Config { fn validate(&self, error_sink: &mut Vec<(String, serde_json::Error)>) { use serde::de::Error; - if self.data.flycheck_command.is_empty() { + if self.data.check_command.is_empty() { error_sink.push(( - "/flycheck/command".to_string(), + "/check/command".to_string(), serde_json::Error::custom("expected a non-empty string"), )); } @@ -1034,7 +1034,7 @@ impl Config { pub fn check_on_save_extra_env(&self) -> FxHashMap { let mut extra_env = self.data.cargo_extraEnv.clone(); - extra_env.extend(self.data.flycheck_extraEnv.clone()); + extra_env.extend(self.data.check_extraEnv.clone()); extra_env } @@ -1146,7 +1146,7 @@ impl Config { } pub fn flycheck(&self) -> FlycheckConfig { - match &self.data.flycheck_overrideCommand { + match &self.data.check_overrideCommand { Some(args) if !args.is_empty() => { let mut args = args.clone(); let command = args.remove(0); @@ -1154,13 +1154,13 @@ impl Config { command, args, extra_env: self.check_on_save_extra_env(), - invocation_strategy: match self.data.flycheck_invocationStrategy { + invocation_strategy: match self.data.check_invocationStrategy { InvocationStrategy::Once => flycheck::InvocationStrategy::Once, InvocationStrategy::PerWorkspace => { flycheck::InvocationStrategy::PerWorkspace } }, - invocation_location: match self.data.flycheck_invocationLocation { + invocation_location: match self.data.check_invocationLocation { InvocationLocation::Root => { flycheck::InvocationLocation::Root(self.root_path.clone()) } @@ -1169,35 +1169,35 @@ impl Config { } } Some(_) | None => FlycheckConfig::CargoCommand { - command: self.data.flycheck_command.clone(), + command: self.data.check_command.clone(), target_triples: self .data - .flycheck_targets + .check_targets .clone() .and_then(|targets| match &targets.0[..] { [] => None, targets => Some(targets.into()), }) .unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()), - all_targets: self.data.flycheck_allTargets, + all_targets: self.data.check_allTargets, no_default_features: self .data - .flycheck_noDefaultFeatures + .check_noDefaultFeatures .unwrap_or(self.data.cargo_noDefaultFeatures), all_features: matches!( - self.data.flycheck_features.as_ref().unwrap_or(&self.data.cargo_features), + self.data.check_features.as_ref().unwrap_or(&self.data.cargo_features), CargoFeaturesDef::All ), features: match self .data - .flycheck_features + .check_features .clone() .unwrap_or_else(|| self.data.cargo_features.clone()) { CargoFeaturesDef::All => vec![], CargoFeaturesDef::Selected(it) => it, }, - extra_args: self.data.flycheck_extraArgs.clone(), + extra_args: self.data.check_extraArgs.clone(), extra_env: self.check_on_save_extra_env(), }, } @@ -1887,13 +1887,6 @@ fn get_field( } fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json::Value { - for ((f1, ..), (f2, ..)) in fields.iter().zip(&fields[1..]) { - fn key(f: &str) -> &str { - f.splitn(2, '_').next().unwrap() - } - assert!(key(f1) <= key(f2), "wrong field order: {f1:?} {f2:?}"); - } - let map = fields .iter() .map(|(field, ty, doc, default)| { diff --git a/crates/rust-analyzer/src/config/patch_old_style.rs b/crates/rust-analyzer/src/config/patch_old_style.rs index 38b70219cb2e..de6ac946a682 100644 --- a/crates/rust-analyzer/src/config/patch_old_style.rs +++ b/crates/rust-analyzer/src/config/patch_old_style.rs @@ -108,9 +108,9 @@ pub(super) fn patch_json_for_outdated_configs(json: &mut Value) { merge(json, json!({ "cargo": { "features": "all" } })); } - // checkOnSave_allFeatures, checkOnSave_features -> flycheck_features + // checkOnSave_allFeatures, checkOnSave_features -> check_features if let Some(Value::Bool(true)) = copy.pointer("/checkOnSave/allFeatures") { - merge(json, json!({ "flycheck": { "features": "all" } })); + merge(json, json!({ "check": { "features": "all" } })); } // completion_addCallArgumentSnippets completion_addCallParenthesis -> completion_callable_snippets @@ -126,13 +126,13 @@ pub(super) fn patch_json_for_outdated_configs(json: &mut Value) { merge(json, json!({ "completion": { "callable": {"snippets": res }} })); // We need to do this due to the checkOnSave_enable -> checkOnSave change, as that key now can either be an object or a bool - // checkOnSave_* -> flycheck_* + // checkOnSave_* -> check_* if let Some(Value::Object(obj)) = copy.pointer("/checkOnSave") { // checkOnSave_enable -> checkOnSave if let Some(b @ Value::Bool(_)) = obj.get("enable") { merge(json, json!({ "checkOnSave": b })); } - merge(json, json!({ "flycheck": obj })); + merge(json, json!({ "check": obj })); } } diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index e6da4f38ab4e..7bdfd4288a19 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -112,7 +112,93 @@ Unsets `#[cfg(test)]` for the specified crates. [[rust-analyzer.checkOnSave]]rust-analyzer.checkOnSave (default: `true`):: + -- -Run the flycheck command for diagnostics on save. +Run the check command for diagnostics on save. +-- +[[rust-analyzer.check.allTargets]]rust-analyzer.check.allTargets (default: `true`):: ++ +-- +Check all targets and tests (`--all-targets`). +-- +[[rust-analyzer.check.command]]rust-analyzer.check.command (default: `"check"`):: ++ +-- +Cargo command to use for `cargo check`. +-- +[[rust-analyzer.check.extraArgs]]rust-analyzer.check.extraArgs (default: `[]`):: ++ +-- +Extra arguments for `cargo check`. +-- +[[rust-analyzer.check.extraEnv]]rust-analyzer.check.extraEnv (default: `{}`):: ++ +-- +Extra environment variables that will be set when running `cargo check`. +Extends `#rust-analyzer.cargo.extraEnv#`. +-- +[[rust-analyzer.check.features]]rust-analyzer.check.features (default: `null`):: ++ +-- +List of features to activate. Defaults to +`#rust-analyzer.cargo.features#`. + +Set to `"all"` to pass `--all-features` to Cargo. +-- +[[rust-analyzer.check.invocationLocation]]rust-analyzer.check.invocationLocation (default: `"workspace"`):: ++ +-- +Specifies the working directory for running checks. +- "workspace": run checks for workspaces in the corresponding workspaces' root directories. + This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`. +- "root": run checks in the project's root directory. +This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` +is set. +-- +[[rust-analyzer.check.invocationStrategy]]rust-analyzer.check.invocationStrategy (default: `"per_workspace"`):: ++ +-- +Specifies the invocation strategy to use when running the checkOnSave command. +If `per_workspace` is set, the command will be executed for each workspace. +If `once` is set, the command will be executed once. +This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` +is set. +-- +[[rust-analyzer.check.noDefaultFeatures]]rust-analyzer.check.noDefaultFeatures (default: `null`):: ++ +-- +Whether to pass `--no-default-features` to Cargo. Defaults to +`#rust-analyzer.cargo.noDefaultFeatures#`. +-- +[[rust-analyzer.check.overrideCommand]]rust-analyzer.check.overrideCommand (default: `null`):: ++ +-- +Override the command rust-analyzer uses instead of `cargo check` for +diagnostics on save. The command is required to output json and +should therefore include `--message-format=json` or a similar option. + +If you're changing this because you're using some tool wrapping +Cargo, you might also want to change +`#rust-analyzer.cargo.buildScripts.overrideCommand#`. + +If there are multiple linked projects, this command is invoked for +each of them, with the working directory being the project root +(i.e., the folder containing the `Cargo.toml`). + +An example command would be: + +```bash +cargo check --workspace --message-format=json --all-targets +``` +. +-- +[[rust-analyzer.check.targets]]rust-analyzer.check.targets (default: `null`):: ++ +-- +Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. + +Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. +`["aarch64-apple-darwin", "x86_64-apple-darwin"]`. + +Aliased as `"checkOnSave.targets"`. -- [[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`):: + @@ -241,92 +327,6 @@ also need to add the folders to Code's `files.watcherExclude`. -- Controls file watching implementation. -- -[[rust-analyzer.flycheck.allTargets]]rust-analyzer.flycheck.allTargets (default: `true`):: -+ --- -Check all targets and tests (`--all-targets`). --- -[[rust-analyzer.flycheck.command]]rust-analyzer.flycheck.command (default: `"check"`):: -+ --- -Cargo command to use for `cargo check`. --- -[[rust-analyzer.flycheck.extraArgs]]rust-analyzer.flycheck.extraArgs (default: `[]`):: -+ --- -Extra arguments for `cargo check`. --- -[[rust-analyzer.flycheck.extraEnv]]rust-analyzer.flycheck.extraEnv (default: `{}`):: -+ --- -Extra environment variables that will be set when running `cargo check`. -Extends `#rust-analyzer.cargo.extraEnv#`. --- -[[rust-analyzer.flycheck.features]]rust-analyzer.flycheck.features (default: `null`):: -+ --- -List of features to activate. Defaults to -`#rust-analyzer.cargo.features#`. - -Set to `"all"` to pass `--all-features` to Cargo. --- -[[rust-analyzer.flycheck.invocationLocation]]rust-analyzer.flycheck.invocationLocation (default: `"workspace"`):: -+ --- -Specifies the working directory for running checks. -- "workspace": run checks for workspaces in the corresponding workspaces' root directories. - This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`. -- "root": run checks in the project's root directory. -This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` -is set. --- -[[rust-analyzer.flycheck.invocationStrategy]]rust-analyzer.flycheck.invocationStrategy (default: `"per_workspace"`):: -+ --- -Specifies the invocation strategy to use when running the checkOnSave command. -If `per_workspace` is set, the command will be executed for each workspace. -If `once` is set, the command will be executed once. -This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#` -is set. --- -[[rust-analyzer.flycheck.noDefaultFeatures]]rust-analyzer.flycheck.noDefaultFeatures (default: `null`):: -+ --- -Whether to pass `--no-default-features` to Cargo. Defaults to -`#rust-analyzer.cargo.noDefaultFeatures#`. --- -[[rust-analyzer.flycheck.overrideCommand]]rust-analyzer.flycheck.overrideCommand (default: `null`):: -+ --- -Override the command rust-analyzer uses instead of `cargo check` for -diagnostics on save. The command is required to output json and -should therefore include `--message-format=json` or a similar option. - -If you're changing this because you're using some tool wrapping -Cargo, you might also want to change -`#rust-analyzer.cargo.buildScripts.overrideCommand#`. - -If there are multiple linked projects, this command is invoked for -each of them, with the working directory being the project root -(i.e., the folder containing the `Cargo.toml`). - -An example command would be: - -```bash -cargo check --workspace --message-format=json --all-targets -``` -. --- -[[rust-analyzer.flycheck.targets]]rust-analyzer.flycheck.targets (default: `null`):: -+ --- -Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. - -Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. -`["aarch64-apple-darwin", "x86_64-apple-darwin"]`. - -Aliased as `"checkOnSave.targets"`. --- [[rust-analyzer.highlightRelated.breakPoints.enable]]rust-analyzer.highlightRelated.breakPoints.enable (default: `true`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index 4fe829382dd9..56018b9929cc 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -557,10 +557,120 @@ } }, "rust-analyzer.checkOnSave": { - "markdownDescription": "Run the flycheck command for diagnostics on save.", + "markdownDescription": "Run the check command for diagnostics on save.", "default": true, "type": "boolean" }, + "rust-analyzer.check.allTargets": { + "markdownDescription": "Check all targets and tests (`--all-targets`).", + "default": true, + "type": "boolean" + }, + "rust-analyzer.check.command": { + "markdownDescription": "Cargo command to use for `cargo check`.", + "default": "check", + "type": "string" + }, + "rust-analyzer.check.extraArgs": { + "markdownDescription": "Extra arguments for `cargo check`.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "rust-analyzer.check.extraEnv": { + "markdownDescription": "Extra environment variables that will be set when running `cargo check`.\nExtends `#rust-analyzer.cargo.extraEnv#`.", + "default": {}, + "type": "object" + }, + "rust-analyzer.check.features": { + "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.", + "default": null, + "anyOf": [ + { + "type": "string", + "enum": [ + "all" + ], + "enumDescriptions": [ + "Pass `--all-features` to cargo" + ] + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ] + }, + "rust-analyzer.check.invocationLocation": { + "markdownDescription": "Specifies the working directory for running checks.\n- \"workspace\": run checks for workspaces in the corresponding workspaces' root directories.\n This falls back to \"root\" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.\n- \"root\": run checks in the project's root directory.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.", + "default": "workspace", + "type": "string", + "enum": [ + "workspace", + "root" + ], + "enumDescriptions": [ + "The command will be executed in the corresponding workspace root.", + "The command will be executed in the project root." + ] + }, + "rust-analyzer.check.invocationStrategy": { + "markdownDescription": "Specifies the invocation strategy to use when running the checkOnSave command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.", + "default": "per_workspace", + "type": "string", + "enum": [ + "per_workspace", + "once" + ], + "enumDescriptions": [ + "The command will be executed for each workspace.", + "The command will be executed once." + ] + }, + "rust-analyzer.check.noDefaultFeatures": { + "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.", + "default": null, + "type": [ + "null", + "boolean" + ] + }, + "rust-analyzer.check.overrideCommand": { + "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", + "default": null, + "type": [ + "null", + "array" + ], + "items": { + "type": "string" + } + }, + "rust-analyzer.check.targets": { + "markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.", + "default": null, + "anyOf": [ + { + "type": "null" + }, + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, "rust-analyzer.completion.autoimport.enable": { "markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.", "default": true, @@ -702,116 +812,6 @@ "Use server-side file watching" ] }, - "rust-analyzer.flycheck.allTargets": { - "markdownDescription": "Check all targets and tests (`--all-targets`).", - "default": true, - "type": "boolean" - }, - "rust-analyzer.flycheck.command": { - "markdownDescription": "Cargo command to use for `cargo check`.", - "default": "check", - "type": "string" - }, - "rust-analyzer.flycheck.extraArgs": { - "markdownDescription": "Extra arguments for `cargo check`.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "rust-analyzer.flycheck.extraEnv": { - "markdownDescription": "Extra environment variables that will be set when running `cargo check`.\nExtends `#rust-analyzer.cargo.extraEnv#`.", - "default": {}, - "type": "object" - }, - "rust-analyzer.flycheck.features": { - "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.", - "default": null, - "anyOf": [ - { - "type": "string", - "enum": [ - "all" - ], - "enumDescriptions": [ - "Pass `--all-features` to cargo" - ] - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "null" - } - ] - }, - "rust-analyzer.flycheck.invocationLocation": { - "markdownDescription": "Specifies the working directory for running checks.\n- \"workspace\": run checks for workspaces in the corresponding workspaces' root directories.\n This falls back to \"root\" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.\n- \"root\": run checks in the project's root directory.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.", - "default": "workspace", - "type": "string", - "enum": [ - "workspace", - "root" - ], - "enumDescriptions": [ - "The command will be executed in the corresponding workspace root.", - "The command will be executed in the project root." - ] - }, - "rust-analyzer.flycheck.invocationStrategy": { - "markdownDescription": "Specifies the invocation strategy to use when running the checkOnSave command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.", - "default": "per_workspace", - "type": "string", - "enum": [ - "per_workspace", - "once" - ], - "enumDescriptions": [ - "The command will be executed for each workspace.", - "The command will be executed once." - ] - }, - "rust-analyzer.flycheck.noDefaultFeatures": { - "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.", - "default": null, - "type": [ - "null", - "boolean" - ] - }, - "rust-analyzer.flycheck.overrideCommand": { - "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", - "default": null, - "type": [ - "null", - "array" - ], - "items": { - "type": "string" - } - }, - "rust-analyzer.flycheck.targets": { - "markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.", - "default": null, - "anyOf": [ - { - "type": "null" - }, - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - }, "rust-analyzer.highlightRelated.breakPoints.enable": { "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.", "default": true, From b89c4f0a0529ca90dbe13d41fdd5e52331770900 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 20 Dec 2022 22:07:00 +0000 Subject: [PATCH 0779/2442] Implement postfix adjustment hints I'd say "First stab at implementing..." but I've been working on this for a month already lol --- crates/ide/src/inlay_hints.rs | 3 + crates/ide/src/inlay_hints/adjustment.rs | 252 ++++++++++++++++++++--- crates/ide/src/static_index.rs | 1 + crates/rust-analyzer/src/config.rs | 3 + crates/rust-analyzer/src/to_proto.rs | 4 + docs/user/generated_config.adoc | 5 + editors/code/package.json | 5 + 7 files changed, 246 insertions(+), 27 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 86d25e2f5ad0..7315a37ebc70 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -35,6 +35,7 @@ pub struct InlayHintsConfig { pub parameter_hints: bool, pub chaining_hints: bool, pub adjustment_hints: AdjustmentHints, + pub adjustment_hints_postfix: bool, pub adjustment_hints_hide_outside_unsafe: bool, pub closure_return_type_hints: ClosureReturnTypeHints, pub binding_mode_hints: bool, @@ -82,6 +83,7 @@ pub enum InlayKind { ClosureReturnTypeHint, GenericParamListHint, AdjustmentHint, + AdjustmentHintPostfix, LifetimeHint, ParameterHint, TypeHint, @@ -446,6 +448,7 @@ mod tests { lifetime_elision_hints: LifetimeElisionHints::Never, closure_return_type_hints: ClosureReturnTypeHints::Never, adjustment_hints: AdjustmentHints::Never, + adjustment_hints_postfix: false, adjustment_hints_hide_outside_unsafe: false, binding_mode_hints: false, hide_named_constructor_hints: false, diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index 1c13f31cf24f..367bd2f6619e 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -5,7 +5,11 @@ //! ``` use hir::{Adjust, AutoBorrow, Mutability, OverloadedDeref, PointerCast, Safety, Semantics}; use ide_db::RootDatabase; -use syntax::ast::{self, AstNode}; + +use syntax::{ + ast::{self, make, AstNode}, + ted, +}; use crate::{AdjustmentHints, InlayHint, InlayHintsConfig, InlayKind}; @@ -32,28 +36,14 @@ pub(super) fn hints( return None; } - let parent = expr.syntax().parent().and_then(ast::Expr::cast); let descended = sema.descend_node_into_attributes(expr.clone()).pop(); let desc_expr = descended.as_ref().unwrap_or(expr); let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?; - let needs_parens = match parent { - Some(parent) => { - match parent { - ast::Expr::AwaitExpr(_) - | ast::Expr::CallExpr(_) - | ast::Expr::CastExpr(_) - | ast::Expr::FieldExpr(_) - | ast::Expr::MethodCallExpr(_) - | ast::Expr::TryExpr(_) => true, - // FIXME: shorthands need special casing, though not sure if adjustments are even valid there - ast::Expr::RecordExpr(_) => false, - ast::Expr::IndexExpr(index) => index.base().as_ref() == Some(expr), - _ => false, - } - } - None => false, - }; - if needs_parens { + + let (needs_outer_parens, needs_inner_parens) = + needs_parens_for_adjustment_hints(expr, config.adjustment_hints_postfix); + + if needs_outer_parens { acc.push(InlayHint { range: expr.syntax().text_range(), kind: InlayKind::OpeningParenthesis, @@ -61,7 +51,32 @@ pub(super) fn hints( tooltip: None, }); } - for adjustment in adjustments.into_iter().rev() { + + if config.adjustment_hints_postfix && needs_inner_parens { + acc.push(InlayHint { + range: expr.syntax().text_range(), + kind: InlayKind::OpeningParenthesis, + label: "(".into(), + tooltip: None, + }); + acc.push(InlayHint { + range: expr.syntax().text_range(), + kind: InlayKind::ClosingParenthesis, + label: ")".into(), + tooltip: None, + }); + } + + let (mut tmp0, mut tmp1); + let iter: &mut dyn Iterator = if config.adjustment_hints_postfix { + tmp0 = adjustments.into_iter(); + &mut tmp0 + } else { + tmp1 = adjustments.into_iter().rev(); + &mut tmp1 + }; + + for adjustment in iter { if adjustment.source == adjustment.target { continue; } @@ -97,12 +112,34 @@ pub(super) fn hints( }; acc.push(InlayHint { range: expr.syntax().text_range(), - kind: InlayKind::AdjustmentHint, - label: text.into(), + kind: if config.adjustment_hints_postfix { + InlayKind::AdjustmentHintPostfix + } else { + InlayKind::AdjustmentHint + }, + label: if config.adjustment_hints_postfix { + format!(".{}", text.trim_end()).into() + } else { + text.into() + }, tooltip: None, }); } - if needs_parens { + if !config.adjustment_hints_postfix && needs_inner_parens { + acc.push(InlayHint { + range: expr.syntax().text_range(), + kind: InlayKind::OpeningParenthesis, + label: "(".into(), + tooltip: None, + }); + acc.push(InlayHint { + range: expr.syntax().text_range(), + kind: InlayKind::ClosingParenthesis, + label: ")".into(), + tooltip: None, + }); + } + if needs_outer_parens { acc.push(InlayHint { range: expr.syntax().text_range(), kind: InlayKind::ClosingParenthesis, @@ -113,6 +150,69 @@ pub(super) fn hints( Some(()) } +/// Returns whatever we need to add paretheses on the inside and/or outside of `expr`, +/// if we are going to add (`postfix`) adjustments hints to it. +fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, bool) { + // This is a very miserable pile of hacks... + // + // `Expr::needs_parens_in` requires that the expression is the child of the other expression, + // that is supposed to be its parent. + // + // But we want to check what would happen if we add `*`/`.*` to the inner expression. + // To check for inner we need `` expr.needs_parens_in(`*expr`) ``, + // to check for outer we need `` `*expr`.needs_parens_in(parent) ``, + // where "expr" is the `expr` parameter, `*expr` is the editted `expr`, + // and "parent" is the parent of the original expression... + // + // For this we utilize mutable mutable trees, which is a HACK, but it works. + + // Make `&expr`/`expr?` + let dummy_expr = { + // `make::*` function go through a string, so they parse wrongly. + // for example `` make::expr_try(`|| a`) `` would result in a + // `|| (a?)` and not `(|| a)?`. + // + // Thus we need dummy parens to preserve the relationship we want. + // The parens are then simply ignored by the following code. + let dummy_paren = make::expr_paren(expr.clone()); + if postfix { + make::expr_try(dummy_paren) + } else { + make::expr_ref(dummy_paren, false) + } + }; + + // Do the dark mutable tree magic. + // This essentially makes `dummy_expr` and `expr` switch places (families), + // so that `expr`'s parent is not `dummy_expr`'s parent. + let dummy_expr = dummy_expr.clone_for_update(); + let expr = expr.clone_for_update(); + ted::replace(expr.syntax(), dummy_expr.syntax()); + + let parent = dummy_expr.syntax().parent(); + let expr = if postfix { + let ast::Expr::TryExpr(e) = &dummy_expr else { unreachable!() }; + let Some(ast::Expr::ParenExpr(e)) = e.expr() else { unreachable!() }; + + e.expr().unwrap() + } else { + let ast::Expr::RefExpr(e) = &dummy_expr else { unreachable!() }; + let Some(ast::Expr::ParenExpr(e)) = e.expr() else { unreachable!() }; + + e.expr().unwrap() + }; + + // At this point + // - `parent` is the parrent of the original expression + // - `dummy_expr` is the original expression wrapped in the operator we want (`*`/`.*`) + // - `expr` is the clone of the original expression (with `dummy_expr` as the parent) + + let needs_outer_parens = parent.map_or(false, |p| dummy_expr.needs_parens_in(p)); + let needs_inner_parens = expr.needs_parens_in(dummy_expr.syntax().clone()); + + (needs_outer_parens, needs_inner_parens) +} + #[cfg(test)] mod tests { use crate::{ @@ -125,7 +225,7 @@ mod tests { check_with_config( InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, r#" -//- minicore: coerce_unsized +//- minicore: coerce_unsized, fn fn main() { let _: u32 = loop {}; //^^^^^^^ @@ -148,12 +248,16 @@ fn main() { //^^^^ let _: unsafe fn() = main as fn(); //^^^^^^^^^^^^ + //^^^^^^^^^^^^( + //^^^^^^^^^^^^) let _: fn() = || {}; //^^^^^ let _: unsafe fn() = || {}; //^^^^^ let _: *const u32 = &mut 0u32 as *mut u32; //^^^^^^^^^^^^^^^^^^^^^ + //^^^^^^^^^^^^^^^^^^^^^( + //^^^^^^^^^^^^^^^^^^^^^) let _: &mut [_] = &mut [0; 0]; //^^^^^^^^^^^ //^^^^^^^^^^^&mut $ @@ -206,6 +310,11 @@ fn main() { //^^^^^^^ //^^^^^^^&mut $ //^^^^^^^* + + let _: &mut dyn Fn() = &mut || (); + //^^^^^^^^^^ + //^^^^^^^^^^&mut $ + //^^^^^^^^^^* } #[derive(Copy, Clone)] @@ -215,12 +324,101 @@ impl Struct { fn by_ref(&self) {} fn by_ref_mut(&mut self) {} } -trait Trait {} -impl Trait for Struct {} "#, ) } + #[test] + fn adjustment_hints_postfix() { + check_with_config( + InlayHintsConfig { + adjustment_hints: AdjustmentHints::Always, + adjustment_hints_postfix: true, + ..DISABLED_CONFIG + }, + r#" +//- minicore: coerce_unsized, fn +fn main() { + + Struct.consume(); + Struct.by_ref(); + //^^^^^^.& + Struct.by_ref_mut(); + //^^^^^^.&mut + + (&Struct).consume(); + //^^^^^^^( + //^^^^^^^) + //^^^^^^^.* + (&Struct).by_ref(); + + (&mut Struct).consume(); + //^^^^^^^^^^^( + //^^^^^^^^^^^) + //^^^^^^^^^^^.* + (&mut Struct).by_ref(); + //^^^^^^^^^^^( + //^^^^^^^^^^^) + //^^^^^^^^^^^.* + //^^^^^^^^^^^.& + (&mut Struct).by_ref_mut(); + + // Check that block-like expressions don't duplicate hints + let _: &mut [u32] = (&mut []); + //^^^^^^^( + //^^^^^^^) + //^^^^^^^.* + //^^^^^^^.&mut + //^^^^^^^. + let _: &mut [u32] = { &mut [] }; + //^^^^^^^( + //^^^^^^^) + //^^^^^^^.* + //^^^^^^^.&mut + //^^^^^^^. + let _: &mut [u32] = unsafe { &mut [] }; + //^^^^^^^( + //^^^^^^^) + //^^^^^^^.* + //^^^^^^^.&mut + //^^^^^^^. + let _: &mut [u32] = if true { + &mut [] + //^^^^^^^( + //^^^^^^^) + //^^^^^^^.* + //^^^^^^^.&mut + //^^^^^^^. + } else { + loop {} + //^^^^^^^. + }; + let _: &mut [u32] = match () { () => &mut [] } + //^^^^^^^( + //^^^^^^^) + //^^^^^^^.* + //^^^^^^^.&mut + //^^^^^^^. + + let _: &mut dyn Fn() = &mut || (); + //^^^^^^^^^^( + //^^^^^^^^^^) + //^^^^^^^^^^.* + //^^^^^^^^^^.&mut + //^^^^^^^^^^. +} + +#[derive(Copy, Clone)] +struct Struct; +impl Struct { + fn consume(self) {} + fn by_ref(&self) {} + fn by_ref_mut(&mut self) {} +} +"#, + ); + } + #[test] fn never_to_never_is_never_shown() { check_with_config( diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 6e31a1420ea7..c6cca0d8698e 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -115,6 +115,7 @@ impl StaticIndex<'_> { closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock, lifetime_elision_hints: crate::LifetimeElisionHints::Never, adjustment_hints: crate::AdjustmentHints::Never, + adjustment_hints_postfix: false, adjustment_hints_hide_outside_unsafe: false, hide_named_constructor_hints: false, hide_closure_initialization_hints: false, diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 0f515a6d5cbf..4d11a84091c5 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -333,6 +333,8 @@ config_data! { inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"", /// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks. inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = "false", + /// Whether to show inlay hints for type adjustments as postfix ops (`.*` instead of `*`, etc). + inlayHints_expressionAdjustmentHints_postfix: bool = "false", /// Whether to show inlay type hints for elided lifetimes in function signatures. inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"", /// Whether to prefer using parameter names as the name for elided lifetime hints if possible. @@ -1252,6 +1254,7 @@ impl Config { }, AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly, }, + adjustment_hints_postfix: self.data.inlayHints_expressionAdjustmentHints_postfix, adjustment_hints_hide_outside_unsafe: self .data .inlayHints_expressionAdjustmentHints_hideOutsideUnsafe, diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index a12bd3952cc1..e736b2ff9a3b 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -452,6 +452,7 @@ pub(crate) fn inlay_hint( | InlayKind::ChainingHint | InlayKind::GenericParamListHint | InlayKind::ClosingParenthesis + | InlayKind::AdjustmentHintPostfix | InlayKind::LifetimeHint | InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()), }, @@ -465,6 +466,7 @@ pub(crate) fn inlay_hint( | InlayKind::ClosureReturnTypeHint | InlayKind::GenericParamListHint | InlayKind::AdjustmentHint + | InlayKind::AdjustmentHintPostfix | InlayKind::LifetimeHint | InlayKind::ParameterHint => false, }), @@ -475,6 +477,7 @@ pub(crate) fn inlay_hint( | InlayKind::ClosureReturnTypeHint | InlayKind::GenericParamListHint | InlayKind::AdjustmentHint + | InlayKind::AdjustmentHintPostfix | InlayKind::TypeHint | InlayKind::DiscriminantHint | InlayKind::ClosingBraceHint => false, @@ -493,6 +496,7 @@ pub(crate) fn inlay_hint( | InlayKind::GenericParamListHint | InlayKind::LifetimeHint | InlayKind::AdjustmentHint + | InlayKind::AdjustmentHintPostfix | InlayKind::ClosingBraceHint => None, }, text_edits: None, diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index d9794e7052a7..60c16ecadf5e 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -469,6 +469,11 @@ Whether to show inlay hints for type adjustments. -- Whether to hide inlay hints for type adjustments outside of `unsafe` blocks. -- +[[rust-analyzer.inlayHints.expressionAdjustmentHints.postfix]]rust-analyzer.inlayHints.expressionAdjustmentHints.postfix (default: `false`):: ++ +-- +Whether to show inlay hints for type adjustments as postfix ops (`.*` instead of `*`, etc). +-- [[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index f508dde4f608..aeb1d97c5f6b 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1000,6 +1000,11 @@ "default": false, "type": "boolean" }, + "rust-analyzer.inlayHints.expressionAdjustmentHints.postfix": { + "markdownDescription": "Whether to show inlay hints for type adjustments as postfix ops (`.*` instead of `*`, etc).", + "default": false, + "type": "boolean" + }, "rust-analyzer.inlayHints.lifetimeElisionHints.enable": { "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.", "default": "never", From 12b7f9f7bfb4d50ee29232d9d40430fa22db7157 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 21 Dec 2022 15:00:05 +0000 Subject: [PATCH 0780/2442] Add an option to minimize parentheses for adjustment hints --- crates/ide/src/inlay_hints.rs | 14 ++- crates/ide/src/inlay_hints/adjustment.rs | 111 ++++++++++++++++++++--- crates/ide/src/lib.rs | 4 +- crates/ide/src/static_index.rs | 3 +- crates/rust-analyzer/src/config.rs | 35 ++++++- docs/user/generated_config.adoc | 4 +- editors/code/package.json | 20 +++- 7 files changed, 162 insertions(+), 29 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 7315a37ebc70..48a7bbfecffa 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -35,7 +35,7 @@ pub struct InlayHintsConfig { pub parameter_hints: bool, pub chaining_hints: bool, pub adjustment_hints: AdjustmentHints, - pub adjustment_hints_postfix: bool, + pub adjustment_hints_mode: AdjustmentHintsMode, pub adjustment_hints_hide_outside_unsafe: bool, pub closure_return_type_hints: ClosureReturnTypeHints, pub binding_mode_hints: bool, @@ -75,6 +75,14 @@ pub enum AdjustmentHints { Never, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum AdjustmentHintsMode { + Prefix, + Postfix, + PreferPrefix, + PreferPostfix, +} + #[derive(Clone, Debug, PartialEq, Eq)] pub enum InlayKind { BindingModeHint, @@ -432,7 +440,7 @@ mod tests { use itertools::Itertools; use test_utils::extract_annotations; - use crate::inlay_hints::AdjustmentHints; + use crate::inlay_hints::{AdjustmentHints, AdjustmentHintsMode}; use crate::DiscriminantHints; use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints}; @@ -448,7 +456,7 @@ mod tests { lifetime_elision_hints: LifetimeElisionHints::Never, closure_return_type_hints: ClosureReturnTypeHints::Never, adjustment_hints: AdjustmentHints::Never, - adjustment_hints_postfix: false, + adjustment_hints_mode: AdjustmentHintsMode::Prefix, adjustment_hints_hide_outside_unsafe: false, binding_mode_hints: false, hide_named_constructor_hints: false, diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index 367bd2f6619e..47e854e4bd74 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -11,7 +11,7 @@ use syntax::{ ted, }; -use crate::{AdjustmentHints, InlayHint, InlayHintsConfig, InlayKind}; +use crate::{AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintsConfig, InlayKind}; pub(super) fn hints( acc: &mut Vec, @@ -40,8 +40,8 @@ pub(super) fn hints( let desc_expr = descended.as_ref().unwrap_or(expr); let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?; - let (needs_outer_parens, needs_inner_parens) = - needs_parens_for_adjustment_hints(expr, config.adjustment_hints_postfix); + let (postfix, needs_outer_parens, needs_inner_parens) = + mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode); if needs_outer_parens { acc.push(InlayHint { @@ -52,7 +52,7 @@ pub(super) fn hints( }); } - if config.adjustment_hints_postfix && needs_inner_parens { + if postfix && needs_inner_parens { acc.push(InlayHint { range: expr.syntax().text_range(), kind: InlayKind::OpeningParenthesis, @@ -68,7 +68,7 @@ pub(super) fn hints( } let (mut tmp0, mut tmp1); - let iter: &mut dyn Iterator = if config.adjustment_hints_postfix { + let iter: &mut dyn Iterator = if postfix { tmp0 = adjustments.into_iter(); &mut tmp0 } else { @@ -112,20 +112,16 @@ pub(super) fn hints( }; acc.push(InlayHint { range: expr.syntax().text_range(), - kind: if config.adjustment_hints_postfix { + kind: if postfix { InlayKind::AdjustmentHintPostfix } else { InlayKind::AdjustmentHint }, - label: if config.adjustment_hints_postfix { - format!(".{}", text.trim_end()).into() - } else { - text.into() - }, + label: if postfix { format!(".{}", text.trim_end()).into() } else { text.into() }, tooltip: None, }); } - if !config.adjustment_hints_postfix && needs_inner_parens { + if !postfix && needs_inner_parens { acc.push(InlayHint { range: expr.syntax().text_range(), kind: InlayKind::OpeningParenthesis, @@ -150,6 +146,41 @@ pub(super) fn hints( Some(()) } +/// Returns whatever the hint should be postfix and if we need to add paretheses on the inside and/or outside of `expr`, +/// if we are going to add (`postfix`) adjustments hints to it. +fn mode_and_needs_parens_for_adjustment_hints( + expr: &ast::Expr, + mode: AdjustmentHintsMode, +) -> (bool, bool, bool) { + use {std::cmp::Ordering::*, AdjustmentHintsMode::*}; + + match mode { + Prefix | Postfix => { + let postfix = matches!(mode, Postfix); + let (inside, outside) = needs_parens_for_adjustment_hints(expr, postfix); + (postfix, inside, outside) + } + PreferPrefix | PreferPostfix => { + let prefer_postfix = matches!(mode, PreferPostfix); + + let (pre_inside, pre_outside) = needs_parens_for_adjustment_hints(expr, false); + let prefix = (false, pre_inside, pre_outside); + let pre_count = pre_inside as u8 + pre_outside as u8; + + let (post_inside, post_outside) = needs_parens_for_adjustment_hints(expr, true); + let postfix = (true, post_inside, post_outside); + let post_count = post_inside as u8 + post_outside as u8; + + match pre_count.cmp(&post_count) { + Less => prefix, + Greater => postfix, + Equal if prefer_postfix => postfix, + Equal => prefix, + } + } + } +} + /// Returns whatever we need to add paretheses on the inside and/or outside of `expr`, /// if we are going to add (`postfix`) adjustments hints to it. fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, bool) { @@ -217,7 +248,7 @@ fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, mod tests { use crate::{ inlay_hints::tests::{check_with_config, DISABLED_CONFIG}, - AdjustmentHints, InlayHintsConfig, + AdjustmentHints, AdjustmentHintsMode, InlayHintsConfig, }; #[test] @@ -333,7 +364,7 @@ impl Struct { check_with_config( InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, - adjustment_hints_postfix: true, + adjustment_hints_mode: AdjustmentHintsMode::Postfix, ..DISABLED_CONFIG }, r#" @@ -419,6 +450,58 @@ impl Struct { ); } + #[test] + fn adjustment_hints_prefer_prefix() { + check_with_config( + InlayHintsConfig { + adjustment_hints: AdjustmentHints::Always, + adjustment_hints_mode: AdjustmentHintsMode::PreferPrefix, + ..DISABLED_CONFIG + }, + r#" +fn main() { + let _: u32 = loop {}; + //^^^^^^^ + + Struct.by_ref(); + //^^^^^^.& + + let (): () = return (); + //^^^^^^^^^ + + struct Struct; + impl Struct { fn by_ref(&self) {} } +} + "#, + ) + } + + #[test] + fn adjustment_hints_prefer_postfix() { + check_with_config( + InlayHintsConfig { + adjustment_hints: AdjustmentHints::Always, + adjustment_hints_mode: AdjustmentHintsMode::PreferPostfix, + ..DISABLED_CONFIG + }, + r#" +fn main() { + let _: u32 = loop {}; + //^^^^^^^. + + Struct.by_ref(); + //^^^^^^.& + + let (): () = return (); + //^^^^^^^^^ + + struct Struct; + impl Struct { fn by_ref(&self) {} } +} + "#, + ) + } + #[test] fn never_to_never_is_never_shown() { check_with_config( diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 200958a43300..239456cb2816 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -81,8 +81,8 @@ pub use crate::{ highlight_related::{HighlightRelatedConfig, HighlightedRange}, hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult}, inlay_hints::{ - AdjustmentHints, ClosureReturnTypeHints, DiscriminantHints, InlayHint, InlayHintLabel, - InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints, + AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint, + InlayHintLabel, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints, }, join_lines::JoinLinesConfig, markup::Markup, diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index c6cca0d8698e..a6b30ba13962 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -13,6 +13,7 @@ use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T}; use crate::{ hover::hover_for_definition, + inlay_hints::AdjustmentHintsMode, moniker::{def_to_moniker, MonikerResult}, parent_module::crates_for, Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult, InlayHint, InlayHintsConfig, @@ -115,7 +116,7 @@ impl StaticIndex<'_> { closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock, lifetime_elision_hints: crate::LifetimeElisionHints::Never, adjustment_hints: crate::AdjustmentHints::Never, - adjustment_hints_postfix: false, + adjustment_hints_mode: AdjustmentHintsMode::Prefix, adjustment_hints_hide_outside_unsafe: false, hide_named_constructor_hints: false, hide_closure_initialization_hints: false, diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 4d11a84091c5..27a86db382d4 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -333,8 +333,8 @@ config_data! { inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"", /// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks. inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = "false", - /// Whether to show inlay hints for type adjustments as postfix ops (`.*` instead of `*`, etc). - inlayHints_expressionAdjustmentHints_postfix: bool = "false", + /// Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc). + inlayHints_expressionAdjustmentHints_mode: AdjustmentHintsModeDef = "\"prefix\"", /// Whether to show inlay type hints for elided lifetimes in function signatures. inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"", /// Whether to prefer using parameter names as the name for elided lifetime hints if possible. @@ -1254,7 +1254,12 @@ impl Config { }, AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly, }, - adjustment_hints_postfix: self.data.inlayHints_expressionAdjustmentHints_postfix, + adjustment_hints_mode: match self.data.inlayHints_expressionAdjustmentHints_mode { + AdjustmentHintsModeDef::Prefix => ide::AdjustmentHintsMode::Prefix, + AdjustmentHintsModeDef::Postfix => ide::AdjustmentHintsMode::Postfix, + AdjustmentHintsModeDef::PreferPrefix => ide::AdjustmentHintsMode::PreferPrefix, + AdjustmentHintsModeDef::PreferPostfix => ide::AdjustmentHintsMode::PreferPostfix, + }, adjustment_hints_hide_outside_unsafe: self .data .inlayHints_expressionAdjustmentHints_hideOutsideUnsafe, @@ -1771,6 +1776,15 @@ enum DiscriminantHintsDef { Fieldless, } +#[derive(Deserialize, Debug, Clone)] +#[serde(rename_all = "snake_case")] +enum AdjustmentHintsModeDef { + Prefix, + Postfix, + PreferPrefix, + PreferPostfix, +} + #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "snake_case")] enum FilesWatcherDef { @@ -2104,6 +2118,21 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json "Only show discriminant hints on fieldless enum variants." ] }, + "AdjustmentHintsModeDef" => set! { + "type": "string", + "enum": [ + "prefix", + "postfix", + "prefer_prefix", + "prefer_postfix", + ], + "enumDescriptions": [ + "Always show adjustment hints as prefix (`*expr`).", + "Always show adjustment hints as postfix (`expr.*`).", + "Show prefix or postfix depending on which uses less parenthesis, prefering prefix.", + "Show prefix or postfix depending on which uses less parenthesis, prefering postfix.", + ] + }, "CargoFeaturesDef" => set! { "anyOf": [ { diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 60c16ecadf5e..0aaf07ebf38a 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -469,10 +469,10 @@ Whether to show inlay hints for type adjustments. -- Whether to hide inlay hints for type adjustments outside of `unsafe` blocks. -- -[[rust-analyzer.inlayHints.expressionAdjustmentHints.postfix]]rust-analyzer.inlayHints.expressionAdjustmentHints.postfix (default: `false`):: +[[rust-analyzer.inlayHints.expressionAdjustmentHints.mode]]rust-analyzer.inlayHints.expressionAdjustmentHints.mode (default: `"prefix"`):: + -- -Whether to show inlay hints for type adjustments as postfix ops (`.*` instead of `*`, etc). +Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc). -- [[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`):: + diff --git a/editors/code/package.json b/editors/code/package.json index aeb1d97c5f6b..5ffce2f55365 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1000,10 +1000,22 @@ "default": false, "type": "boolean" }, - "rust-analyzer.inlayHints.expressionAdjustmentHints.postfix": { - "markdownDescription": "Whether to show inlay hints for type adjustments as postfix ops (`.*` instead of `*`, etc).", - "default": false, - "type": "boolean" + "rust-analyzer.inlayHints.expressionAdjustmentHints.mode": { + "markdownDescription": "Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).", + "default": "prefix", + "type": "string", + "enum": [ + "prefix", + "postfix", + "prefer_prefix", + "prefer_postfix" + ], + "enumDescriptions": [ + "Always show adjustment hints as prefix (`*expr`).", + "Always show adjustment hints as postfix (`expr.*`).", + "Show prefix or postfix depending on which uses less parenthesis, prefering prefix.", + "Show prefix or postfix depending on which uses less parenthesis, prefering postfix." + ] }, "rust-analyzer.inlayHints.lifetimeElisionHints.enable": { "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.", From a9676cfbe3f81515483fb563f20c74e27cfa7c41 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 21 Dec 2022 15:31:57 +0000 Subject: [PATCH 0781/2442] Add a "bug" test for adjustment hints to check for status quo --- crates/ide/src/inlay_hints/adjustment.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index 47e854e4bd74..9f6984b59e91 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -609,4 +609,20 @@ fn a() { "#, ); } + + #[test] + fn bug() { + check_with_config( + InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, + r#" +fn main() { + // These should be identical, but they are not... + + let () = return; + let (): () = return; + //^^^^^^ +} + "#, + ) + } } From b6169c2a2e5a24e9905a2614e6fe469fb37f50c9 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 9 Jan 2023 13:37:37 +0000 Subject: [PATCH 0782/2442] Add a fixme to remove hacks --- crates/ide/src/inlay_hints/adjustment.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index 9f6984b59e91..bdd7c05e008c 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -196,6 +196,8 @@ fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, // and "parent" is the parent of the original expression... // // For this we utilize mutable mutable trees, which is a HACK, but it works. + // + // FIXME: comeup with a better API for `needs_parens_in`, so that we don't have to do *this* // Make `&expr`/`expr?` let dummy_expr = { From 44c84a8d2848c9fae4d496c0d9dc9e8c98c8f1ef Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 6 Dec 2022 17:34:47 +0000 Subject: [PATCH 0783/2442] Add `convert_ufcs_to_method` assist --- .../src/handlers/convert_ufcs_to_method.rs | 211 ++++++++++++++++++ crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 19 ++ 3 files changed, 232 insertions(+) create mode 100644 crates/ide-assists/src/handlers/convert_ufcs_to_method.rs diff --git a/crates/ide-assists/src/handlers/convert_ufcs_to_method.rs b/crates/ide-assists/src/handlers/convert_ufcs_to_method.rs new file mode 100644 index 000000000000..8704e40b0d7b --- /dev/null +++ b/crates/ide-assists/src/handlers/convert_ufcs_to_method.rs @@ -0,0 +1,211 @@ +use syntax::{ + ast::{self, make, AstNode, HasArgList}, + TextRange, +}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: convert_ufcs_to_method +// +// Transforms universal function call syntax into a method call. +// +// ``` +// fn main() { +// std::ops::Add::add$0(1, 2); +// } +// # mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } } +// ``` +// -> +// ``` +// fn main() { +// 1.add(2); +// } +// # mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } } +// ``` +pub(crate) fn convert_ufcs_to_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let call = ctx.find_node_at_offset::()?; + let ast::Expr::PathExpr(path_expr) = call.expr()? else { return None }; + let path = path_expr.path()?; + + let cursor_in_range = path.syntax().text_range().contains_range(ctx.selection_trimmed()); + if !cursor_in_range { + return None; + } + + let args = call.arg_list()?; + let l_paren = args.l_paren_token()?; + let mut args_iter = args.args(); + let first_arg = args_iter.next()?; + let second_arg = args_iter.next(); + + _ = path.qualifier()?; + let method_name = path.segment()?.name_ref()?; + + let res = ctx.sema.resolve_path(&path)?; + let hir::PathResolution::Def(hir::ModuleDef::Function(fun)) = res else { return None }; + if !fun.has_self_param(ctx.sema.db) { + return None; + } + + // `core::ops::Add::add(` -> `` + let delete_path = + TextRange::new(path.syntax().text_range().start(), l_paren.text_range().end()); + + // Parens around `expr` if needed + let parens = needs_parens_as_receiver(&first_arg).then(|| { + let range = first_arg.syntax().text_range(); + (range.start(), range.end()) + }); + + // `, ` -> `.add(` + let replace_comma = TextRange::new( + first_arg.syntax().text_range().end(), + second_arg + .map(|a| a.syntax().text_range().start()) + .unwrap_or_else(|| first_arg.syntax().text_range().end()), + ); + + acc.add( + AssistId("convert_ufcs_to_method", AssistKind::RefactorRewrite), + "Convert UFCS to a method call", + call.syntax().text_range(), + |edit| { + edit.delete(delete_path); + if let Some((open, close)) = parens { + edit.insert(open, "("); + edit.insert(close, ")"); + } + edit.replace(replace_comma, format!(".{method_name}(")); + }, + ) +} + +fn needs_parens_as_receiver(expr: &ast::Expr) -> bool { + // Make `(expr).dummy()` + let dummy_call = make::expr_method_call( + make::expr_paren(expr.clone()), + make::name_ref("dummy"), + make::arg_list([]), + ); + + // Get the `expr` clone with the right parent back + // (unreachable!s are fine since we've just constructed the expression) + let ast::Expr::MethodCallExpr(call) = &dummy_call else { unreachable!() }; + let Some(receiver) = call.receiver() else { unreachable!() }; + let ast::Expr::ParenExpr(parens) = receiver else { unreachable!() }; + let Some(expr) = parens.expr() else { unreachable!() }; + + expr.needs_parens_in(dummy_call.syntax().clone()) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn ufcs2method_simple() { + check_assist( + convert_ufcs_to_method, + r#" +struct S; +impl S { fn f(self, S: S) {} } +fn f() { S::$0f(S, S); }"#, + r#" +struct S; +impl S { fn f(self, S: S) {} } +fn f() { S.f(S); }"#, + ); + } + + #[test] + fn ufcs2method_trait() { + check_assist( + convert_ufcs_to_method, + r#" +//- minicore: add +fn f() { ::$0add(2, 2); }"#, + r#" +fn f() { 2.add(2); }"#, + ); + + check_assist( + convert_ufcs_to_method, + r#" +//- minicore: add +fn f() { core::ops::Add::$0add(2, 2); }"#, + r#" +fn f() { 2.add(2); }"#, + ); + + check_assist( + convert_ufcs_to_method, + r#" +//- minicore: add +use core::ops::Add; +fn f() { <_>::$0add(2, 2); }"#, + r#" +use core::ops::Add; +fn f() { 2.add(2); }"#, + ); + } + + #[test] + fn ufcs2method_single_arg() { + check_assist( + convert_ufcs_to_method, + r#" + struct S; + impl S { fn f(self) {} } + fn f() { S::$0f(S); }"#, + r#" + struct S; + impl S { fn f(self) {} } + fn f() { S.f(); }"#, + ); + } + + #[test] + fn ufcs2method_parens() { + check_assist( + convert_ufcs_to_method, + r#" +//- minicore: deref +struct S; +impl core::ops::Deref for S { + type Target = S; + fn deref(&self) -> &S { self } +} +fn f() { core::ops::Deref::$0deref(&S); }"#, + r#" +struct S; +impl core::ops::Deref for S { + type Target = S; + fn deref(&self) -> &S { self } +} +fn f() { (&S).deref(); }"#, + ); + } + + #[test] + fn ufcs2method_doesnt_apply_with_cursor_not_on_path() { + check_assist_not_applicable( + convert_ufcs_to_method, + r#" +//- minicore: add +fn f() { core::ops::Add::add(2,$0 2); }"#, + ); + } + + #[test] + fn ufcs2method_doesnt_apply_with_no_self() { + check_assist_not_applicable( + convert_ufcs_to_method, + r#" +struct S; +impl S { fn assoc(S: S, S: S) {} } +fn f() { S::assoc$0(S, S); }"#, + ); + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index f7ac9d8fd6bb..6da51cfa4f70 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -126,6 +126,7 @@ mod handlers { mod convert_to_guarded_return; mod convert_two_arm_bool_match_to_matches_macro; mod convert_while_to_loop; + mod convert_ufcs_to_method; mod destructure_tuple_binding; mod expand_glob_import; mod extract_expressions_from_format_string; @@ -218,6 +219,7 @@ mod handlers { convert_bool_then::convert_bool_then_to_if, convert_bool_then::convert_if_to_bool_then, convert_comment_block::convert_comment_block, + convert_ufcs_to_method::convert_ufcs_to_method, convert_integer_literal::convert_integer_literal, convert_into_to_from::convert_into_to_from, convert_iter_for_each_to_for::convert_iter_for_each_to_for, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 210df6999d8c..d84f343c5510 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -554,6 +554,25 @@ fn main() { ) } +#[test] +fn doctest_convert_ufcs_to_method() { + check_doc_test( + "convert_ufcs_to_method", + r#####" +fn main() { + std::ops::Add::add$0(1, 2); +} +mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } } +"#####, + r#####" +fn main() { + 1.add(2); +} +mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } } +"#####, + ) +} + #[test] fn doctest_convert_while_to_loop() { check_doc_test( From 769273ca4ca41fe3ca704ff7793de95c5def1728 Mon Sep 17 00:00:00 2001 From: Tom Kunc Date: Mon, 9 Jan 2023 07:01:41 -0700 Subject: [PATCH 0784/2442] Simplify code with @Veykril's suggestion. --- .../ide-assists/src/handlers/inline_macro.rs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_macro.rs b/crates/ide-assists/src/handlers/inline_macro.rs index d669826aa7aa..9d03f03d201a 100644 --- a/crates/ide-assists/src/handlers/inline_macro.rs +++ b/crates/ide-assists/src/handlers/inline_macro.rs @@ -34,25 +34,16 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // } // ``` pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let tok = ctx.token_at_offset().right_biased()?; + let unexpanded = ctx.find_node_at_offset::()?; + let expanded = ctx.sema.expand(&unexpanded)?.clone_for_update(); - let mut anc = tok.parent_ancestors(); - let (_name, expanded, unexpanded) = loop { - let node = anc.next()?; - if let Some(mac) = ast::MacroCall::cast(node.clone()) { - break ( - mac.path()?.segment()?.name_ref()?.to_string(), - ctx.sema.expand(&mac)?.clone_for_update(), - node, - ); - } - }; + let text_range = unexpanded.syntax().text_range(); acc.add( AssistId("inline_macro", AssistKind::RefactorRewrite), format!("Inline macro"), - unexpanded.text_range(), - |builder| builder.replace(unexpanded.text_range(), expanded.to_string()), + text_range, + |builder| builder.replace(text_range, expanded.to_string()), ) } From c782353a907ea121dcae670a5f0d8e14b8865b19 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 9 Jan 2023 13:59:02 +0000 Subject: [PATCH 0785/2442] Rename assist: `convert_ufcs_to_method` => `unqualify_method_call` --- ..._to_method.rs => unqualify_method_call.rs} | 36 +++++++++--------- crates/ide-assists/src/lib.rs | 4 +- crates/ide-assists/src/tests/generated.rs | 38 +++++++++---------- 3 files changed, 39 insertions(+), 39 deletions(-) rename crates/ide-assists/src/handlers/{convert_ufcs_to_method.rs => unqualify_method_call.rs} (85%) diff --git a/crates/ide-assists/src/handlers/convert_ufcs_to_method.rs b/crates/ide-assists/src/handlers/unqualify_method_call.rs similarity index 85% rename from crates/ide-assists/src/handlers/convert_ufcs_to_method.rs rename to crates/ide-assists/src/handlers/unqualify_method_call.rs index 8704e40b0d7b..e9d4e270cdcf 100644 --- a/crates/ide-assists/src/handlers/convert_ufcs_to_method.rs +++ b/crates/ide-assists/src/handlers/unqualify_method_call.rs @@ -5,7 +5,7 @@ use syntax::{ use crate::{AssistContext, AssistId, AssistKind, Assists}; -// Assist: convert_ufcs_to_method +// Assist: unqualify_method_call // // Transforms universal function call syntax into a method call. // @@ -22,7 +22,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // } // # mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } } // ``` -pub(crate) fn convert_ufcs_to_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { +pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let call = ctx.find_node_at_offset::()?; let ast::Expr::PathExpr(path_expr) = call.expr()? else { return None }; let path = path_expr.path()?; @@ -66,8 +66,8 @@ pub(crate) fn convert_ufcs_to_method(acc: &mut Assists, ctx: &AssistContext<'_>) ); acc.add( - AssistId("convert_ufcs_to_method", AssistKind::RefactorRewrite), - "Convert UFCS to a method call", + AssistId("unqualify_method_call", AssistKind::RefactorRewrite), + "Unqualify method call", call.syntax().text_range(), |edit| { edit.delete(delete_path); @@ -105,9 +105,9 @@ mod tests { use super::*; #[test] - fn ufcs2method_simple() { + fn unqualify_method_call_simple() { check_assist( - convert_ufcs_to_method, + unqualify_method_call, r#" struct S; impl S { fn f(self, S: S) {} } @@ -120,9 +120,9 @@ fn f() { S.f(S); }"#, } #[test] - fn ufcs2method_trait() { + fn unqualify_method_call_trait() { check_assist( - convert_ufcs_to_method, + unqualify_method_call, r#" //- minicore: add fn f() { ::$0add(2, 2); }"#, @@ -131,7 +131,7 @@ fn f() { 2.add(2); }"#, ); check_assist( - convert_ufcs_to_method, + unqualify_method_call, r#" //- minicore: add fn f() { core::ops::Add::$0add(2, 2); }"#, @@ -140,7 +140,7 @@ fn f() { 2.add(2); }"#, ); check_assist( - convert_ufcs_to_method, + unqualify_method_call, r#" //- minicore: add use core::ops::Add; @@ -152,9 +152,9 @@ fn f() { 2.add(2); }"#, } #[test] - fn ufcs2method_single_arg() { + fn unqualify_method_call_single_arg() { check_assist( - convert_ufcs_to_method, + unqualify_method_call, r#" struct S; impl S { fn f(self) {} } @@ -167,9 +167,9 @@ fn f() { 2.add(2); }"#, } #[test] - fn ufcs2method_parens() { + fn unqualify_method_call_parens() { check_assist( - convert_ufcs_to_method, + unqualify_method_call, r#" //- minicore: deref struct S; @@ -189,9 +189,9 @@ fn f() { (&S).deref(); }"#, } #[test] - fn ufcs2method_doesnt_apply_with_cursor_not_on_path() { + fn unqualify_method_call_doesnt_apply_with_cursor_not_on_path() { check_assist_not_applicable( - convert_ufcs_to_method, + unqualify_method_call, r#" //- minicore: add fn f() { core::ops::Add::add(2,$0 2); }"#, @@ -199,9 +199,9 @@ fn f() { core::ops::Add::add(2,$0 2); }"#, } #[test] - fn ufcs2method_doesnt_apply_with_no_self() { + fn unqualify_method_call_doesnt_apply_with_no_self() { check_assist_not_applicable( - convert_ufcs_to_method, + unqualify_method_call, r#" struct S; impl S { fn assoc(S: S, S: S) {} } diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 6da51cfa4f70..6747b950074f 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -126,7 +126,6 @@ mod handlers { mod convert_to_guarded_return; mod convert_two_arm_bool_match_to_matches_macro; mod convert_while_to_loop; - mod convert_ufcs_to_method; mod destructure_tuple_binding; mod expand_glob_import; mod extract_expressions_from_format_string; @@ -202,6 +201,7 @@ mod handlers { mod unnecessary_async; mod unwrap_block; mod unwrap_result_return_type; + mod unqualify_method_call; mod wrap_return_type_in_result; pub(crate) fn all() -> &'static [Handler] { @@ -219,7 +219,6 @@ mod handlers { convert_bool_then::convert_bool_then_to_if, convert_bool_then::convert_if_to_bool_then, convert_comment_block::convert_comment_block, - convert_ufcs_to_method::convert_ufcs_to_method, convert_integer_literal::convert_integer_literal, convert_into_to_from::convert_into_to_from, convert_iter_for_each_to_for::convert_iter_for_each_to_for, @@ -308,6 +307,7 @@ mod handlers { unwrap_block::unwrap_block, unwrap_result_return_type::unwrap_result_return_type, unwrap_tuple::unwrap_tuple, + unqualify_method_call::unqualify_method_call, wrap_return_type_in_result::wrap_return_type_in_result, // These are manually sorted for better priorities. By default, // priority is determined by the size of the target range (smaller diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index d84f343c5510..2644e7dd11cd 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -554,25 +554,6 @@ fn main() { ) } -#[test] -fn doctest_convert_ufcs_to_method() { - check_doc_test( - "convert_ufcs_to_method", - r#####" -fn main() { - std::ops::Add::add$0(1, 2); -} -mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } } -"#####, - r#####" -fn main() { - 1.add(2); -} -mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } } -"#####, - ) -} - #[test] fn doctest_convert_while_to_loop() { check_doc_test( @@ -2552,6 +2533,25 @@ pub async fn bar() { foo() } ) } +#[test] +fn doctest_unqualify_method_call() { + check_doc_test( + "unqualify_method_call", + r#####" +fn main() { + std::ops::Add::add$0(1, 2); +} +mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } } +"#####, + r#####" +fn main() { + 1.add(2); +} +mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } } +"#####, + ) +} + #[test] fn doctest_unwrap_block() { check_doc_test( From bdaad9eb157b3a56f318d7e818c80bb65236211e Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 9 Jan 2023 14:26:48 +0000 Subject: [PATCH 0786/2442] Make `qualify_method_call` `RefactorRewrite` --- crates/ide-assists/src/handlers/qualify_method_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/qualify_method_call.rs b/crates/ide-assists/src/handlers/qualify_method_call.rs index 1ea87429c509..e7014597a1d8 100644 --- a/crates/ide-assists/src/handlers/qualify_method_call.rs +++ b/crates/ide-assists/src/handlers/qualify_method_call.rs @@ -53,7 +53,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call, resolved_call); acc.add( - AssistId("qualify_method_call", AssistKind::RefactorInline), + AssistId("qualify_method_call", AssistKind::RefactorRewrite), format!("Qualify `{ident}` method call"), range, |builder| { From 9eb50d3cde97690f8149f560b70f56f6dafa4da3 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 9 Jan 2023 17:03:36 +0100 Subject: [PATCH 0787/2442] Make it clearer when the server expects an initialized notification --- lib/lsp-server/src/lib.rs | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/lib/lsp-server/src/lib.rs b/lib/lsp-server/src/lib.rs index b95cec4f0136..beccde40a897 100644 --- a/lib/lsp-server/src/lib.rs +++ b/lib/lsp-server/src/lib.rs @@ -114,10 +114,8 @@ impl Connection { /// ``` pub fn initialize_start(&self) -> Result<(RequestId, serde_json::Value), ProtocolError> { loop { - match self.receiver.recv() { - Ok(Message::Request(req)) if req.is_initialize() => { - return Ok((req.id, req.params)) - } + break match self.receiver.recv() { + Ok(Message::Request(req)) if req.is_initialize() => Ok((req.id, req.params)), // Respond to non-initialize requests with ServerNotInitialized Ok(Message::Request(req)) => { let resp = Response::new_err( @@ -126,14 +124,11 @@ impl Connection { format!("expected initialize request, got {req:?}"), ); self.sender.send(resp.into()).unwrap(); + continue; } - Ok(msg) => { - return Err(ProtocolError(format!("expected initialize request, got {msg:?}"))) - } + Ok(msg) => Err(ProtocolError(format!("expected initialize request, got {msg:?}"))), Err(e) => { - return Err(ProtocolError(format!( - "expected initialize request, got error: {e}" - ))) + Err(ProtocolError(format!("expected initialize request, got error: {e}"))) } }; } @@ -148,17 +143,14 @@ impl Connection { let resp = Response::new_ok(initialize_id, initialize_result); self.sender.send(resp.into()).unwrap(); match &self.receiver.recv() { - Ok(Message::Notification(n)) if n.is_initialized() => (), + Ok(Message::Notification(n)) if n.is_initialized() => Ok(()), Ok(msg) => { - return Err(ProtocolError(format!("expected Message::Notification, got: {msg:?}",))) + Err(ProtocolError(format!(r#"expected initialized notification, got: {msg:?}"#))) } Err(e) => { - return Err(ProtocolError(format!( - "expected initialized notification, got error: {e}", - ))) + Err(ProtocolError(format!("expected initialized notification, got error: {e}",))) } } - Ok(()) } /// Initialize the connection. Sends the server capabilities From 1b8141b54cb5f89bd3dee7bfbab41109d1b48cb6 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Tue, 3 Jan 2023 10:16:16 -0500 Subject: [PATCH 0788/2442] Parse + decorate rendered ANSI cargo output Use ANSI control characters to display text decorations matching the VScode terminal theme, and strip them out when providing text content for rustc diagnostics. This adds the small `anser` library to parse the control codes, and it also supports HTML output so it should be fairly easy to switch to a rendered HTML/webview implementation if desired. --- editors/code/package-lock.json | 11 ++ editors/code/package.json | 1 + editors/code/src/client.ts | 11 +- editors/code/src/diagnostics.ts | 212 ++++++++++++++++++++++++++++++++ editors/code/src/main.ts | 61 ++++++--- 5 files changed, 272 insertions(+), 24 deletions(-) create mode 100644 editors/code/src/diagnostics.ts diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index ee69d2247604..4844837a06f3 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -9,6 +9,7 @@ "version": "0.5.0-dev", "license": "MIT OR Apache-2.0", "dependencies": { + "anser": "^2.1.1", "d3": "^7.6.1", "d3-graphviz": "^5.0.2", "vscode-languageclient": "^8.0.2" @@ -394,6 +395,11 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/anser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/anser/-/anser-2.1.1.tgz", + "integrity": "sha512-nqLm4HxOTpeLOxcmB3QWmV5TcDFhW9y/fyQ+hivtDFcK4OQ+pQ5fzPnXHM1Mfcm0VkLtvVi1TCPr++Qy0Q/3EQ==" + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -4096,6 +4102,11 @@ "uri-js": "^4.2.2" } }, + "anser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/anser/-/anser-2.1.1.tgz", + "integrity": "sha512-nqLm4HxOTpeLOxcmB3QWmV5TcDFhW9y/fyQ+hivtDFcK4OQ+pQ5fzPnXHM1Mfcm0VkLtvVi1TCPr++Qy0Q/3EQ==" + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", diff --git a/editors/code/package.json b/editors/code/package.json index 468368668fcf..3fe189e2b3b1 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -35,6 +35,7 @@ "test": "cross-env TEST_VARIABLE=test node ./out/tests/runTests.js" }, "dependencies": { + "anser": "^2.1.1", "d3": "^7.6.1", "d3-graphviz": "^5.0.2", "vscode-languageclient": "^8.0.2" diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index e6595340aae9..74cf44f42f71 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -3,6 +3,7 @@ import * as vscode from "vscode"; import * as ra from "../src/lsp_ext"; import * as Is from "vscode-languageclient/lib/common/utils/is"; import { assert } from "./util"; +import * as diagnostics from "./diagnostics"; import { WorkspaceEdit } from "vscode"; import { Config, substituteVSCodeVariables } from "./config"; import { randomUUID } from "crypto"; @@ -120,12 +121,12 @@ export async function createClient( }, async handleDiagnostics( uri: vscode.Uri, - diagnostics: vscode.Diagnostic[], + diagnosticList: vscode.Diagnostic[], next: lc.HandleDiagnosticsSignature ) { const preview = config.previewRustcOutput; const errorCode = config.useRustcErrorCode; - diagnostics.forEach((diag, idx) => { + diagnosticList.forEach((diag, idx) => { // Abuse the fact that VSCode leaks the LSP diagnostics data field through the // Diagnostic class, if they ever break this we are out of luck and have to go // back to the worst diagnostics experience ever:) @@ -154,8 +155,8 @@ export async function createClient( } diag.code = { target: vscode.Uri.from({ - scheme: "rust-analyzer-diagnostics-view", - path: "/diagnostic message", + scheme: diagnostics.URI_SCHEME, + path: `/diagnostic message [${idx.toString()}]`, fragment: uri.toString(), query: idx.toString(), }), @@ -163,7 +164,7 @@ export async function createClient( }; } }); - return next(uri, diagnostics); + return next(uri, diagnosticList); }, async provideHover( document: vscode.TextDocument, diff --git a/editors/code/src/diagnostics.ts b/editors/code/src/diagnostics.ts new file mode 100644 index 000000000000..9695d8bf26d5 --- /dev/null +++ b/editors/code/src/diagnostics.ts @@ -0,0 +1,212 @@ +import * as anser from "anser"; +import * as vscode from "vscode"; +import { ProviderResult, Range, TextEditorDecorationType, ThemeColor, window } from "vscode"; +import { Ctx } from "./ctx"; + +export const URI_SCHEME = "rust-analyzer-diagnostics-view"; + +export class TextDocumentProvider implements vscode.TextDocumentContentProvider { + private _onDidChange = new vscode.EventEmitter(); + + public constructor(private readonly ctx: Ctx) {} + + get onDidChange(): vscode.Event { + return this._onDidChange.event; + } + + triggerUpdate(uri: vscode.Uri) { + if (uri.scheme === URI_SCHEME) { + this._onDidChange.fire(uri); + } + } + + dispose() { + this._onDidChange.dispose(); + } + + async provideTextDocumentContent(uri: vscode.Uri): Promise { + const contents = getRenderedDiagnostic(this.ctx, uri); + return anser.ansiToText(contents); + } +} + +function getRenderedDiagnostic(ctx: Ctx, uri: vscode.Uri): string { + const diags = ctx.client?.diagnostics?.get(vscode.Uri.parse(uri.fragment, true)); + if (!diags) { + return "Unable to find original rustc diagnostic"; + } + + const diag = diags[parseInt(uri.query)]; + if (!diag) { + return "Unable to find original rustc diagnostic"; + } + const rendered = (diag as unknown as { data?: { rendered?: string } }).data?.rendered; + + if (!rendered) { + return "Unable to find original rustc diagnostic"; + } + + return rendered; +} + +interface AnserStyle { + fg: string; + bg: string; + fg_truecolor: string; + bg_truecolor: string; + decorations: Array; +} + +export class AnsiDecorationProvider implements vscode.Disposable { + private _decorationTypes = new Map(); + + public constructor(private readonly ctx: Ctx) {} + + dispose(): void { + for (const decorationType of this._decorationTypes.values()) { + decorationType.dispose(); + } + + this._decorationTypes.clear(); + } + + async provideDecorations(editor: vscode.TextEditor) { + if (editor.document.uri.scheme !== URI_SCHEME) { + return; + } + + const decorations = (await this._getDecorations(editor.document.uri)) || []; + for (const [decorationType, ranges] of decorations) { + editor.setDecorations(decorationType, ranges); + } + } + + private _getDecorations( + uri: vscode.Uri + ): ProviderResult<[TextEditorDecorationType, Range[]][]> { + const stringContents = getRenderedDiagnostic(this.ctx, uri); + const lines = stringContents.split("\n"); + + const result = new Map(); + // Populate all known decoration types in the result. This forces any + // lingering decorations to be cleared if the text content changes to + // something without ANSI codes for a given decoration type. + for (const decorationType of this._decorationTypes.values()) { + result.set(decorationType, []); + } + + for (const [lineNumber, line] of lines.entries()) { + const totalEscapeLength = 0; + + // eslint-disable-next-line camelcase + const parsed = anser.ansiToJson(line, { use_classes: true }); + + let offset = 0; + + for (const span of parsed) { + const { content, ...style } = span; + + const range = new Range( + lineNumber, + offset - totalEscapeLength, + lineNumber, + offset + content.length - totalEscapeLength + ); + + offset += content.length; + + const decorationType = this._getDecorationType(style); + + if (!result.has(decorationType)) { + result.set(decorationType, []); + } + + result.get(decorationType)!.push(range); + } + } + + return [...result]; + } + + private _getDecorationType(style: AnserStyle): TextEditorDecorationType { + let decorationType = this._decorationTypes.get(style); + + if (decorationType) { + return decorationType; + } + + const fontWeight = style.decorations.find((s) => s === "bold"); + const fontStyle = style.decorations.find((s) => s === "italic"); + const textDecoration = style.decorations.find((s) => s === "underline"); + + decorationType = window.createTextEditorDecorationType({ + backgroundColor: AnsiDecorationProvider._convertColor(style.bg, style.bg_truecolor), + color: AnsiDecorationProvider._convertColor(style.fg, style.fg_truecolor), + fontWeight, + fontStyle, + textDecoration, + }); + + this._decorationTypes.set(style, decorationType); + + return decorationType; + } + + // NOTE: This could just be a kebab-case to camelCase conversion, but I think it's + // a short enough list to just write these by hand + static readonly _anserToThemeColor: Record = { + "ansi-black": "ansiBlack", + "ansi-white": "ansiWhite", + "ansi-red": "ansiRed", + "ansi-green": "ansiGreen", + "ansi-yellow": "ansiYellow", + "ansi-blue": "ansiBlue", + "ansi-magenta": "ansiMagenta", + "ansi-cyan": "ansiCyan", + + "ansi-bright-black": "ansiBrightBlack", + "ansi-bright-white": "ansiBrightWhite", + "ansi-bright-red": "ansiBrightRed", + "ansi-bright-green": "ansiBrightGreen", + "ansi-bright-yellow": "ansiBrightYellow", + "ansi-bright-blue": "ansiBrightBlue", + "ansi-bright-magenta": "ansiBrightMagenta", + "ansi-bright-cyan": "ansiBrightCyan", + }; + + private static _convertColor( + color?: string, + truecolor?: string + ): ThemeColor | string | undefined { + if (!color) { + return undefined; + } + + if (color === "ansi-truecolor") { + if (!truecolor) { + return undefined; + } + return `rgb(${truecolor})`; + } + + const paletteMatch = color.match(/ansi-palette-(.+)/); + if (paletteMatch) { + const paletteColor = paletteMatch[1]; + // anser won't return both the RGB and the color name at the same time, + // so just fake a single foreground control char with the palette number: + const spans = anser.ansiToJson(`\x1b[38;5;${paletteColor}m`); + const rgb = spans[1].fg; + + if (rgb) { + return `rgb(${rgb})`; + } + } + + const themeColor = AnsiDecorationProvider._anserToThemeColor[color]; + if (themeColor) { + return new ThemeColor("terminal." + themeColor); + } + + return undefined; + } +} diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 9a9667b2cd20..dd439317c709 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -3,6 +3,7 @@ import * as lc from "vscode-languageclient/node"; import * as commands from "./commands"; import { CommandFactory, Ctx, fetchWorkspace } from "./ctx"; +import * as diagnostics from "./diagnostics"; import { activateTaskProvider } from "./tasks"; import { setContextValue } from "./util"; @@ -48,30 +49,52 @@ async function activateServer(ctx: Ctx): Promise { ctx.pushExtCleanup(activateTaskProvider(ctx.config)); } + const diagnosticProvider = new diagnostics.TextDocumentProvider(ctx); ctx.pushExtCleanup( vscode.workspace.registerTextDocumentContentProvider( - "rust-analyzer-diagnostics-view", - new (class implements vscode.TextDocumentContentProvider { - async provideTextDocumentContent(uri: vscode.Uri): Promise { - const diags = ctx.client?.diagnostics?.get( - vscode.Uri.parse(uri.fragment, true) - ); - if (!diags) { - return "Unable to find original rustc diagnostic"; - } - - const diag = diags[parseInt(uri.query)]; - if (!diag) { - return "Unable to find original rustc diagnostic"; - } - const rendered = (diag as unknown as { data?: { rendered?: string } }).data - ?.rendered; - return rendered ?? "Unable to find original rustc diagnostic"; - } - })() + diagnostics.URI_SCHEME, + diagnosticProvider ) ); + const decorationProvider = new diagnostics.AnsiDecorationProvider(ctx); + ctx.pushExtCleanup(decorationProvider); + + async function decorateVisibleEditors(document: vscode.TextDocument) { + for (const editor of vscode.window.visibleTextEditors) { + if (document === editor.document) { + await decorationProvider.provideDecorations(editor); + } + } + } + + vscode.workspace.onDidChangeTextDocument( + async (event) => await decorateVisibleEditors(event.document), + null, + ctx.subscriptions + ); + vscode.workspace.onDidOpenTextDocument(decorateVisibleEditors, null, ctx.subscriptions); + vscode.window.onDidChangeActiveTextEditor( + async (editor) => { + if (editor) { + diagnosticProvider.triggerUpdate(editor.document.uri); + await decorateVisibleEditors(editor.document); + } + }, + null, + ctx.subscriptions + ); + vscode.window.onDidChangeVisibleTextEditors( + async (visibleEditors) => { + for (const editor of visibleEditors) { + diagnosticProvider.triggerUpdate(editor.document.uri); + await decorationProvider.provideDecorations(editor); + } + }, + null, + ctx.subscriptions + ); + vscode.workspace.onDidChangeWorkspaceFolders( async (_) => ctx.onWorkspaceFolderChanges(), null, From 40207906f42c018a775dfdffdfeb89c99660fe0a Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Wed, 28 Dec 2022 09:41:24 -0500 Subject: [PATCH 0789/2442] Default to use colored ANSI diagnostics --- crates/flycheck/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 590a93fbaa1a..2911c2589a30 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -297,8 +297,12 @@ impl FlycheckActor { let mut cmd = Command::new(toolchain::cargo()); cmd.arg(command); cmd.current_dir(&self.root); - cmd.args(["--workspace", "--message-format=json", "--manifest-path"]) - .arg(self.root.join("Cargo.toml").as_os_str()); + cmd.args([ + "--workspace", + "--message-format=json-diagnostic-rendered-ansi", + "--manifest-path", + ]) + .arg(self.root.join("Cargo.toml").as_os_str()); for target in target_triples { cmd.args(["--target", target.as_str()]); From c3e4bc313611d571123d4e4257af58784e42f47d Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 25 Dec 2022 13:52:42 -0500 Subject: [PATCH 0790/2442] Update docs to include note about ANSI diagnostics --- crates/rust-analyzer/src/config.rs | 4 +++- docs/user/generated_config.adoc | 4 +++- editors/code/package.json | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index cb55a3275835..006256544f37 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -160,7 +160,9 @@ config_data! { check_noDefaultFeatures | checkOnSave_noDefaultFeatures: Option = "null", /// Override the command rust-analyzer uses instead of `cargo check` for /// diagnostics on save. The command is required to output json and - /// should therefore include `--message-format=json` or a similar option. + /// should therefore include `--message-format=json` or a similar option + /// (for colored diagnostics, use + /// `--message-format=json-diagnostic-rendered-ansi`). /// /// If you're changing this because you're using some tool wrapping /// Cargo, you might also want to change diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 755c69e12cf3..5a3019831ae0 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -173,7 +173,9 @@ Whether to pass `--no-default-features` to Cargo. Defaults to -- Override the command rust-analyzer uses instead of `cargo check` for diagnostics on save. The command is required to output json and -should therefore include `--message-format=json` or a similar option. +should therefore include `--message-format=json` or a similar option +(for colored diagnostics, use +`--message-format=json-diagnostic-rendered-ansi`). If you're changing this because you're using some tool wrapping Cargo, you might also want to change diff --git a/editors/code/package.json b/editors/code/package.json index 3fe189e2b3b1..77da5e54538b 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -644,7 +644,7 @@ ] }, "rust-analyzer.check.overrideCommand": { - "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", + "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(for colored diagnostics, use\n`--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", "default": null, "type": [ "null", From 738ce83d858aa498c3ff28be3417101ab5f9ce6f Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Tue, 3 Jan 2023 10:49:47 -0500 Subject: [PATCH 0791/2442] Strip colors before matching preview diagnostics --- editors/code/src/client.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 74cf44f42f71..c6d64ebc1ed9 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -1,3 +1,4 @@ +import * as anser from "anser"; import * as lc from "vscode-languageclient/node"; import * as vscode from "vscode"; import * as ra from "../src/lsp_ext"; @@ -139,9 +140,10 @@ export async function createClient( ?.rendered; if (rendered) { if (preview) { + const decolorized = anser.ansiToText(rendered); const index = - rendered.match(/^(note|help):/m)?.index || rendered.length; - diag.message = rendered + decolorized.match(/^(note|help):/m)?.index || rendered.length; + diag.message = decolorized .substring(0, index) .replace(/^ -->[^\n]+\n/m, ""); } From 65cf7abbe2ee75cce74592fa0af75356181566be Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Wed, 4 Jan 2023 12:04:45 -0500 Subject: [PATCH 0792/2442] Use experimental capability to enable color codes --- crates/flycheck/src/lib.rs | 18 ++++++++++++------ crates/rust-analyzer/src/config.rs | 10 ++++++++-- docs/user/generated_config.adoc | 4 ++-- editors/code/package.json | 2 +- editors/code/src/client.ts | 1 + 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 2911c2589a30..11f7b068ecb1 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -47,6 +47,7 @@ pub enum FlycheckConfig { features: Vec, extra_args: Vec, extra_env: FxHashMap, + ansi_color_output: bool, }, CustomCommand { command: String, @@ -293,16 +294,21 @@ impl FlycheckActor { extra_args, features, extra_env, + ansi_color_output, } => { let mut cmd = Command::new(toolchain::cargo()); cmd.arg(command); cmd.current_dir(&self.root); - cmd.args([ - "--workspace", - "--message-format=json-diagnostic-rendered-ansi", - "--manifest-path", - ]) - .arg(self.root.join("Cargo.toml").as_os_str()); + cmd.arg("--workspace"); + + cmd.arg(if *ansi_color_output { + "--message-format=json-diagnostic-rendered-ansi" + } else { + "--message-format=json" + }); + + cmd.arg("--manifest-path"); + cmd.arg(self.root.join("Cargo.toml").as_os_str()); for target in target_triples { cmd.args(["--target", target.as_str()]); diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 006256544f37..b0afbdc9a426 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -161,8 +161,8 @@ config_data! { /// Override the command rust-analyzer uses instead of `cargo check` for /// diagnostics on save. The command is required to output json and /// should therefore include `--message-format=json` or a similar option - /// (for colored diagnostics, use - /// `--message-format=json-diagnostic-rendered-ansi`). + /// (if your client supports the `colorDiagnosticOutput` experimental + /// capability, you can use `--message-format=json-diagnostic-rendered-ansi`). /// /// If you're changing this because you're using some tool wrapping /// Cargo, you might also want to change @@ -1008,6 +1008,11 @@ impl Config { self.experimental("serverStatusNotification") } + /// Whether the client supports colored output for full diagnostics from `checkOnSave`. + pub fn color_diagnostic_output(&self) -> bool { + self.experimental("colorDiagnosticOutput") + } + pub fn publish_diagnostics(&self) -> bool { self.data.diagnostics_enable } @@ -1206,6 +1211,7 @@ impl Config { }, extra_args: self.data.check_extraArgs.clone(), extra_env: self.check_on_save_extra_env(), + ansi_color_output: self.color_diagnostic_output(), }, } } diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 5a3019831ae0..b33a2e79525d 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -174,8 +174,8 @@ Whether to pass `--no-default-features` to Cargo. Defaults to Override the command rust-analyzer uses instead of `cargo check` for diagnostics on save. The command is required to output json and should therefore include `--message-format=json` or a similar option -(for colored diagnostics, use -`--message-format=json-diagnostic-rendered-ansi`). +(if your client supports the `colorDiagnosticOutput` experimental +capability, you can use `--message-format=json-diagnostic-rendered-ansi`). If you're changing this because you're using some tool wrapping Cargo, you might also want to change diff --git a/editors/code/package.json b/editors/code/package.json index 77da5e54538b..930564bd7cab 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -644,7 +644,7 @@ ] }, "rust-analyzer.check.overrideCommand": { - "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(for colored diagnostics, use\n`--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", + "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(if your client supports the `colorDiagnosticOutput` experimental\ncapability, you can use `--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", "default": null, "type": [ "null", diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index c6d64ebc1ed9..82cdf0390aca 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -333,6 +333,7 @@ class ExperimentalFeatures implements lc.StaticFeature { caps.codeActionGroup = true; caps.hoverActions = true; caps.serverStatusNotification = true; + caps.colorDiagnosticOutput = true; caps.commands = { commands: [ "rust-analyzer.runSingle", From 283dfc45dd8fb1e6bbe78c8b2e90cb5d543f2f06 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Mon, 9 Jan 2023 11:44:38 -0500 Subject: [PATCH 0793/2442] Add docs for `colorDiagnosticOutput` capability --- docs/dev/lsp-extensions.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 1bbb4c2323c0..a4780af1a261 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -792,3 +792,29 @@ export interface ClientCommandOptions { commands: string[]; } ``` + +## Colored Diagnostic Output + +**Experimental Client Capability:** `{ "colorDiagnosticOutput": boolean }` + +If this capability is set, the "full compiler diagnostics" provided by `checkOnSave` +will include ANSI color and style codes to render the diagnostic in a similar manner +as `cargo`. This is translated into `--message-format=json-diagnostic-rendered-ansi` +when flycheck is run, instead of the default `--message-format=json`. + +The full compiler rendered diagnostics are included in the server response +regardless of this capability: + +```typescript +// https://microsoft.github.io/language-server-protocol/specifications/specification-current#diagnostic +export interface Diagnostic { + ... + data?: { + /** + * The human-readable compiler output as it would be printed to a terminal. + * Includes ANSI color and style codes if the client has set the experimental + * `colorDiagnosticOutput` capability. + */ + rendered?: string; + }; +} From 68723043db2e7ee6e780c7f42cd9e57df72a1fd0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 9 Jan 2023 19:29:28 +0100 Subject: [PATCH 0794/2442] Split out hir-def attribute handling parts into hir-expand --- Cargo.lock | 13 + crates/hir-def/Cargo.toml | 1 + crates/hir-def/src/adt.rs | 2 +- crates/hir-def/src/attr.rs | 332 +----------------- crates/hir-def/src/body.rs | 8 +- crates/hir-def/src/body/lower.rs | 2 +- crates/hir-def/src/data.rs | 2 +- crates/hir-def/src/db.rs | 2 +- crates/hir-def/src/expr.rs | 2 +- crates/hir-def/src/generics.rs | 2 +- crates/hir-def/src/item_scope.rs | 6 +- crates/hir-def/src/item_tree.rs | 15 +- crates/hir-def/src/item_tree/lower.rs | 24 +- crates/hir-def/src/item_tree/pretty.rs | 1 - crates/hir-def/src/keys.rs | 3 +- crates/hir-def/src/lib.rs | 13 +- crates/hir-def/src/nameres/attr_resolution.rs | 3 +- crates/hir-def/src/nameres/collector.rs | 3 +- crates/hir-def/src/nameres/diagnostics.rs | 3 +- crates/hir-def/src/path.rs | 2 +- crates/hir-def/src/path/lower.rs | 3 +- crates/hir-def/src/pretty.rs | 2 +- crates/hir-def/src/resolver.rs | 2 +- crates/hir-def/src/type_ref.rs | 2 +- crates/hir-expand/Cargo.toml | 1 + crates/hir-expand/src/attrs.rs | 313 +++++++++++++++++ crates/hir-expand/src/lib.rs | 3 + crates/hir-ty/Cargo.toml | 1 + crates/hir-ty/src/display.rs | 2 +- crates/hir-ty/src/interner.rs | 7 +- crates/hir-ty/src/lower.rs | 2 +- crates/hir-ty/src/utils.rs | 2 +- crates/hir/src/lib.rs | 3 +- crates/hir/src/semantics/source_to_def.rs | 3 +- crates/intern/Cargo.toml | 13 + .../src/intern.rs => intern/src/lib.rs} | 19 +- 36 files changed, 435 insertions(+), 382 deletions(-) create mode 100644 crates/hir-expand/src/attrs.rs create mode 100644 crates/intern/Cargo.toml rename crates/{hir-def/src/intern.rs => intern/src/lib.rs} (92%) diff --git a/Cargo.lock b/Cargo.lock index d27ae416f04b..5f426d885626 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -519,6 +519,7 @@ dependencies = [ "hkalbasi-rustc-ap-rustc_abi", "hkalbasi-rustc-ap-rustc_index", "indexmap", + "intern", "itertools", "la-arena", "limit", @@ -544,6 +545,7 @@ dependencies = [ "either", "expect-test", "hashbrown", + "intern", "itertools", "la-arena", "limit", @@ -574,6 +576,7 @@ dependencies = [ "hir-def", "hir-expand", "hkalbasi-rustc-ap-rustc_index", + "intern", "itertools", "la-arena", "limit", @@ -803,6 +806,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "intern" +version = "0.0.0" +dependencies = [ + "dashmap", + "hashbrown", + "once_cell", + "rustc-hash", +] + [[package]] name = "itertools" version = "0.10.5" diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index 698be76656cc..a1078427707b 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -29,6 +29,7 @@ smallvec = "1.10.0" tracing = "0.1.35" stdx = { path = "../stdx", version = "0.0.0" } +intern = { path = "../intern", version = "0.0.0" } base-db = { path = "../base-db", version = "0.0.0" } syntax = { path = "../syntax", version = "0.0.0" } profile = { path = "../profile", version = "0.0.0" } diff --git a/crates/hir-def/src/adt.rs b/crates/hir-def/src/adt.rs index db3b41948814..cd35ba00f6f5 100644 --- a/crates/hir-def/src/adt.rs +++ b/crates/hir-def/src/adt.rs @@ -8,6 +8,7 @@ use hir_expand::{ name::{AsName, Name}, HirFileId, InFile, }; +use intern::Interned; use la_arena::{Arena, ArenaMap}; use rustc_abi::{Integer, IntegerType}; use syntax::ast::{self, HasName, HasVisibility}; @@ -17,7 +18,6 @@ use crate::{ body::{CfgExpander, LowerCtx}, builtin_type::{BuiltinInt, BuiltinUint}, db::DefDatabase, - intern::Interned, item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId}, layout::{Align, ReprFlags, ReprOptions}, nameres::diagnostics::DefDiagnostic, diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index ab5d180e1bb9..eb88a74e448d 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -1,27 +1,27 @@ //! A higher level attributes based on TokenTree, with also some shortcuts. -use std::{fmt, hash::Hash, ops, sync::Arc}; +use std::{hash::Hash, ops, sync::Arc}; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; use either::Either; -use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; +use hir_expand::{ + attrs::{collect_attrs, Attr, AttrId, RawAttrs}, + HirFileId, InFile, +}; use itertools::Itertools; use la_arena::{ArenaMap, Idx, RawIdx}; -use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct}; -use smallvec::{smallvec, SmallVec}; +use mbe::DelimiterKind; use syntax::{ - ast::{self, AstNode, HasAttrs, IsString}, - match_ast, AstPtr, AstToken, SmolStr, SyntaxNode, TextRange, TextSize, + ast::{self, HasAttrs, IsString}, + AstPtr, AstToken, SmolStr, TextRange, TextSize, }; use tt::Subtree; use crate::{ db::DefDatabase, - intern::Interned, item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeNode}, nameres::{ModuleOrigin, ModuleSource}, - path::{ModPath, PathKind}, src::{HasChildSource, HasSource}, AdtId, AttrDefId, EnumId, GenericParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroId, VariantId, @@ -47,12 +47,6 @@ impl From for String { } } -/// Syntactical attributes, without filtering of `cfg_attr`s. -#[derive(Default, Debug, Clone, PartialEq, Eq)] -pub(crate) struct RawAttrs { - entries: Option>, -} - #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct Attrs(RawAttrs); @@ -62,30 +56,21 @@ pub struct AttrsWithOwner { owner: AttrDefId, } -impl ops::Deref for RawAttrs { - type Target = [Attr]; - - fn deref(&self) -> &[Attr] { - match &self.entries { - Some(it) => &*it, - None => &[], - } - } -} impl Attrs { pub fn get(&self, id: AttrId) -> Option<&Attr> { (**self).iter().find(|attr| attr.id == id) } + + pub(crate) fn filter(db: &dyn DefDatabase, krate: CrateId, raw_attrs: RawAttrs) -> Attrs { + Attrs(raw_attrs.filter(db.upcast(), krate)) + } } impl ops::Deref for Attrs { type Target = [Attr]; fn deref(&self) -> &[Attr] { - match &self.0.entries { - Some(it) => &*it, - None => &[], - } + &self.0 } } @@ -97,114 +82,6 @@ impl ops::Deref for AttrsWithOwner { } } -impl RawAttrs { - pub(crate) const EMPTY: Self = Self { entries: None }; - - pub(crate) fn new(db: &dyn DefDatabase, owner: &dyn ast::HasAttrs, hygiene: &Hygiene) -> Self { - let entries = collect_attrs(owner) - .filter_map(|(id, attr)| match attr { - Either::Left(attr) => { - attr.meta().and_then(|meta| Attr::from_src(db, meta, hygiene, id)) - } - Either::Right(comment) => comment.doc_comment().map(|doc| Attr { - id, - input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), - path: Interned::new(ModPath::from(hir_expand::name!(doc))), - }), - }) - .collect::>(); - - Self { entries: if entries.is_empty() { None } else { Some(entries) } } - } - - fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::HasAttrs>) -> Self { - let hygiene = Hygiene::new(db.upcast(), owner.file_id); - Self::new(db, owner.value, &hygiene) - } - - pub(crate) fn merge(&self, other: Self) -> Self { - // FIXME: This needs to fixup `AttrId`s - match (&self.entries, other.entries) { - (None, None) => Self::EMPTY, - (None, entries @ Some(_)) => Self { entries }, - (Some(entries), None) => Self { entries: Some(entries.clone()) }, - (Some(a), Some(b)) => { - let last_ast_index = a.last().map_or(0, |it| it.id.ast_index + 1); - Self { - entries: Some( - a.iter() - .cloned() - .chain(b.iter().map(|it| { - let mut it = it.clone(); - it.id.ast_index += last_ast_index; - it - })) - .collect(), - ), - } - } - } - } - - /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. - pub(crate) fn filter(self, db: &dyn DefDatabase, krate: CrateId) -> Attrs { - let has_cfg_attrs = self.iter().any(|attr| { - attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]) - }); - if !has_cfg_attrs { - return Attrs(self); - } - - let crate_graph = db.crate_graph(); - let new_attrs = self - .iter() - .flat_map(|attr| -> SmallVec<[_; 1]> { - let is_cfg_attr = - attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]); - if !is_cfg_attr { - return smallvec![attr.clone()]; - } - - let subtree = match attr.token_tree_value() { - Some(it) => it, - _ => return smallvec![attr.clone()], - }; - - // Input subtree is: `(cfg, $(attr),+)` - // Split it up into a `cfg` subtree and the `attr` subtrees. - // FIXME: There should be a common API for this. - let mut parts = subtree.token_trees.split(|tt| { - matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))) - }); - let cfg = match parts.next() { - Some(it) => it, - None => return smallvec![], - }; - let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; - let cfg = CfgExpr::parse(&cfg); - let index = attr.id; - let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { - let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; - // FIXME hygiene - let hygiene = Hygiene::new_unhygienic(); - Attr::from_tt(db, &tree, &hygiene, index) - }); - - let cfg_options = &crate_graph[krate].cfg_options; - if cfg_options.check(&cfg) == Some(false) { - smallvec![] - } else { - cov_mark::hit!(cfg_attr_active); - - attrs.collect() - } - }) - .collect(); - - Attrs(RawAttrs { entries: Some(new_attrs) }) - } -} - impl Attrs { pub const EMPTY: Self = Self(RawAttrs::EMPTY); @@ -403,7 +280,7 @@ impl AttrsWithOwner { .raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into())) .clone(), ModuleOrigin::BlockExpr { block } => RawAttrs::from_attrs_owner( - db, + db.upcast(), InFile::new(block.file_id, block.to_node(db.upcast())) .as_ref() .map(|it| it as &dyn ast::HasAttrs), @@ -439,7 +316,7 @@ impl AttrsWithOwner { GenericParamId::ConstParamId(it) => { let src = it.parent().child_source(db); RawAttrs::from_attrs_owner( - db, + db.upcast(), src.with_value(src.value[it.local_id()].as_ref().either( |it| match it { ast::TypeOrConstParam::Type(it) => it as _, @@ -452,7 +329,7 @@ impl AttrsWithOwner { GenericParamId::TypeParamId(it) => { let src = it.parent().child_source(db); RawAttrs::from_attrs_owner( - db, + db.upcast(), src.with_value(src.value[it.local_id()].as_ref().either( |it| match it { ast::TypeOrConstParam::Type(it) => it as _, @@ -464,14 +341,14 @@ impl AttrsWithOwner { } GenericParamId::LifetimeParamId(it) => { let src = it.parent.child_source(db); - RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id])) + RawAttrs::from_attrs_owner(db.upcast(), src.with_value(&src.value[it.local_id])) } }, AttrDefId::ExternBlockId(it) => attrs_from_item_tree(it.lookup(db).id, db), }; - let attrs = raw_attrs.filter(db, def.krate(db)); - Self { attrs, owner: def } + let attrs = raw_attrs.filter(db.upcast(), def.krate(db)); + Self { attrs: Attrs(attrs), owner: def } } pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap { @@ -627,40 +504,6 @@ fn doc_indent(attrs: &Attrs) -> usize { .unwrap_or(0) } -fn inner_attributes( - syntax: &SyntaxNode, -) -> Option>> { - let node = match_ast! { - match syntax { - ast::SourceFile(_) => syntax.clone(), - ast::ExternBlock(it) => it.extern_item_list()?.syntax().clone(), - ast::Fn(it) => it.body()?.stmt_list()?.syntax().clone(), - ast::Impl(it) => it.assoc_item_list()?.syntax().clone(), - ast::Module(it) => it.item_list()?.syntax().clone(), - ast::BlockExpr(it) => { - use syntax::SyntaxKind::{BLOCK_EXPR , EXPR_STMT}; - // Block expressions accept outer and inner attributes, but only when they are the outer - // expression of an expression statement or the final expression of another block expression. - let may_carry_attributes = matches!( - it.syntax().parent().map(|it| it.kind()), - Some(BLOCK_EXPR | EXPR_STMT) - ); - if !may_carry_attributes { - return None - } - syntax.clone() - }, - _ => return None, - } - }; - - let attrs = ast::AttrDocCommentIter::from_syntax_node(&node).filter(|el| match el { - Either::Left(attr) => attr.kind().is_inner(), - Either::Right(comment) => comment.is_inner(), - }); - Some(attrs) -} - #[derive(Debug)] pub struct AttrSourceMap { source: Vec>, @@ -779,128 +622,6 @@ fn get_doc_string_in_attr(it: &ast::Attr) -> Option { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct AttrId { - pub(crate) ast_index: u32, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Attr { - pub(crate) id: AttrId, - pub(crate) path: Interned, - pub(crate) input: Option>, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum AttrInput { - /// `#[attr = "string"]` - Literal(SmolStr), - /// `#[attr(subtree)]` - TokenTree(tt::Subtree, mbe::TokenMap), -} - -impl fmt::Display for AttrInput { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - AttrInput::Literal(lit) => write!(f, " = \"{}\"", lit.escape_debug()), - AttrInput::TokenTree(subtree, _) => subtree.fmt(f), - } - } -} - -impl Attr { - fn from_src( - db: &dyn DefDatabase, - ast: ast::Meta, - hygiene: &Hygiene, - id: AttrId, - ) -> Option { - let path = Interned::new(ModPath::from_src(db.upcast(), ast.path()?, hygiene)?); - let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { - let value = match lit.kind() { - ast::LiteralKind::String(string) => string.value()?.into(), - _ => lit.syntax().first_token()?.text().trim_matches('"').into(), - }; - Some(Interned::new(AttrInput::Literal(value))) - } else if let Some(tt) = ast.token_tree() { - let (tree, map) = syntax_node_to_token_tree(tt.syntax()); - Some(Interned::new(AttrInput::TokenTree(tree, map))) - } else { - None - }; - Some(Attr { id, path, input }) - } - - fn from_tt( - db: &dyn DefDatabase, - tt: &tt::Subtree, - hygiene: &Hygiene, - id: AttrId, - ) -> Option { - let (parse, _) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MetaItem); - let ast = ast::Meta::cast(parse.syntax_node())?; - - Self::from_src(db, ast, hygiene, id) - } - - pub fn path(&self) -> &ModPath { - &self.path - } -} - -impl Attr { - /// #[path = "string"] - pub fn string_value(&self) -> Option<&SmolStr> { - match self.input.as_deref()? { - AttrInput::Literal(it) => Some(it), - _ => None, - } - } - - /// #[path(ident)] - pub fn single_ident_value(&self) -> Option<&tt::Ident> { - match self.input.as_deref()? { - AttrInput::TokenTree(subtree, _) => match &*subtree.token_trees { - [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] => Some(ident), - _ => None, - }, - _ => None, - } - } - - /// #[path TokenTree] - pub fn token_tree_value(&self) -> Option<&Subtree> { - match self.input.as_deref()? { - AttrInput::TokenTree(subtree, _) => Some(subtree), - _ => None, - } - } - - /// Parses this attribute as a token tree consisting of comma separated paths. - pub fn parse_path_comma_token_tree(&self) -> Option + '_> { - let args = self.token_tree_value()?; - - if args.delimiter_kind() != Some(DelimiterKind::Parenthesis) { - return None; - } - let paths = args - .token_trees - .split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })))) - .filter_map(|tts| { - if tts.is_empty() { - return None; - } - let segments = tts.iter().filter_map(|tt| match tt { - tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()), - _ => None, - }); - Some(ModPath::from_segments(PathKind::Plain, segments)) - }); - - Some(paths) - } -} - #[derive(Debug, Clone, Copy)] pub struct AttrQuery<'attr> { attrs: &'attr Attrs, @@ -953,21 +674,6 @@ fn attrs_from_item_tree(id: ItemTreeId, db: &dyn DefDatabase tree.raw_attrs(mod_item.into()).clone() } -fn collect_attrs( - owner: &dyn ast::HasAttrs, -) -> impl Iterator)> { - let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten(); - let outer_attrs = - ast::AttrDocCommentIter::from_syntax_node(owner.syntax()).filter(|el| match el { - Either::Left(attr) => attr.kind().is_outer(), - Either::Right(comment) => comment.is_outer(), - }); - outer_attrs - .chain(inner_attrs) - .enumerate() - .map(|(id, attr)| (AttrId { ast_index: id as u32 }, attr)) -} - pub(crate) fn variants_attrs_source_map( db: &dyn DefDatabase, def: EnumId, diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 78fbaa9d7d35..9713256813eb 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -12,7 +12,9 @@ use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; use drop_bomb::DropBomb; use either::Either; -use hir_expand::{hygiene::Hygiene, ExpandError, ExpandResult, HirFileId, InFile, MacroCallId}; +use hir_expand::{ + attrs::RawAttrs, hygiene::Hygiene, ExpandError, ExpandResult, HirFileId, InFile, MacroCallId, +}; use la_arena::{Arena, ArenaMap}; use limit::Limit; use profile::Count; @@ -20,7 +22,7 @@ use rustc_hash::FxHashMap; use syntax::{ast, AstPtr, SyntaxNodePtr}; use crate::{ - attr::{Attrs, RawAttrs}, + attr::Attrs, db::DefDatabase, expr::{dummy_expr_id, Expr, ExprId, Label, LabelId, Pat, PatId}, item_scope::BuiltinShadowMode, @@ -64,7 +66,7 @@ impl CfgExpander { } pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { - RawAttrs::new(db, owner, &self.hygiene).filter(db, self.krate) + Attrs::filter(db, self.krate, RawAttrs::new(db.upcast(), owner, &self.hygiene)) } pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool { diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index e8da24e3adda..4c29e16b2b81 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -10,6 +10,7 @@ use hir_expand::{ name::{name, AsName, Name}, AstId, ExpandError, HirFileId, InFile, }; +use intern::Interned; use la_arena::Arena; use once_cell::unsync::OnceCell; use profile::Count; @@ -33,7 +34,6 @@ use crate::{ Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat, RecordLitField, Statement, }, - intern::Interned, item_scope::BuiltinShadowMode, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index e6b05f27a544..f461e85b0182 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroDefKind}; +use intern::Interned; use smallvec::SmallVec; use syntax::ast; @@ -10,7 +11,6 @@ use crate::{ attr::Attrs, body::{Expander, Mark}, db::DefDatabase, - intern::Interned, item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId}, nameres::{ attr_resolution::ResolvedAttr, diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 431c8255497b..65cdd1b69b17 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use base_db::{salsa, CrateId, SourceDatabase, Upcast}; use either::Either; use hir_expand::{db::AstDatabase, HirFileId}; +use intern::Interned; use la_arena::ArenaMap; use syntax::{ast, AstPtr, SmolStr}; @@ -17,7 +18,6 @@ use crate::{ }, generics::GenericParams, import_map::ImportMap, - intern::Interned, item_tree::{AttrOwner, ItemTree}, lang_item::{LangItemTarget, LangItems}, nameres::{diagnostics::DefDiagnostic, DefMap}, diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs index 7b6569421195..48028b7c6a82 100644 --- a/crates/hir-def/src/expr.rs +++ b/crates/hir-def/src/expr.rs @@ -15,11 +15,11 @@ use std::fmt; use hir_expand::name::Name; +use intern::Interned; use la_arena::{Idx, RawIdx}; use crate::{ builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, - intern::Interned, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, BlockId, diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index f74559f5d663..b2ab0c30e037 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -9,6 +9,7 @@ use hir_expand::{ name::{AsName, Name}, ExpandResult, HirFileId, InFile, }; +use intern::Interned; use la_arena::{Arena, ArenaMap, Idx}; use once_cell::unsync::Lazy; use std::ops::DerefMut; @@ -20,7 +21,6 @@ use crate::{ child_by_source::ChildBySource, db::DefDatabase, dyn_map::DynMap, - intern::Interned, keys, src::{HasChildSource, HasSource}, type_ref::{LifetimeRef, TypeBound, TypeRef}, diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index c7b213b7e981..53a4173ff423 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -4,7 +4,7 @@ use std::collections::hash_map::Entry; use base_db::CrateId; -use hir_expand::{name::Name, AstId, MacroCallId}; +use hir_expand::{attrs::AttrId, name::Name, AstId, MacroCallId}; use itertools::Itertools; use once_cell::sync::Lazy; use profile::Count; @@ -14,8 +14,8 @@ use stdx::format_to; use syntax::ast; use crate::{ - attr::AttrId, db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, - ConstId, HasModule, ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId, + db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, HasModule, + ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId, }; #[derive(Copy, Clone, Debug)] diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 80297f8adf16..3e1f7d44460f 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -48,10 +48,12 @@ use base_db::CrateId; use either::Either; use hir_expand::{ ast_id_map::FileAstId, + attrs::RawAttrs, hygiene::Hygiene, name::{name, AsName, Name}, ExpandTo, HirFileId, InFile, }; +use intern::Interned; use la_arena::{Arena, Idx, IdxRange, RawIdx}; use profile::Count; use rustc_hash::FxHashMap; @@ -60,10 +62,9 @@ use stdx::never; use syntax::{ast, match_ast, SyntaxKind}; use crate::{ - attr::{Attrs, RawAttrs}, + attr::Attrs, db::DefDatabase, generics::GenericParams, - intern::Interned, path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, visibility::RawVisibility, @@ -120,7 +121,7 @@ impl ItemTree { let mut item_tree = match_ast! { match syntax { ast::SourceFile(file) => { - top_attrs = Some(RawAttrs::new(db, &file, ctx.hygiene())); + top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.hygiene())); ctx.lower_module_items(&file) }, ast::MacroItems(items) => { @@ -152,7 +153,11 @@ impl ItemTree { /// Returns the inner attributes of the source file. pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: CrateId) -> Attrs { - self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone().filter(db, krate) + Attrs::filter( + db, + krate, + self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone(), + ) } pub(crate) fn raw_attrs(&self, of: AttrOwner) -> &RawAttrs { @@ -160,7 +165,7 @@ impl ItemTree { } pub(crate) fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs { - self.raw_attrs(of).clone().filter(db, krate) + Attrs::filter(db, krate, self.raw_attrs(of).clone()) } pub fn pretty_print(&self) -> String { diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index b25274bccc9a..27705cbbbdc5 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -99,7 +99,7 @@ impl<'a> Ctx<'a> { } fn lower_mod_item(&mut self, item: &ast::Item) -> Option { - let attrs = RawAttrs::new(self.db, item, self.hygiene()); + let attrs = RawAttrs::new(self.db.upcast(), item, self.hygiene()); let item: ModItem = match item { ast::Item::Struct(ast) => self.lower_struct(ast)?.into(), ast::Item::Union(ast) => self.lower_union(ast)?.into(), @@ -173,7 +173,7 @@ impl<'a> Ctx<'a> { for field in fields.fields() { if let Some(data) = self.lower_record_field(&field) { let idx = self.data().fields.alloc(data); - self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, self.hygiene())); + self.add_attrs(idx.into(), RawAttrs::new(self.db.upcast(), &field, self.hygiene())); } } let end = self.next_field_idx(); @@ -194,7 +194,7 @@ impl<'a> Ctx<'a> { for (i, field) in fields.fields().enumerate() { let data = self.lower_tuple_field(i, &field); let idx = self.data().fields.alloc(data); - self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, self.hygiene())); + self.add_attrs(idx.into(), RawAttrs::new(self.db.upcast(), &field, self.hygiene())); } let end = self.next_field_idx(); IdxRange::new(start..end) @@ -239,7 +239,10 @@ impl<'a> Ctx<'a> { for variant in variants.variants() { if let Some(data) = self.lower_variant(&variant) { let idx = self.data().variants.alloc(data); - self.add_attrs(idx.into(), RawAttrs::new(self.db, &variant, self.hygiene())); + self.add_attrs( + idx.into(), + RawAttrs::new(self.db.upcast(), &variant, self.hygiene()), + ); } } let end = self.next_variant_idx(); @@ -283,7 +286,10 @@ impl<'a> Ctx<'a> { }; let ty = Interned::new(self_type); let idx = self.data().params.alloc(Param::Normal(None, ty)); - self.add_attrs(idx.into(), RawAttrs::new(self.db, &self_param, self.hygiene())); + self.add_attrs( + idx.into(), + RawAttrs::new(self.db.upcast(), &self_param, self.hygiene()), + ); has_self_param = true; } for param in param_list.params() { @@ -307,7 +313,7 @@ impl<'a> Ctx<'a> { self.data().params.alloc(Param::Normal(name, ty)) } }; - self.add_attrs(idx.into(), RawAttrs::new(self.db, ¶m, self.hygiene())); + self.add_attrs(idx.into(), RawAttrs::new(self.db.upcast(), ¶m, self.hygiene())); } } let end_param = self.next_param_idx(); @@ -442,7 +448,7 @@ impl<'a> Ctx<'a> { let items = trait_def.assoc_item_list().map(|list| { list.assoc_items() .filter_map(|item| { - let attrs = RawAttrs::new(self.db, &item, self.hygiene()); + let attrs = RawAttrs::new(self.db.upcast(), &item, self.hygiene()); self.lower_assoc_item(&item).map(|item| { self.add_attrs(ModItem::from(item).into(), attrs); item @@ -471,7 +477,7 @@ impl<'a> Ctx<'a> { .flat_map(|it| it.assoc_items()) .filter_map(|item| { let assoc = self.lower_assoc_item(&item)?; - let attrs = RawAttrs::new(self.db, &item, self.hygiene()); + let attrs = RawAttrs::new(self.db.upcast(), &item, self.hygiene()); self.add_attrs(ModItem::from(assoc).into(), attrs); Some(assoc) }) @@ -541,7 +547,7 @@ impl<'a> Ctx<'a> { // (in other words, the knowledge that they're in an extern block must not be used). // This is because an extern block can contain macros whose ItemTree's top-level items // should be considered to be in an extern block too. - let attrs = RawAttrs::new(self.db, &item, self.hygiene()); + let attrs = RawAttrs::new(self.db.upcast(), &item, self.hygiene()); let id: ModItem = match item { ast::ExternItem::Fn(ast) => self.lower_function(&ast)?.into(), ast::ExternItem::Static(ast) => self.lower_static(&ast)?.into(), diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index 48c40df22ff5..8f230b87d010 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -3,7 +3,6 @@ use std::fmt::{self, Write}; use crate::{ - attr::RawAttrs, generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget}, pretty::{print_path, print_type_bounds, print_type_ref}, visibility::RawVisibility, diff --git a/crates/hir-def/src/keys.rs b/crates/hir-def/src/keys.rs index c5cb9a2af537..72beec8186c1 100644 --- a/crates/hir-def/src/keys.rs +++ b/crates/hir-def/src/keys.rs @@ -2,12 +2,11 @@ use std::marker::PhantomData; -use hir_expand::MacroCallId; +use hir_expand::{attrs::AttrId, MacroCallId}; use rustc_hash::FxHashMap; use syntax::{ast, AstNode, AstPtr}; use crate::{ - attr::AttrId, dyn_map::{DynMap, Policy}, ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, Macro2Id, MacroRulesId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 8267ef09cb0a..cc0ea14d0156 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -28,7 +28,6 @@ pub mod dyn_map; pub mod keys; pub mod item_tree; -pub mod intern; pub mod adt; pub mod data; @@ -61,10 +60,10 @@ use std::{ sync::Arc, }; -use attr::Attr; use base_db::{impl_intern_key, salsa, CrateId, ProcMacroKind}; use hir_expand::{ ast_id_map::FileAstId, + attrs::{Attr, AttrId, AttrInput}, builtin_attr_macro::BuiltinAttrExpander, builtin_derive_macro::BuiltinDeriveExpander, builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander}, @@ -82,7 +81,6 @@ use syntax::ast; use crate::{ adt::VariantData, - attr::AttrId, builtin_type::BuiltinType, item_tree::{ Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, ModItem, @@ -971,7 +969,7 @@ fn attr_macro_as_call_id( is_derive: bool, ) -> MacroCallId { let mut arg = match macro_attr.input.as_deref() { - Some(attr::AttrInput::TokenTree(tt, map)) => (tt.clone(), map.clone()), + Some(AttrInput::TokenTree(tt, map)) => (tt.clone(), map.clone()), _ => Default::default(), }; @@ -990,3 +988,10 @@ fn attr_macro_as_call_id( ); res } +intern::impl_internable!( + crate::type_ref::TypeRef, + crate::type_ref::TraitRef, + crate::type_ref::TypeBound, + crate::path::GenericArgs, + generics::GenericParams, +); diff --git a/crates/hir-def/src/nameres/attr_resolution.rs b/crates/hir-def/src/nameres/attr_resolution.rs index 3650204ee9d7..79cabeb0fb7a 100644 --- a/crates/hir-def/src/nameres/attr_resolution.rs +++ b/crates/hir-def/src/nameres/attr_resolution.rs @@ -1,10 +1,9 @@ //! Post-nameres attribute resolution. -use hir_expand::MacroCallId; +use hir_expand::{attrs::Attr, MacroCallId}; use syntax::{ast, SmolStr}; use crate::{ - attr::Attr, attr_macro_as_call_id, builtin_attr, db::DefDatabase, item_scope::BuiltinShadowMode, diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 160203b77834..ad31e9aac2b5 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -10,6 +10,7 @@ use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ ast_id_map::FileAstId, + attrs::{Attr, AttrId}, builtin_attr_macro::find_builtin_attr, builtin_derive_macro::find_builtin_derive, builtin_fn_macro::find_builtin_macro, @@ -26,7 +27,7 @@ use stdx::always; use syntax::{ast, SmolStr}; use crate::{ - attr::{Attr, AttrId, Attrs}, + attr::Attrs, attr_macro_as_call_id, db::DefDatabase, derive_macro_as_call_id, diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index 066142291981..74b25f4cc982 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -2,12 +2,11 @@ use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; -use hir_expand::MacroCallKind; +use hir_expand::{attrs::AttrId, MacroCallKind}; use la_arena::Idx; use syntax::ast::{self, AnyHasAttrs}; use crate::{ - attr::AttrId, item_tree::{self, ItemTreeId}, nameres::LocalModuleId, path::ModPath, diff --git a/crates/hir-def/src/path.rs b/crates/hir-def/src/path.rs index 592223f7d85f..25a23fcd61a5 100644 --- a/crates/hir-def/src/path.rs +++ b/crates/hir-def/src/path.rs @@ -8,10 +8,10 @@ use std::{ use crate::{ body::LowerCtx, - intern::Interned, type_ref::{ConstScalarOrPath, LifetimeRef}, }; use hir_expand::name::Name; +use intern::Interned; use syntax::ast; use crate::type_ref::{TypeBound, TypeRef}; diff --git a/crates/hir-def/src/path/lower.rs b/crates/hir-def/src/path/lower.rs index cfa3a6baaf8b..d570191595b6 100644 --- a/crates/hir-def/src/path/lower.rs +++ b/crates/hir-def/src/path/lower.rs @@ -1,9 +1,10 @@ //! Transforms syntax into `Path` objects, ideally with accounting for hygiene -use crate::{intern::Interned, type_ref::ConstScalarOrPath}; +use crate::type_ref::ConstScalarOrPath; use either::Either; use hir_expand::name::{name, AsName}; +use intern::Interned; use syntax::ast::{self, AstNode, HasTypeBounds}; use super::AssociatedTypeBinding; diff --git a/crates/hir-def/src/pretty.rs b/crates/hir-def/src/pretty.rs index befd0c5ffa05..1c0bd204d309 100644 --- a/crates/hir-def/src/pretty.rs +++ b/crates/hir-def/src/pretty.rs @@ -3,10 +3,10 @@ use std::fmt::{self, Write}; use hir_expand::mod_path::PathKind; +use intern::Interned; use itertools::Itertools; use crate::{ - intern::Interned, path::{GenericArg, GenericArgs, Path}, type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef}, }; diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 1ef7f9577fe8..86958e3daea4 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -4,6 +4,7 @@ use std::{hash::BuildHasherDefault, sync::Arc}; use base_db::CrateId; use hir_expand::name::{name, Name}; use indexmap::IndexMap; +use intern::Interned; use rustc_hash::FxHashSet; use smallvec::{smallvec, SmallVec}; @@ -13,7 +14,6 @@ use crate::{ db::DefDatabase, expr::{ExprId, LabelId, PatId}, generics::{GenericParams, TypeOrConstParamData}, - intern::Interned, item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, nameres::DefMap, path::{ModPath, PathKind}, diff --git a/crates/hir-def/src/type_ref.rs b/crates/hir-def/src/type_ref.rs index f8bb78ddcfe0..0149fdaa43cf 100644 --- a/crates/hir-def/src/type_ref.rs +++ b/crates/hir-def/src/type_ref.rs @@ -7,13 +7,13 @@ use hir_expand::{ name::{AsName, Name}, AstId, }; +use intern::Interned; use syntax::ast::{self, HasName}; use crate::{ body::LowerCtx, builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, expr::Literal, - intern::Interned, path::Path, }; diff --git a/crates/hir-expand/Cargo.toml b/crates/hir-expand/Cargo.toml index 77eb1fd45043..a73e690a7e05 100644 --- a/crates/hir-expand/Cargo.toml +++ b/crates/hir-expand/Cargo.toml @@ -22,6 +22,7 @@ hashbrown = { version = "0.12.1", features = [ smallvec = { version = "1.10.0", features = ["const_new"] } stdx = { path = "../stdx", version = "0.0.0" } +intern = { path = "../intern", version = "0.0.0" } base-db = { path = "../base-db", version = "0.0.0" } cfg = { path = "../cfg", version = "0.0.0" } syntax = { path = "../syntax", version = "0.0.0" } diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs new file mode 100644 index 000000000000..6967d153271f --- /dev/null +++ b/crates/hir-expand/src/attrs.rs @@ -0,0 +1,313 @@ +use std::{fmt, ops, sync::Arc}; + +use base_db::CrateId; +use cfg::CfgExpr; +use either::Either; +use intern::Interned; +use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct}; +use smallvec::{smallvec, SmallVec}; +use syntax::{ast, match_ast, AstNode, SmolStr, SyntaxNode}; +use tt::Subtree; + +use crate::{ + db::AstDatabase, + hygiene::Hygiene, + mod_path::{ModPath, PathKind}, + name::AsName, + InFile, +}; + +/// Syntactical attributes, without filtering of `cfg_attr`s. +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct RawAttrs { + entries: Option>, +} + +impl ops::Deref for RawAttrs { + type Target = [Attr]; + + fn deref(&self) -> &[Attr] { + match &self.entries { + Some(it) => &*it, + None => &[], + } + } +} + +impl RawAttrs { + pub const EMPTY: Self = Self { entries: None }; + + pub fn new(db: &dyn AstDatabase, owner: &dyn ast::HasAttrs, hygiene: &Hygiene) -> Self { + let entries = collect_attrs(owner) + .filter_map(|(id, attr)| match attr { + Either::Left(attr) => { + attr.meta().and_then(|meta| Attr::from_src(db, meta, hygiene, id)) + } + Either::Right(comment) => comment.doc_comment().map(|doc| Attr { + id, + input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), + path: Interned::new(ModPath::from(crate::name!(doc))), + }), + }) + .collect::>(); + + Self { entries: if entries.is_empty() { None } else { Some(entries) } } + } + + pub fn from_attrs_owner(db: &dyn AstDatabase, owner: InFile<&dyn ast::HasAttrs>) -> Self { + let hygiene = Hygiene::new(db, owner.file_id); + Self::new(db, owner.value, &hygiene) + } + + pub fn merge(&self, other: Self) -> Self { + match (&self.entries, other.entries) { + (None, None) => Self::EMPTY, + (None, entries @ Some(_)) => Self { entries }, + (Some(entries), None) => Self { entries: Some(entries.clone()) }, + (Some(a), Some(b)) => { + let last_ast_index = a.last().map_or(0, |it| it.id.ast_index + 1); + Self { + entries: Some( + a.iter() + .cloned() + .chain(b.iter().map(|it| { + let mut it = it.clone(); + it.id.ast_index += last_ast_index; + it + })) + .collect(), + ), + } + } + } + } + + /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. + pub fn filter(self, db: &dyn AstDatabase, krate: CrateId) -> RawAttrs { + let has_cfg_attrs = self + .iter() + .any(|attr| attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr])); + if !has_cfg_attrs { + return self; + } + + let crate_graph = db.crate_graph(); + let new_attrs = self + .iter() + .flat_map(|attr| -> SmallVec<[_; 1]> { + let is_cfg_attr = + attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr]); + if !is_cfg_attr { + return smallvec![attr.clone()]; + } + + let subtree = match attr.token_tree_value() { + Some(it) => it, + _ => return smallvec![attr.clone()], + }; + + // Input subtree is: `(cfg, $(attr),+)` + // Split it up into a `cfg` subtree and the `attr` subtrees. + // FIXME: There should be a common API for this. + let mut parts = subtree.token_trees.split(|tt| { + matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))) + }); + let cfg = match parts.next() { + Some(it) => it, + None => return smallvec![], + }; + let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; + let cfg = CfgExpr::parse(&cfg); + let index = attr.id; + let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { + let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; + // FIXME hygiene + let hygiene = Hygiene::new_unhygienic(); + Attr::from_tt(db, &tree, &hygiene, index) + }); + + let cfg_options = &crate_graph[krate].cfg_options; + if cfg_options.check(&cfg) == Some(false) { + smallvec![] + } else { + cov_mark::hit!(cfg_attr_active); + + attrs.collect() + } + }) + .collect(); + + RawAttrs { entries: Some(new_attrs) } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct AttrId { + pub ast_index: u32, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Attr { + pub id: AttrId, + pub path: Interned, + pub input: Option>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum AttrInput { + /// `#[attr = "string"]` + Literal(SmolStr), + /// `#[attr(subtree)]` + TokenTree(tt::Subtree, mbe::TokenMap), +} + +impl fmt::Display for AttrInput { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + AttrInput::Literal(lit) => write!(f, " = \"{}\"", lit.escape_debug()), + AttrInput::TokenTree(subtree, _) => subtree.fmt(f), + } + } +} + +impl Attr { + fn from_src( + db: &dyn AstDatabase, + ast: ast::Meta, + hygiene: &Hygiene, + id: AttrId, + ) -> Option { + let path = Interned::new(ModPath::from_src(db, ast.path()?, hygiene)?); + let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { + let value = match lit.kind() { + ast::LiteralKind::String(string) => string.value()?.into(), + _ => lit.syntax().first_token()?.text().trim_matches('"').into(), + }; + Some(Interned::new(AttrInput::Literal(value))) + } else if let Some(tt) = ast.token_tree() { + let (tree, map) = syntax_node_to_token_tree(tt.syntax()); + Some(Interned::new(AttrInput::TokenTree(tree, map))) + } else { + None + }; + Some(Attr { id, path, input }) + } + + fn from_tt( + db: &dyn AstDatabase, + tt: &tt::Subtree, + hygiene: &Hygiene, + id: AttrId, + ) -> Option { + let (parse, _) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MetaItem); + let ast = ast::Meta::cast(parse.syntax_node())?; + + Self::from_src(db, ast, hygiene, id) + } + + pub fn path(&self) -> &ModPath { + &self.path + } +} + +impl Attr { + /// #[path = "string"] + pub fn string_value(&self) -> Option<&SmolStr> { + match self.input.as_deref()? { + AttrInput::Literal(it) => Some(it), + _ => None, + } + } + + /// #[path(ident)] + pub fn single_ident_value(&self) -> Option<&tt::Ident> { + match self.input.as_deref()? { + AttrInput::TokenTree(subtree, _) => match &*subtree.token_trees { + [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] => Some(ident), + _ => None, + }, + _ => None, + } + } + + /// #[path TokenTree] + pub fn token_tree_value(&self) -> Option<&Subtree> { + match self.input.as_deref()? { + AttrInput::TokenTree(subtree, _) => Some(subtree), + _ => None, + } + } + + /// Parses this attribute as a token tree consisting of comma separated paths. + pub fn parse_path_comma_token_tree(&self) -> Option + '_> { + let args = self.token_tree_value()?; + + if args.delimiter_kind() != Some(DelimiterKind::Parenthesis) { + return None; + } + let paths = args + .token_trees + .split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })))) + .filter_map(|tts| { + if tts.is_empty() { + return None; + } + let segments = tts.iter().filter_map(|tt| match tt { + tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()), + _ => None, + }); + Some(ModPath::from_segments(PathKind::Plain, segments)) + }); + + Some(paths) + } +} + +pub fn collect_attrs( + owner: &dyn ast::HasAttrs, +) -> impl Iterator)> { + let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten(); + let outer_attrs = + ast::AttrDocCommentIter::from_syntax_node(owner.syntax()).filter(|el| match el { + Either::Left(attr) => attr.kind().is_outer(), + Either::Right(comment) => comment.is_outer(), + }); + outer_attrs + .chain(inner_attrs) + .enumerate() + .map(|(id, attr)| (AttrId { ast_index: id as u32 }, attr)) +} + +fn inner_attributes( + syntax: &SyntaxNode, +) -> Option>> { + let node = match_ast! { + match syntax { + ast::SourceFile(_) => syntax.clone(), + ast::ExternBlock(it) => it.extern_item_list()?.syntax().clone(), + ast::Fn(it) => it.body()?.stmt_list()?.syntax().clone(), + ast::Impl(it) => it.assoc_item_list()?.syntax().clone(), + ast::Module(it) => it.item_list()?.syntax().clone(), + ast::BlockExpr(it) => { + use syntax::SyntaxKind::{BLOCK_EXPR , EXPR_STMT}; + // Block expressions accept outer and inner attributes, but only when they are the outer + // expression of an expression statement or the final expression of another block expression. + let may_carry_attributes = matches!( + it.syntax().parent().map(|it| it.kind()), + Some(BLOCK_EXPR | EXPR_STMT) + ); + if !may_carry_attributes { + return None + } + syntax.clone() + }, + _ => return None, + } + }; + + let attrs = ast::AttrDocCommentIter::from_syntax_node(&node).filter(|el| match el { + Either::Left(attr) => attr.kind().is_inner(), + Either::Right(comment) => comment.is_inner(), + }); + Some(attrs) +} diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index bc5f9f3b8afd..9d61588a8b51 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -17,6 +17,7 @@ pub mod proc_macro; pub mod quote; pub mod eager; pub mod mod_path; +pub mod attrs; mod fixup; pub use mbe::{Origin, ValueResult}; @@ -1031,3 +1032,5 @@ impl ExpandTo { pub struct UnresolvedMacro { pub path: ModPath, } + +intern::impl_internable!(ModPath, attrs::AttrInput); diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index ae837ac6dce8..75b33da1f230 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -29,6 +29,7 @@ typed-arena = "2.0.1" rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false } stdx = { path = "../stdx", version = "0.0.0" } +intern = { path = "../intern", version = "0.0.0" } hir-def = { path = "../hir-def", version = "0.0.0" } hir-expand = { path = "../hir-expand", version = "0.0.0" } base-db = { path = "../base-db", version = "0.0.0" } diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 66e813eed8b4..f9642aa7475a 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -11,7 +11,6 @@ use hir_def::{ db::DefDatabase, find_path, generics::{TypeOrConstParamData, TypeParamProvenance}, - intern::{Internable, Interned}, item_scope::ItemInNs, path::{Path, PathKind}, type_ref::{ConstScalar, TraitBoundModifier, TypeBound, TypeRef}, @@ -19,6 +18,7 @@ use hir_def::{ HasModule, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId, }; use hir_expand::{hygiene::Hygiene, name::Name}; +use intern::{Internable, Interned}; use itertools::Itertools; use smallvec::SmallVec; use syntax::SmolStr; diff --git a/crates/hir-ty/src/interner.rs b/crates/hir-ty/src/interner.rs index 441503a300e5..7bf73560cbe6 100644 --- a/crates/hir-ty/src/interner.rs +++ b/crates/hir-ty/src/interner.rs @@ -4,11 +4,8 @@ use crate::{chalk_db, tls, GenericArg}; use base_db::salsa::InternId; use chalk_ir::{Goal, GoalData}; -use hir_def::{ - intern::{impl_internable, InternStorage, Internable, Interned}, - type_ref::ConstScalar, - TypeAliasId, -}; +use hir_def::{type_ref::ConstScalar, TypeAliasId}; +use intern::{impl_internable, Interned}; use smallvec::SmallVec; use std::{fmt, sync::Arc}; diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 592410008a67..4b1f40f91d6e 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -23,7 +23,6 @@ use hir_def::{ generics::{ TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, }, - intern::Interned, lang_item::lang_attr, path::{GenericArg, ModPath, Path, PathKind, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, @@ -35,6 +34,7 @@ use hir_def::{ TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, }; use hir_expand::{name::Name, ExpandResult}; +use intern::Interned; use itertools::Either; use la_arena::ArenaMap; use rustc_hash::FxHashSet; diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 9893566bd549..4f516e18be6e 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -11,13 +11,13 @@ use hir_def::{ GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, }, - intern::Interned, resolver::{HasResolver, TypeNs}, type_ref::{TraitBoundModifier, TypeRef}, ConstParamId, FunctionId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, }; use hir_expand::name::Name; +use intern::Interned; use itertools::Either; use rustc_hash::FxHashSet; use smallvec::{smallvec, SmallVec}; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 08fd4453dfca..ad44e240423e 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -107,7 +107,7 @@ pub use { cfg::{CfgAtom, CfgExpr, CfgOptions}, hir_def::{ adt::StructKind, - attr::{Attr, Attrs, AttrsWithOwner, Documentation}, + attr::{Attrs, AttrsWithOwner, Documentation}, builtin_attr::AttributeTemplate, find_path::PrefixKind, import_map, @@ -122,6 +122,7 @@ pub use { ModuleDefId, }, hir_expand::{ + attrs::Attr, name::{known, Name}, ExpandResult, HirFileId, InFile, MacroFile, Origin, }, diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index fa45e3c12eb0..2b5bfda1d434 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -87,7 +87,6 @@ use base_db::FileId; use hir_def::{ - attr::AttrId, child_by_source::ChildBySource, dyn_map::DynMap, expr::{LabelId, PatId}, @@ -96,7 +95,7 @@ use hir_def::{ GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, }; -use hir_expand::{name::AsName, HirFileId, MacroCallId}; +use hir_expand::{attrs::AttrId, name::AsName, HirFileId, MacroCallId}; use rustc_hash::FxHashMap; use smallvec::SmallVec; use stdx::impl_from; diff --git a/crates/intern/Cargo.toml b/crates/intern/Cargo.toml new file mode 100644 index 000000000000..dd5110255c50 --- /dev/null +++ b/crates/intern/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "intern" +version = "0.0.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +# We need to freeze the version of the crate, as the raw-api feature is considered unstable +dashmap = { version = "=5.4.0", features = ["raw-api"] } +hashbrown = { version = "0.12.1", default-features = false } +once_cell = "1.15.0" +rustc-hash = "1.1.0" diff --git a/crates/hir-def/src/intern.rs b/crates/intern/src/lib.rs similarity index 92% rename from crates/hir-def/src/intern.rs rename to crates/intern/src/lib.rs index f08521a34032..fb2903696b37 100644 --- a/crates/hir-def/src/intern.rs +++ b/crates/intern/src/lib.rs @@ -14,8 +14,6 @@ use hashbrown::HashMap; use once_cell::sync::OnceCell; use rustc_hash::FxHasher; -use crate::generics::GenericParams; - type InternMap = DashMap, (), BuildHasherDefault>; type Guard = dashmap::RwLockWriteGuard< 'static, @@ -204,9 +202,9 @@ pub trait Internable: Hash + Eq + 'static { #[doc(hidden)] macro_rules! _impl_internable { ( $($t:path),+ $(,)? ) => { $( - impl Internable for $t { - fn storage() -> &'static InternStorage { - static STORAGE: InternStorage<$t> = InternStorage::new(); + impl $crate::Internable for $t { + fn storage() -> &'static $crate::InternStorage { + static STORAGE: $crate::InternStorage<$t> = $crate::InternStorage::new(); &STORAGE } } @@ -215,13 +213,4 @@ macro_rules! _impl_internable { pub use crate::_impl_internable as impl_internable; -impl_internable!( - crate::type_ref::TypeRef, - crate::type_ref::TraitRef, - crate::type_ref::TypeBound, - crate::path::ModPath, - crate::path::GenericArgs, - crate::attr::AttrInput, - GenericParams, - str, -); +impl_internable!(str,); From 621e96bd6ad0cf35c4dc4d1cfd8f6bc83096946f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 9 Jan 2023 20:47:51 +0100 Subject: [PATCH 0795/2442] Encode one level of cfg_attr in attr_id --- crates/hir-def/src/attr.rs | 2 +- crates/hir-def/src/child_by_source.rs | 2 +- crates/hir-def/src/lib.rs | 6 +- crates/hir-def/src/nameres/collector.rs | 4 +- crates/hir-def/src/nameres/diagnostics.rs | 8 +-- crates/hir-expand/src/attrs.rs | 79 ++++++++++++++++------- crates/hir-expand/src/db.rs | 9 ++- crates/hir-expand/src/hygiene.rs | 2 +- crates/hir-expand/src/lib.rs | 24 ++++--- crates/hir/src/lib.rs | 8 ++- crates/intern/Cargo.toml | 7 +- 11 files changed, 99 insertions(+), 52 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index eb88a74e448d..a0113fd048ce 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -546,7 +546,7 @@ impl AttrSourceMap { } fn source_of_id(&self, id: AttrId) -> InFile<&Either> { - let ast_idx = id.ast_index as usize; + let ast_idx = id.ast_index(); let file_id = match self.mod_def_site_file_id { Some((file_id, def_site_cut)) if def_site_cut <= ast_idx => file_id, _ => self.file_id, diff --git a/crates/hir-def/src/child_by_source.rs b/crates/hir-def/src/child_by_source.rs index bb13165257ba..19d2fe956f09 100644 --- a/crates/hir-def/src/child_by_source.rs +++ b/crates/hir-def/src/child_by_source.rs @@ -117,7 +117,7 @@ impl ChildBySource for ItemScope { let adt = ast_id.to_node(db.upcast()); calls.for_each(|(attr_id, call_id, calls)| { if let Some(Either::Left(attr)) = - adt.doc_comments_and_attrs().nth(attr_id.ast_index as usize) + adt.doc_comments_and_attrs().nth(attr_id.ast_index()) { res[keys::DERIVE_MACRO_CALL].insert(attr, (attr_id, call_id, calls.into())); } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index cc0ea14d0156..8eae2e92f426 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -941,7 +941,7 @@ pub fn macro_id_to_def_id(db: &dyn db::DefDatabase, id: MacroId) -> MacroDefId { fn derive_macro_as_call_id( db: &dyn db::DefDatabase, item_attr: &AstIdWithPath, - derive_attr: AttrId, + derive_attr_index: AttrId, derive_pos: u32, krate: CrateId, resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>, @@ -954,7 +954,7 @@ fn derive_macro_as_call_id( MacroCallKind::Derive { ast_id: item_attr.ast_id, derive_index: derive_pos, - derive_attr_index: derive_attr.ast_index, + derive_attr_index, }, ); Ok((macro_id, def_id, call_id)) @@ -982,7 +982,7 @@ fn attr_macro_as_call_id( MacroCallKind::Attr { ast_id: item_attr.ast_id, attr_args: Arc::new(arg), - invoc_attr_index: macro_attr.id.ast_index, + invoc_attr_index: macro_attr.id, is_derive, }, ); diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index ad31e9aac2b5..33a787fd9f95 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -452,7 +452,7 @@ impl DefCollector<'_> { MacroCallKind::Attr { ast_id: ast_id.ast_id, attr_args: Default::default(), - invoc_attr_index: attr.id.ast_index, + invoc_attr_index: attr.id, is_derive: false, }, attr.path().clone(), @@ -1407,7 +1407,7 @@ impl DefCollector<'_> { directive.module_id, MacroCallKind::Derive { ast_id: ast_id.ast_id, - derive_attr_index: derive_attr.ast_index, + derive_attr_index: *derive_attr, derive_index: *derive_pos as u32, }, ast_id.path.clone(), diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index 74b25f4cc982..b024d7c6777c 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -31,9 +31,9 @@ pub enum DefDiagnosticKind { UnimplementedBuiltinMacro { ast: AstId }, - InvalidDeriveTarget { ast: AstId, id: u32 }, + InvalidDeriveTarget { ast: AstId, id: usize }, - MalformedDerive { ast: AstId, id: u32 }, + MalformedDerive { ast: AstId, id: usize }, } #[derive(Debug, PartialEq, Eq)] @@ -119,7 +119,7 @@ impl DefDiagnostic { ) -> Self { Self { in_module: container, - kind: DefDiagnosticKind::InvalidDeriveTarget { ast, id: id.ast_index }, + kind: DefDiagnosticKind::InvalidDeriveTarget { ast, id: id.ast_index() }, } } @@ -130,7 +130,7 @@ impl DefDiagnostic { ) -> Self { Self { in_module: container, - kind: DefDiagnosticKind::MalformedDerive { ast, id: id.ast_index }, + kind: DefDiagnosticKind::MalformedDerive { ast, id: id.ast_index() }, } } } diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs index 6967d153271f..c7135732b8a2 100644 --- a/crates/hir-expand/src/attrs.rs +++ b/crates/hir-expand/src/attrs.rs @@ -1,3 +1,4 @@ +//! A higher level attributes based on TokenTree, with also some shortcuts. use std::{fmt, ops, sync::Arc}; use base_db::CrateId; @@ -65,14 +66,16 @@ impl RawAttrs { (None, entries @ Some(_)) => Self { entries }, (Some(entries), None) => Self { entries: Some(entries.clone()) }, (Some(a), Some(b)) => { - let last_ast_index = a.last().map_or(0, |it| it.id.ast_index + 1); + let last_ast_index = a.last().map_or(0, |it| it.id.ast_index() + 1) as u32; Self { entries: Some( a.iter() .cloned() .chain(b.iter().map(|it| { let mut it = it.clone(); - it.id.ast_index += last_ast_index; + it.id.id = it.id.ast_index() as u32 + last_ast_index + | (it.id.cfg_attr_index().unwrap_or(0) as u32) + << AttrId::AST_INDEX_BITS; it })) .collect(), @@ -83,6 +86,7 @@ impl RawAttrs { } /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. + // FIXME: This should return a different type pub fn filter(self, db: &dyn AstDatabase, krate: CrateId) -> RawAttrs { let has_cfg_attrs = self .iter() @@ -106,27 +110,22 @@ impl RawAttrs { _ => return smallvec![attr.clone()], }; - // Input subtree is: `(cfg, $(attr),+)` - // Split it up into a `cfg` subtree and the `attr` subtrees. - // FIXME: There should be a common API for this. - let mut parts = subtree.token_trees.split(|tt| { - matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))) - }); - let cfg = match parts.next() { + let (cfg, parts) = match parse_cfg_attr_input(subtree) { Some(it) => it, - None => return smallvec![], + None => return smallvec![attr.clone()], }; - let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; - let cfg = CfgExpr::parse(&cfg); let index = attr.id; - let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { - let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; - // FIXME hygiene - let hygiene = Hygiene::new_unhygienic(); - Attr::from_tt(db, &tree, &hygiene, index) - }); + let attrs = + parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map(|(idx, attr)| { + let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; + // FIXME hygiene + let hygiene = Hygiene::new_unhygienic(); + Attr::from_tt(db, &tree, &hygiene, index.with_cfg_attr(idx)) + }); let cfg_options = &crate_graph[krate].cfg_options; + let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; + let cfg = CfgExpr::parse(&cfg); if cfg_options.check(&cfg) == Some(false) { smallvec![] } else { @@ -143,7 +142,32 @@ impl RawAttrs { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct AttrId { - pub ast_index: u32, + id: u32, +} + +// FIXME: This only handles a single level of cfg_attr nesting +// that is `#[cfg_attr(all(), cfg_attr(all(), cfg(any())))]` breaks again +impl AttrId { + const CFG_ATTR_BITS: usize = 7; + const AST_INDEX_MASK: usize = 0x00FF_FFFF; + const AST_INDEX_BITS: usize = Self::AST_INDEX_MASK.count_ones() as usize; + const CFG_ATTR_SET_BITS: u32 = 1 << 31; + + pub fn ast_index(&self) -> usize { + self.id as usize & Self::AST_INDEX_MASK + } + + pub fn cfg_attr_index(&self) -> Option { + if self.id & Self::CFG_ATTR_SET_BITS == 0 { + None + } else { + Some(self.id as usize >> Self::AST_INDEX_BITS) + } + } + + pub fn with_cfg_attr(self, idx: usize) -> AttrId { + AttrId { id: self.id | (idx as u32) << Self::AST_INDEX_BITS | Self::CFG_ATTR_SET_BITS } + } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -272,10 +296,7 @@ pub fn collect_attrs( Either::Left(attr) => attr.kind().is_outer(), Either::Right(comment) => comment.is_outer(), }); - outer_attrs - .chain(inner_attrs) - .enumerate() - .map(|(id, attr)| (AttrId { ast_index: id as u32 }, attr)) + outer_attrs.chain(inner_attrs).enumerate().map(|(id, attr)| (AttrId { id: id as u32 }, attr)) } fn inner_attributes( @@ -311,3 +332,15 @@ fn inner_attributes( }); Some(attrs) } + +// Input subtree is: `(cfg, $(attr),+)` +// Split it up into a `cfg` subtree and the `attr` subtrees. +pub fn parse_cfg_attr_input( + subtree: &Subtree, +) -> Option<(&[tt::TokenTree], impl Iterator)> { + let mut parts = subtree + .token_trees + .split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })))); + let cfg = parts.next()?; + Some((cfg, parts.filter(|it| !it.is_empty()))) +} diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index b28e60187def..ec5886824f86 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -168,7 +168,9 @@ pub fn expand_speculative( // Attributes may have an input token tree, build the subtree and map for this as well // then try finding a token id for our token if it is inside this input subtree. let item = ast::Item::cast(speculative_args.clone())?; - item.doc_comments_and_attrs().nth(invoc_attr_index as usize).and_then(Either::left) + item.doc_comments_and_attrs() + .nth(invoc_attr_index.ast_index()) + .and_then(Either::left) }?; match attr.token_tree() { Some(token_tree) => { @@ -321,6 +323,7 @@ fn macro_arg( } fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet { + // FIXME: handle `cfg_attr` (|| { let censor = match loc.kind { MacroCallKind::FnLike { .. } => return None, @@ -328,7 +331,7 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet FxHashSet { + // FIXME: handle `cfg_attr` let tt = ast_id .to_node(db) .doc_comments_and_attrs() - .nth(invoc_attr_index as usize) + .nth(invoc_attr_index.ast_index()) .and_then(Either::left)? .token_tree()?; Some(InFile::new(ast_id.file_id, tt)) @@ -398,8 +400,7 @@ impl MacroDefId { } } -// FIXME: attribute indices do not account for `cfg_attr`, which means that we'll strip the whole -// `cfg_attr` instead of just one of the attributes it expands to +// FIXME: attribute indices do not account for nested `cfg_attr` impl MacroCallKind { /// Returns the file containing the macro invocation. @@ -420,7 +421,7 @@ impl MacroCallKind { // FIXME: handle `cfg_attr` ast_id.with_value(ast_id.to_node(db)).map(|it| { it.doc_comments_and_attrs() - .nth(*derive_attr_index as usize) + .nth(derive_attr_index.ast_index()) .and_then(|it| match it { Either::Left(attr) => Some(attr.syntax().clone()), Either::Right(_) => None, @@ -432,7 +433,7 @@ impl MacroCallKind { // FIXME: handle `cfg_attr` ast_id.with_value(ast_id.to_node(db)).map(|it| { it.doc_comments_and_attrs() - .nth(*invoc_attr_index as usize) + .nth(invoc_attr_index.ast_index()) .and_then(|it| match it { Either::Left(attr) => Some(attr.syntax().clone()), Either::Right(_) => None, @@ -489,19 +490,21 @@ impl MacroCallKind { MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(), MacroCallKind::Derive { ast_id, derive_attr_index, .. } => { // FIXME: should be the range of the macro name, not the whole derive + // FIXME: handle `cfg_attr` ast_id .to_node(db) .doc_comments_and_attrs() - .nth(derive_attr_index as usize) + .nth(derive_attr_index.ast_index()) .expect("missing derive") .expect_left("derive is a doc comment?") .syntax() .text_range() } + // FIXME: handle `cfg_attr` MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => ast_id .to_node(db) .doc_comments_and_attrs() - .nth(invoc_attr_index as usize) + .nth(invoc_attr_index.ast_index()) .expect("missing attribute") .expect_left("attribute macro is a doc comment?") .syntax() @@ -593,9 +596,10 @@ impl ExpansionInfo { let token_range = token.value.text_range(); match &loc.kind { MacroCallKind::Attr { attr_args, invoc_attr_index, is_derive, .. } => { + // FIXME: handle `cfg_attr` let attr = item .doc_comments_and_attrs() - .nth(*invoc_attr_index as usize) + .nth(invoc_attr_index.ast_index()) .and_then(Either::left)?; match attr.token_tree() { Some(token_tree) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index ad44e240423e..ec66660f34a5 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -785,7 +785,7 @@ fn precise_macro_call_location( let token = (|| { let derive_attr = node .doc_comments_and_attrs() - .nth(*derive_attr_index as usize) + .nth(derive_attr_index.ast_index()) .and_then(Either::left)?; let token_tree = derive_attr.meta()?.token_tree()?; let group_by = token_tree @@ -813,9 +813,11 @@ fn precise_macro_call_location( let node = ast_id.to_node(db.upcast()); let attr = node .doc_comments_and_attrs() - .nth((*invoc_attr_index) as usize) + .nth(invoc_attr_index.ast_index()) .and_then(Either::left) - .unwrap_or_else(|| panic!("cannot find attribute #{invoc_attr_index}")); + .unwrap_or_else(|| { + panic!("cannot find attribute #{}", invoc_attr_index.ast_index()) + }); ( ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))), diff --git a/crates/intern/Cargo.toml b/crates/intern/Cargo.toml index dd5110255c50..78007fc860ff 100644 --- a/crates/intern/Cargo.toml +++ b/crates/intern/Cargo.toml @@ -1,9 +1,14 @@ [package] name = "intern" version = "0.0.0" +description = "TBD" +license = "MIT OR Apache-2.0" edition = "2021" +rust-version = "1.65" + +[lib] +doctest = false -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] # We need to freeze the version of the crate, as the raw-api feature is considered unstable From 9a15cc81b4ba96cfc8164ba4848cbf648d40f86a Mon Sep 17 00:00:00 2001 From: bvanjoi Date: Fri, 6 Jan 2023 18:52:41 +0800 Subject: [PATCH 0796/2442] fix(ty): should query impls in nearest block --- crates/hir-ty/src/method_resolution.rs | 9 +++- crates/ide/src/goto_definition.rs | 64 ++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 2f5fa3083c7a..680e01e26b3c 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -1094,13 +1094,13 @@ fn iterate_inherent_methods( None => return ControlFlow::Continue(()), }; - let (module, block) = match visible_from_module { + let (module, mut block) = match visible_from_module { VisibleFromModule::Filter(module) => (Some(module), module.containing_block()), VisibleFromModule::IncludeBlock(block) => (None, Some(block)), VisibleFromModule::None => (None, None), }; - if let Some(block_id) = block { + while let Some(block_id) = block { if let Some(impls) = db.inherent_impls_in_block(block_id) { impls_for_self_ty( &impls, @@ -1113,6 +1113,11 @@ fn iterate_inherent_methods( callback, )?; } + + block = db + .block_def_map(block_id) + .and_then(|map| map.parent()) + .and_then(|module| module.containing_block()); } for krate in def_crates { diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 73fd518a9ef0..93019527f44d 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -1916,4 +1916,68 @@ fn main() { "#, ) } + + #[test] + fn query_impls_in_nearest_block() { + check( + r#" +struct S1; +impl S1 { + fn e() -> () {} +} +fn f1() { + struct S1; + impl S1 { + fn e() -> () {} + //^ + } + fn f2() { + fn f3() { + S1::e$0(); + } + } +} +"#, + ); + + check( + r#" +struct S1; +impl S1 { + fn e() -> () {} +} +fn f1() { + struct S1; + impl S1 { + fn e() -> () {} + //^ + } + fn f2() { + struct S2; + S1::e$0(); + } +} +fn f12() { + struct S1; + impl S1 { + fn e() -> () {} + } +} +"#, + ); + + check( + r#" +struct S1; +impl S1 { + fn e() -> () {} + //^ +} +fn f2() { + struct S2; + S1::e$0(); +} +"#, + ); + } } From ef4debc8b1d9b71de01e966cf17133ae2a1f5c43 Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Fri, 30 Dec 2022 11:20:48 +0000 Subject: [PATCH 0797/2442] comment out disabled code --- crates/syntax/src/syntax_node.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/syntax/src/syntax_node.rs b/crates/syntax/src/syntax_node.rs index a08c01597d3f..524be8139d14 100644 --- a/crates/syntax/src/syntax_node.rs +++ b/crates/syntax/src/syntax_node.rs @@ -48,10 +48,10 @@ impl SyntaxTreeBuilder { pub fn finish(self) -> Parse { let (green, errors) = self.finish_raw(); // Disable block validation, see https://github.com/rust-lang/rust-analyzer/pull/10357 - if cfg!(debug_assertions) && false { - let node = SyntaxNode::new_root(green.clone()); - crate::validation::validate_block_structure(&node); - } + // if cfg!(debug_assertions) { + // let node = SyntaxNode::new_root(green.clone()); + // crate::validation::validate_block_structure(&node); + // } Parse::new(green, errors) } From b971b5b64f784a08a0d787eb8c9a6a0bb928779b Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Tue, 10 Jan 2023 07:06:26 +0000 Subject: [PATCH 0798/2442] suppress lint --- crates/syntax/src/syntax_node.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/syntax/src/syntax_node.rs b/crates/syntax/src/syntax_node.rs index 524be8139d14..2e9e0bc226b9 100644 --- a/crates/syntax/src/syntax_node.rs +++ b/crates/syntax/src/syntax_node.rs @@ -48,10 +48,11 @@ impl SyntaxTreeBuilder { pub fn finish(self) -> Parse { let (green, errors) = self.finish_raw(); // Disable block validation, see https://github.com/rust-lang/rust-analyzer/pull/10357 - // if cfg!(debug_assertions) { - // let node = SyntaxNode::new_root(green.clone()); - // crate::validation::validate_block_structure(&node); - // } + #[allow(clippy::overly_complex_bool_expr)] + if cfg!(debug_assertions) && false { + let node = SyntaxNode::new_root(green.clone()); + crate::validation::validate_block_structure(&node); + } Parse::new(green, errors) } From db41e6b40892b89ebb7184ceda8e94896bf8d37f Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Tue, 10 Jan 2023 07:16:27 +0000 Subject: [PATCH 0799/2442] remove 'deny_clippy' test --- crates/rust-analyzer/tests/slow-tests/tidy.rs | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs index 35b5af731925..8e3097fce423 100644 --- a/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs @@ -82,7 +82,6 @@ fn files_are_tidy() { check_dbg(&path, &text); check_test_attrs(&path, &text); check_trailing_ws(&path, &text); - deny_clippy(&path, &text); tidy_docs.visit(&path, &text); tidy_marks.visit(&path, &text); } @@ -144,32 +143,6 @@ fn check_cargo_toml(path: &Path, text: String) { } } -fn deny_clippy(path: &Path, text: &str) { - let ignore = &[ - // The documentation in string literals may contain anything for its own purposes - "ide-db/src/generated/lints.rs", - // The tests test clippy lint hovers - "ide/src/hover/tests.rs", - // The tests test clippy lint completions - "ide-completion/src/tests/attribute.rs", - ]; - if ignore.iter().any(|p| path.ends_with(p)) { - return; - } - - if text.contains("\u{61}llow(clippy") { - panic!( - "\n\nallowing lints is forbidden: {}. -rust-analyzer intentionally doesn't check clippy on CI. -You can allow lint globally via `xtask clippy`. -See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion. - -", - path.display() - ) - } -} - #[cfg(not(feature = "in-rust-tree"))] #[test] fn check_licenses() { From 56ffe63c3c108f1c6002ac59b76511a0b81953c6 Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Tue, 10 Jan 2023 07:18:17 +0000 Subject: [PATCH 0800/2442] derive 'Hash' --- crates/base-db/src/input.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 5fa4a8024950..b44a157e2538 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -84,15 +84,10 @@ pub struct CrateGraph { arena: NoHashHashMap, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct CrateId(pub u32); impl stdx::hash::NoHashHashable for CrateId {} -impl std::hash::Hash for CrateId { - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateName(SmolStr); From 6153ea8dce1dcd60ecff446332c2639be8a6b452 Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Tue, 10 Jan 2023 08:28:28 +0000 Subject: [PATCH 0801/2442] loop-that-never-loops --- crates/hir-def/src/attr.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index ab5d180e1bb9..fb1e72b0d0d8 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -251,17 +251,17 @@ impl Attrs { let enum_ = &item_tree[loc.id.value]; let cfg_options = &crate_graph[krate].cfg_options; - let variant = 'tri: loop { - let mut idx = 0; - for variant in enum_.variants.clone() { - let attrs = item_tree.attrs(db, krate, variant.into()); - if attrs.is_cfg_enabled(cfg_options) { - if it.local_id == Idx::from_raw(RawIdx::from(idx)) { - break 'tri variant; - } - idx += 1; + let mut idx = 0; + let Some(variant) = enum_.variants.clone().find(|variant| { + let attrs = item_tree.attrs(db, krate, (*variant).into()); + if attrs.is_cfg_enabled(cfg_options) { + if it.local_id == Idx::from_raw(RawIdx::from(idx)) { + return true } + idx += 1; } + false + }) else { return Arc::new(res); }; (item_tree[variant].fields.clone(), item_tree, krate) From 4267b11c4097b52ec59323c29709a8d06ed7b4cd Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 10 Jan 2023 09:43:08 +0100 Subject: [PATCH 0802/2442] Revert "Use ZWNJ to prevent VSCode from forming ligatures between hints and code" --- editors/code/src/client.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 82cdf0390aca..1fbe9d4ea033 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -102,24 +102,6 @@ export async function createClient( } }, }, - async provideInlayHints(document, viewPort, token, next) { - const inlays = await next(document, viewPort, token); - if (!inlays) { - return inlays; - } - // U+200C is a zero-width non-joiner to prevent the editor from forming a ligature - // between code and hints - for (const inlay of inlays) { - if (typeof inlay.label === "string") { - inlay.label = `\u{200c}${inlay.label}\u{200c}`; - } else if (Array.isArray(inlay.label)) { - for (const it of inlay.label) { - it.value = `\u{200c}${it.value}\u{200c}`; - } - } - } - return inlays; - }, async handleDiagnostics( uri: vscode.Uri, diagnosticList: vscode.Diagnostic[], From 220996c5c1446add4fb508e60542f383857dc257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 10 Jan 2023 17:25:02 +0200 Subject: [PATCH 0803/2442] Tweak wording and remove blank issue template --- .github/ISSUE_TEMPLATE/blank_issue.md | 10 ---------- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/blank_issue.md diff --git a/.github/ISSUE_TEMPLATE/blank_issue.md b/.github/ISSUE_TEMPLATE/blank_issue.md deleted file mode 100644 index a08ad07cbf8d..000000000000 --- a/.github/ISSUE_TEMPLATE/blank_issue.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: Blank Issue -about: Create a blank issue. -title: '' -labels: '' -assignees: '' - ---- - - diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index c2e21933c9a6..b2a2153f0941 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -22,4 +22,4 @@ Otherwise please try to provide information which will help us to fix the issue **rustc version**: (eg. output of `rustc -V`) -**relevant settings**: (eg. client settings, or environment variables like `CARGO`, `RUSTUP_HOME` or `CARGO_HOME`) +**relevant settings**: (eg. client settings, or environment variables like `CARGO`, `RUSTC`, `RUSTUP_HOME` or `CARGO_HOME`) From 95d14c393c7efd7ccb56076eb2bc799e5a367c68 Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Tue, 10 Jan 2023 18:20:12 +0000 Subject: [PATCH 0804/2442] avoid 'cloning' types that implement 'Copy' --- crates/hir-ty/src/lower.rs | 2 +- crates/hir/src/lib.rs | 2 +- crates/mbe/src/benchmark.rs | 2 +- crates/mbe/src/expander/transcriber.rs | 2 +- crates/mbe/src/parser.rs | 2 +- crates/mbe/src/tt_iter.rs | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 4b1f40f91d6e..6a58546982d8 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -1931,7 +1931,7 @@ pub(crate) fn const_or_path_to_chalk( debruijn: DebruijnIndex, ) -> Const { match value { - ConstScalarOrPath::Scalar(s) => intern_const_scalar(s.clone(), expected_ty), + ConstScalarOrPath::Scalar(s) => intern_const_scalar(*s, expected_ty), ConstScalarOrPath::Path(n) => { let path = ModPath::from_segments(PathKind::Plain, Some(n.clone())); path_to_const(db, resolver, &path, mode, args, debruijn) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index ec66660f34a5..6baf53e35c6b 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -923,7 +923,7 @@ impl Struct { } pub fn repr(self, db: &dyn HirDatabase) -> Option { - db.struct_data(self.id).repr.clone() + db.struct_data(self.id).repr } pub fn kind(self, db: &dyn HirDatabase) -> StructKind { diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs index 4b7500250187..0fee6dfe4333 100644 --- a/crates/mbe/src/benchmark.rs +++ b/crates/mbe/src/benchmark.rs @@ -145,7 +145,7 @@ fn invocation_fixtures(rules: &FxHashMap) -> Vec<(Stri Op::Ident(it) => parent.token_trees.push(tt::Leaf::from(it.clone()).into()), Op::Punct(puncts) => { for punct in puncts { - parent.token_trees.push(tt::Leaf::from(punct.clone()).into()); + parent.token_trees.push(tt::Leaf::from(*punct).into()); } } Op::Repeat { tokens, kind, separator } => { diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs index db0d327bf409..fb316320ae78 100644 --- a/crates/mbe/src/expander/transcriber.rs +++ b/crates/mbe/src/expander/transcriber.rs @@ -138,7 +138,7 @@ fn expand_subtree( Op::Ident(it) => arena.push(tt::Leaf::from(it.clone()).into()), Op::Punct(puncts) => { for punct in puncts { - arena.push(tt::Leaf::from(punct.clone()).into()); + arena.push(tt::Leaf::from(*punct).into()); } } Op::Subtree { tokens, delimiter } => { diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index fad905e97f45..875dc1ad87bd 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs @@ -126,7 +126,7 @@ fn next_op( src.next().expect("first token already peeked"); // Note that the '$' itself is a valid token inside macro_rules. let second = match src.next() { - None => return Ok(Op::Punct(smallvec![p.clone()])), + None => return Ok(Op::Punct(smallvec![*p])), Some(it) => it, }; match second { diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs index bee7b5de6ac3..7787c74da883 100644 --- a/crates/mbe/src/tt_iter.rs +++ b/crates/mbe/src/tt_iter.rs @@ -114,7 +114,7 @@ impl<'a> TtIter<'a> { ('.', '.', Some('.' | '=')) | ('<', '<', Some('=')) | ('>', '>', Some('=')) => { let _ = self.next().unwrap(); let _ = self.next().unwrap(); - Ok(smallvec![first, second.clone(), third.unwrap().clone()]) + Ok(smallvec![first, *second, *third.unwrap()]) } ('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _) | ('-' | '=' | '>', '>', _) @@ -125,7 +125,7 @@ impl<'a> TtIter<'a> { | ('<', '<', _) | ('|', '|', _) => { let _ = self.next().unwrap(); - Ok(smallvec![first, second.clone()]) + Ok(smallvec![first, *second]) } _ => Ok(smallvec![first]), } From ac3844a0bb9a13260bf211354dbc014e892d7491 Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Tue, 10 Jan 2023 18:48:51 +0000 Subject: [PATCH 0805/2442] a number of code simplifications --- crates/hir-def/src/body/pretty.rs | 2 +- crates/hir-def/src/nameres/collector.rs | 20 ++- crates/hir/src/lib.rs | 4 +- .../src/handlers/generate_default_from_new.rs | 6 +- .../ide-assists/src/handlers/merge_imports.rs | 2 +- .../src/handlers/unmerge_match_arm.rs | 3 +- crates/ide-db/src/rename.rs | 8 +- crates/ide-db/src/search.rs | 40 +++--- .../src/handlers/json_is_not_rust.rs | 122 ++++++++---------- .../src/handlers/private_assoc_item.rs | 5 +- .../src/handlers/unresolved_proc_macro.rs | 5 +- crates/mbe/src/expander/transcriber.rs | 2 +- crates/project-model/src/workspace.rs | 4 +- 13 files changed, 99 insertions(+), 124 deletions(-) diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index 10b9b26bbeaa..41783081ecd7 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -80,7 +80,7 @@ impl<'a> Write for Printer<'a> { fn write_str(&mut self, s: &str) -> fmt::Result { for line in s.split_inclusive('\n') { if self.needs_indent { - match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() { + match self.buf.chars().rev().find(|ch| *ch != ' ') { Some('\n') | None => {} _ => self.buf.push('\n'), } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 33a787fd9f95..c69599079b5e 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -1600,17 +1600,15 @@ impl ModCollector<'_, '_> { FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db); let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); - if self.def_collector.is_proc_macro { - if self.module_id == def_map.root { - if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { - let crate_root = def_map.module_id(def_map.root); - self.def_collector.export_proc_macro( - proc_macro, - ItemTreeId::new(self.tree_id, id), - fn_id, - crate_root, - ); - } + if self.def_collector.is_proc_macro && self.module_id == def_map.root { + if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { + let crate_root = def_map.module_id(def_map.root); + self.def_collector.export_proc_macro( + proc_macro, + ItemTreeId::new(self.tree_id, id), + fn_id, + crate_root, + ); } } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index ec66660f34a5..c1e165b6381e 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -472,8 +472,8 @@ impl Module { let def_map = self.id.def_map(db.upcast()); let children = def_map[self.id.local_id] .children - .iter() - .map(|(_, module_id)| Module { id: def_map.module_id(*module_id) }) + .values() + .map(|module_id| Module { id: def_map.module_id(*module_id) }) .collect::>(); children.into_iter() } diff --git a/crates/ide-assists/src/handlers/generate_default_from_new.rs b/crates/ide-assists/src/handlers/generate_default_from_new.rs index 2d074a33e7fd..860372941f79 100644 --- a/crates/ide-assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide-assists/src/handlers/generate_default_from_new.rs @@ -82,18 +82,18 @@ fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: let generic_params = impl_.generic_param_list().map(|generic_params| { let lifetime_params = generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam); - let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| { + let ty_or_const_params = generic_params.type_or_const_params().map(|param| { // remove defaults since they can't be specified in impls match param { ast::TypeOrConstParam::Type(param) => { let param = param.clone_for_update(); param.remove_default(); - Some(ast::GenericParam::TypeParam(param)) + ast::GenericParam::TypeParam(param) } ast::TypeOrConstParam::Const(param) => { let param = param.clone_for_update(); param.remove_default(); - Some(ast::GenericParam::ConstParam(param)) + ast::GenericParam::ConstParam(param) } } }); diff --git a/crates/ide-assists/src/handlers/merge_imports.rs b/crates/ide-assists/src/handlers/merge_imports.rs index 2bdbec93b1f9..d7ddc5f23f5d 100644 --- a/crates/ide-assists/src/handlers/merge_imports.rs +++ b/crates/ide-assists/src/handlers/merge_imports.rs @@ -92,7 +92,7 @@ trait Merge: AstNode + Clone { fn try_merge_from(self, items: &mut dyn Iterator) -> Option> { let mut edits = Vec::new(); let mut merged = self.clone(); - while let Some(item) = items.next() { + for item in items { merged = merged.try_merge(&item)?; edits.push(Edit::Remove(item.into_either())); } diff --git a/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/crates/ide-assists/src/handlers/unmerge_match_arm.rs index 9565f0ee6f26..db789cfa3342 100644 --- a/crates/ide-assists/src/handlers/unmerge_match_arm.rs +++ b/crates/ide-assists/src/handlers/unmerge_match_arm.rs @@ -86,8 +86,7 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O it.prev_sibling_or_token() }) .map(|it| it.kind()) - .skip_while(|it| it.is_trivia()) - .next() + .find(|it| !it.is_trivia()) == Some(T![,]); let has_arms_after = neighbor(&match_arm, Direction::Next).is_some(); if !has_comma_after && !has_arms_after { diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index cd4a7e1554cd..8f310b0f42fb 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -334,11 +334,9 @@ pub fn source_edit_from_references( } _ => false, }; - if !has_emitted_edit { - if !edited_ranges.contains(&range.start()) { - edit.replace(range, new_name.to_string()); - edited_ranges.push(range.start()); - } + if !has_emitted_edit && !edited_ranges.contains(&range.start()) { + edit.replace(range, new_name.to_string()); + edited_ranges.push(range.start()); } } diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index b2b0e49085c8..f6d4ccc3ce5a 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -494,20 +494,28 @@ impl<'a> FindUsages<'a> { } // Search for `super` and `crate` resolving to our module - match self.def { - Definition::Module(module) => { - let scope = search_scope - .intersection(&SearchScope::module_and_children(self.sema.db, module)); + if let Definition::Module(module) = self.def { + let scope = + search_scope.intersection(&SearchScope::module_and_children(self.sema.db, module)); - let is_crate_root = - module.is_crate_root(self.sema.db).then(|| Finder::new("crate")); - let finder = &Finder::new("super"); + let is_crate_root = module.is_crate_root(self.sema.db).then(|| Finder::new("crate")); + let finder = &Finder::new("super"); - for (text, file_id, search_range) in scope_files(sema, &scope) { - let tree = Lazy::new(move || sema.parse(file_id).syntax().clone()); + for (text, file_id, search_range) in scope_files(sema, &scope) { + let tree = Lazy::new(move || sema.parse(file_id).syntax().clone()); + for offset in match_indices(&text, finder, search_range) { + if let Some(iter) = find_nodes("super", &tree, offset) { + for name_ref in iter.filter_map(ast::NameRef::cast) { + if self.found_name_ref(&name_ref, sink) { + return; + } + } + } + } + if let Some(finder) = &is_crate_root { for offset in match_indices(&text, finder, search_range) { - if let Some(iter) = find_nodes("super", &tree, offset) { + if let Some(iter) = find_nodes("crate", &tree, offset) { for name_ref in iter.filter_map(ast::NameRef::cast) { if self.found_name_ref(&name_ref, sink) { return; @@ -515,20 +523,8 @@ impl<'a> FindUsages<'a> { } } } - if let Some(finder) = &is_crate_root { - for offset in match_indices(&text, finder, search_range) { - if let Some(iter) = find_nodes("crate", &tree, offset) { - for name_ref in iter.filter_map(ast::NameRef::cast) { - if self.found_name_ref(&name_ref, sink) { - return; - } - } - } - } - } } } - _ => (), } // search for module `self` references in our module's definition source diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index e8df6dcf285d..04ce1e0feeed 100644 --- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -99,76 +99,66 @@ pub(crate) fn json_in_items( && node.last_token().map(|x| x.kind()) == Some(SyntaxKind::R_CURLY) { let node_string = node.to_string(); - if let Ok(it) = serde_json::from_str(&node_string) { - if let serde_json::Value::Object(it) = it { - let import_scope = ImportScope::find_insert_use_container(node, sema)?; - let range = node.text_range(); - let mut edit = TextEdit::builder(); - edit.delete(range); - let mut state = State::default(); - let semantics_scope = sema.scope(node)?; - let scope_resolve = - |it| semantics_scope.speculative_resolve(&make::path_from_text(it)); - let scope_has = |it| scope_resolve(it).is_some(); - let deserialize_resolved = scope_resolve("::serde::Deserialize"); - let serialize_resolved = scope_resolve("::serde::Serialize"); - state.has_deserialize = deserialize_resolved.is_some(); - state.has_serialize = serialize_resolved.is_some(); - state.build_struct(&it); - edit.insert(range.start(), state.result); - acc.push( - Diagnostic::new( - "json-is-not-rust", - "JSON syntax is not valid as a Rust item", - range, - ) - .severity(Severity::WeakWarning) - .with_fixes(Some(vec![{ - let mut scb = SourceChangeBuilder::new(file_id); - let scope = match import_scope { - ImportScope::File(it) => ImportScope::File(scb.make_mut(it)), - ImportScope::Module(it) => ImportScope::Module(scb.make_mut(it)), - ImportScope::Block(it) => ImportScope::Block(scb.make_mut(it)), - }; - let current_module = semantics_scope.module(); - if !scope_has("Serialize") { - if let Some(PathResolution::Def(it)) = serialize_resolved { - if let Some(it) = current_module.find_use_path_prefixed( - sema.db, - it, - config.insert_use.prefix_kind, - config.prefer_no_std, - ) { - insert_use( - &scope, - mod_path_to_ast(&it), - &config.insert_use, - ); - } + if let Ok(serde_json::Value::Object(it)) = serde_json::from_str(&node_string) { + let import_scope = ImportScope::find_insert_use_container(node, sema)?; + let range = node.text_range(); + let mut edit = TextEdit::builder(); + edit.delete(range); + let mut state = State::default(); + let semantics_scope = sema.scope(node)?; + let scope_resolve = + |it| semantics_scope.speculative_resolve(&make::path_from_text(it)); + let scope_has = |it| scope_resolve(it).is_some(); + let deserialize_resolved = scope_resolve("::serde::Deserialize"); + let serialize_resolved = scope_resolve("::serde::Serialize"); + state.has_deserialize = deserialize_resolved.is_some(); + state.has_serialize = serialize_resolved.is_some(); + state.build_struct(&it); + edit.insert(range.start(), state.result); + acc.push( + Diagnostic::new( + "json-is-not-rust", + "JSON syntax is not valid as a Rust item", + range, + ) + .severity(Severity::WeakWarning) + .with_fixes(Some(vec![{ + let mut scb = SourceChangeBuilder::new(file_id); + let scope = match import_scope { + ImportScope::File(it) => ImportScope::File(scb.make_mut(it)), + ImportScope::Module(it) => ImportScope::Module(scb.make_mut(it)), + ImportScope::Block(it) => ImportScope::Block(scb.make_mut(it)), + }; + let current_module = semantics_scope.module(); + if !scope_has("Serialize") { + if let Some(PathResolution::Def(it)) = serialize_resolved { + if let Some(it) = current_module.find_use_path_prefixed( + sema.db, + it, + config.insert_use.prefix_kind, + config.prefer_no_std, + ) { + insert_use(&scope, mod_path_to_ast(&it), &config.insert_use); } } - if !scope_has("Deserialize") { - if let Some(PathResolution::Def(it)) = deserialize_resolved { - if let Some(it) = current_module.find_use_path_prefixed( - sema.db, - it, - config.insert_use.prefix_kind, - config.prefer_no_std, - ) { - insert_use( - &scope, - mod_path_to_ast(&it), - &config.insert_use, - ); - } + } + if !scope_has("Deserialize") { + if let Some(PathResolution::Def(it)) = deserialize_resolved { + if let Some(it) = current_module.find_use_path_prefixed( + sema.db, + it, + config.insert_use.prefix_kind, + config.prefer_no_std, + ) { + insert_use(&scope, mod_path_to_ast(&it), &config.insert_use); } } - let mut sc = scb.finish(); - sc.insert_source_edit(file_id, edit.finish()); - fix("convert_json_to_struct", "Convert JSON to struct", sc, range) - }])), - ); - } + } + let mut sc = scb.finish(); + sc.insert_source_edit(file_id, edit.finish()); + fix("convert_json_to_struct", "Convert JSON to struct", sc, range) + }])), + ); } } Some(()) diff --git a/crates/ide-diagnostics/src/handlers/private_assoc_item.rs b/crates/ide-diagnostics/src/handlers/private_assoc_item.rs index b363a516dd1c..0b3121c765d8 100644 --- a/crates/ide-diagnostics/src/handlers/private_assoc_item.rs +++ b/crates/ide-diagnostics/src/handlers/private_assoc_item.rs @@ -11,10 +11,7 @@ pub(crate) fn private_assoc_item( d: &hir::PrivateAssocItem, ) -> Diagnostic { // FIXME: add quickfix - let name = match d.item.name(ctx.sema.db) { - Some(name) => format!("`{}` ", name), - None => String::new(), - }; + let name = d.item.name(ctx.sema.db).map(|name| format!("`{name}` ")).unwrap_or_default(); Diagnostic::new( "private-assoc-item", format!( diff --git a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs index b2ed19104e27..9a984ba6bf07 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs @@ -34,10 +34,7 @@ pub(crate) fn unresolved_proc_macro( let message = format!( "{message}: {}", if config_enabled { - match def_map.proc_macro_loading_error() { - Some(e) => e, - None => "proc macro not found in the built dylib", - } + def_map.proc_macro_loading_error().unwrap_or("proc macro not found in the built dylib") } else { match d.kind { hir::MacroKind::Attr if proc_macros_enabled => { diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs index db0d327bf409..605ddd4a065d 100644 --- a/crates/mbe/src/expander/transcriber.rs +++ b/crates/mbe/src/expander/transcriber.rs @@ -212,7 +212,7 @@ fn expand_var(ctx: &mut ExpandCtx<'_>, v: &SmolStr, id: tt::TokenId) -> ExpandRe } else { ctx.bindings.get(v, &mut ctx.nesting).map_or_else( |e| ExpandResult { value: Fragment::Tokens(tt::TokenTree::empty()), err: Some(e) }, - |it| ExpandResult::ok(it), + ExpandResult::ok, ) } } diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index e2382aa37e8e..5ab767a0e5fa 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -366,11 +366,11 @@ impl ProjectWorkspace { _ => None, }) .collect(); - let ref mut outputs = match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) { + let outputs = &mut (match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) { Ok(it) => Ok(it.into_iter()), // io::Error is not Clone? Err(e) => Err(Arc::new(e)), - }; + }); workspaces .iter() From 5b1cd8245f64d6501f0866c49e948e2d8a75038a Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Tue, 10 Jan 2023 19:44:19 +0000 Subject: [PATCH 0806/2442] fixup --- crates/project-model/src/workspace.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 5ab767a0e5fa..d562066533ee 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -366,11 +366,11 @@ impl ProjectWorkspace { _ => None, }) .collect(); - let outputs = &mut (match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) { + let outputs = &mut match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) { Ok(it) => Ok(it.into_iter()), // io::Error is not Clone? Err(e) => Err(Arc::new(e)), - }); + }; workspaces .iter() From 95fc3ba41cff006a3ae4c3c730122b0503fdefab Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Tue, 10 Jan 2023 19:51:21 +0000 Subject: [PATCH 0807/2442] fixup --- crates/hir-def/src/body/pretty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index 41783081ecd7..4b4664a1cf4a 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -113,7 +113,7 @@ impl<'a> Printer<'a> { } fn newline(&mut self) { - match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() { + match self.buf.chars().rev().find(|ch| *ch != ' ') { Some('\n') | None => {} _ => writeln!(self).unwrap(), } From d218b237fd8e5495c5399f0c1651c7dbf3b3daaf Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Tue, 10 Jan 2023 20:40:08 +0000 Subject: [PATCH 0808/2442] collapse some nested blocks --- crates/hir-ty/src/infer/expr.rs | 34 +++++++++---------- crates/hir-ty/src/layout.rs | 17 ++++------ .../src/handlers/extract_type_alias.rs | 22 ++++++------ crates/ide-db/src/rename.rs | 22 ++++++------ crates/ide-db/src/symbol_index.rs | 8 ++--- crates/ide/src/hover/render.rs | 8 ++--- crates/ide/src/join_lines.rs | 6 ++-- crates/ide/src/syntax_highlighting.rs | 9 +++-- crates/ide/src/typing.rs | 6 ++-- crates/rust-analyzer/src/main_loop.rs | 8 ++--- 10 files changed, 62 insertions(+), 78 deletions(-) diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 8f9cdac3784c..ea04a3d17b13 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -1136,18 +1136,16 @@ impl<'a> InferenceContext<'a> { if self.diverges.is_always() { // we don't even make an attempt at coercion self.table.new_maybe_never_var() - } else { - if let Some(t) = expected.only_has_type(&mut self.table) { - if self.coerce(Some(expr), &TyBuilder::unit(), &t).is_err() { - self.result.type_mismatches.insert( - expr.into(), - TypeMismatch { expected: t.clone(), actual: TyBuilder::unit() }, - ); - } - t - } else { - TyBuilder::unit() + } else if let Some(t) = expected.only_has_type(&mut self.table) { + if self.coerce(Some(expr), &TyBuilder::unit(), &t).is_err() { + self.result.type_mismatches.insert( + expr.into(), + TypeMismatch { expected: t.clone(), actual: TyBuilder::unit() }, + ); } + t + } else { + TyBuilder::unit() } } } @@ -1314,13 +1312,13 @@ impl<'a> InferenceContext<'a> { } else { param_ty }; - if !coercion_target.is_unknown() { - if self.coerce(Some(arg), &ty, &coercion_target).is_err() { - self.result.type_mismatches.insert( - arg.into(), - TypeMismatch { expected: coercion_target, actual: ty.clone() }, - ); - } + if !coercion_target.is_unknown() + && self.coerce(Some(arg), &ty, &coercion_target).is_err() + { + self.result.type_mismatches.insert( + arg.into(), + TypeMismatch { expected: coercion_target, actual: ty.clone() }, + ); } } } diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index 7a1cca3143ec..958d3dabe0ed 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -251,17 +251,14 @@ fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result Ty { match pointee.kind(Interner) { - TyKind::Adt(AdtId(adt), subst) => match adt { - &hir_def::AdtId::StructId(i) => { - let data = db.struct_data(i); - let mut it = data.variant_data.fields().iter().rev(); - match it.next() { - Some((f, _)) => field_ty(db, i.into(), f, subst), - None => pointee, - } + TyKind::Adt(AdtId(hir_def::AdtId::StructId(i)), subst) => { + let data = db.struct_data(*i); + let mut it = data.variant_data.fields().iter().rev(); + match it.next() { + Some((f, _)) => field_ty(db, (*i).into(), f, subst), + None => pointee, } - _ => pointee, - }, + } _ => pointee, } } diff --git a/crates/ide-assists/src/handlers/extract_type_alias.rs b/crates/ide-assists/src/handlers/extract_type_alias.rs index 0505f5784f81..6c0238f35d0f 100644 --- a/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -161,19 +161,17 @@ fn collect_used_generics<'gp>( .and_then(|lt| known_generics.iter().find(find_lifetime(<.text()))), ), ast::Type::ArrayType(ar) => { - if let Some(expr) = ar.expr() { - if let ast::Expr::PathExpr(p) = expr { - if let Some(path) = p.path() { - if let Some(name_ref) = path.as_single_name_ref() { - if let Some(param) = known_generics.iter().find(|gp| { - if let ast::GenericParam::ConstParam(cp) = gp { - cp.name().map_or(false, |n| n.text() == name_ref.text()) - } else { - false - } - }) { - generics.push(param); + if let Some(ast::Expr::PathExpr(p)) = ar.expr() { + if let Some(path) = p.path() { + if let Some(name_ref) = path.as_single_name_ref() { + if let Some(param) = known_generics.iter().find(|gp| { + if let ast::GenericParam::ConstParam(cp) = gp { + cp.name().map_or(false, |n| n.text() == name_ref.text()) + } else { + false } + }) { + generics.push(param); } } } diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index 8f310b0f42fb..0e5906097c3d 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -389,19 +389,17 @@ fn source_edit_from_name_ref( edit.delete(TextRange::new(s, e)); return true; } - } else if init == name_ref { - if field_name.text() == new_name { - cov_mark::hit!(test_rename_local_put_init_shorthand); - // Foo { field: local } -> Foo { field } - // ^^^^^^^ delete this + } else if init == name_ref && field_name.text() == new_name { + cov_mark::hit!(test_rename_local_put_init_shorthand); + // Foo { field: local } -> Foo { field } + // ^^^^^^^ delete this - // same names, we can use a shorthand here instead. - // we do not want to erase attributes hence this range start - let s = field_name.syntax().text_range().end(); - let e = init.syntax().text_range().end(); - edit.delete(TextRange::new(s, e)); - return true; - } + // same names, we can use a shorthand here instead. + // we do not want to erase attributes hence this range start + let s = field_name.syntax().text_range().end(); + let e = init.syntax().text_range().end(); + edit.delete(TextRange::new(s, e)); + return true; } } // init shorthand diff --git a/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs index c054cc159796..a91ffd1ec4fd 100644 --- a/crates/ide-db/src/symbol_index.rs +++ b/crates/ide-db/src/symbol_index.rs @@ -323,10 +323,10 @@ impl Query { if symbol.name != self.query { continue; } - } else if self.case_sensitive { - if self.query.chars().any(|c| !symbol.name.contains(c)) { - continue; - } + } else if self.case_sensitive + && self.query.chars().any(|c| !symbol.name.contains(c)) + { + continue; } res.push(symbol.clone()); diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 47257f0bfad0..cb537d7ef79d 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -64,12 +64,10 @@ pub(super) fn type_info( bt_end = if config.markdown() { "```\n" } else { "" } ) .into() + } else if config.markdown() { + Markup::fenced_block(&original.display(sema.db)) } else { - if config.markdown() { - Markup::fenced_block(&original.display(sema.db)) - } else { - original.display(sema.db).to_string().into() - } + original.display(sema.db).to_string().into() }; res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); Some(res) diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index edc48e84d725..1cfde2362455 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs @@ -161,10 +161,8 @@ fn remove_newline( } } - if config.join_assignments { - if join_assignments(edit, &prev, &next).is_some() { - return; - } + if config.join_assignments && join_assignments(edit, &prev, &next).is_some() { + return; } if config.unwrap_trivial_blocks { diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 50371d620eb2..454a250f3ded 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -413,11 +413,10 @@ fn traverse( let string = ast::String::cast(token); let string_to_highlight = ast::String::cast(descended_token.clone()); if let Some((string, expanded_string)) = string.zip(string_to_highlight) { - if string.is_raw() { - if inject::ra_fixture(hl, sema, config, &string, &expanded_string).is_some() - { - continue; - } + if string.is_raw() + && inject::ra_fixture(hl, sema, config, &string, &expanded_string).is_some() + { + continue; } highlight_format_string(hl, &string, &expanded_string, range); highlight_escape_string(hl, &string, range.start()); diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs index eba5a485636e..c26548756250 100644 --- a/crates/ide/src/typing.rs +++ b/crates/ide/src/typing.rs @@ -205,10 +205,8 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option { if expr_stmt.semicolon_token().is_some() { return None; } - } else { - if !ast::StmtList::can_cast(binop.syntax().parent()?.kind()) { - return None; - } + } else if !ast::StmtList::can_cast(binop.syntax().parent()?.kind()) { + return None; } let expr = binop.rhs()?; diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 0bc940dfe8da..a270049019f3 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -307,10 +307,10 @@ impl GlobalState { } } - if !was_quiescent || state_changed || memdocs_added_or_removed { - if self.config.publish_diagnostics() { - self.update_diagnostics() - } + if (!was_quiescent || state_changed || memdocs_added_or_removed) + && self.config.publish_diagnostics() + { + self.update_diagnostics() } } From a3114c3697c21310dbf8a11feea74712bf1eddd7 Mon Sep 17 00:00:00 2001 From: "daniel.eades" Date: Wed, 11 Jan 2023 16:07:35 +0000 Subject: [PATCH 0809/2442] move loop index inside iterator --- crates/hir-def/src/attr.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index fb1e72b0d0d8..c209bd949073 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -251,19 +251,18 @@ impl Attrs { let enum_ = &item_tree[loc.id.value]; let cfg_options = &crate_graph[krate].cfg_options; - let mut idx = 0; - let Some(variant) = enum_.variants.clone().find(|variant| { + + let Some(variant) = enum_.variants.clone().filter(|variant| { let attrs = item_tree.attrs(db, krate, (*variant).into()); - if attrs.is_cfg_enabled(cfg_options) { - if it.local_id == Idx::from_raw(RawIdx::from(idx)) { - return true - } - idx += 1; - } - false - }) else { + attrs.is_cfg_enabled(cfg_options) + }) + .zip(0u32..) + .find(|(_variant, idx)| it.local_id == Idx::from_raw(RawIdx::from(*idx))) + .map(|(variant, _idx)| variant) + else { return Arc::new(res); }; + (item_tree[variant].fields.clone(), item_tree, krate) } VariantId::StructId(it) => { From bb4e272d8a05c5b6a000808c5c84d722d582603d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 11 Jan 2023 17:10:04 +0100 Subject: [PATCH 0810/2442] Refine search for const and function assoc items --- crates/hir-ty/src/method_resolution.rs | 12 +- crates/hir/src/lib.rs | 2 +- crates/hir/src/source_analyzer.rs | 10 +- crates/ide-db/src/search.rs | 62 +++--- crates/ide/src/highlight_related.rs | 2 - crates/ide/src/references.rs | 261 +++++++++++++++++++++++++ crates/rust-analyzer/src/config.rs | 6 +- 7 files changed, 319 insertions(+), 36 deletions(-) diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index ae25704f2047..64376e10bcc5 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -712,17 +712,17 @@ fn lookup_impl_assoc_item_for_trait_ref( let table = InferenceTable::new(db, env); let impl_data = find_matching_impl(impls, table, trait_ref)?; - impl_data.items.iter().find_map(|it| match it { + impl_data.items.iter().find_map(|&it| match it { AssocItemId::FunctionId(f) => { - (db.function_data(*f).name == *name).then_some(AssocItemId::FunctionId(*f)) + (db.function_data(f).name == *name).then_some(AssocItemId::FunctionId(f)) } AssocItemId::ConstId(c) => db - .const_data(*c) + .const_data(c) .name .as_ref() - .map(|n| *n == *name) - .and_then(|result| if result { Some(AssocItemId::ConstId(*c)) } else { None }), - _ => None, + .map(|n| n == name) + .and_then(|result| if result { Some(AssocItemId::ConstId(c)) } else { None }), + AssocItemId::TypeAliasId(_) => None, }) } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index a1d2ec02f23b..2fc2673bd222 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2129,7 +2129,7 @@ pub enum AssocItem { Const(Const), TypeAlias(TypeAlias), } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum AssocItemContainer { Trait(Trait), Impl(Impl), diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 059b80bcf139..2354eb2c9cca 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -504,7 +504,7 @@ impl SourceAnalyzer { AssocItemId::ConstId(const_id) => { self.resolve_impl_const_or_trait_def(db, const_id, subs).into() } - _ => assoc, + assoc => assoc, }; return Some(PathResolution::Def(AssocItem::from(assoc).into())); @@ -517,7 +517,13 @@ impl SourceAnalyzer { prefer_value_ns = true; } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) { let pat_id = self.pat_id(&path_pat.into())?; - if let Some((assoc, _)) = infer.assoc_resolutions_for_pat(pat_id) { + if let Some((assoc, subs)) = infer.assoc_resolutions_for_pat(pat_id) { + let assoc = match assoc { + AssocItemId::ConstId(const_id) => { + self.resolve_impl_const_or_trait_def(db, const_id, subs).into() + } + assoc => assoc, + }; return Some(PathResolution::Def(AssocItem::from(assoc).into())); } if let Some(VariantId::EnumVariantId(variant)) = diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index f6d4ccc3ce5a..fd09fdeb0bda 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -7,7 +7,9 @@ use std::{mem, sync::Arc}; use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; -use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility}; +use hir::{ + AsAssocItem, DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility, +}; use memchr::memmem::Finder; use once_cell::unsync::Lazy; use parser::SyntaxKind; @@ -311,15 +313,15 @@ impl Definition { pub fn usages<'a>(self, sema: &'a Semantics<'_, RootDatabase>) -> FindUsages<'a> { FindUsages { + def: self, + assoc_item_container: self.as_assoc_item(sema.db).map(|a| a.container(sema.db)), + sema, + scope: None, + include_self_kw_refs: None, local_repr: match self { Definition::Local(local) => Some(local.representative(sema.db)), _ => None, }, - def: self, - trait_assoc_def: as_trait_assoc_def(sema.db, self), - sema, - scope: None, - include_self_kw_refs: None, search_self_mod: false, } } @@ -328,8 +330,7 @@ impl Definition { #[derive(Clone)] pub struct FindUsages<'a> { def: Definition, - /// If def is an assoc item from a trait or trait impl, this is the corresponding item of the trait definition - trait_assoc_def: Option, + assoc_item_container: Option, sema: &'a Semantics<'a, RootDatabase>, scope: Option, include_self_kw_refs: Option, @@ -380,7 +381,9 @@ impl<'a> FindUsages<'a> { let sema = self.sema; let search_scope = { - let base = self.trait_assoc_def.unwrap_or(self.def).search_scope(sema.db); + // FIXME: Is the trait scope needed for trait impl assoc items? + let base = + as_trait_assoc_def(sema.db, self.def).unwrap_or(self.def).search_scope(sema.db); match &self.scope { None => base, Some(scope) => base.intersection(scope), @@ -651,13 +654,26 @@ impl<'a> FindUsages<'a> { sink(file_id, reference) } Some(NameRefClass::Definition(def)) - if match self.trait_assoc_def { - Some(trait_assoc_def) => { - // we have a trait assoc item, so force resolve all assoc items to their trait version - convert_to_def_in_trait(self.sema.db, def) == trait_assoc_def - } - None => self.def == def, - } => + if self.def == def + // is our def a trait assoc item? then we want to find everything + || matches!(self.assoc_item_container, Some(hir::AssocItemContainer::Trait(_))) + && convert_to_def_in_trait(self.sema.db, def) == self.def => + { + let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); + let reference = FileReference { + range, + name: ast::NameLike::NameRef(name_ref.clone()), + category: ReferenceCategory::new(&def, name_ref), + }; + sink(file_id, reference) + } + // FIXME: special case type aliases, we can't filter between impl and trait defs here as we lack the substitutions + // so we always resolve all assoc type aliases to both their trait def and impl defs + Some(NameRefClass::Definition(def)) + if self.assoc_item_container.is_some() + && matches!(self.def, Definition::TypeAlias(_)) + && convert_to_def_in_trait(self.sema.db, def) + == convert_to_def_in_trait(self.sema.db, self.def) => { let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { @@ -748,12 +764,14 @@ impl<'a> FindUsages<'a> { false } Some(NameClass::Definition(def)) if def != self.def => { - // if the def we are looking for is a trait (impl) assoc item, we'll have to resolve the items to trait definition assoc item - if !matches!( - self.trait_assoc_def, - Some(trait_assoc_def) - if convert_to_def_in_trait(self.sema.db, def) == trait_assoc_def - ) { + // only when looking for trait assoc items, we want to find other assoc items + if !matches!(self.assoc_item_container, Some(hir::AssocItemContainer::Trait(_))) + // FIXME: special case type aliases, we can't filter between impl and trait defs here as we lack the substitutions + // so we always resolve all assoc type aliases to both their trait def and impl defs + && !(matches!(self.def, Definition::TypeAlias(_)) + && convert_to_def_in_trait(self.sema.db, def) + == convert_to_def_in_trait(self.sema.db, self.def)) + { return false; } let FileRange { file_id, range } = self.sema.original_range(name.syntax()); diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs index 55f8779eed7d..c889eb930f30 100644 --- a/crates/ide/src/highlight_related.rs +++ b/crates/ide/src/highlight_related.rs @@ -1356,7 +1356,6 @@ fn main() { r#" trait Trait { fn func(self) {} - //^^^^ } impl Trait for () { @@ -1376,7 +1375,6 @@ fn main() { r#" trait Trait { fn func(self) {} - //^^^^ } impl Trait for () { diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 0f758cfa2d34..e49f68c57ba8 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -1636,4 +1636,265 @@ pub fn deri$0ve(_stream: TokenStream) -> TokenStream {} "#]], ); } + + #[test] + fn assoc_items_trait_def() { + check( + r#" +trait Trait { + const CONST$0: usize; +} + +impl Trait for () { + const CONST: usize = 0; +} + +impl Trait for ((),) { + const CONST: usize = 0; +} + +fn f() { + let _ = <()>::CONST; + + let _ = T::CONST; +} +"#, + expect![[r#" + CONST Const FileId(0) 18..37 24..29 + + FileId(0) 71..76 + FileId(0) 125..130 + FileId(0) 183..188 + FileId(0) 206..211 + "#]], + ); + check( + r#" +trait Trait { + type TypeAlias$0; +} + +impl Trait for () { + type TypeAlias = (); +} + +impl Trait for ((),) { + type TypeAlias = (); +} + +fn f() { + let _: <() as Trait>::TypeAlias; + + let _: T::TypeAlias; +} +"#, + expect![[r#" + TypeAlias TypeAlias FileId(0) 18..33 23..32 + + FileId(0) 66..75 + FileId(0) 117..126 + FileId(0) 181..190 + FileId(0) 207..216 + "#]], + ); + check( + r#" +trait Trait { + fn function$0() {} +} + +impl Trait for () { + fn function() {} +} + +impl Trait for ((),) { + fn function() {} +} + +fn f() { + let _ = <()>::function; + + let _ = T::function; +} +"#, + expect![[r#" + function Function FileId(0) 18..34 21..29 + + FileId(0) 65..73 + FileId(0) 112..120 + FileId(0) 166..174 + FileId(0) 192..200 + "#]], + ); + } + + #[test] + fn assoc_items_trait_impl_def() { + check( + r#" +trait Trait { + const CONST: usize; +} + +impl Trait for () { + const CONST$0: usize = 0; +} + +impl Trait for ((),) { + const CONST: usize = 0; +} + +fn f() { + let _ = <()>::CONST; + + let _ = T::CONST; +} +"#, + expect![[r#" + CONST Const FileId(0) 65..88 71..76 + + FileId(0) 183..188 + "#]], + ); + check( + r#" +trait Trait { + type TypeAlias; +} + +impl Trait for () { + type TypeAlias$0 = (); +} + +impl Trait for ((),) { + type TypeAlias = (); +} + +fn f() { + let _: <() as Trait>::TypeAlias; + + let _: T::TypeAlias; +} +"#, + expect![[r#" + TypeAlias TypeAlias FileId(0) 61..81 66..75 + + FileId(0) 23..32 + FileId(0) 117..126 + FileId(0) 181..190 + FileId(0) 207..216 + "#]], + ); + check( + r#" +trait Trait { + fn function() {} +} + +impl Trait for () { + fn function$0() {} +} + +impl Trait for ((),) { + fn function() {} +} + +fn f() { + let _ = <()>::function; + + let _ = T::function; +} +"#, + expect![[r#" + function Function FileId(0) 62..78 65..73 + + FileId(0) 166..174 + "#]], + ); + } + + #[test] + fn assoc_items_ref() { + check( + r#" +trait Trait { + const CONST: usize; +} + +impl Trait for () { + const CONST: usize = 0; +} + +impl Trait for ((),) { + const CONST: usize = 0; +} + +fn f() { + let _ = <()>::CONST$0; + + let _ = T::CONST; +} +"#, + expect![[r#" + CONST Const FileId(0) 65..88 71..76 + + FileId(0) 183..188 + "#]], + ); + check( + r#" +trait Trait { + type TypeAlias; +} + +impl Trait for () { + type TypeAlias = (); +} + +impl Trait for ((),) { + type TypeAlias = (); +} + +fn f() { + let _: <() as Trait>::TypeAlias$0; + + let _: T::TypeAlias; +} +"#, + expect![[r#" + TypeAlias TypeAlias FileId(0) 18..33 23..32 + + FileId(0) 66..75 + FileId(0) 117..126 + FileId(0) 181..190 + FileId(0) 207..216 + "#]], + ); + check( + r#" +trait Trait { + fn function() {} +} + +impl Trait for () { + fn function() {} +} + +impl Trait for ((),) { + fn function() {} +} + +fn f() { + let _ = <()>::function$0; + + let _ = T::function; +} +"#, + expect![[r#" + function Function FileId(0) 62..78 65..73 + + FileId(0) 166..174 + "#]], + ); + } } diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index b0afbdc9a426..6d6e367e3740 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -1044,7 +1044,7 @@ impl Config { &self.data.cargo_extraEnv } - pub fn check_on_save_extra_env(&self) -> FxHashMap { + pub fn check_extra_env(&self) -> FxHashMap { let mut extra_env = self.data.cargo_extraEnv.clone(); extra_env.extend(self.data.check_extraEnv.clone()); extra_env @@ -1165,7 +1165,7 @@ impl Config { FlycheckConfig::CustomCommand { command, args, - extra_env: self.check_on_save_extra_env(), + extra_env: self.check_extra_env(), invocation_strategy: match self.data.check_invocationStrategy { InvocationStrategy::Once => flycheck::InvocationStrategy::Once, InvocationStrategy::PerWorkspace => { @@ -1210,7 +1210,7 @@ impl Config { CargoFeaturesDef::Selected(it) => it, }, extra_args: self.data.check_extraArgs.clone(), - extra_env: self.check_on_save_extra_env(), + extra_env: self.check_extra_env(), ansi_color_output: self.color_diagnostic_output(), }, } From 1ce3e820dcb3ca90dec6d3b008e14531c54afc06 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 11 Jan 2023 22:39:05 +0100 Subject: [PATCH 0811/2442] feat: Make unlinked_file diagnostic quickfixes work for inline modules --- crates/hir-expand/src/lib.rs | 8 + .../src/handlers/unlinked_file.rs | 219 ++++++++++++++---- crates/vfs/src/vfs_path.rs | 17 +- 3 files changed, 202 insertions(+), 42 deletions(-) diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 5554c7517f5a..b879eec4cc8d 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -356,6 +356,14 @@ impl HirFileId { } } + #[inline] + pub fn file_id(self) -> Option { + match self.0 & Self::MACRO_FILE_TAG_MASK { + 0 => Some(FileId(self.0)), + _ => None, + } + } + fn repr(self) -> HirFileIdRepr { match self.0 & Self::MACRO_FILE_TAG_MASK { 0 => HirFileIdRepr::FileId(FileId(self.0)), diff --git a/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/crates/ide-diagnostics/src/handlers/unlinked_file.rs index be70f0ac4f79..4bb3789d69d0 100644 --- a/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ b/crates/ide-diagnostics/src/handlers/unlinked_file.rs @@ -1,6 +1,8 @@ //! Diagnostic emitted for files that aren't part of any crate. -use hir::db::DefDatabase; +use std::iter; + +use hir::{db::DefDatabase, InFile, ModuleSource}; use ide_db::{ base_db::{FileId, FileLoader, SourceDatabase, SourceDatabaseExt}, source_change::SourceChange, @@ -42,45 +44,106 @@ fn fixes(ctx: &DiagnosticsContext<'_>, file_id: FileId) -> Option> { let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(file_id)); let our_path = source_root.path_for_file(&file_id)?; - let (mut module_name, _) = our_path.name_and_extension()?; - - // Candidates to look for: - // - `mod.rs`, `main.rs` and `lib.rs` in the same folder - // - `$dir.rs` in the parent folder, where `$dir` is the directory containing `self.file_id` let parent = our_path.parent()?; - let paths = { - let parent = if module_name == "mod" { - // for mod.rs we need to actually look up one higher - // and take the parent as our to be module name - let (name, _) = parent.name_and_extension()?; - module_name = name; - parent.parent()? - } else { - parent - }; - let mut paths = - vec![parent.join("mod.rs")?, parent.join("lib.rs")?, parent.join("main.rs")?]; - - // `submod/bla.rs` -> `submod.rs` - let parent_mod = (|| { - let (name, _) = parent.name_and_extension()?; - parent.parent()?.join(&format!("{name}.rs")) - })(); - paths.extend(parent_mod); - paths + let (module_name, _) = our_path.name_and_extension()?; + let (parent, module_name) = if module_name == "mod" { + // for mod.rs we need to actually look up one higher + // and take the parent as our to be module name + let (name, _) = parent.name_and_extension()?; + (parent.parent()?, name.to_owned()) + } else { + (parent, module_name.to_owned()) }; - for &parent_id in paths.iter().filter_map(|path| source_root.file_for_path(path)) { + // check crate roots, i.e. main.rs, lib.rs, ... + 'outer: for &krate in &*ctx.sema.db.relevant_crates(file_id) { + let crate_def_map = ctx.sema.db.crate_def_map(krate); + if let Some(root_file_id) = crate_def_map[crate_def_map.root()].origin.file_id() { + if let Some(path) = source_root.path_for_file(&root_file_id) { + let parent2 = path.parent()?; + if let Some(rel) = parent.strip_prefix(&parent2) { + let mut current = &crate_def_map[crate_def_map.root()]; + for ele in rel.as_ref().components() { + let seg = match ele { + std::path::Component::Normal(seg) => seg.to_str()?, + std::path::Component::RootDir => continue, + // shouldn't occur + _ => continue 'outer, + }; + match current.children.iter().find(|(name, _)| name.to_smol_str() == seg) { + Some((_, child)) => { + current = &crate_def_map[*child]; + } + None => continue 'outer, + } + } + let InFile { file_id: parent_file_id, value: source } = + current.definition_source(ctx.sema.db); + if let Some(parent_file_id) = parent_file_id.file_id() { + return make_fixes( + ctx.sema.db, + parent_file_id, + source, + &module_name, + file_id, + ); + } + } + } + } + } + // build all parent paths of the form `../module_name/mod.rs` and `../module_name.rs` + let paths = iter::successors(Some(parent.clone()), |prev| prev.parent()).filter_map(|path| { + let parent = path.parent()?; + let (name, _) = path.name_and_extension()?; + Some(([parent.join(&format!("{name}.rs"))?, path.join("mod.rs")?], name.to_owned())) + }); + let mut stack = vec![]; + if let Some(&parent_id) = paths + .inspect(|(_, name)| stack.push(name.clone())) + .find_map(|(paths, _)| paths.into_iter().find_map(|path| source_root.file_for_path(&path))) + { + stack.pop(); for &krate in ctx.sema.db.relevant_crates(parent_id).iter() { let crate_def_map = ctx.sema.db.crate_def_map(krate); - for (_, module) in crate_def_map.modules() { - if module.origin.is_inline() { - // We don't handle inline `mod parent {}`s, they use different paths. - continue; - } - + 'outer: for (_, module) in crate_def_map.modules() { if module.origin.file_id() == Some(parent_id) { - return make_fixes(ctx.sema.db, parent_id, module_name, file_id); + if module.origin.is_inline() { + continue; + } + if stack.is_empty() { + return make_fixes( + ctx.sema.db, + parent_id, + module.definition_source(ctx.sema.db).value, + &module_name, + file_id, + ); + } else { + let mut current = module; + for s in stack.iter().rev() { + match module.children.iter().find(|(name, _)| name.to_smol_str() == s) { + Some((_, child)) => { + current = &crate_def_map[*child]; + } + None => break 'outer, + } + } + let InFile { file_id: parent_file_id, value: source } = + current.definition_source(ctx.sema.db); + if let Some(parent_file_id) = parent_file_id.file_id() { + if current.origin.is_inline() { + return make_fixes( + ctx.sema.db, + parent_file_id, + source, + &module_name, + file_id, + ); + } + } + break; + } } } } @@ -92,6 +155,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, file_id: FileId) -> Option> { fn make_fixes( db: &RootDatabase, parent_file_id: FileId, + source: ModuleSource, new_mod_name: &str, added_file_id: FileId, ) -> Option> { @@ -102,14 +166,18 @@ fn make_fixes( let mod_decl = format!("mod {new_mod_name};"); let pub_mod_decl = format!("pub mod {new_mod_name};"); - let ast: ast::SourceFile = db.parse(parent_file_id).tree(); - let mut mod_decl_builder = TextEdit::builder(); let mut pub_mod_decl_builder = TextEdit::builder(); + let mut items = match &source { + ModuleSource::SourceFile(it) => it.items(), + ModuleSource::Module(it) => it.item_list()?.items(), + ModuleSource::BlockExpr(_) => return None, + }; + // If there's an existing `mod m;` statement matching the new one, don't emit a fix (it's // probably `#[cfg]`d out). - for item in ast.items() { + for item in items.clone() { if let ast::Item::Module(m) = item { if let Some(name) = m.name() { if m.item_list().is_none() && name.to_string() == new_mod_name { @@ -121,7 +189,7 @@ fn make_fixes( } // If there are existing `mod m;` items, append after them (after the first group of them, rather). - match ast.items().skip_while(|item| !is_outline_mod(item)).take_while(is_outline_mod).last() { + match items.clone().skip_while(|item| !is_outline_mod(item)).take_while(is_outline_mod).last() { Some(last) => { cov_mark::hit!(unlinked_file_append_to_existing_mods); let offset = last.syntax().text_range().end(); @@ -130,7 +198,7 @@ fn make_fixes( } None => { // Prepend before the first item in the file. - match ast.items().next() { + match items.next() { Some(item) => { cov_mark::hit!(unlinked_file_prepend_before_first_item); let offset = item.syntax().text_range().start(); @@ -140,7 +208,13 @@ fn make_fixes( None => { // No items in the file, so just append at the end. cov_mark::hit!(unlinked_file_empty_file); - let offset = ast.syntax().text_range().end(); + let offset = match &source { + ModuleSource::SourceFile(it) => it.syntax().text_range().end(), + ModuleSource::Module(it) => { + it.item_list()?.r_curly_token()?.text_range().start() + } + ModuleSource::BlockExpr(_) => return None, + }; mod_decl_builder.insert(offset, format!("{mod_decl}\n")); pub_mod_decl_builder.insert(offset, format!("{pub_mod_decl}\n")); } @@ -167,7 +241,6 @@ fn make_fixes( #[cfg(test)] mod tests { - use crate::tests::{check_diagnostics, check_fix, check_fixes, check_no_fix}; #[test] @@ -330,6 +403,70 @@ $0 mod foo; //- /foo.rs +"#, + ); + } + + #[test] + fn unlinked_file_insert_into_inline_simple() { + check_fix( + r#" +//- /main.rs +mod bar; +//- /bar.rs +mod foo { + +} +//- /bar/foo/baz.rs +$0 +"#, + r#" +mod foo { + +mod baz; +} +"#, + ); + } + + #[test] + fn unlinked_file_insert_into_inline_simple_modrs() { + check_fix( + r#" +//- /main.rs +mod bar; +//- /bar.rs +mod baz { + +} +//- /bar/baz/foo/mod.rs +$0 +"#, + r#" +mod baz { + +mod foo; +} +"#, + ); + } + + #[test] + fn unlinked_file_insert_into_inline_simple_modrs_main() { + check_fix( + r#" +//- /main.rs +mod bar { + +} +//- /bar/foo/mod.rs +$0 +"#, + r#" +mod bar { + +mod foo; +} "#, ); } diff --git a/crates/vfs/src/vfs_path.rs b/crates/vfs/src/vfs_path.rs index b23c9f1966d5..38501a8ba5a3 100644 --- a/crates/vfs/src/vfs_path.rs +++ b/crates/vfs/src/vfs_path.rs @@ -1,7 +1,7 @@ //! Abstract-ish representation of paths for VFS. use std::fmt; -use paths::{AbsPath, AbsPathBuf}; +use paths::{AbsPath, AbsPathBuf, RelPath}; /// Path in [`Vfs`]. /// @@ -84,6 +84,14 @@ impl VfsPath { } } + pub fn strip_prefix(&self, other: &VfsPath) -> Option<&RelPath> { + match (&self.0, &other.0) { + (VfsPathRepr::PathBuf(lhs), VfsPathRepr::PathBuf(rhs)) => lhs.strip_prefix(rhs), + (VfsPathRepr::VirtualPath(lhs), VfsPathRepr::VirtualPath(rhs)) => lhs.strip_prefix(rhs), + (VfsPathRepr::PathBuf(_) | VfsPathRepr::VirtualPath(_), _) => None, + } + } + /// Returns the `VfsPath` without its final component, if there is one. /// /// Returns [`None`] if the path is a root or prefix. @@ -320,6 +328,13 @@ impl VirtualPath { self.0.starts_with(&other.0) } + fn strip_prefix(&self, base: &VirtualPath) -> Option<&RelPath> { + <_ as AsRef>::as_ref(&self.0) + .strip_prefix(&base.0) + .ok() + .map(RelPath::new_unchecked) + } + /// Remove the last component of `self`. /// /// This will find the last `'/'` in `self`, and remove everything after it, From 5214a98d9c8030998a233e2308ef371535f8ae86 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 11 Jan 2023 23:04:35 +0100 Subject: [PATCH 0812/2442] Simplify --- .../src/handlers/unlinked_file.rs | 153 +++++++++--------- 1 file changed, 72 insertions(+), 81 deletions(-) diff --git a/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/crates/ide-diagnostics/src/handlers/unlinked_file.rs index 4bb3789d69d0..f527aa290c4c 100644 --- a/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ b/crates/ide-diagnostics/src/handlers/unlinked_file.rs @@ -46,52 +46,51 @@ fn fixes(ctx: &DiagnosticsContext<'_>, file_id: FileId) -> Option> { let our_path = source_root.path_for_file(&file_id)?; let parent = our_path.parent()?; let (module_name, _) = our_path.name_and_extension()?; - let (parent, module_name) = if module_name == "mod" { + let (parent, module_name) = match module_name { // for mod.rs we need to actually look up one higher // and take the parent as our to be module name - let (name, _) = parent.name_and_extension()?; - (parent.parent()?, name.to_owned()) - } else { - (parent, module_name.to_owned()) + "mod" => { + let (name, _) = parent.name_and_extension()?; + (parent.parent()?, name.to_owned()) + } + _ => (parent, module_name.to_owned()), }; // check crate roots, i.e. main.rs, lib.rs, ... - 'outer: for &krate in &*ctx.sema.db.relevant_crates(file_id) { + 'crates: for &krate in &*ctx.sema.db.relevant_crates(file_id) { let crate_def_map = ctx.sema.db.crate_def_map(krate); - if let Some(root_file_id) = crate_def_map[crate_def_map.root()].origin.file_id() { - if let Some(path) = source_root.path_for_file(&root_file_id) { - let parent2 = path.parent()?; - if let Some(rel) = parent.strip_prefix(&parent2) { - let mut current = &crate_def_map[crate_def_map.root()]; - for ele in rel.as_ref().components() { - let seg = match ele { - std::path::Component::Normal(seg) => seg.to_str()?, - std::path::Component::RootDir => continue, - // shouldn't occur - _ => continue 'outer, - }; - match current.children.iter().find(|(name, _)| name.to_smol_str() == seg) { - Some((_, child)) => { - current = &crate_def_map[*child]; - } - None => continue 'outer, - } - } - let InFile { file_id: parent_file_id, value: source } = - current.definition_source(ctx.sema.db); - if let Some(parent_file_id) = parent_file_id.file_id() { - return make_fixes( - ctx.sema.db, - parent_file_id, - source, - &module_name, - file_id, - ); - } - } + + let root_module = &crate_def_map[crate_def_map.root()]; + let Some(root_file_id) = root_module.origin.file_id() else { continue }; + let Some(crate_root_path) = source_root.path_for_file(&root_file_id) else { continue }; + let Some(rel) = parent.strip_prefix(&crate_root_path.parent()?) else { continue }; + + // try resolving the relative difference of the paths as inline modules + let mut current = root_module; + for ele in rel.as_ref().components() { + let seg = match ele { + std::path::Component::Normal(seg) => seg.to_str()?, + std::path::Component::RootDir => continue, + // shouldn't occur + _ => continue 'crates, + }; + match current.children.iter().find(|(name, _)| name.to_smol_str() == seg) { + Some((_, &child)) => current = &crate_def_map[child], + None => continue 'crates, + } + if !current.origin.is_inline() { + continue 'crates; } } + + let InFile { file_id: parent_file_id, value: source } = + current.definition_source(ctx.sema.db); + let parent_file_id = parent_file_id.file_id()?; + return make_fixes(ctx.sema.db, parent_file_id, source, &module_name, file_id); } + + // if we aren't adding to a crate root, walk backwards such that we support `#[path = ...]` overrides if possible + // build all parent paths of the form `../module_name/mod.rs` and `../module_name.rs` let paths = iter::successors(Some(parent.clone()), |prev| prev.parent()).filter_map(|path| { let parent = path.parent()?; @@ -99,53 +98,45 @@ fn fixes(ctx: &DiagnosticsContext<'_>, file_id: FileId) -> Option> { Some(([parent.join(&format!("{name}.rs"))?, path.join("mod.rs")?], name.to_owned())) }); let mut stack = vec![]; - if let Some(&parent_id) = paths - .inspect(|(_, name)| stack.push(name.clone())) - .find_map(|(paths, _)| paths.into_iter().find_map(|path| source_root.file_for_path(&path))) - { - stack.pop(); - for &krate in ctx.sema.db.relevant_crates(parent_id).iter() { - let crate_def_map = ctx.sema.db.crate_def_map(krate); - 'outer: for (_, module) in crate_def_map.modules() { - if module.origin.file_id() == Some(parent_id) { - if module.origin.is_inline() { - continue; - } - if stack.is_empty() { - return make_fixes( - ctx.sema.db, - parent_id, - module.definition_source(ctx.sema.db).value, - &module_name, - file_id, - ); - } else { - let mut current = module; - for s in stack.iter().rev() { - match module.children.iter().find(|(name, _)| name.to_smol_str() == s) { - Some((_, child)) => { - current = &crate_def_map[*child]; - } - None => break 'outer, - } - } - let InFile { file_id: parent_file_id, value: source } = - current.definition_source(ctx.sema.db); - if let Some(parent_file_id) = parent_file_id.file_id() { - if current.origin.is_inline() { - return make_fixes( - ctx.sema.db, - parent_file_id, - source, - &module_name, - file_id, - ); - } - } - break; + let &parent_id = + paths.inspect(|(_, name)| stack.push(name.clone())).find_map(|(paths, _)| { + paths.into_iter().find_map(|path| source_root.file_for_path(&path)) + })?; + stack.pop(); + 'crates: for &krate in ctx.sema.db.relevant_crates(parent_id).iter() { + let crate_def_map = ctx.sema.db.crate_def_map(krate); + let Some((_, module)) = + crate_def_map.modules() + .find(|(_, module)| module.origin.file_id() == Some(parent_id) && !module.origin.is_inline()) + else { continue }; + + if stack.is_empty() { + return make_fixes( + ctx.sema.db, + parent_id, + module.definition_source(ctx.sema.db).value, + &module_name, + file_id, + ); + } else { + // direct parent file is missing, + // try finding a parent that has an inline tree from here on + let mut current = module; + for s in stack.iter().rev() { + match module.children.iter().find(|(name, _)| name.to_smol_str() == s) { + Some((_, child)) => { + current = &crate_def_map[*child]; } + None => continue 'crates, + } + if !current.origin.is_inline() { + continue 'crates; } } + let InFile { file_id: parent_file_id, value: source } = + current.definition_source(ctx.sema.db); + let parent_file_id = parent_file_id.file_id()?; + return make_fixes(ctx.sema.db, parent_file_id, source, &module_name, file_id); } } From 6f201cfc56783beacb98c9e9033ddd58567c4517 Mon Sep 17 00:00:00 2001 From: Roland Fredenhagen Date: Thu, 12 Jan 2023 02:28:13 +0100 Subject: [PATCH 0813/2442] Assist: desugar doc-comment --- .../src/handlers/convert_comment_block.rs | 4 +- .../src/handlers/desugar_doc_comment.rs | 313 ++++++++++++++++++ crates/ide-assists/src/handlers/raw_string.rs | 2 +- crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 15 + 5 files changed, 333 insertions(+), 3 deletions(-) create mode 100644 crates/ide-assists/src/handlers/desugar_doc_comment.rs diff --git a/crates/ide-assists/src/handlers/convert_comment_block.rs b/crates/ide-assists/src/handlers/convert_comment_block.rs index 312cb65abd2a..282820b16725 100644 --- a/crates/ide-assists/src/handlers/convert_comment_block.rs +++ b/crates/ide-assists/src/handlers/convert_comment_block.rs @@ -107,7 +107,7 @@ fn line_to_block(acc: &mut Assists, comment: ast::Comment) -> Option<()> { /// The line -> block assist can be invoked from anywhere within a sequence of line comments. /// relevant_line_comments crawls backwards and forwards finding the complete sequence of comments that will /// be joined. -fn relevant_line_comments(comment: &ast::Comment) -> Vec { +pub fn relevant_line_comments(comment: &ast::Comment) -> Vec { // The prefix identifies the kind of comment we're dealing with let prefix = comment.prefix(); let same_prefix = |c: &ast::Comment| c.prefix() == prefix; @@ -159,7 +159,7 @@ fn relevant_line_comments(comment: &ast::Comment) -> Vec { // */ // // But since such comments aren't idiomatic we're okay with this. -fn line_comment_text(indentation: IndentLevel, comm: ast::Comment) -> String { +pub fn line_comment_text(indentation: IndentLevel, comm: ast::Comment) -> String { let contents_without_prefix = comm.text().strip_prefix(comm.prefix()).unwrap(); let contents = contents_without_prefix.strip_prefix(' ').unwrap_or(contents_without_prefix); diff --git a/crates/ide-assists/src/handlers/desugar_doc_comment.rs b/crates/ide-assists/src/handlers/desugar_doc_comment.rs new file mode 100644 index 000000000000..ea7044a54451 --- /dev/null +++ b/crates/ide-assists/src/handlers/desugar_doc_comment.rs @@ -0,0 +1,313 @@ +use either::Either; +use itertools::Itertools; +use syntax::{ + ast::{self, edit::IndentLevel, CommentPlacement, Whitespace}, + AstToken, TextRange, +}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +use super::{ + convert_comment_block::{line_comment_text, relevant_line_comments}, + raw_string::required_hashes, +}; + +// Assist: desugar_doc_comment +// +// Desugars doc-comments to the attribute form. +// +// ``` +// /// Multi-line$0 +// /// comment +// ``` +// -> +// ``` +// #[doc = r"Multi-line +// comment"] +// ``` +pub(crate) fn desugar_doc_comment(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let comment = ctx.find_token_at_offset::()?; + // Only allow doc comments + let Some(placement) = comment.kind().doc else { return None; }; + + // Only allow comments which are alone on their line + if let Some(prev) = comment.syntax().prev_token() { + if Whitespace::cast(prev).filter(|w| w.text().contains('\n')).is_none() { + return None; + } + } + + let indentation = IndentLevel::from_token(comment.syntax()).to_string(); + + let (target, comments) = match comment.kind().shape { + ast::CommentShape::Block => (comment.syntax().text_range(), Either::Left(comment)), + ast::CommentShape::Line => { + // Find all the comments we'll be desugaring + let comments = relevant_line_comments(&comment); + + // Establish the target of our edit based on the comments we found + ( + TextRange::new( + comments[0].syntax().text_range().start(), + comments.last().unwrap().syntax().text_range().end(), + ), + Either::Right(comments), + ) + } + }; + + acc.add( + AssistId("desugar_doc_comment", AssistKind::RefactorRewrite), + "Desugar doc-comment to attribute macro", + target, + |edit| { + let text = match comments { + Either::Left(comment) => { + let text = comment.text(); + text[comment.prefix().len()..(text.len() - "*/".len())] + .trim() + .lines() + .map(|l| l.strip_prefix(&indentation).unwrap_or(l)) + .join("\n") + } + Either::Right(comments) => { + comments.into_iter().map(|c| line_comment_text(IndentLevel(0), c)).join("\n") + } + }; + + let hashes = "#".repeat(required_hashes(&text)); + + let prefix = match placement { + CommentPlacement::Inner => "#!", + CommentPlacement::Outer => "#", + }; + + let output = format!(r#"{prefix}[doc = r{hashes}"{text}"{hashes}]"#); + + edit.replace(target, output) + }, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn single_line() { + check_assist( + desugar_doc_comment, + r#" +/// line$0 comment +fn main() { + foo(); +} +"#, + r#" +#[doc = r"line comment"] +fn main() { + foo(); +} +"#, + ); + check_assist( + desugar_doc_comment, + r#" +//! line$0 comment +fn main() { + foo(); +} +"#, + r#" +#![doc = r"line comment"] +fn main() { + foo(); +} +"#, + ); + } + + #[test] + fn single_line_indented() { + check_assist( + desugar_doc_comment, + r#" +fn main() { + /// line$0 comment + struct Foo; +} +"#, + r#" +fn main() { + #[doc = r"line comment"] + struct Foo; +} +"#, + ); + } + + #[test] + fn multiline() { + check_assist( + desugar_doc_comment, + r#" +fn main() { + /// above + /// line$0 comment + /// + /// below + struct Foo; +} +"#, + r#" +fn main() { + #[doc = r"above +line comment + +below"] + struct Foo; +} +"#, + ); + } + + #[test] + fn end_of_line() { + check_assist_not_applicable( + desugar_doc_comment, + r#" +fn main() { /// end-of-line$0 comment + struct Foo; +} +"#, + ); + } + + #[test] + fn single_line_different_kinds() { + check_assist( + desugar_doc_comment, + r#" +fn main() { + //! different prefix + /// line$0 comment + /// below + struct Foo; +} +"#, + r#" +fn main() { + //! different prefix + #[doc = r"line comment +below"] + struct Foo; +} +"#, + ); + } + + #[test] + fn single_line_separate_chunks() { + check_assist( + desugar_doc_comment, + r#" +/// different chunk + +/// line$0 comment +/// below +"#, + r#" +/// different chunk + +#[doc = r"line comment +below"] +"#, + ); + } + + #[test] + fn block_comment() { + check_assist( + desugar_doc_comment, + r#" +/** + hi$0 there +*/ +"#, + r#" +#[doc = r"hi there"] +"#, + ); + } + + #[test] + fn inner_doc_block() { + check_assist( + desugar_doc_comment, + r#" +/*! + hi$0 there +*/ +"#, + r#" +#![doc = r"hi there"] +"#, + ); + } + + #[test] + fn block_indent() { + check_assist( + desugar_doc_comment, + r#" +fn main() { + /*! + hi$0 there + + ``` + code_sample + ``` + */ +} +"#, + r#" +fn main() { + #![doc = r"hi there + +``` + code_sample +```"] +} +"#, + ); + } + + #[test] + fn end_of_line_block() { + check_assist_not_applicable( + desugar_doc_comment, + r#" +fn main() { + foo(); /** end-of-line$0 comment */ +} +"#, + ); + } + + #[test] + fn regular_comment() { + check_assist_not_applicable(desugar_doc_comment, r#"// some$0 comment"#); + check_assist_not_applicable(desugar_doc_comment, r#"/* some$0 comment*/"#); + } + + #[test] + fn quotes_and_escapes() { + check_assist( + desugar_doc_comment, + r###"/// some$0 "\ "## comment"###, + r####"#[doc = r###"some "\ "## comment"###]"####, + ); + } +} diff --git a/crates/ide-assists/src/handlers/raw_string.rs b/crates/ide-assists/src/handlers/raw_string.rs index c9bc25b27a5e..eff5a1f21f27 100644 --- a/crates/ide-assists/src/handlers/raw_string.rs +++ b/crates/ide-assists/src/handlers/raw_string.rs @@ -155,7 +155,7 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< }) } -fn required_hashes(s: &str) -> usize { +pub fn required_hashes(s: &str) -> usize { let mut res = 0usize; for idx in s.match_indices('"').map(|(i, _)| i) { let (_, sub) = s.split_at(idx + 1); diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 7813c9f9cbe8..546ef96260f2 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -126,6 +126,7 @@ mod handlers { mod convert_to_guarded_return; mod convert_two_arm_bool_match_to_matches_macro; mod convert_while_to_loop; + mod desugar_doc_comment; mod destructure_tuple_binding; mod expand_glob_import; mod extract_expressions_from_format_string; @@ -231,6 +232,7 @@ mod handlers { convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct, convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro, convert_while_to_loop::convert_while_to_loop, + desugar_doc_comment::desugar_doc_comment, destructure_tuple_binding::destructure_tuple_binding, expand_glob_import::expand_glob_import, extract_expressions_from_format_string::extract_expressions_from_format_string, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 006ae4b30341..16a06b60de90 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -597,6 +597,21 @@ fn main() { ) } +#[test] +fn doctest_desugar_doc_comment() { + check_doc_test( + "desugar_doc_comment", + r#####" +/// Multi-line$0 +/// comment +"#####, + r#####" +#[doc = r"Multi-line +comment"] +"#####, + ) +} + #[test] fn doctest_expand_glob_import() { check_doc_test( From 03bc46f96ba5c0bdf352cf32660d8760172dd010 Mon Sep 17 00:00:00 2001 From: Roland Fredenhagen Date: Thu, 12 Jan 2023 09:54:48 +0100 Subject: [PATCH 0814/2442] Convert pub to pub(crate) --- crates/ide-assists/src/handlers/convert_comment_block.rs | 4 ++-- crates/ide-assists/src/handlers/raw_string.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ide-assists/src/handlers/convert_comment_block.rs b/crates/ide-assists/src/handlers/convert_comment_block.rs index 282820b16725..1acd5ee97283 100644 --- a/crates/ide-assists/src/handlers/convert_comment_block.rs +++ b/crates/ide-assists/src/handlers/convert_comment_block.rs @@ -107,7 +107,7 @@ fn line_to_block(acc: &mut Assists, comment: ast::Comment) -> Option<()> { /// The line -> block assist can be invoked from anywhere within a sequence of line comments. /// relevant_line_comments crawls backwards and forwards finding the complete sequence of comments that will /// be joined. -pub fn relevant_line_comments(comment: &ast::Comment) -> Vec { +pub(crate) fn relevant_line_comments(comment: &ast::Comment) -> Vec { // The prefix identifies the kind of comment we're dealing with let prefix = comment.prefix(); let same_prefix = |c: &ast::Comment| c.prefix() == prefix; @@ -159,7 +159,7 @@ pub fn relevant_line_comments(comment: &ast::Comment) -> Vec { // */ // // But since such comments aren't idiomatic we're okay with this. -pub fn line_comment_text(indentation: IndentLevel, comm: ast::Comment) -> String { +pub(crate) fn line_comment_text(indentation: IndentLevel, comm: ast::Comment) -> String { let contents_without_prefix = comm.text().strip_prefix(comm.prefix()).unwrap(); let contents = contents_without_prefix.strip_prefix(' ').unwrap_or(contents_without_prefix); diff --git a/crates/ide-assists/src/handlers/raw_string.rs b/crates/ide-assists/src/handlers/raw_string.rs index eff5a1f21f27..b1b3bab7e514 100644 --- a/crates/ide-assists/src/handlers/raw_string.rs +++ b/crates/ide-assists/src/handlers/raw_string.rs @@ -155,7 +155,7 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< }) } -pub fn required_hashes(s: &str) -> usize { +pub(crate) fn required_hashes(s: &str) -> usize { let mut res = 0usize; for idx in s.match_indices('"').map(|(i, _)| i) { let (_, sub) = s.split_at(idx + 1); From 14777ce75190d21f52ae068e3d43a7d16de84ca7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jan 2023 11:24:44 +0100 Subject: [PATCH 0815/2442] fix indentation of unlinked_file quickfix --- .../src/handlers/unlinked_file.rs | 38 +++++++++---------- crates/ide/src/goto_declaration.rs | 1 + 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/crates/ide-diagnostics/src/handlers/unlinked_file.rs index f527aa290c4c..3d45a75913ad 100644 --- a/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ b/crates/ide-diagnostics/src/handlers/unlinked_file.rs @@ -9,7 +9,7 @@ use ide_db::{ RootDatabase, }; use syntax::{ - ast::{self, HasModuleItem, HasName}, + ast::{self, edit::IndentLevel, HasModuleItem, HasName}, AstNode, TextRange, TextSize, }; use text_edit::TextEdit; @@ -184,30 +184,36 @@ fn make_fixes( Some(last) => { cov_mark::hit!(unlinked_file_append_to_existing_mods); let offset = last.syntax().text_range().end(); - mod_decl_builder.insert(offset, format!("\n{mod_decl}")); - pub_mod_decl_builder.insert(offset, format!("\n{pub_mod_decl}")); + let indent = IndentLevel::from_node(last.syntax()); + mod_decl_builder.insert(offset, format!("\n{indent}{mod_decl}")); + pub_mod_decl_builder.insert(offset, format!("\n{indent}{pub_mod_decl}")); } None => { // Prepend before the first item in the file. match items.next() { - Some(item) => { + Some(first) => { cov_mark::hit!(unlinked_file_prepend_before_first_item); - let offset = item.syntax().text_range().start(); - mod_decl_builder.insert(offset, format!("{mod_decl}\n\n")); - pub_mod_decl_builder.insert(offset, format!("{pub_mod_decl}\n\n")); + let offset = first.syntax().text_range().start(); + let indent = IndentLevel::from_node(first.syntax()); + mod_decl_builder.insert(offset, format!("{mod_decl}\n\n{indent}")); + pub_mod_decl_builder.insert(offset, format!("{pub_mod_decl}\n\n{indent}")); } None => { // No items in the file, so just append at the end. cov_mark::hit!(unlinked_file_empty_file); + let mut indent = IndentLevel::from(0); let offset = match &source { ModuleSource::SourceFile(it) => it.syntax().text_range().end(), ModuleSource::Module(it) => { + indent = IndentLevel::from_node(it.syntax()) + 1; it.item_list()?.r_curly_token()?.text_range().start() } - ModuleSource::BlockExpr(_) => return None, + ModuleSource::BlockExpr(it) => { + it.stmt_list()?.r_curly_token()?.text_range().start() + } }; - mod_decl_builder.insert(offset, format!("{mod_decl}\n")); - pub_mod_decl_builder.insert(offset, format!("{pub_mod_decl}\n")); + mod_decl_builder.insert(offset, format!("{indent}{mod_decl}\n")); + pub_mod_decl_builder.insert(offset, format!("{indent}{pub_mod_decl}\n")); } } } @@ -406,15 +412,13 @@ mod foo; mod bar; //- /bar.rs mod foo { - } //- /bar/foo/baz.rs $0 "#, r#" mod foo { - -mod baz; + mod baz; } "#, ); @@ -428,15 +432,13 @@ mod baz; mod bar; //- /bar.rs mod baz { - } //- /bar/baz/foo/mod.rs $0 "#, r#" mod baz { - -mod foo; + mod foo; } "#, ); @@ -448,15 +450,13 @@ mod foo; r#" //- /main.rs mod bar { - } //- /bar/foo/mod.rs $0 "#, r#" mod bar { - -mod foo; + mod foo; } "#, ); diff --git a/crates/ide/src/goto_declaration.rs b/crates/ide/src/goto_declaration.rs index c7130a2a4bb0..e70bc2ec5417 100644 --- a/crates/ide/src/goto_declaration.rs +++ b/crates/ide/src/goto_declaration.rs @@ -17,6 +17,7 @@ use crate::{ // This is the same as `Go to Definition` with the following exceptions: // - outline modules will navigate to the `mod name;` item declaration // - trait assoc items will navigate to the assoc item of the trait declaration opposed to the trait impl +// - fields in patterns will navigate to the field declaration of the struct, union or variant pub(crate) fn goto_declaration( db: &RootDatabase, position: FilePosition, From 7413a9954f2d2967f790fc634509a0850ff81769 Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Thu, 12 Jan 2023 10:48:10 +0000 Subject: [PATCH 0816/2442] interior-mutable types should be 'static' rather than 'const --- crates/hir-def/src/nameres/mod_resolution.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/hir-def/src/nameres/mod_resolution.rs b/crates/hir-def/src/nameres/mod_resolution.rs index 4c263846d27d..51c565fe1233 100644 --- a/crates/hir-def/src/nameres/mod_resolution.rs +++ b/crates/hir-def/src/nameres/mod_resolution.rs @@ -7,7 +7,7 @@ use syntax::SmolStr; use crate::{db::DefDatabase, HirFileId}; -const MOD_DEPTH_LIMIT: Limit = Limit::new(32); +static MOD_DEPTH_LIMIT: Limit = Limit::new(32); #[derive(Clone, Debug)] pub(super) struct ModDir { From c4b36b64aae0d5bace5d19e0fbd64d1db9114bf9 Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Thu, 12 Jan 2023 11:53:45 +0000 Subject: [PATCH 0817/2442] remove recursive 'Display' implementations --- .../src/abis/abi_1_58/proc_macro/mod.rs | 24 +++++++++---------- .../src/abis/abi_1_63/proc_macro/mod.rs | 24 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs b/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs index c5145d00e329..a94b909941d9 100644 --- a/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs +++ b/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/mod.rs @@ -123,8 +123,8 @@ impl FromStr for TokenStream { /// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters and negative numeric literals. impl fmt::Display for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() } } @@ -522,8 +522,8 @@ impl From for TokenTree { /// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters and negative numeric literals. impl fmt::Display for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() } } @@ -619,8 +619,8 @@ impl Group { /// into the same group (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters. impl fmt::Display for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() } } @@ -693,8 +693,8 @@ impl Punct { /// Prints the punctuation character as a string that should be losslessly convertible /// back into the same character. impl fmt::Display for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() } } @@ -771,8 +771,8 @@ impl Ident { /// Prints the identifier as a string that should be losslessly convertible /// back into the same identifier. impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() } } @@ -1014,8 +1014,8 @@ impl FromStr for Literal { /// Prints the literal as a string that should be losslessly convertible /// back into the same literal (except for possible rounding for floating point literals). impl fmt::Display for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() } } diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs index 7ab1f421daf8..89bd10da5e48 100644 --- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs +++ b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/mod.rs @@ -124,8 +124,8 @@ impl FromStr for TokenStream { /// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters and negative numeric literals. impl fmt::Display for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() } } @@ -572,8 +572,8 @@ impl From for TokenTree { /// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters and negative numeric literals. impl fmt::Display for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() } } @@ -669,8 +669,8 @@ impl Group { /// into the same group (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters. impl fmt::Display for Group { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() } } @@ -743,8 +743,8 @@ impl Punct { /// Prints the punctuation character as a string that should be losslessly convertible /// back into the same character. impl fmt::Display for Punct { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() } } @@ -821,8 +821,8 @@ impl Ident { /// Prints the identifier as a string that should be losslessly convertible /// back into the same identifier. impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() } } @@ -1064,8 +1064,8 @@ impl FromStr for Literal { /// Prints the literal as a string that should be losslessly convertible /// back into the same literal (except for possible rounding for floating point literals). impl fmt::Display for Literal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() } } From 9721505bf1cc441334c9973525a5c9de826e51bb Mon Sep 17 00:00:00 2001 From: Neel Yadav Date: Wed, 30 Nov 2022 20:14:06 -0600 Subject: [PATCH 0818/2442] Fix panicking Option unwraping in match arm analysis --- crates/ide-assists/src/handlers/convert_match_to_let_else.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/convert_match_to_let_else.rs b/crates/ide-assists/src/handlers/convert_match_to_let_else.rs index 5bf04a3ad371..fbd81c80151d 100644 --- a/crates/ide-assists/src/handlers/convert_match_to_let_else.rs +++ b/crates/ide-assists/src/handlers/convert_match_to_let_else.rs @@ -87,7 +87,7 @@ fn find_arms( let mut extracting = None; let mut diverging = None; for arm in arms { - if ctx.sema.type_of_expr(&arm.expr().unwrap()).unwrap().original().is_never() { + if ctx.sema.type_of_expr(&arm.expr()?)?.original().is_never() { diverging = Some(arm); } else { extracting = Some(arm); From aa73366b0b91e1b99a0e6059e7f8dfbcb41cf929 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 13 Jan 2023 11:44:02 +0000 Subject: [PATCH 0819/2442] internal: explain the idea behind rust-project.json --- crates/project-model/src/project_json.rs | 44 ++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs index 9af0eafe9fdd..a990fb267a7d 100644 --- a/crates/project-model/src/project_json.rs +++ b/crates/project-model/src/project_json.rs @@ -4,6 +4,50 @@ //! idea here is that people who do not use Cargo, can instead teach their build //! system to generate `rust-project.json` which can be ingested by //! rust-analyzer. +//! +//! This short file is a somewhat big conceptual piece of the architecture of +//! rust-analyzer, so it's worth elaborating on the underlying ideas and +//! motivation. +//! +//! For rust-analyzer to function, it needs some information about the project. +//! Specifically, it maintains an in-memory data structure which lists all the +//! crates (compilation units) and dependencies between them. This is necessary +//! a global singleton, as we do want, eg, find usages to always search across +//! the whole project, rather than just in the "current" crate. +//! +//! Normally, we get this "crate graph" by calling `cargo metadata +//! --message-format=json` for each cargo workspace and merging results. This +//! works for your typical cargo project, but breaks down for large folks who +//! have a monorepo with an infitine amount of Rust which is build with bazel or +//! some such. +//! +//! To support this use-case, we need to make _something_ configurable. To avoid +//! [midlayer mistake](https://lwn.net/Articles/336262/), we allow configuring +//! the lowest possible layer. `ProjectJson` is essentially a hook to just set +//! that global singleton in-memory data structure. It is optimized for power, +//! not for convenience (you'd be using cargo anyway if you wanted nice things, +//! right? :) +//! +//! `rust-project.json` also isn't necessary a file. Architecturally, we support +//! any convenient way to specify this data, which today is: +//! +//! * file on disk +//! * a field in the config (ie, you can send a JSON request with the contents +//! of rust-project.json to rust-analyzer, no need to write anything to disk) +//! +//! Another possible thing we don't do today, but which would be totally valid, +//! is to add an extension point to VS Code extension to register custom +//! project. +//! +//! In general, it is assumed that if you are going to use `rust-project.json`, +//! you'd write a fair bit of custom code gluing your build system to ra through +//! this JSON format. This logic can take form of a VS Code extension, or a +//! proxy process which injects data into "configure" LSP request, or maybe just +//! a simple build system rule to generate the file. +//! +//! In particular, the logic for lazily loading parts of the monorepo as the +//! user explores them belongs to that extension (it's totally valid to change +//! rust-project.json over time via configuration request!) use std::path::PathBuf; From 87315ef5c39647d1ddab66d58153840562dab353 Mon Sep 17 00:00:00 2001 From: Alex Kladov Date: Fri, 13 Jan 2023 11:57:02 +0000 Subject: [PATCH 0820/2442] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Laurențiu Nicola --- crates/project-model/src/project_json.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs index a990fb267a7d..319897890fc5 100644 --- a/crates/project-model/src/project_json.rs +++ b/crates/project-model/src/project_json.rs @@ -18,10 +18,11 @@ //! Normally, we get this "crate graph" by calling `cargo metadata //! --message-format=json` for each cargo workspace and merging results. This //! works for your typical cargo project, but breaks down for large folks who -//! have a monorepo with an infitine amount of Rust which is build with bazel or +//! have a monorepo with an infinite amount of Rust code which is built with bazel or //! some such. //! -//! To support this use-case, we need to make _something_ configurable. To avoid +//! To support this use case, we need to make _something_ configurable. To avoid +//! a [midlayer mistake](https://lwn.net/Articles/336262/), we allow configuring //! [midlayer mistake](https://lwn.net/Articles/336262/), we allow configuring //! the lowest possible layer. `ProjectJson` is essentially a hook to just set //! that global singleton in-memory data structure. It is optimized for power, From bd350085f66c5e392a14b11d40ac24b4fd139aca Mon Sep 17 00:00:00 2001 From: Alex Kladov Date: Fri, 13 Jan 2023 12:01:04 +0000 Subject: [PATCH 0821/2442] Update crates/project-model/src/project_json.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Laurențiu Nicola --- crates/project-model/src/project_json.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs index 319897890fc5..4b2448e47f1f 100644 --- a/crates/project-model/src/project_json.rs +++ b/crates/project-model/src/project_json.rs @@ -23,7 +23,6 @@ //! //! To support this use case, we need to make _something_ configurable. To avoid //! a [midlayer mistake](https://lwn.net/Articles/336262/), we allow configuring -//! [midlayer mistake](https://lwn.net/Articles/336262/), we allow configuring //! the lowest possible layer. `ProjectJson` is essentially a hook to just set //! that global singleton in-memory data structure. It is optimized for power, //! not for convenience (you'd be using cargo anyway if you wanted nice things, From aafb0f1f8dd4c57d258374ac554b3162c497847d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Jan 2023 15:03:37 +0100 Subject: [PATCH 0822/2442] Use smallvec for inlay-hint parts --- Cargo.lock | 1 + crates/ide/Cargo.toml | 1 + crates/ide/src/inlay_hints.rs | 15 +++++++++++---- crates/ide/src/inlay_hints/closing_brace.rs | 5 ++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f426d885626..13d8d40ddd37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -645,6 +645,7 @@ dependencies = [ "profile", "pulldown-cmark", "pulldown-cmark-to-cmark", + "smallvec", "stdx", "syntax", "test-utils", diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index 73f202630f15..397383bc3a0b 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -20,6 +20,7 @@ pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.1", default-features = false } url = "2.3.1" dot = "0.1.4" +smallvec = "1.10.0" stdx = { path = "../stdx", version = "0.0.0" } syntax = { path = "../syntax", version = "0.0.0" } diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 48a7bbfecffa..f4a9d7b653a2 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -7,6 +7,7 @@ use either::Either; use hir::{known, HasVisibility, HirDisplay, HirWrite, ModuleDef, ModuleDefId, Semantics}; use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase}; use itertools::Itertools; +use smallvec::{smallvec, SmallVec}; use stdx::never; use syntax::{ ast::{self, AstNode}, @@ -83,7 +84,7 @@ pub enum AdjustmentHintsMode { PreferPostfix, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum InlayKind { BindingModeHint, ChainingHint, @@ -102,9 +103,15 @@ pub enum InlayKind { #[derive(Debug)] pub struct InlayHint { + /// The text range this inlay hint applies to. pub range: TextRange, + /// The kind of this inlay hint. This is used to determine side and padding of the hint for + /// rendering purposes. pub kind: InlayKind, + /// The actual label to show in the inlay hint. pub label: InlayHintLabel, + /// The tooltip to show when hovering over the inlay hint, this may invoke other actions like + /// hover requests to show. pub tooltip: Option, } @@ -117,7 +124,7 @@ pub enum InlayTooltip { #[derive(Default)] pub struct InlayHintLabel { - pub parts: Vec, + pub parts: SmallVec<[InlayHintLabelPart; 1]>, } impl InlayHintLabel { @@ -145,13 +152,13 @@ impl InlayHintLabel { impl From for InlayHintLabel { fn from(s: String) -> Self { - Self { parts: vec![InlayHintLabelPart { text: s, linked_location: None }] } + Self { parts: smallvec![InlayHintLabelPart { text: s, linked_location: None }] } } } impl From<&str> for InlayHintLabel { fn from(s: &str) -> Self { - Self { parts: vec![InlayHintLabelPart { text: s.into(), linked_location: None }] } + Self { parts: smallvec![InlayHintLabelPart { text: s.into(), linked_location: None }] } } } diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs index e340c64c54b5..12abefc140d5 100644 --- a/crates/ide/src/inlay_hints/closing_brace.rs +++ b/crates/ide/src/inlay_hints/closing_brace.rs @@ -5,6 +5,7 @@ //! ``` use hir::{HirDisplay, Semantics}; use ide_db::{base_db::FileRange, RootDatabase}; +use smallvec::smallvec; use syntax::{ ast::{self, AstNode, HasName}, match_ast, SyntaxKind, SyntaxNode, T, @@ -116,7 +117,9 @@ pub(super) fn hints( acc.push(InlayHint { range: closing_token.text_range(), kind: InlayKind::ClosingBraceHint, - label: InlayHintLabel { parts: vec![InlayHintLabelPart { text: label, linked_location }] }, + label: InlayHintLabel { + parts: smallvec![InlayHintLabelPart { text: label, linked_location }], + }, tooltip: None, // provided by label part location }); From e9724e55dfcbd6142a4a746e36bdd28f685072d6 Mon Sep 17 00:00:00 2001 From: bvanjoi Date: Sat, 14 Jan 2023 18:51:49 +0800 Subject: [PATCH 0823/2442] fix: check orpat in missing match --- .../src/handlers/add_missing_match_arms.rs | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 8e4ac69ae6f6..0461cc790eb3 100644 --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -269,6 +269,7 @@ fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool { (Pat::TuplePat(tpat), Pat::TuplePat(tvar)) => { tpat.fields().zip(tvar.fields()).all(|(p, v)| does_pat_match_variant(&p, &v)) } + (Pat::OrPat(opat), _) => opat.pats().any(|p| does_pat_match_variant(&p, var)), _ => utils::does_pat_match_variant(pat, var), } } @@ -525,6 +526,19 @@ fn foo(a: bool) { add_missing_match_arms, r#" fn foo(a: bool) { + match (a, a)$0 { + (true | false, true) => {} + (true, false) => {} + (false, false) => {} + } +} +"#, + ); + + check_assist_not_applicable( + add_missing_match_arms, + r#" +fn foo(a: bool) { match (a, a)$0 { (true, true) => {} (true, false) => {} @@ -565,6 +579,26 @@ fn foo(a: bool) { add_missing_match_arms, r#" fn foo(a: bool) { + match (a, a)$0 { + (true | false, true) => {} + } +} +"#, + r#" +fn foo(a: bool) { + match (a, a) { + (true | false, true) => {} + $0(true, false) => todo!(), + (false, false) => todo!(), + } +} +"#, + ); + + check_assist( + add_missing_match_arms, + r#" +fn foo(a: bool) { match (a, a)$0 { (false, true) => {} } @@ -882,6 +916,33 @@ fn main() { } "#, ); + + check_assist( + add_missing_match_arms, + r#" +enum E { A, B, C } +fn main() { + use E::*; + match (A, B, C)$0 { + (A | B , A, A | B | C) => (), + (A | B | C , B | C, A | B | C) => (), + } +} +"#, + r#" +enum E { A, B, C } +fn main() { + use E::*; + match (A, B, C) { + (A | B , A, A | B | C) => (), + (A | B | C , B | C, A | B | C) => (), + $0(C, A, A) => todo!(), + (C, A, B) => todo!(), + (C, A, C) => todo!(), + } +} +"#, + ) } #[test] From 60075a6625bb5d4064ef02123b84bd81e574c8e6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jan 2023 12:19:29 +0100 Subject: [PATCH 0824/2442] Remove hover inlay tooltips, replace them with location links --- crates/ide/src/inlay_hints.rs | 88 ++++++---- crates/ide/src/inlay_hints/adjustment.rs | 43 +---- crates/ide/src/inlay_hints/bind_pat.rs | 28 +--- crates/ide/src/inlay_hints/binding_mode.rs | 18 +- crates/ide/src/inlay_hints/chaining.rs | 158 +++--------------- crates/ide/src/inlay_hints/closing_brace.rs | 10 +- crates/ide/src/inlay_hints/closure_ret.rs | 5 +- crates/ide/src/inlay_hints/discriminant.rs | 23 ++- crates/ide/src/inlay_hints/fn_lifetime_fn.rs | 5 +- crates/ide/src/inlay_hints/implicit_static.rs | 3 +- crates/ide/src/inlay_hints/param_name.rs | 9 +- crates/ide/src/lib.rs | 3 +- crates/rust-analyzer/src/handlers.rs | 50 +----- crates/rust-analyzer/src/lsp_ext.rs | 7 +- crates/rust-analyzer/src/to_proto.rs | 117 ++++++------- 15 files changed, 187 insertions(+), 380 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index f4a9d7b653a2..108696673ef0 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -11,7 +11,7 @@ use smallvec::{smallvec, SmallVec}; use stdx::never; use syntax::{ ast::{self, AstNode}, - match_ast, NodeOrToken, SyntaxNode, TextRange, TextSize, + match_ast, NodeOrToken, SyntaxNode, TextRange, }; use crate::{navigation_target::TryToNav, FileId}; @@ -110,16 +110,21 @@ pub struct InlayHint { pub kind: InlayKind, /// The actual label to show in the inlay hint. pub label: InlayHintLabel, - /// The tooltip to show when hovering over the inlay hint, this may invoke other actions like - /// hover requests to show. - pub tooltip: Option, +} + +impl InlayHint { + fn closing_paren(range: TextRange) -> InlayHint { + InlayHint { range, kind: InlayKind::ClosingParenthesis, label: InlayHintLabel::from(")") } + } + fn opening_paren(range: TextRange) -> InlayHint { + InlayHint { range, kind: InlayKind::OpeningParenthesis, label: InlayHintLabel::from("(") } + } } #[derive(Debug)] pub enum InlayTooltip { String(String), - HoverRanged(FileId, TextRange), - HoverOffset(FileId, TextSize), + Markdown(String), } #[derive(Default)] @@ -128,37 +133,59 @@ pub struct InlayHintLabel { } impl InlayHintLabel { - pub fn as_simple_str(&self) -> Option<&str> { - match &*self.parts { - [part] => part.as_simple_str(), - _ => None, + pub fn simple( + s: impl Into, + tooltip: Option, + linked_location: Option, + ) -> InlayHintLabel { + InlayHintLabel { + parts: smallvec![InlayHintLabelPart { text: s.into(), linked_location, tooltip }], } } pub fn prepend_str(&mut self, s: &str) { match &mut *self.parts { - [part, ..] if part.as_simple_str().is_some() => part.text = format!("{s}{}", part.text), - _ => self.parts.insert(0, InlayHintLabelPart { text: s.into(), linked_location: None }), + [InlayHintLabelPart { text, linked_location: None, tooltip: None }, ..] => { + text.insert_str(0, s) + } + _ => self.parts.insert( + 0, + InlayHintLabelPart { text: s.into(), linked_location: None, tooltip: None }, + ), } } pub fn append_str(&mut self, s: &str) { match &mut *self.parts { - [.., part] if part.as_simple_str().is_some() => part.text.push_str(s), - _ => self.parts.push(InlayHintLabelPart { text: s.into(), linked_location: None }), + [.., InlayHintLabelPart { text, linked_location: None, tooltip: None }] => { + text.push_str(s) + } + _ => self.parts.push(InlayHintLabelPart { + text: s.into(), + linked_location: None, + tooltip: None, + }), } } } impl From for InlayHintLabel { fn from(s: String) -> Self { - Self { parts: smallvec![InlayHintLabelPart { text: s, linked_location: None }] } + Self { + parts: smallvec![InlayHintLabelPart { text: s, linked_location: None, tooltip: None }], + } } } impl From<&str> for InlayHintLabel { fn from(s: &str) -> Self { - Self { parts: smallvec![InlayHintLabelPart { text: s.into(), linked_location: None }] } + Self { + parts: smallvec![InlayHintLabelPart { + text: s.into(), + linked_location: None, + tooltip: None + }], + } } } @@ -182,25 +209,25 @@ pub struct InlayHintLabelPart { /// When setting this, no tooltip must be set on the containing hint, or VS Code will display /// them both. pub linked_location: Option, -} - -impl InlayHintLabelPart { - pub fn as_simple_str(&self) -> Option<&str> { - match self { - Self { text, linked_location: None } => Some(text), - _ => None, - } - } + /// The tooltip to show when hovering over the inlay hint, this may invoke other actions like + /// hover requests to show. + pub tooltip: Option, } impl fmt::Debug for InlayHintLabelPart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.as_simple_str() { - Some(string) => string.fmt(f), - None => f + match self { + Self { text, linked_location: None, tooltip: None } => text.fmt(f), + Self { text, linked_location, tooltip } => f .debug_struct("InlayHintLabelPart") - .field("text", &self.text) - .field("linked_location", &self.linked_location) + .field("text", text) + .field("linked_location", linked_location) + .field( + "tooltip", + &tooltip.as_ref().map_or("", |it| match it { + InlayTooltip::String(it) | InlayTooltip::Markdown(it) => it, + }), + ) .finish(), } } @@ -249,6 +276,7 @@ impl InlayHintLabelBuilder<'_> { self.result.parts.push(InlayHintLabelPart { text: take(&mut self.last_part), linked_location: self.location.take(), + tooltip: None, }); } diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index bdd7c05e008c..9c4caec605fe 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -44,27 +44,12 @@ pub(super) fn hints( mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode); if needs_outer_parens { - acc.push(InlayHint { - range: expr.syntax().text_range(), - kind: InlayKind::OpeningParenthesis, - label: "(".into(), - tooltip: None, - }); + acc.push(InlayHint::opening_paren(expr.syntax().text_range())); } if postfix && needs_inner_parens { - acc.push(InlayHint { - range: expr.syntax().text_range(), - kind: InlayKind::OpeningParenthesis, - label: "(".into(), - tooltip: None, - }); - acc.push(InlayHint { - range: expr.syntax().text_range(), - kind: InlayKind::ClosingParenthesis, - label: ")".into(), - tooltip: None, - }); + acc.push(InlayHint::opening_paren(expr.syntax().text_range())); + acc.push(InlayHint::closing_paren(expr.syntax().text_range())); } let (mut tmp0, mut tmp1); @@ -118,30 +103,14 @@ pub(super) fn hints( InlayKind::AdjustmentHint }, label: if postfix { format!(".{}", text.trim_end()).into() } else { text.into() }, - tooltip: None, }); } if !postfix && needs_inner_parens { - acc.push(InlayHint { - range: expr.syntax().text_range(), - kind: InlayKind::OpeningParenthesis, - label: "(".into(), - tooltip: None, - }); - acc.push(InlayHint { - range: expr.syntax().text_range(), - kind: InlayKind::ClosingParenthesis, - label: ")".into(), - tooltip: None, - }); + acc.push(InlayHint::opening_paren(expr.syntax().text_range())); + acc.push(InlayHint::closing_paren(expr.syntax().text_range())); } if needs_outer_parens { - acc.push(InlayHint { - range: expr.syntax().text_range(), - kind: InlayKind::ClosingParenthesis, - label: ")".into(), - tooltip: None, - }); + acc.push(InlayHint::closing_paren(expr.syntax().text_range())); } Some(()) } diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs index adec19c765a1..1a4bd353e773 100644 --- a/crates/ide/src/inlay_hints/bind_pat.rs +++ b/crates/ide/src/inlay_hints/bind_pat.rs @@ -12,9 +12,7 @@ use syntax::{ match_ast, }; -use crate::{ - inlay_hints::closure_has_block_body, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip, -}; +use crate::{inlay_hints::closure_has_block_body, InlayHint, InlayHintsConfig, InlayKind}; use super::label_of_ty; @@ -22,7 +20,7 @@ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: FileId, + _file_id: FileId, pat: &ast::IdentPat, ) -> Option<()> { if !config.type_hints { @@ -52,10 +50,6 @@ pub(super) fn hints( }, kind: InlayKind::TypeHint, label, - tooltip: pat - .name() - .map(|it| it.syntax().text_range()) - .map(|it| InlayTooltip::HoverRanged(file_id, it)), }); Some(()) @@ -326,14 +320,6 @@ fn main(a: SliceIter<'_, Container>) { label: [ "impl Iterator>", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 484..554, - ), - ), }, InlayHint { range: 484..485, @@ -350,6 +336,7 @@ fn main(a: SliceIter<'_, Container>) { range: 289..298, }, ), + tooltip: "", }, "<", InlayHintLabelPart { @@ -362,17 +349,10 @@ fn main(a: SliceIter<'_, Container>) { range: 238..247, }, ), + tooltip: "", }, ">", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 484..485, - ), - ), }, ] "#]], diff --git a/crates/ide/src/inlay_hints/binding_mode.rs b/crates/ide/src/inlay_hints/binding_mode.rs index a0166d0048ab..d0e42bc9141b 100644 --- a/crates/ide/src/inlay_hints/binding_mode.rs +++ b/crates/ide/src/inlay_hints/binding_mode.rs @@ -7,7 +7,7 @@ use ide_db::RootDatabase; use syntax::ast::{self, AstNode}; -use crate::{InlayHint, InlayHintsConfig, InlayKind, InlayTooltip}; +use crate::{InlayHint, InlayHintsConfig, InlayKind}; pub(super) fn hints( acc: &mut Vec, @@ -44,7 +44,6 @@ pub(super) fn hints( range, kind: InlayKind::BindingModeHint, label: r.to_string().into(), - tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), }); }); match pat { @@ -59,22 +58,11 @@ pub(super) fn hints( range: pat.syntax().text_range(), kind: InlayKind::BindingModeHint, label: bm.to_string().into(), - tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), }); } ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => { - acc.push(InlayHint { - range: pat.syntax().text_range(), - kind: InlayKind::OpeningParenthesis, - label: "(".into(), - tooltip: None, - }); - acc.push(InlayHint { - range: pat.syntax().text_range(), - kind: InlayKind::ClosingParenthesis, - label: ")".into(), - tooltip: None, - }); + acc.push(InlayHint::opening_paren(pat.syntax().text_range())); + acc.push(InlayHint::closing_paren(pat.syntax().text_range())); } _ => (), } diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index 8810d5d34dbd..c00fb83a88e1 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -5,7 +5,7 @@ use syntax::{ Direction, NodeOrToken, SyntaxKind, T, }; -use crate::{FileId, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip}; +use crate::{FileId, InlayHint, InlayHintsConfig, InlayKind}; use super::label_of_ty; @@ -13,7 +13,7 @@ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: FileId, + _file_id: FileId, expr: &ast::Expr, ) -> Option<()> { if !config.chaining_hints { @@ -61,7 +61,6 @@ pub(super) fn hints( range: expr.syntax().text_range(), kind: InlayKind::ChainingHint, label: label_of_ty(famous_defs, config, ty)?, - tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())), }); } } @@ -124,17 +123,10 @@ fn main() { range: 63..64, }, ), + tooltip: "", }, "", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 147..172, - ), - ), }, InlayHint { range: 147..154, @@ -151,17 +143,10 @@ fn main() { range: 7..8, }, ), + tooltip: "", }, "", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 147..154, - ), - ), }, ] "#]], @@ -214,14 +199,6 @@ fn main() { label: [ "C", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 143..190, - ), - ), }, InlayHint { range: 143..179, @@ -229,14 +206,6 @@ fn main() { label: [ "B", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 143..179, - ), - ), }, ] "#]], @@ -282,17 +251,10 @@ fn main() { range: 51..52, }, ), + tooltip: "", }, "", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 143..190, - ), - ), }, InlayHint { range: 143..179, @@ -309,17 +271,10 @@ fn main() { range: 29..30, }, ), + tooltip: "", }, "", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 143..179, - ), - ), }, ] "#]], @@ -366,6 +321,7 @@ fn main() { range: 23..24, }, ), + tooltip: "", }, "<", InlayHintLabelPart { @@ -378,17 +334,10 @@ fn main() { range: 55..56, }, ), + tooltip: "", }, ">", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 246..283, - ), - ), }, InlayHint { range: 246..265, @@ -405,6 +354,7 @@ fn main() { range: 7..8, }, ), + tooltip: "", }, "<", InlayHintLabelPart { @@ -417,17 +367,10 @@ fn main() { range: 55..56, }, ), + tooltip: "", }, ">", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 246..265, - ), - ), }, ] "#]], @@ -467,14 +410,6 @@ fn main() { label: [ "impl Iterator", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 174..241, - ), - ), }, InlayHint { range: 174..224, @@ -482,14 +417,6 @@ fn main() { label: [ "impl Iterator", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 174..224, - ), - ), }, InlayHint { range: 174..206, @@ -497,14 +424,6 @@ fn main() { label: [ "impl Iterator", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 174..206, - ), - ), }, InlayHint { range: 174..189, @@ -521,17 +440,10 @@ fn main() { range: 24..30, }, ), + tooltip: "", }, "", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 174..189, - ), - ), }, ] "#]], @@ -577,17 +489,10 @@ fn main() { range: 7..13, }, ), + tooltip: "", }, "", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 124..130, - ), - ), }, InlayHint { range: 145..185, @@ -604,17 +509,10 @@ fn main() { range: 7..13, }, ), + tooltip: "", }, "", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 145..185, - ), - ), }, InlayHint { range: 145..168, @@ -631,32 +529,28 @@ fn main() { range: 7..13, }, ), + tooltip: "", }, "", ], - tooltip: Some( - HoverRanged( - FileId( - 0, - ), - 145..168, - ), - ), }, InlayHint { range: 222..228, kind: ParameterHint, label: [ - "self", - ], - tooltip: Some( - HoverOffset( - FileId( - 0, + InlayHintLabelPart { + text: "self", + linked_location: Some( + FileRange { + file_id: FileId( + 0, + ), + range: 42..46, + }, ), - 42, - ), - ), + tooltip: "", + }, + ], }, ] "#]], diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs index 12abefc140d5..684d74282bd9 100644 --- a/crates/ide/src/inlay_hints/closing_brace.rs +++ b/crates/ide/src/inlay_hints/closing_brace.rs @@ -5,15 +5,12 @@ //! ``` use hir::{HirDisplay, Semantics}; use ide_db::{base_db::FileRange, RootDatabase}; -use smallvec::smallvec; use syntax::{ ast::{self, AstNode, HasName}, match_ast, SyntaxKind, SyntaxNode, T, }; -use crate::{ - inlay_hints::InlayHintLabelPart, FileId, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind, -}; +use crate::{FileId, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind}; pub(super) fn hints( acc: &mut Vec, @@ -117,10 +114,7 @@ pub(super) fn hints( acc.push(InlayHint { range: closing_token.text_range(), kind: InlayKind::ClosingBraceHint, - label: InlayHintLabel { - parts: smallvec![InlayHintLabelPart { text: label, linked_location }], - }, - tooltip: None, // provided by label part location + label: InlayHintLabel::simple(label, None, linked_location), }); None diff --git a/crates/ide/src/inlay_hints/closure_ret.rs b/crates/ide/src/inlay_hints/closure_ret.rs index d9929beaac0c..b1aa726ba5e2 100644 --- a/crates/ide/src/inlay_hints/closure_ret.rs +++ b/crates/ide/src/inlay_hints/closure_ret.rs @@ -4,7 +4,7 @@ use syntax::ast::{self, AstNode}; use crate::{ inlay_hints::closure_has_block_body, ClosureReturnTypeHints, InlayHint, InlayHintsConfig, - InlayKind, InlayTooltip, + InlayKind, }; use super::label_of_ty; @@ -13,7 +13,7 @@ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: FileId, + _file_id: FileId, closure: ast::ClosureExpr, ) -> Option<()> { if config.closure_return_type_hints == ClosureReturnTypeHints::Never { @@ -43,7 +43,6 @@ pub(super) fn hints( range: param_list.syntax().text_range(), kind: InlayKind::ClosureReturnTypeHint, label: label_of_ty(famous_defs, config, ty)?, - tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())), }); Some(()) } diff --git a/crates/ide/src/inlay_hints/discriminant.rs b/crates/ide/src/inlay_hints/discriminant.rs index f32c4bdf2883..6afc4b633070 100644 --- a/crates/ide/src/inlay_hints/discriminant.rs +++ b/crates/ide/src/inlay_hints/discriminant.rs @@ -7,7 +7,9 @@ use ide_db::{base_db::FileId, famous_defs::FamousDefs}; use syntax::ast::{self, AstNode, HasName}; -use crate::{DiscriminantHints, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip}; +use crate::{ + DiscriminantHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind, InlayTooltip, +}; pub(super) fn hints( acc: &mut Vec, @@ -42,14 +44,17 @@ pub(super) fn hints( None => name.syntax().text_range(), }, kind: InlayKind::DiscriminantHint, - label: match &d { - Ok(v) => format!("{}", v).into(), - Err(_) => "?".into(), - }, - tooltip: Some(InlayTooltip::String(match &d { - Ok(_) => "enum variant discriminant".into(), - Err(e) => format!("{e:?}").into(), - })), + label: InlayHintLabel::simple( + match &d { + Ok(v) => format!("{}", v), + Err(_) => "?".into(), + }, + Some(InlayTooltip::String(match &d { + Ok(_) => "enum variant discriminant".into(), + Err(e) => format!("{e:?}").into(), + })), + None, + ), }); Some(()) diff --git a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs index 2aa5e3dc734f..ce6f2e486c0b 100644 --- a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs +++ b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs @@ -10,7 +10,7 @@ use syntax::{ SyntaxToken, }; -use crate::{InlayHint, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints}; +use crate::{InlayHint, InlayHintsConfig, InlayKind, LifetimeElisionHints}; pub(super) fn hints( acc: &mut Vec, @@ -25,7 +25,6 @@ pub(super) fn hints( range: t.text_range(), kind: InlayKind::LifetimeHint, label: label.into(), - tooltip: Some(InlayTooltip::String("Elided lifetime".into())), }; let param_list = func.param_list()?; @@ -190,14 +189,12 @@ pub(super) fn hints( if is_empty { "" } else { ", " } ) .into(), - tooltip: Some(InlayTooltip::String("Elided lifetimes".into())), }); } (None, allocated_lifetimes) => acc.push(InlayHint { range: func.name()?.syntax().text_range(), kind: InlayKind::GenericParamListHint, label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(), - tooltip: Some(InlayTooltip::String("Elided lifetimes".into())), }), } Some(()) diff --git a/crates/ide/src/inlay_hints/implicit_static.rs b/crates/ide/src/inlay_hints/implicit_static.rs index 588a0e3b6a4b..f65b1d09a406 100644 --- a/crates/ide/src/inlay_hints/implicit_static.rs +++ b/crates/ide/src/inlay_hints/implicit_static.rs @@ -8,7 +8,7 @@ use syntax::{ SyntaxKind, }; -use crate::{InlayHint, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints}; +use crate::{InlayHint, InlayHintsConfig, InlayKind, LifetimeElisionHints}; pub(super) fn hints( acc: &mut Vec, @@ -34,7 +34,6 @@ pub(super) fn hints( range: t.text_range(), kind: InlayKind::LifetimeHint, label: "'static".to_owned().into(), - tooltip: Some(InlayTooltip::String("Elided static lifetime".into())), }); } } diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs index ecee67632e35..dbbc35d5893c 100644 --- a/crates/ide/src/inlay_hints/param_name.rs +++ b/crates/ide/src/inlay_hints/param_name.rs @@ -10,7 +10,7 @@ use ide_db::{base_db::FileRange, RootDatabase}; use stdx::to_lower_snake_case; use syntax::ast::{self, AstNode, HasArgList, HasName, UnaryOp}; -use crate::{InlayHint, InlayHintsConfig, InlayKind, InlayTooltip}; +use crate::{InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind}; pub(super) fn hints( acc: &mut Vec, @@ -43,12 +43,12 @@ pub(super) fn hints( !should_hide_param_name_hint(sema, &callable, param_name, arg) }) .map(|(param, param_name, _, FileRange { range, .. })| { - let mut tooltip = None; + let mut linked_location = None; if let Some(name) = param { if let hir::CallableKind::Function(f) = callable.kind() { // assert the file is cached so we can map out of macros if let Some(_) = sema.source(f) { - tooltip = sema.original_range_opt(name.syntax()); + linked_location = sema.original_range_opt(name.syntax()); } } } @@ -56,8 +56,7 @@ pub(super) fn hints( InlayHint { range, kind: InlayKind::ParameterHint, - label: param_name.into(), - tooltip: tooltip.map(|it| InlayTooltip::HoverOffset(it.file_id, it.range.start())), + label: InlayHintLabel::simple(param_name, None, linked_location), } }); diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 239456cb2816..8424d82aa183 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -82,7 +82,8 @@ pub use crate::{ hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult}, inlay_hints::{ AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint, - InlayHintLabel, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints, + InlayHintLabel, InlayHintLabelPart, InlayHintsConfig, InlayKind, InlayTooltip, + LifetimeElisionHints, }, join_lines::JoinLinesConfig, markup::Markup, diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 59bdd3061272..033ef75cca0d 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -29,7 +29,6 @@ use project_model::{ManifestPath, ProjectWorkspace, TargetKind}; use serde_json::json; use stdx::{format_to, never}; use syntax::{algo, ast, AstNode, TextRange, TextSize}; -use tracing::error; use vfs::AbsPathBuf; use crate::{ @@ -1360,55 +1359,10 @@ pub(crate) fn handle_inlay_hints( } pub(crate) fn handle_inlay_hints_resolve( - snap: GlobalStateSnapshot, - mut hint: InlayHint, + _snap: GlobalStateSnapshot, + hint: InlayHint, ) -> Result { let _p = profile::span("handle_inlay_hints_resolve"); - let data = match hint.data.take() { - Some(it) => it, - None => return Ok(hint), - }; - - let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?; - - match snap.url_file_version(&resolve_data.text_document.uri) { - Some(version) if version == resolve_data.text_document.version => {} - Some(version) => { - error!( - "attempted inlayHints/resolve of '{}' at version {} while server version is {}", - resolve_data.text_document.uri, resolve_data.text_document.version, version, - ); - return Ok(hint); - } - None => { - error!( - "attempted inlayHints/resolve of unknown file '{}' at version {}", - resolve_data.text_document.uri, resolve_data.text_document.version, - ); - return Ok(hint); - } - } - let file_range = from_proto::file_range_uri( - &snap, - &resolve_data.text_document.uri, - match resolve_data.position { - PositionOrRange::Position(pos) => Range::new(pos, pos), - PositionOrRange::Range(range) => range, - }, - )?; - let info = match snap.analysis.hover(&snap.config.hover(), file_range)? { - None => return Ok(hint), - Some(info) => info, - }; - - let markup_kind = - snap.config.hover().documentation.map_or(ide::HoverDocFormat::Markdown, |kind| kind); - - // FIXME: hover actions? - hint.tooltip = Some(lsp_types::InlayHintTooltip::MarkupContent(to_proto::markup_content( - info.info.markup, - markup_kind, - ))); Ok(hint) } diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 65620b4209b4..b117acd1b0f7 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -3,11 +3,11 @@ use std::{collections::HashMap, path::PathBuf}; use lsp_types::request::Request; +use lsp_types::PositionEncodingKind; use lsp_types::{ notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams, PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams, }; -use lsp_types::{PositionEncodingKind, VersionedTextDocumentIdentifier}; use serde::{Deserialize, Serialize}; pub enum AnalyzerStatus {} @@ -568,10 +568,7 @@ pub struct CompletionResolveData { } #[derive(Debug, Serialize, Deserialize)] -pub struct InlayHintResolveData { - pub text_document: VersionedTextDocumentIdentifier, - pub position: PositionOrRange, -} +pub struct InlayHintResolveData {} #[derive(Debug, Serialize, Deserialize)] pub struct CompletionImport { diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index e736b2ff9a3b..d9cbb2bc206a 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -9,9 +9,9 @@ use ide::{ Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint, - InlayHintLabel, InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, - Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, - TextSize, + InlayHintLabel, InlayHintLabelPart, InlayKind, Markup, NavigationTarget, ReferenceCategory, + RenameError, Runnable, Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, + TextEdit, TextRange, TextSize, }; use itertools::Itertools; use serde_json::to_value; @@ -438,6 +438,8 @@ pub(crate) fn inlay_hint( _ => {} } + let (label, tooltip) = inlay_hint_label(snap, inlay_hint.label)?; + Ok(lsp_types::InlayHint { position: match inlay_hint.kind { // before annotated thing @@ -481,7 +483,9 @@ pub(crate) fn inlay_hint( | InlayKind::TypeHint | InlayKind::DiscriminantHint | InlayKind::ClosingBraceHint => false, - InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"), + InlayKind::BindingModeHint => { + matches!(&label, lsp_types::InlayHintLabel::String(s) if s != "&") + } InlayKind::ParameterHint | InlayKind::LifetimeHint => true, }), kind: match inlay_hint.kind { @@ -500,68 +504,67 @@ pub(crate) fn inlay_hint( | InlayKind::ClosingBraceHint => None, }, text_edits: None, - data: (|| match inlay_hint.tooltip { - Some(ide::InlayTooltip::HoverOffset(file_id, offset)) => { - let uri = url(snap, file_id); - let line_index = snap.file_line_index(file_id).ok()?; - - let text_document = lsp_types::VersionedTextDocumentIdentifier { - version: snap.url_file_version(&uri)?, - uri, - }; - to_value(lsp_ext::InlayHintResolveData { - text_document, - position: lsp_ext::PositionOrRange::Position(position(&line_index, offset)), - }) - .ok() - } - Some(ide::InlayTooltip::HoverRanged(file_id, text_range)) => { - let uri = url(snap, file_id); - let text_document = lsp_types::VersionedTextDocumentIdentifier { - version: snap.url_file_version(&uri)?, - uri, - }; - let line_index = snap.file_line_index(file_id).ok()?; - to_value(lsp_ext::InlayHintResolveData { - text_document, - position: lsp_ext::PositionOrRange::Range(range(&line_index, text_range)), - }) - .ok() - } - _ => None, - })(), - tooltip: Some(match inlay_hint.tooltip { - Some(ide::InlayTooltip::String(s)) => lsp_types::InlayHintTooltip::String(s), - _ => lsp_types::InlayHintTooltip::String(inlay_hint.label.to_string()), - }), - label: inlay_hint_label(snap, inlay_hint.label)?, + data: None, + tooltip, + label, }) } fn inlay_hint_label( snap: &GlobalStateSnapshot, - label: InlayHintLabel, -) -> Cancellable { - Ok(match label.as_simple_str() { - Some(s) => lsp_types::InlayHintLabel::String(s.into()), - None => lsp_types::InlayHintLabel::LabelParts( - label + mut label: InlayHintLabel, +) -> Cancellable<(lsp_types::InlayHintLabel, Option)> { + let res = match &*label.parts { + [InlayHintLabelPart { linked_location: None, .. }] => { + let InlayHintLabelPart { text, tooltip, .. } = label.parts.pop().unwrap(); + ( + lsp_types::InlayHintLabel::String(text), + match tooltip { + Some(ide::InlayTooltip::String(s)) => { + Some(lsp_types::InlayHintTooltip::String(s)) + } + Some(ide::InlayTooltip::Markdown(s)) => { + Some(lsp_types::InlayHintTooltip::MarkupContent(lsp_types::MarkupContent { + kind: lsp_types::MarkupKind::Markdown, + value: s, + })) + } + None => None, + }, + ) + } + _ => { + let parts = label .parts .into_iter() .map(|part| { - Ok(lsp_types::InlayHintLabelPart { - value: part.text, - tooltip: None, - location: part - .linked_location - .map(|range| location(snap, range)) - .transpose()?, - command: None, - }) + part.linked_location.map(|range| location(snap, range)).transpose().map( + |location| lsp_types::InlayHintLabelPart { + value: part.text, + tooltip: match part.tooltip { + Some(ide::InlayTooltip::String(s)) => { + Some(lsp_types::InlayHintLabelPartTooltip::String(s)) + } + Some(ide::InlayTooltip::Markdown(s)) => { + Some(lsp_types::InlayHintLabelPartTooltip::MarkupContent( + lsp_types::MarkupContent { + kind: lsp_types::MarkupKind::Markdown, + value: s, + }, + )) + } + None => None, + }, + location, + command: None, + }, + ) }) - .collect::>>()?, - ), - }) + .collect::>()?; + (lsp_types::InlayHintLabel::LabelParts(parts), None) + } + }; + Ok(res) } static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1); From f2444b2a402f8d551152cb482686c7839574ac1d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jan 2023 12:20:12 +0100 Subject: [PATCH 0825/2442] Remove unnecessary Hint suffix on InlayKind variants --- crates/ide/src/inlay_hints.rs | 22 ++--- crates/ide/src/inlay_hints/adjustment.rs | 6 +- crates/ide/src/inlay_hints/bind_pat.rs | 6 +- crates/ide/src/inlay_hints/binding_mode.rs | 8 +- crates/ide/src/inlay_hints/chaining.rs | 34 +++---- crates/ide/src/inlay_hints/closing_brace.rs | 2 +- crates/ide/src/inlay_hints/closure_ret.rs | 2 +- crates/ide/src/inlay_hints/discriminant.rs | 2 +- crates/ide/src/inlay_hints/fn_lifetime_fn.rs | 6 +- crates/ide/src/inlay_hints/implicit_static.rs | 2 +- crates/ide/src/inlay_hints/param_name.rs | 2 +- crates/rust-analyzer/src/to_proto.rs | 88 +++++++++---------- docs/dev/lsp-extensions.md | 2 +- 13 files changed, 87 insertions(+), 95 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 108696673ef0..861bf1c66cbe 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -86,17 +86,17 @@ pub enum AdjustmentHintsMode { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum InlayKind { - BindingModeHint, - ChainingHint, - ClosingBraceHint, - ClosureReturnTypeHint, - GenericParamListHint, - AdjustmentHint, - AdjustmentHintPostfix, - LifetimeHint, - ParameterHint, - TypeHint, - DiscriminantHint, + BindingMode, + Chaining, + ClosingBrace, + ClosureReturnType, + GenericParamList, + Adjustment, + AdjustmentPostfix, + Lifetime, + Parameter, + Type, + Discriminant, OpeningParenthesis, ClosingParenthesis, } diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index 9c4caec605fe..581813f3b770 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -97,11 +97,7 @@ pub(super) fn hints( }; acc.push(InlayHint { range: expr.syntax().text_range(), - kind: if postfix { - InlayKind::AdjustmentHintPostfix - } else { - InlayKind::AdjustmentHint - }, + kind: if postfix { InlayKind::AdjustmentPostfix } else { InlayKind::Adjustment }, label: if postfix { format!(".{}", text.trim_end()).into() } else { text.into() }, }); } diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs index 1a4bd353e773..5227c651ff45 100644 --- a/crates/ide/src/inlay_hints/bind_pat.rs +++ b/crates/ide/src/inlay_hints/bind_pat.rs @@ -48,7 +48,7 @@ pub(super) fn hints( Some(name) => name.syntax().text_range(), None => pat.syntax().text_range(), }, - kind: InlayKind::TypeHint, + kind: InlayKind::Type, label, }); @@ -316,14 +316,14 @@ fn main(a: SliceIter<'_, Container>) { [ InlayHint { range: 484..554, - kind: ChainingHint, + kind: Chaining, label: [ "impl Iterator>", ], }, InlayHint { range: 484..485, - kind: ChainingHint, + kind: Chaining, label: [ "", InlayHintLabelPart { diff --git a/crates/ide/src/inlay_hints/binding_mode.rs b/crates/ide/src/inlay_hints/binding_mode.rs index d0e42bc9141b..11b9cd269bfa 100644 --- a/crates/ide/src/inlay_hints/binding_mode.rs +++ b/crates/ide/src/inlay_hints/binding_mode.rs @@ -40,11 +40,7 @@ pub(super) fn hints( (true, false) => "&", _ => return, }; - acc.push(InlayHint { - range, - kind: InlayKind::BindingModeHint, - label: r.to_string().into(), - }); + acc.push(InlayHint { range, kind: InlayKind::BindingMode, label: r.to_string().into() }); }); match pat { ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => { @@ -56,7 +52,7 @@ pub(super) fn hints( }; acc.push(InlayHint { range: pat.syntax().text_range(), - kind: InlayKind::BindingModeHint, + kind: InlayKind::BindingMode, label: bm.to_string().into(), }); } diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index c00fb83a88e1..e0045a53d746 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -59,7 +59,7 @@ pub(super) fn hints( } acc.push(InlayHint { range: expr.syntax().text_range(), - kind: InlayKind::ChainingHint, + kind: InlayKind::Chaining, label: label_of_ty(famous_defs, config, ty)?, }); } @@ -110,7 +110,7 @@ fn main() { [ InlayHint { range: 147..172, - kind: ChainingHint, + kind: Chaining, label: [ "", InlayHintLabelPart { @@ -130,7 +130,7 @@ fn main() { }, InlayHint { range: 147..154, - kind: ChainingHint, + kind: Chaining, label: [ "", InlayHintLabelPart { @@ -195,14 +195,14 @@ fn main() { [ InlayHint { range: 143..190, - kind: ChainingHint, + kind: Chaining, label: [ "C", ], }, InlayHint { range: 143..179, - kind: ChainingHint, + kind: Chaining, label: [ "B", ], @@ -238,7 +238,7 @@ fn main() { [ InlayHint { range: 143..190, - kind: ChainingHint, + kind: Chaining, label: [ "", InlayHintLabelPart { @@ -258,7 +258,7 @@ fn main() { }, InlayHint { range: 143..179, - kind: ChainingHint, + kind: Chaining, label: [ "", InlayHintLabelPart { @@ -308,7 +308,7 @@ fn main() { [ InlayHint { range: 246..283, - kind: ChainingHint, + kind: Chaining, label: [ "", InlayHintLabelPart { @@ -341,7 +341,7 @@ fn main() { }, InlayHint { range: 246..265, - kind: ChainingHint, + kind: Chaining, label: [ "", InlayHintLabelPart { @@ -406,28 +406,28 @@ fn main() { [ InlayHint { range: 174..241, - kind: ChainingHint, + kind: Chaining, label: [ "impl Iterator", ], }, InlayHint { range: 174..224, - kind: ChainingHint, + kind: Chaining, label: [ "impl Iterator", ], }, InlayHint { range: 174..206, - kind: ChainingHint, + kind: Chaining, label: [ "impl Iterator", ], }, InlayHint { range: 174..189, - kind: ChainingHint, + kind: Chaining, label: [ "&mut ", InlayHintLabelPart { @@ -476,7 +476,7 @@ fn main() { [ InlayHint { range: 124..130, - kind: TypeHint, + kind: Type, label: [ "", InlayHintLabelPart { @@ -496,7 +496,7 @@ fn main() { }, InlayHint { range: 145..185, - kind: ChainingHint, + kind: Chaining, label: [ "", InlayHintLabelPart { @@ -516,7 +516,7 @@ fn main() { }, InlayHint { range: 145..168, - kind: ChainingHint, + kind: Chaining, label: [ "", InlayHintLabelPart { @@ -536,7 +536,7 @@ fn main() { }, InlayHint { range: 222..228, - kind: ParameterHint, + kind: Parameter, label: [ InlayHintLabelPart { text: "self", diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs index 684d74282bd9..aae805f78d69 100644 --- a/crates/ide/src/inlay_hints/closing_brace.rs +++ b/crates/ide/src/inlay_hints/closing_brace.rs @@ -113,7 +113,7 @@ pub(super) fn hints( .flatten(); acc.push(InlayHint { range: closing_token.text_range(), - kind: InlayKind::ClosingBraceHint, + kind: InlayKind::ClosingBrace, label: InlayHintLabel::simple(label, None, linked_location), }); diff --git a/crates/ide/src/inlay_hints/closure_ret.rs b/crates/ide/src/inlay_hints/closure_ret.rs index b1aa726ba5e2..f03a18b8e960 100644 --- a/crates/ide/src/inlay_hints/closure_ret.rs +++ b/crates/ide/src/inlay_hints/closure_ret.rs @@ -41,7 +41,7 @@ pub(super) fn hints( } acc.push(InlayHint { range: param_list.syntax().text_range(), - kind: InlayKind::ClosureReturnTypeHint, + kind: InlayKind::ClosureReturnType, label: label_of_ty(famous_defs, config, ty)?, }); Some(()) diff --git a/crates/ide/src/inlay_hints/discriminant.rs b/crates/ide/src/inlay_hints/discriminant.rs index 6afc4b633070..310295cc3793 100644 --- a/crates/ide/src/inlay_hints/discriminant.rs +++ b/crates/ide/src/inlay_hints/discriminant.rs @@ -43,7 +43,7 @@ pub(super) fn hints( Some(field_list) => name.syntax().text_range().cover(field_list.syntax().text_range()), None => name.syntax().text_range(), }, - kind: InlayKind::DiscriminantHint, + kind: InlayKind::Discriminant, label: InlayHintLabel::simple( match &d { Ok(v) => format!("{}", v), diff --git a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs index ce6f2e486c0b..b7182085b312 100644 --- a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs +++ b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs @@ -23,7 +23,7 @@ pub(super) fn hints( let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint { range: t.text_range(), - kind: InlayKind::LifetimeHint, + kind: InlayKind::Lifetime, label: label.into(), }; @@ -182,7 +182,7 @@ pub(super) fn hints( let is_empty = gpl.generic_params().next().is_none(); acc.push(InlayHint { range: angle_tok.text_range(), - kind: InlayKind::LifetimeHint, + kind: InlayKind::Lifetime, label: format!( "{}{}", allocated_lifetimes.iter().format(", "), @@ -193,7 +193,7 @@ pub(super) fn hints( } (None, allocated_lifetimes) => acc.push(InlayHint { range: func.name()?.syntax().text_range(), - kind: InlayKind::GenericParamListHint, + kind: InlayKind::GenericParamList, label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(), }), } diff --git a/crates/ide/src/inlay_hints/implicit_static.rs b/crates/ide/src/inlay_hints/implicit_static.rs index f65b1d09a406..1122ee2e3925 100644 --- a/crates/ide/src/inlay_hints/implicit_static.rs +++ b/crates/ide/src/inlay_hints/implicit_static.rs @@ -32,7 +32,7 @@ pub(super) fn hints( let t = ty.amp_token()?; acc.push(InlayHint { range: t.text_range(), - kind: InlayKind::LifetimeHint, + kind: InlayKind::Lifetime, label: "'static".to_owned().into(), }); } diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs index dbbc35d5893c..9cdae6324104 100644 --- a/crates/ide/src/inlay_hints/param_name.rs +++ b/crates/ide/src/inlay_hints/param_name.rs @@ -55,7 +55,7 @@ pub(super) fn hints( InlayHint { range, - kind: InlayKind::ParameterHint, + kind: InlayKind::Parameter, label: InlayHintLabel::simple(param_name, None, linked_location), } }); diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index d9cbb2bc206a..0f0642bb4b56 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -431,10 +431,10 @@ pub(crate) fn inlay_hint( mut inlay_hint: InlayHint, ) -> Cancellable { match inlay_hint.kind { - InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"), - InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "), - InlayKind::ClosureReturnTypeHint => inlay_hint.label.prepend_str(" -> "), - InlayKind::DiscriminantHint => inlay_hint.label.prepend_str(" = "), + InlayKind::Parameter if render_colons => inlay_hint.label.append_str(":"), + InlayKind::Type if render_colons => inlay_hint.label.prepend_str(": "), + InlayKind::ClosureReturnType => inlay_hint.label.prepend_str(" -> "), + InlayKind::Discriminant => inlay_hint.label.prepend_str(" = "), _ => {} } @@ -444,64 +444,64 @@ pub(crate) fn inlay_hint( position: match inlay_hint.kind { // before annotated thing InlayKind::OpeningParenthesis - | InlayKind::ParameterHint - | InlayKind::AdjustmentHint - | InlayKind::BindingModeHint => position(line_index, inlay_hint.range.start()), + | InlayKind::Parameter + | InlayKind::Adjustment + | InlayKind::BindingMode => position(line_index, inlay_hint.range.start()), // after annotated thing - InlayKind::ClosureReturnTypeHint - | InlayKind::TypeHint - | InlayKind::DiscriminantHint - | InlayKind::ChainingHint - | InlayKind::GenericParamListHint + InlayKind::ClosureReturnType + | InlayKind::Type + | InlayKind::Discriminant + | InlayKind::Chaining + | InlayKind::GenericParamList | InlayKind::ClosingParenthesis - | InlayKind::AdjustmentHintPostfix - | InlayKind::LifetimeHint - | InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()), + | InlayKind::AdjustmentPostfix + | InlayKind::Lifetime + | InlayKind::ClosingBrace => position(line_index, inlay_hint.range.end()), }, padding_left: Some(match inlay_hint.kind { - InlayKind::TypeHint => !render_colons, - InlayKind::ChainingHint | InlayKind::ClosingBraceHint => true, + InlayKind::Type => !render_colons, + InlayKind::Chaining | InlayKind::ClosingBrace => true, InlayKind::ClosingParenthesis - | InlayKind::DiscriminantHint + | InlayKind::Discriminant | InlayKind::OpeningParenthesis - | InlayKind::BindingModeHint - | InlayKind::ClosureReturnTypeHint - | InlayKind::GenericParamListHint - | InlayKind::AdjustmentHint - | InlayKind::AdjustmentHintPostfix - | InlayKind::LifetimeHint - | InlayKind::ParameterHint => false, + | InlayKind::BindingMode + | InlayKind::ClosureReturnType + | InlayKind::GenericParamList + | InlayKind::Adjustment + | InlayKind::AdjustmentPostfix + | InlayKind::Lifetime + | InlayKind::Parameter => false, }), padding_right: Some(match inlay_hint.kind { InlayKind::ClosingParenthesis | InlayKind::OpeningParenthesis - | InlayKind::ChainingHint - | InlayKind::ClosureReturnTypeHint - | InlayKind::GenericParamListHint - | InlayKind::AdjustmentHint - | InlayKind::AdjustmentHintPostfix - | InlayKind::TypeHint - | InlayKind::DiscriminantHint - | InlayKind::ClosingBraceHint => false, - InlayKind::BindingModeHint => { + | InlayKind::Chaining + | InlayKind::ClosureReturnType + | InlayKind::GenericParamList + | InlayKind::Adjustment + | InlayKind::AdjustmentPostfix + | InlayKind::Type + | InlayKind::Discriminant + | InlayKind::ClosingBrace => false, + InlayKind::BindingMode => { matches!(&label, lsp_types::InlayHintLabel::String(s) if s != "&") } - InlayKind::ParameterHint | InlayKind::LifetimeHint => true, + InlayKind::Parameter | InlayKind::Lifetime => true, }), kind: match inlay_hint.kind { - InlayKind::ParameterHint => Some(lsp_types::InlayHintKind::PARAMETER), - InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => { + InlayKind::Parameter => Some(lsp_types::InlayHintKind::PARAMETER), + InlayKind::ClosureReturnType | InlayKind::Type | InlayKind::Chaining => { Some(lsp_types::InlayHintKind::TYPE) } InlayKind::ClosingParenthesis - | InlayKind::DiscriminantHint + | InlayKind::Discriminant | InlayKind::OpeningParenthesis - | InlayKind::BindingModeHint - | InlayKind::GenericParamListHint - | InlayKind::LifetimeHint - | InlayKind::AdjustmentHint - | InlayKind::AdjustmentHintPostfix - | InlayKind::ClosingBraceHint => None, + | InlayKind::BindingMode + | InlayKind::GenericParamList + | InlayKind::Lifetime + | InlayKind::Adjustment + | InlayKind::AdjustmentPostfix + | InlayKind::ClosingBrace => None, }, text_edits: None, data: None, diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index a4780af1a261..0f24ddbbc00e 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ [^\n]+\n/m, ""); } - let value; - if (errorCode) { - if (typeof diag.code === "string" || typeof diag.code === "number") { - value = diag.code; - } else { - value = diag.code?.value; - } - } diag.code = { target: vscode.Uri.from({ scheme: diagnostics.URI_SCHEME, @@ -153,7 +206,8 @@ export async function createClient( fragment: uri.toString(), query: idx.toString(), }), - value: value ?? "Click for full compiler diagnostic", + value: + errorCode && value ? value : "Click for full compiler diagnostic", }; } }); diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index c2dca733df8f..5515921ed149 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -82,6 +82,7 @@ export class Ctx { private state: PersistentState; private commandFactories: Record; private commandDisposables: Disposable[]; + private unlinkedFiles: vscode.Uri[]; get client() { return this._client; @@ -99,6 +100,7 @@ export class Ctx { this.clientSubscriptions = []; this.commandDisposables = []; this.commandFactories = commandFactories; + this.unlinkedFiles = []; this.state = new PersistentState(extCtx.globalState); this.config = new Config(extCtx); @@ -218,7 +220,8 @@ export class Ctx { this.outputChannel, initializationOptions, serverOptions, - this.config + this.config, + this.unlinkedFiles ); this.pushClientCleanup( this._client.onNotification(ra.serverStatus, (params) => From 6778d1a6ebf865250c83398c0b2a984413284c47 Mon Sep 17 00:00:00 2001 From: feniljain Date: Thu, 16 Mar 2023 22:52:35 +0530 Subject: [PATCH 1181/2442] feat: do not remove other variants, just push them down in list --- crates/ide-completion/src/completions.rs | 6 +----- crates/ide-completion/src/completions/expr.rs | 1 - crates/ide-completion/src/completions/pattern.rs | 1 - crates/ide-completion/src/render.rs | 13 ++++++++++++- crates/ide-completion/src/render/pattern.rs | 11 +++++++++-- crates/ide-completion/src/tests/record.rs | 2 ++ 6 files changed, 24 insertions(+), 10 deletions(-) diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index ec8a23e907c6..50be5c788fb2 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -536,7 +536,6 @@ fn enum_variants_with_paths( enum_: hir::Enum, impl_: &Option, cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath), - missing_variants: Option>, ) { let mut process_variant = |variant: Variant| { let self_path = hir::ModPath::from_segments( @@ -547,10 +546,7 @@ fn enum_variants_with_paths( cb(acc, ctx, variant, self_path); }; - let variants = match missing_variants { - Some(missing_variants) => missing_variants, - None => enum_.variants(ctx.db), - }; + let variants = enum_.variants(ctx.db); if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) { diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index 8946011280a9..3192b21cfb2e 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -208,7 +208,6 @@ pub(crate) fn complete_expr_path( |acc, ctx, variant, path| { acc.add_qualified_enum_variant(ctx, path_ctx, variant, path) }, - None, ); } } diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs index 6ad6a06f11ae..58d5bf114cca 100644 --- a/crates/ide-completion/src/completions/pattern.rs +++ b/crates/ide-completion/src/completions/pattern.rs @@ -58,7 +58,6 @@ pub(crate) fn complete_pattern( |acc, ctx, variant, path| { acc.add_qualified_variant_pat(ctx, pattern_ctx, variant, path); }, - Some(pattern_ctx.missing_variants.clone()), ); } } diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 86302cb0678f..eb2df395c4d5 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -32,11 +32,22 @@ pub(crate) struct RenderContext<'a> { completion: &'a CompletionContext<'a>, is_private_editable: bool, import_to_add: Option, + // For variants which are missing + // in match completion context + // + // Option -> only applicable for enums + // bool -> is enum variant missing or not? + is_variant_missing: Option, } impl<'a> RenderContext<'a> { pub(crate) fn new(completion: &'a CompletionContext<'a>) -> RenderContext<'a> { - RenderContext { completion, is_private_editable: false, import_to_add: None } + RenderContext { + completion, + is_private_editable: false, + import_to_add: None, + is_variant_missing: None, + } } pub(crate) fn private_editable(mut self, private_editable: bool) -> Self { diff --git a/crates/ide-completion/src/render/pattern.rs b/crates/ide-completion/src/render/pattern.rs index 37c65abba937..d70f02127d5c 100644 --- a/crates/ide-completion/src/render/pattern.rs +++ b/crates/ide-completion/src/render/pattern.rs @@ -43,7 +43,7 @@ pub(crate) fn render_struct_pat( } pub(crate) fn render_variant_pat( - ctx: RenderContext<'_>, + mut ctx: RenderContext<'_>, pattern_ctx: &PatternContext, path_ctx: Option<&PathCompletionCtx>, variant: hir::Variant, @@ -56,6 +56,11 @@ pub(crate) fn render_variant_pat( let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?; let enum_ty = variant.parent_enum(ctx.db()).ty(ctx.db()); + // Missing in context of match statement completions + if pattern_ctx.missing_variants.contains(&variant) { + ctx.is_variant_missing = Some(true); + } + let (name, escaped_name) = match path { Some(path) => (path.unescaped().to_string().into(), path.to_string().into()), None => { @@ -97,7 +102,9 @@ fn build_completion( ) -> CompletionItem { let mut relevance = ctx.completion_relevance(); - relevance.type_match = super::compute_type_match(ctx.completion, &adt_ty); + if let Some(true) = ctx.is_variant_missing { + relevance.type_match = super::compute_type_match(ctx.completion, &adt_ty); + } let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label); item.set_documentation(ctx.docs(def)) diff --git a/crates/ide-completion/src/tests/record.rs b/crates/ide-completion/src/tests/record.rs index 727114610e7b..2de42e8435e4 100644 --- a/crates/ide-completion/src/tests/record.rs +++ b/crates/ide-completion/src/tests/record.rs @@ -67,6 +67,7 @@ fn foo(baz: Baz) { ev Err ev Ok bn Baz::Bar Baz::Bar$0 + bn Baz::Foo Baz::Foo$0 bn Err(…) Err($1)$0 bn Ok(…) Ok($1)$0 kw mut @@ -93,6 +94,7 @@ fn foo(baz: Baz) { ev Err ev Ok bn Baz::Bar Baz::Bar$0 + bn Baz::Foo Baz::Foo$0 bn Err(…) Err($1)$0 bn Ok(…) Ok($1)$0 kw mut From b7b9ae59a081f0ecbd11d66e205307328cd5cfbe Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Wed, 8 Mar 2023 20:58:52 +0330 Subject: [PATCH 1182/2442] desugar `? operator` --- crates/hir-def/src/body.rs | 5 +- crates/hir-def/src/body/lower.rs | 93 +++++++++++++++++-- crates/hir-def/src/body/pretty.rs | 4 - crates/hir-def/src/expr.rs | 4 - crates/hir-def/src/lang_item.rs | 21 +++-- crates/hir-def/src/path.rs | 83 ++++++++++++----- crates/hir-def/src/path/lower.rs | 9 +- crates/hir-def/src/resolver.rs | 48 ++++++++-- crates/hir-ty/src/consteval.rs | 8 +- crates/hir-ty/src/consteval/tests.rs | 67 +++++++++++++ crates/hir-ty/src/db.rs | 4 + crates/hir-ty/src/diagnostics/unsafe_check.rs | 2 +- crates/hir-ty/src/infer.rs | 36 ++++--- crates/hir-ty/src/infer/expr.rs | 30 +++--- crates/hir-ty/src/infer/path.rs | 2 +- crates/hir-ty/src/lower.rs | 88 ++++++++++++------ crates/hir-ty/src/mir/eval.rs | 62 +++++++------ crates/hir-ty/src/mir/lower.rs | 18 +++- crates/hir-ty/src/mir/lower/as_place.rs | 2 +- crates/hir-ty/src/mir/pretty.rs | 1 + crates/hir-ty/src/utils.rs | 2 +- crates/hir/src/semantics.rs | 5 +- crates/hir/src/source_analyzer.rs | 34 +++---- .../handlers/replace_try_expr_with_match.rs | 6 +- crates/ide-assists/src/tests/generated.rs | 2 +- crates/ide/src/hover/tests.rs | 8 +- crates/test-utils/src/minicore.rs | 64 ++++++++++++- 27 files changed, 517 insertions(+), 191 deletions(-) diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index b70e658efd79..7f9b9476dcd9 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -391,7 +391,7 @@ impl Body { } }; let expander = Expander::new(db, file_id, module); - let (mut body, source_map) = Body::new(db, expander, params, body); + let (mut body, source_map) = Body::new(db, expander, params, body, module.krate); body.shrink_to_fit(); (Arc::new(body), Arc::new(source_map)) @@ -420,8 +420,9 @@ impl Body { expander: Expander, params: Option<(ast::ParamList, impl Iterator)>, body: Option, + krate: CrateId, ) -> (Body, BodySourceMap) { - lower::lower(db, expander, params, body) + lower::lower(db, expander, params, body, krate) } fn shrink_to_fit(&mut self) { diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index fedaf3955985..348b7589ff4f 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -3,6 +3,7 @@ use std::{mem, sync::Arc}; +use base_db::CrateId; use either::Either; use hir_expand::{ ast_id_map::AstIdMap, @@ -36,6 +37,7 @@ use crate::{ RecordFieldPat, RecordLitField, Statement, }, item_scope::BuiltinShadowMode, + lang_item::LangItem, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro, @@ -80,9 +82,11 @@ pub(super) fn lower( expander: Expander, params: Option<(ast::ParamList, impl Iterator)>, body: Option, + krate: CrateId, ) -> (Body, BodySourceMap) { ExprCollector { db, + krate, source_map: BodySourceMap::default(), ast_id_map: db.ast_id_map(expander.current_file_id), body: Body { @@ -107,6 +111,7 @@ struct ExprCollector<'a> { expander: Expander, ast_id_map: Arc, body: Body, + krate: CrateId, source_map: BodySourceMap, is_lowering_assignee_expr: bool, is_lowering_generator: bool, @@ -176,8 +181,7 @@ impl ExprCollector<'_> { self.source_map.expr_map.insert(src, id); id } - // desugared exprs don't have ptr, that's wrong and should be fixed - // somehow. + // FIXME: desugared exprs don't have ptr, that's wrong and should be fixed somehow. fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { self.body.exprs.alloc(expr) } @@ -199,6 +203,10 @@ impl ExprCollector<'_> { self.source_map.pat_map.insert(src, id); id } + // FIXME: desugared pats don't have ptr, that's wrong and should be fixed somehow. + fn alloc_pat_desugared(&mut self, pat: Pat) -> PatId { + self.body.pats.alloc(pat) + } fn missing_pat(&mut self) -> PatId { self.body.pats.alloc(Pat::Missing) } @@ -437,10 +445,7 @@ impl ExprCollector<'_> { let expr = self.collect_expr_opt(e.expr()); self.alloc_expr(Expr::Await { expr }, syntax_ptr) } - ast::Expr::TryExpr(e) => { - let expr = self.collect_expr_opt(e.expr()); - self.alloc_expr(Expr::Try { expr }, syntax_ptr) - } + ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e), ast::Expr::CastExpr(e) => { let expr = self.collect_expr_opt(e.expr()); let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty())); @@ -601,6 +606,82 @@ impl ExprCollector<'_> { }) } + fn collect_try_operator(&mut self, syntax_ptr: AstPtr, e: ast::TryExpr) -> ExprId { + let (try_branch, cf_continue, cf_break, try_from_residual) = 'if_chain: { + if let Some(try_branch) = LangItem::TryTraitBranch.path(self.db, self.krate) { + if let Some(cf_continue) = + LangItem::ControlFlowContinue.path(self.db, self.krate) + { + if let Some(cf_break) = + LangItem::ControlFlowBreak.path(self.db, self.krate) + { + if let Some(try_from_residual) = + LangItem::TryTraitFromResidual.path(self.db, self.krate) + { + break 'if_chain ( + try_branch, + cf_continue, + cf_break, + try_from_residual, + ); + } + } + } + } + // Some of the needed lang items are missing, so we can't desugar + return self.alloc_expr(Expr::Missing, syntax_ptr); + }; + let operand = self.collect_expr_opt(e.expr()); + let try_branch = self.alloc_expr(Expr::Path(try_branch), syntax_ptr.clone()); + let expr = self.alloc_expr( + Expr::Call { + callee: try_branch, + args: Box::new([operand]), + is_assignee_expr: false, + }, + syntax_ptr.clone(), + ); + let continue_binding = + self.alloc_binding(name![v1], BindingAnnotation::Unannotated); + let continue_bpat = + self.alloc_pat_desugared(Pat::Bind { id: continue_binding, subpat: None }); + self.add_definition_to_binding(continue_binding, continue_bpat); + let continue_arm = MatchArm { + pat: self.alloc_pat_desugared(Pat::TupleStruct { + path: Some(Box::new(cf_continue)), + args: Box::new([continue_bpat]), + ellipsis: None, + }), + guard: None, + expr: self.alloc_expr(Expr::Path(Path::from(name![v1])), syntax_ptr.clone()), + }; + let break_binding = self.alloc_binding(name![v1], BindingAnnotation::Unannotated); + let break_bpat = + self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None }); + self.add_definition_to_binding(break_binding, break_bpat); + let break_arm = MatchArm { + pat: self.alloc_pat_desugared(Pat::TupleStruct { + path: Some(Box::new(cf_break)), + args: Box::new([break_bpat]), + ellipsis: None, + }), + guard: None, + expr: { + let x = + self.alloc_expr(Expr::Path(Path::from(name![v1])), syntax_ptr.clone()); + let callee = + self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr.clone()); + let result = self.alloc_expr( + Expr::Call { callee, args: Box::new([x]), is_assignee_expr: false }, + syntax_ptr.clone(), + ); + self.alloc_expr(Expr::Return { expr: Some(result) }, syntax_ptr.clone()) + }, + }; + let arms = Box::new([continue_arm, break_arm]); + self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) + } + fn collect_macro_call( &mut self, mcall: ast::MacroCall, diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index 5a9b825a2530..c091ad0d150f 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -288,10 +288,6 @@ impl<'a> Printer<'a> { self.print_expr(*expr); w!(self, ".await"); } - Expr::Try { expr } => { - self.print_expr(*expr); - w!(self, "?"); - } Expr::Cast { expr, type_ref } => { self.print_expr(*expr); w!(self, " as "); diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs index 19fa6b25419e..5b8758224371 100644 --- a/crates/hir-def/src/expr.rs +++ b/crates/hir-def/src/expr.rs @@ -192,9 +192,6 @@ pub enum Expr { Await { expr: ExprId, }, - Try { - expr: ExprId, - }, Cast { expr: ExprId, type_ref: Interned, @@ -383,7 +380,6 @@ impl Expr { } Expr::Field { expr, .. } | Expr::Await { expr } - | Expr::Try { expr } | Expr::Cast { expr, .. } | Expr::Ref { expr, .. } | Expr::UnaryOp { expr, .. } diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 4096e0a38267..818054188bea 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -8,8 +8,8 @@ use rustc_hash::FxHashMap; use syntax::SmolStr; use crate::{ - db::DefDatabase, AdtId, AssocItemId, AttrDefId, CrateId, EnumId, EnumVariantId, FunctionId, - ImplId, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId, + db::DefDatabase, path::Path, AdtId, AssocItemId, AttrDefId, CrateId, EnumId, EnumVariantId, + FunctionId, ImplId, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -220,11 +220,6 @@ macro_rules! language_item_table { } } - /// Opposite of [`LangItem::name`] - pub fn from_name(name: &hir_expand::name::Name) -> Option { - Self::from_str(name.as_str()?) - } - /// Opposite of [`LangItem::name`] pub fn from_str(name: &str) -> Option { match name { @@ -236,6 +231,18 @@ macro_rules! language_item_table { } } +impl LangItem { + /// Opposite of [`LangItem::name`] + pub fn from_name(name: &hir_expand::name::Name) -> Option { + Self::from_str(name.as_str()?) + } + + pub fn path(&self, db: &dyn DefDatabase, start_crate: CrateId) -> Option { + let t = db.lang_item(start_crate, *self)?; + Some(Path::LangItem(t)) + } +} + language_item_table! { // Variant name, Name, Getter method name, Target Generic requirements; Sized, sized, sized_trait, Target::Trait, GenericRequirement::Exact(0); diff --git a/crates/hir-def/src/path.rs b/crates/hir-def/src/path.rs index f3197d1800f2..c67c29818f5b 100644 --- a/crates/hir-def/src/path.rs +++ b/crates/hir-def/src/path.rs @@ -8,6 +8,7 @@ use std::{ use crate::{ body::LowerCtx, + lang_item::LangItemTarget, type_ref::{ConstRefOrPath, LifetimeRef}, }; use hir_expand::name::Name; @@ -36,13 +37,19 @@ impl Display for ImportAlias { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Path { - /// Type based path like `::foo`. - /// Note that paths like `::foo` are desugared to `Trait::::foo`. - type_anchor: Option>, - mod_path: Interned, - /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`. - generic_args: Option>]>>, +pub enum Path { + /// A normal path + Normal { + /// Type based path like `::foo`. + /// Note that paths like `::foo` are desugared to `Trait::::foo`. + type_anchor: Option>, + mod_path: Interned, + /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`. + generic_args: Option>]>>, + }, + /// A link to a lang item. It is used in desugaring of things like `x?`. We can show these + /// links via a normal path since they might be private and not accessible in the usage place. + LangItem(LangItemTarget), } /// Generic arguments to a path segment (e.g. the `i32` in `Option`). This @@ -102,51 +109,77 @@ impl Path { ) -> Path { let generic_args = generic_args.into(); assert_eq!(path.len(), generic_args.len()); - Path { type_anchor: None, mod_path: Interned::new(path), generic_args: Some(generic_args) } + Path::Normal { + type_anchor: None, + mod_path: Interned::new(path), + generic_args: Some(generic_args), + } + } + + /// Converts a known mod path to `Path`. + pub fn from_known_path_with_no_generic(path: ModPath) -> Path { + Path::Normal { type_anchor: None, mod_path: Interned::new(path), generic_args: None } } pub fn kind(&self) -> &PathKind { - &self.mod_path.kind + match self { + Path::Normal { mod_path, .. } => &mod_path.kind, + Path::LangItem(_) => &PathKind::Abs, + } } pub fn type_anchor(&self) -> Option<&TypeRef> { - self.type_anchor.as_deref() + match self { + Path::Normal { type_anchor, .. } => type_anchor.as_deref(), + Path::LangItem(_) => None, + } } pub fn segments(&self) -> PathSegments<'_> { - let s = PathSegments { - segments: self.mod_path.segments(), - generic_args: self.generic_args.as_deref(), + let Path::Normal { mod_path, generic_args, .. } = self else { + return PathSegments { + segments: &[], + generic_args: None, + }; }; + let s = + PathSegments { segments: mod_path.segments(), generic_args: generic_args.as_deref() }; if let Some(generic_args) = s.generic_args { assert_eq!(s.segments.len(), generic_args.len()); } s } - pub fn mod_path(&self) -> &ModPath { - &self.mod_path + pub fn mod_path(&self) -> Option<&ModPath> { + match self { + Path::Normal { mod_path, .. } => Some(&mod_path), + Path::LangItem(_) => None, + } } pub fn qualifier(&self) -> Option { - if self.mod_path.is_ident() { + let Path::Normal { mod_path, generic_args, type_anchor } = self else { + return None; + }; + if mod_path.is_ident() { return None; } - let res = Path { - type_anchor: self.type_anchor.clone(), + let res = Path::Normal { + type_anchor: type_anchor.clone(), mod_path: Interned::new(ModPath::from_segments( - self.mod_path.kind, - self.mod_path.segments()[..self.mod_path.segments().len() - 1].iter().cloned(), + mod_path.kind, + mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(), )), - generic_args: self.generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()), + generic_args: generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()), }; Some(res) } pub fn is_self_type(&self) -> bool { - self.type_anchor.is_none() - && self.generic_args.as_deref().is_none() - && self.mod_path.is_Self() + let Path::Normal { mod_path, generic_args, type_anchor } = self else { + return false; + }; + type_anchor.is_none() && generic_args.as_deref().is_none() && mod_path.is_Self() } } @@ -222,7 +255,7 @@ impl GenericArgs { impl From for Path { fn from(name: Name) -> Path { - Path { + Path::Normal { type_anchor: None, mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))), generic_args: None, diff --git a/crates/hir-def/src/path/lower.rs b/crates/hir-def/src/path/lower.rs index b7542bd777d0..407f38daad4f 100644 --- a/crates/hir-def/src/path/lower.rs +++ b/crates/hir-def/src/path/lower.rs @@ -75,8 +75,11 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option>::Foo desugars to Trait::Foo Some(trait_ref) => { - let Path { mod_path, generic_args: path_generic_args, .. } = - Path::from_src(trait_ref.path()?, ctx)?; + let Path::Normal { mod_path, generic_args: path_generic_args, .. } = + Path::from_src(trait_ref.path()?, ctx)? else + { + return None; + }; let num_segments = mod_path.segments().len(); kind = mod_path.kind; @@ -157,7 +160,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option Option<(TypeNs, Option)> { + let path = match path { + Path::Normal { mod_path, .. } => mod_path, + Path::LangItem(l) => { + return Some(( + match *l { + LangItemTarget::Union(x) => TypeNs::AdtId(x.into()), + LangItemTarget::TypeAlias(x) => TypeNs::TypeAliasId(x), + LangItemTarget::Struct(x) => TypeNs::AdtId(x.into()), + LangItemTarget::EnumVariant(x) => TypeNs::EnumVariantId(x), + LangItemTarget::EnumId(x) => TypeNs::AdtId(x.into()), + LangItemTarget::Trait(x) => TypeNs::TraitId(x), + LangItemTarget::Function(_) + | LangItemTarget::ImplDef(_) + | LangItemTarget::Static(_) => return None, + }, + None, + )) + } + }; let first_name = path.segments().first()?; let skip_to_mod = path.kind != PathKind::Plain; if skip_to_mod { @@ -217,7 +237,7 @@ impl Resolver { pub fn resolve_path_in_type_ns_fully( &self, db: &dyn DefDatabase, - path: &ModPath, + path: &Path, ) -> Option { let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?; if unresolved.is_some() { @@ -245,8 +265,24 @@ impl Resolver { pub fn resolve_path_in_value_ns( &self, db: &dyn DefDatabase, - path: &ModPath, + path: &Path, ) -> Option { + let path = match path { + Path::Normal { mod_path, .. } => mod_path, + Path::LangItem(l) => { + return Some(ResolveValueResult::ValueNs(match *l { + LangItemTarget::Function(x) => ValueNs::FunctionId(x), + LangItemTarget::Static(x) => ValueNs::StaticId(x), + LangItemTarget::Struct(x) => ValueNs::StructId(x), + LangItemTarget::EnumVariant(x) => ValueNs::EnumVariantId(x), + LangItemTarget::Union(_) + | LangItemTarget::ImplDef(_) + | LangItemTarget::TypeAlias(_) + | LangItemTarget::Trait(_) + | LangItemTarget::EnumId(_) => return None, + })) + } + }; let n_segments = path.segments().len(); let tmp = name![self]; let first_name = if path.is_self() { &tmp } else { path.segments().first()? }; @@ -340,7 +376,7 @@ impl Resolver { pub fn resolve_path_in_value_ns_fully( &self, db: &dyn DefDatabase, - path: &ModPath, + path: &Path, ) -> Option { match self.resolve_path_in_value_ns(db, path)? { ResolveValueResult::ValueNs(it) => Some(it), @@ -441,7 +477,7 @@ impl Resolver { &Scope::ImplDefScope(impl_) => { if let Some(target_trait) = &db.impl_data(impl_).target_trait { if let Some(TypeNs::TraitId(trait_)) = - self.resolve_path_in_type_ns_fully(db, target_trait.path.mod_path()) + self.resolve_path_in_type_ns_fully(db, &target_trait.path) { traits.insert(trait_); } diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 5830c48988fe..fcb3445a5427 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -4,7 +4,7 @@ use base_db::CrateId; use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData}; use hir_def::{ expr::Expr, - path::ModPath, + path::Path, resolver::{Resolver, ValueNs}, type_ref::ConstRef, ConstId, EnumVariantId, @@ -72,7 +72,7 @@ impl From for ConstEvalError { pub(crate) fn path_to_const( db: &dyn HirDatabase, resolver: &Resolver, - path: &ModPath, + path: &Path, mode: ParamLoweringMode, args_lazy: impl FnOnce() -> Generics, debruijn: DebruijnIndex, @@ -89,7 +89,7 @@ pub(crate) fn path_to_const( Some(x) => ConstValue::BoundVar(BoundVar::new(debruijn, x)), None => { never!( - "Generic list doesn't contain this param: {:?}, {}, {:?}", + "Generic list doesn't contain this param: {:?}, {:?}, {:?}", args, path, p @@ -228,7 +228,7 @@ pub(crate) fn eval_to_const( let db = ctx.db; if let Expr::Path(p) = &ctx.body.exprs[expr] { let resolver = &ctx.resolver; - if let Some(c) = path_to_const(db, resolver, p.mod_path(), mode, args, debruijn) { + if let Some(c) = path_to_const(db, resolver, p, mode, args, debruijn) { return c; } } diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 6a29e8ce52e6..3bec2ee88bfa 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -801,6 +801,73 @@ fn options() { ); } +#[test] +fn from_trait() { + check_number( + r#" + //- minicore: from + struct E1(i32); + struct E2(i32); + + impl From for E2 { + fn from(E1(x): E1) -> Self { + E2(1000 * x) + } + } + const GOAL: i32 = { + let x: E2 = E1(2).into(); + x.0 + }; + "#, + 2000, + ); +} + +#[test] +fn try_operator() { + check_number( + r#" + //- minicore: option, try + const fn f(x: Option, y: Option) -> Option { + Some(x? * y?) + } + const fn g(x: Option, y: Option) -> i32 { + match f(x, y) { + Some(k) => k, + None => 5, + } + } + const GOAL: i32 = g(Some(10), Some(20)) + g(Some(30), None) + g(None, Some(40)) + g(None, None); + "#, + 215, + ); + check_number( + r#" + //- minicore: result, try, from + struct E1(i32); + struct E2(i32); + + impl From for E2 { + fn from(E1(x): E1) -> Self { + E2(1000 * x) + } + } + + const fn f(x: Result) -> Result { + Ok(x? * 10) + } + const fn g(x: Result) -> i32 { + match f(x) { + Ok(k) => 7 * k, + Err(E2(k)) => 5 * k, + } + } + const GOAL: i32 = g(Ok(2)) + g(Err(E1(3))); + "#, + 15140, + ); +} + #[test] fn or_pattern() { check_number( diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 304c78767f12..8f1af4c2f8e2 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -97,6 +97,10 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::lower::generic_predicates_query)] fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders]>; + #[salsa::invoke(crate::lower::trait_environment_for_body_query)] + #[salsa::transparent] + fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc; + #[salsa::invoke(crate::lower::trait_environment_query)] fn trait_environment(&self, def: GenericDefId) -> Arc; diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs index d25c0ccf00dc..664822ee6fb4 100644 --- a/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -73,7 +73,7 @@ fn walk_unsafe( } Expr::Path(path) => { let resolver = resolver_for_expr(db.upcast(), def, current); - let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path()); + let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path); if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial { if db.static_data(id).mutable { unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 7de5b4295fcc..00b5f7948ac4 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -25,16 +25,16 @@ use hir_def::{ expr::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, PatId}, lang_item::{LangItem, LangItemTarget}, layout::Integer, - path::Path, + path::{ModPath, Path}, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, type_ref::TypeRef, - AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, - ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId, + AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, ItemContainerId, Lookup, + TraitId, TypeAliasId, VariantId, }; use hir_expand::name::{name, Name}; use la_arena::ArenaMap; use rustc_hash::{FxHashMap, FxHashSet}; -use stdx::always; +use stdx::{always, never}; use crate::{ db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany, @@ -110,10 +110,7 @@ pub(crate) fn normalize(db: &dyn HirDatabase, owner: DefWithBodyId, ty: Ty) -> T if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) { return ty; } - let krate = owner.module(db.upcast()).krate(); - let trait_env = owner - .as_generic_def_id() - .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d)); + let trait_env = db.trait_environment_for_body(owner); let mut table = unify::InferenceTable::new(db, trait_env); let ty_with_vars = table.normalize_associated_types_in(ty); @@ -506,10 +503,7 @@ impl<'a> InferenceContext<'a> { body: &'a Body, resolver: Resolver, ) -> Self { - let krate = owner.module(db.upcast()).krate(); - let trait_env = owner - .as_generic_def_id() - .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d)); + let trait_env = db.trait_environment_for_body(owner); InferenceContext { result: InferenceResult::default(), table: unify::InferenceTable::new(db, trait_env.clone()), @@ -851,7 +845,7 @@ impl<'a> InferenceContext<'a> { // FIXME: this should resolve assoc items as well, see this example: // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 let (resolution, unresolved) = if value_ns { - match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path()) { + match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path) { Some(ResolveValueResult::ValueNs(value)) => match value { ValueNs::EnumVariantId(var) => { let substs = ctx.substs_from_path(path, var.into(), true); @@ -872,11 +866,15 @@ impl<'a> InferenceContext<'a> { None => return (self.err_ty(), None), } } else { - match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { + match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) { Some(it) => it, None => return (self.err_ty(), None), } }; + let Some(mod_path) = path.mod_path() else { + never!("resolver should always resolve lang item paths"); + return (self.err_ty(), None); + }; return match resolution { TypeNs::AdtId(AdtId::StructId(strukt)) => { let substs = ctx.substs_from_path(path, strukt.into(), true); @@ -900,7 +898,7 @@ impl<'a> InferenceContext<'a> { let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); let substs = generics.placeholder_subst(self.db); let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); - self.resolve_variant_on_alias(ty, unresolved, path) + self.resolve_variant_on_alias(ty, unresolved, mod_path) } TypeNs::TypeAliasId(it) => { let container = it.lookup(self.db.upcast()).container; @@ -917,7 +915,7 @@ impl<'a> InferenceContext<'a> { let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst) .fill_with_inference_vars(&mut self.table) .build(); - self.resolve_variant_on_alias(ty, unresolved, path) + self.resolve_variant_on_alias(ty, unresolved, mod_path) } TypeNs::AdtSelfType(_) => { // FIXME this could happen in array size expressions, once we're checking them @@ -953,9 +951,9 @@ impl<'a> InferenceContext<'a> { &mut self, ty: Ty, unresolved: Option, - path: &Path, + path: &ModPath, ) -> (Ty, Option) { - let remaining = unresolved.map(|x| path.segments().skip(x).len()).filter(|x| x > &0); + let remaining = unresolved.map(|x| path.segments()[x..].len()).filter(|x| x > &0); match remaining { None => { let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id { @@ -969,7 +967,7 @@ impl<'a> InferenceContext<'a> { (ty, variant) } Some(1) => { - let segment = path.mod_path().segments().last().unwrap(); + let segment = path.segments().last().unwrap(); // this could be an enum variant or associated type if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { let enum_data = self.db.enum_data(enum_id); diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index ee186673ee13..7bf227a27f28 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -601,21 +601,21 @@ impl<'a> InferenceContext<'a> { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); self.resolve_associated_type(inner_ty, self.resolve_future_future_output()) } - Expr::Try { expr } => { - let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); - if let Some(trait_) = self.resolve_lang_trait(LangItem::Try) { - if let Some(func) = self.db.trait_data(trait_).method_by_name(&name!(branch)) { - let subst = TyBuilder::subst_for_def(self.db, trait_, None) - .push(inner_ty.clone()) - .build(); - self.write_method_resolution(tgt_expr, func, subst.clone()); - } - let try_output = self.resolve_output_on(trait_); - self.resolve_associated_type(inner_ty, try_output) - } else { - self.err_ty() - } - } + // Expr::Try { expr } => { + // let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); + // if let Some(trait_) = self.resolve_lang_trait(LangItem::Try) { + // if let Some(func) = self.db.trait_data(trait_).method_by_name(&name!(branch)) { + // let subst = TyBuilder::subst_for_def(self.db, trait_, None) + // .push(inner_ty.clone()) + // .build(); + // self.write_method_resolution(tgt_expr, func, subst.clone()); + // } + // let try_output = self.resolve_output_on(trait_); + // self.resolve_associated_type(inner_ty, try_output) + // } else { + // self.err_ty() + // } + // } Expr::Cast { expr, type_ref } => { let cast_ty = self.make_ty(type_ref); // FIXME: propagate the "castable to" expectation diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 2267fedaa8e9..266e41018758 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -39,7 +39,7 @@ impl<'a> InferenceContext<'a> { } else { // FIXME: report error, unresolved first path segment let value_or_partial = - self.resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path())?; + self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?; match value_or_partial { ResolveValueResult::ValueNs(it) => (it, None), diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 23b15087e316..e7490087e762 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -25,12 +25,12 @@ use hir_def::{ TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, }, lang_item::{lang_attr, LangItem}, - path::{GenericArg, ModPath, Path, PathKind, PathSegment, PathSegments}, + path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{ConstRefOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef}, - AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, - HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StaticId, StructId, - TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, + AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, + GenericDefId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StaticId, + StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, }; use hir_expand::{name::Name, ExpandResult}; use intern::Interned; @@ -425,11 +425,10 @@ impl<'a> TyLoweringContext<'a> { if path.segments().len() > 1 { return None; } - let resolution = - match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { - Some((it, None)) => it, - _ => return None, - }; + let resolution = match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) { + Some((it, None)) => it, + _ => return None, + }; match resolution { TypeNs::GenericParam(param_id) => Some(param_id.into()), _ => None, @@ -608,7 +607,7 @@ impl<'a> TyLoweringContext<'a> { } let (resolution, remaining_index) = - match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { + match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) { Some(it) => it, None => return (TyKind::Error.intern(Interner), None), }; @@ -716,7 +715,7 @@ impl<'a> TyLoweringContext<'a> { resolved: ValueTyDefId, infer_args: bool, ) -> Substitution { - let last = path.segments().last().expect("path should have at least one segment"); + let last = path.segments().last(); let (segment, generic_def) = match resolved { ValueTyDefId::FunctionId(it) => (last, Some(it.into())), ValueTyDefId::StructId(it) => (last, Some(it.into())), @@ -732,13 +731,20 @@ impl<'a> TyLoweringContext<'a> { let len = path.segments().len(); let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx)); let segment = match penultimate { - Some(segment) if segment.args_and_bindings.is_some() => segment, + Some(segment) if segment.args_and_bindings.is_some() => Some(segment), _ => last, }; (segment, Some(var.parent.into())) } }; - self.substs_from_path_segment(segment, generic_def, infer_args, None) + if let Some(segment) = segment { + self.substs_from_path_segment(segment, generic_def, infer_args, None) + } else if let Some(generic_def) = generic_def { + // lang item + self.substs_from_args_and_bindings(None, Some(generic_def), infer_args, None) + } else { + Substitution::empty(Interner) + } } fn substs_from_path_segment( @@ -747,6 +753,21 @@ impl<'a> TyLoweringContext<'a> { def: Option, infer_args: bool, explicit_self_ty: Option, + ) -> Substitution { + self.substs_from_args_and_bindings( + segment.args_and_bindings, + def, + infer_args, + explicit_self_ty, + ) + } + + fn substs_from_args_and_bindings( + &self, + args_and_bindings: Option<&GenericArgs>, + def: Option, + infer_args: bool, + explicit_self_ty: Option, ) -> Substitution { // Remember that the item's own generic args come before its parent's. let mut substs = Vec::new(); @@ -780,7 +801,7 @@ impl<'a> TyLoweringContext<'a> { }; let mut had_explicit_args = false; - if let Some(generic_args) = &segment.args_and_bindings { + if let Some(generic_args) = &args_and_bindings { if !generic_args.has_self_type { fill_self_params(); } @@ -879,12 +900,11 @@ impl<'a> TyLoweringContext<'a> { path: &Path, explicit_self_ty: Option, ) -> Option { - let resolved = - match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path.mod_path())? { - // FIXME(trait_alias): We need to handle trait alias here. - TypeNs::TraitId(tr) => tr, - _ => return None, - }; + let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? { + // FIXME(trait_alias): We need to handle trait alias here. + TypeNs::TraitId(tr) => tr, + _ => return None, + }; let segment = path.segments().last().expect("path should have at least one segment"); Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty)) } @@ -1381,9 +1401,7 @@ pub(crate) fn generic_predicates_for_param_query( Some(it) => it, None => return true, }; - let tr = match resolver - .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()) - { + let tr = match resolver.resolve_path_in_type_ns_fully(db.upcast(), path) { Some(TypeNs::TraitId(tr)) => tr, _ => return false, }; @@ -1423,6 +1441,17 @@ pub(crate) fn generic_predicates_for_param_recover( Arc::new([]) } +pub(crate) fn trait_environment_for_body_query( + db: &dyn HirDatabase, + def: DefWithBodyId, +) -> Arc { + let Some(def) = def.as_generic_def_id() else { + let krate = def.module(db.upcast()).krate(); + return Arc::new(TraitEnvironment::empty(krate)); + }; + db.trait_environment(def) +} + pub(crate) fn trait_environment_query( db: &dyn HirDatabase, def: GenericDefId, @@ -1948,7 +1977,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( // as types. Maybe here is not the best place to do it, but // it works. if let TypeRef::Path(p) = t { - let p = p.mod_path(); + let p = p.mod_path()?; if p.kind == PathKind::Plain { if let [n] = p.segments() { let c = ConstRefOrPath::Path(n.clone()); @@ -1977,8 +2006,15 @@ pub(crate) fn const_or_path_to_chalk( ConstRefOrPath::Scalar(s) => intern_const_ref(db, s, expected_ty, resolver.krate()), ConstRefOrPath::Path(n) => { let path = ModPath::from_segments(PathKind::Plain, Some(n.clone())); - path_to_const(db, resolver, &path, mode, args, debruijn) - .unwrap_or_else(|| unknown_const(expected_ty)) + path_to_const( + db, + resolver, + &Path::from_known_path_with_no_generic(path), + mode, + args, + debruijn, + ) + .unwrap_or_else(|| unknown_const(expected_ty)) } } } diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index c5d843d9ebd8..1ff6e106021f 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1,6 +1,6 @@ //! This module provides a MIR interpreter, which is used in const eval. -use std::{borrow::Cow, collections::HashMap, iter}; +use std::{borrow::Cow, collections::HashMap, iter, sync::Arc}; use base_db::CrateId; use chalk_ir::{ @@ -24,7 +24,8 @@ use crate::{ layout::layout_of_ty, mapping::from_chalk, method_resolution::lookup_impl_method, - CallableDefId, Const, ConstScalar, Interner, MemoryMap, Substitution, Ty, TyBuilder, TyExt, + CallableDefId, Const, ConstScalar, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, + TyBuilder, TyExt, }; use super::{ @@ -34,6 +35,7 @@ use super::{ pub struct Evaluator<'a> { db: &'a dyn HirDatabase, + trait_env: Arc, stack: Vec, heap: Vec, crate_id: CrateId, @@ -217,8 +219,7 @@ pub fn interpret_mir( assert_placeholder_ty_is_unused: bool, ) -> Result { let ty = body.locals[return_slot()].ty.clone(); - let mut evaluator = - Evaluator::new(db, body.owner.module(db.upcast()).krate(), assert_placeholder_ty_is_unused); + let mut evaluator = Evaluator::new(db, body, assert_placeholder_ty_is_unused); let bytes = evaluator.interpret_mir_with_no_arg(&body)?; let memory_map = evaluator.create_memory_map( &bytes, @@ -231,13 +232,16 @@ pub fn interpret_mir( impl Evaluator<'_> { pub fn new<'a>( db: &'a dyn HirDatabase, - crate_id: CrateId, + body: &MirBody, assert_placeholder_ty_is_unused: bool, ) -> Evaluator<'a> { + let crate_id = body.owner.module(db.upcast()).krate(); + let trait_env = db.trait_environment_for_body(body.owner); Evaluator { stack: vec![0], heap: vec![0], db, + trait_env, crate_id, assert_placeholder_ty_is_unused, stack_depth_limit: 100, @@ -500,15 +504,9 @@ impl Evaluator<'_> { } else if let Some(x) = self.detect_lang_function(def) { self.exec_lang_item(x, arg_bytes)? } else { - let trait_env = { - let Some(d) = body.owner.as_generic_def_id() else { - not_supported!("trait resolving in non generic def id"); - }; - self.db.trait_environment(d) - }; let (imp, generic_args) = lookup_impl_method( self.db, - trait_env, + self.trait_env.clone(), def, generic_args.clone(), ); @@ -584,7 +582,7 @@ impl Evaluator<'_> { .to_owned()); } Terminator::Unreachable => { - return Err(MirEvalError::UndefinedBehavior("unreachable executed")) + return Err(MirEvalError::UndefinedBehavior("unreachable executed")); } _ => not_supported!("unknown terminator"), } @@ -710,8 +708,24 @@ impl Evaluator<'_> { let ty = self.place_ty(p, locals)?; let bytes = self.eval_place(p, locals)?.get(&self)?; let layout = self.layout(&ty)?; + let enum_id = 'b: { + match ty.kind(Interner) { + TyKind::Adt(e, _) => match e.0 { + AdtId::EnumId(e) => break 'b e, + _ => (), + }, + _ => (), + } + return Ok(Owned(0u128.to_le_bytes().to_vec())); + }; match layout.variants { - Variants::Single { .. } => Owned(0u128.to_le_bytes().to_vec()), + Variants::Single { index } => { + let r = self.db.const_eval_discriminant(EnumVariantId { + parent: enum_id, + local_id: index.0, + })?; + Owned(r.to_le_bytes().to_vec()) + } Variants::Multiple { tag, tag_encoding, .. } => { let Some(target_data_layout) = self.db.target_data_layout(self.crate_id) else { not_supported!("missing target data layout"); @@ -727,13 +741,6 @@ impl Evaluator<'_> { let tag = &bytes[offset..offset + size]; let candidate_discriminant = i128::from_le_bytes(pad16(tag, false)) .wrapping_sub(niche_start as i128); - let enum_id = match ty.kind(Interner) { - TyKind::Adt(e, _) => match e.0 { - AdtId::EnumId(e) => e, - _ => not_supported!("Non enum with multi variant layout"), - }, - _ => not_supported!("Non adt with multi variant layout"), - }; let enum_data = self.db.enum_data(enum_id); let result = 'b: { for (local_id, _) in enum_data.variants.iter() { @@ -790,8 +797,8 @@ impl Evaluator<'_> { Owned(result) } AggregateKind::Adt(x, subst) => { - let (size, variant_layout, tag) = - self.layout_of_variant(*x, subst.clone(), locals)?; + let subst = self.subst_filler(subst, locals); + let (size, variant_layout, tag) = self.layout_of_variant(*x, subst, locals)?; Owned(self.make_by_layout(size, &variant_layout, tag, values, locals)?) } }, @@ -1124,12 +1131,13 @@ impl Evaluator<'_> { } fn detect_lang_function(&self, def: FunctionId) -> Option { + use LangItem::*; let candidate = lang_attr(self.db.upcast(), def)?; - // filter normal lang functions out - if [LangItem::IntoIterIntoIter, LangItem::IteratorNext].contains(&candidate) { - return None; + // We want to execute these functions with special logic + if [PanicFmt, BeginPanic, SliceLen].contains(&candidate) { + return Some(candidate); } - Some(candidate) + None } fn create_memory_map(&self, bytes: &[u8], ty: &Ty, locals: &Locals<'_>) -> Result { diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index c4dd7c0ace46..3b9a31c772a5 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -13,7 +13,7 @@ use hir_def::{ layout::LayoutError, path::Path, resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, - DefWithBodyId, EnumVariantId, HasModule, + DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, TraitId, }; use hir_expand::name::Name; use la_arena::ArenaMap; @@ -50,6 +50,8 @@ pub enum MirLowerError { ConstEvalError(Box), LayoutError(LayoutError), IncompleteExpr, + /// Trying to lower a trait function, instead of an implementation + TraitFunctionDefinition(TraitId, Name), UnresolvedName(String), RecordLiteralWithoutPath, UnresolvedMethod, @@ -200,12 +202,21 @@ impl MirLowerCtx<'_> { mut current: BasicBlockId, ) -> Result> { match &self.body.exprs[expr_id] { - Expr::Missing => Err(MirLowerError::IncompleteExpr), + Expr::Missing => { + if let DefWithBodyId::FunctionId(f) = self.owner { + let assoc = self.db.lookup_intern_function(f); + if let ItemContainerId::TraitId(t) = assoc.container { + let name = &self.db.function_data(f).name; + return Err(MirLowerError::TraitFunctionDefinition(t, name.clone())); + } + } + Err(MirLowerError::IncompleteExpr) + }, Expr::Path(p) => { let unresolved_name = || MirLowerError::unresolved_path(self.db, p); let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id); let pr = resolver - .resolve_path_in_value_ns(self.db.upcast(), p.mod_path()) + .resolve_path_in_value_ns(self.db.upcast(), p) .ok_or_else(unresolved_name)?; let pr = match pr { ResolveValueResult::ValueNs(v) => v, @@ -608,7 +619,6 @@ impl MirLowerCtx<'_> { } } Expr::Await { .. } => not_supported!("await"), - Expr::Try { .. } => not_supported!("? operator"), Expr::Yeet { .. } => not_supported!("yeet"), Expr::TryBlock { .. } => not_supported!("try block"), Expr::Async { .. } => not_supported!("async block"), diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs index fe8147dcd3e7..b683dd7f90d6 100644 --- a/crates/hir-ty/src/mir/lower/as_place.rs +++ b/crates/hir-ty/src/mir/lower/as_place.rs @@ -125,7 +125,7 @@ impl MirLowerCtx<'_> { match &self.body.exprs[expr_id] { Expr::Path(p) => { let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id); - let Some(pr) = resolver.resolve_path_in_value_ns(self.db.upcast(), p.mod_path()) else { + let Some(pr) = resolver.resolve_path_in_value_ns(self.db.upcast(), p) else { return Err(MirLowerError::unresolved_path(self.db, p)); }; let pr = match pr { diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index ffc08b7e346c..70364d088231 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -77,6 +77,7 @@ impl Display for LocalName { impl<'a> MirPrettyCtx<'a> { fn for_body(&mut self) { + wln!(self, "// {:?}", self.body.owner); self.with_block(|this| { this.locals(); wln!(this); diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 34d957e26ef5..a6967414aa85 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -130,7 +130,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra WherePredicate::Lifetime { .. } => None, }) .filter(|(_, bound_modifier)| matches!(bound_modifier, TraitBoundModifier::None)) - .filter_map(|(path, _)| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { + .filter_map(|(path, _)| match resolver.resolve_path_in_type_ns_fully(db, path) { Some(TypeNs::TraitId(t)) => Some(t), _ => None, }) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 407ba6f65844..9709970db1ee 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1076,10 +1076,7 @@ impl<'db> SemanticsImpl<'db> { let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id); let ctx = body::LowerCtx::with_hygiene(self.db.upcast(), &hygiene); let hir_path = Path::from_src(path.clone(), &ctx)?; - match analyze - .resolver - .resolve_path_in_type_ns_fully(self.db.upcast(), hir_path.mod_path())? - { + match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? { TypeNs::TraitId(id) => Some(Trait { id }), _ => None, } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index c24d196e1b62..5b18e445727f 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -420,7 +420,10 @@ impl SourceAnalyzer { None } else { // Shorthand syntax, resolve to the local - let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone())); + let path = Path::from_known_path_with_no_generic(ModPath::from_segments( + PathKind::Plain, + once(local_name.clone()), + )); match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { Some(ValueNs::LocalBinding(binding_id)) => { Some(Local { binding_id, parent: self.resolver.body_owner()? }) @@ -461,7 +464,7 @@ impl SourceAnalyzer { ) -> Option { let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id); let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?; - self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into()) + self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()?).map(|it| it.into()) } pub(crate) fn resolve_bind_pat_to_const( @@ -801,15 +804,11 @@ impl SourceAnalyzer { func: FunctionId, substs: Substitution, ) -> FunctionId { - let krate = self.resolver.krate(); let owner = match self.resolver.body_owner() { Some(it) => it, None => return func, }; - let env = owner.as_generic_def_id().map_or_else( - || Arc::new(hir_ty::TraitEnvironment::empty(krate)), - |d| db.trait_environment(d), - ); + let env = db.trait_environment_for_body(owner); method_resolution::lookup_impl_method(db, env, func, substs).0 } @@ -819,15 +818,11 @@ impl SourceAnalyzer { const_id: ConstId, subs: Substitution, ) -> ConstId { - let krate = self.resolver.krate(); let owner = match self.resolver.body_owner() { Some(it) => it, None => return const_id, }; - let env = owner.as_generic_def_id().map_or_else( - || Arc::new(hir_ty::TraitEnvironment::empty(krate)), - |d| db.trait_environment(d), - ); + let env = db.trait_environment_for_body(owner); method_resolution::lookup_impl_const(db, env, const_id, subs).0 } @@ -946,7 +941,7 @@ pub(crate) fn resolve_hir_path_as_macro( resolver: &Resolver, path: &Path, ) -> Option { - resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(Into::into) + resolver.resolve_path_as_macro(db.upcast(), path.mod_path()?).map(Into::into) } fn resolve_hir_path_( @@ -962,8 +957,7 @@ fn resolve_hir_path_( res.map(|ty_ns| (ty_ns, path.segments().first())) } None => { - let (ty, remaining_idx) = - resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?; + let (ty, remaining_idx) = resolver.resolve_path_in_type_ns(db.upcast(), path)?; match remaining_idx { Some(remaining_idx) => { if remaining_idx + 1 == path.segments().len() { @@ -1019,7 +1013,7 @@ fn resolve_hir_path_( let body_owner = resolver.body_owner(); let values = || { - resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| { + resolver.resolve_path_in_value_ns_fully(db.upcast(), path).and_then(|val| { let res = match val { ValueNs::LocalBinding(binding_id) => { let var = Local { parent: body_owner?, binding_id }; @@ -1039,14 +1033,14 @@ fn resolve_hir_path_( let items = || { resolver - .resolve_module_path_in_items(db.upcast(), path.mod_path()) + .resolve_module_path_in_items(db.upcast(), path.mod_path()?) .take_types() .map(|it| PathResolution::Def(it.into())) }; let macros = || { resolver - .resolve_path_as_macro(db.upcast(), path.mod_path()) + .resolve_path_as_macro(db.upcast(), path.mod_path()?) .map(|def| PathResolution::Def(ModuleDef::Macro(def.into()))) }; @@ -1074,7 +1068,7 @@ fn resolve_hir_path_qualifier( path: &Path, ) -> Option { resolver - .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()) + .resolve_path_in_type_ns_fully(db.upcast(), &path) .map(|ty| match ty { TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()), @@ -1089,7 +1083,7 @@ fn resolve_hir_path_qualifier( }) .or_else(|| { resolver - .resolve_module_path_in_items(db.upcast(), path.mod_path()) + .resolve_module_path_in_items(db.upcast(), path.mod_path()?) .take_types() .map(|it| PathResolution::Def(it.into())) }) diff --git a/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs b/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs index 38fccb33829a..2e26f59d030f 100644 --- a/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs +++ b/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs @@ -20,7 +20,7 @@ use crate::assist_context::{AssistContext, Assists}; // Replaces a `try` expression with a `match` expression. // // ``` -// # //- minicore:option +// # //- minicore: try, option // fn handle() { // let pat = Some(true)$0?; // } @@ -111,7 +111,7 @@ mod tests { check_assist( replace_try_expr_with_match, r#" -//- minicore:option +//- minicore: try, option fn test() { let pat = Some(true)$0?; } @@ -132,7 +132,7 @@ fn test() { check_assist( replace_try_expr_with_match, r#" -//- minicore:result +//- minicore: try, from, result fn test() { let pat = Ok(true)$0?; } diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index e5a8d675a9ea..aff11367de9a 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -2352,7 +2352,7 @@ fn doctest_replace_try_expr_with_match() { check_doc_test( "replace_try_expr_with_match", r#####" -//- minicore:option +//- minicore: try, option fn handle() { let pat = Some(true)$0?; } diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 57bf0f9ad5f3..70ec915e9674 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -5009,7 +5009,7 @@ fn foo() { fn hover_try_expr_res() { check_hover_range( r#" -//- minicore:result +//- minicore: try, from, result struct FooError; fn foo() -> Result<(), FooError> { @@ -5023,7 +5023,7 @@ fn foo() -> Result<(), FooError> { ); check_hover_range( r#" -//- minicore:result +//- minicore: try, from, result struct FooError; struct BarError; @@ -5044,6 +5044,7 @@ fn foo() -> Result<(), FooError> { fn hover_try_expr() { check_hover_range( r#" +//- minicore: try struct NotResult(T, U); struct Short; struct Looooong; @@ -5061,6 +5062,7 @@ fn foo() -> NotResult<(), Looooong> { ); check_hover_range( r#" +//- minicore: try struct NotResult(T, U); struct Short; struct Looooong; @@ -5092,7 +5094,7 @@ fn foo() -> Option<()> { "#, expect![[r#" ```rust - as Try>::Output + i32 ```"#]], ); } diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index ca6de4061a4b..8dd9f306c8a6 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -181,7 +181,7 @@ pub mod convert { } // endregion:as_ref // region:infallible - pub enum Infallibe {} + pub enum Infallible {} // endregion:infallible } @@ -380,11 +380,15 @@ pub mod ops { // endregion:fn // region:try mod try_ { + use super::super::convert::Infallible; + pub enum ControlFlow { + #[lang = "Continue"] Continue(C), + #[lang = "Break"] Break(B), } - pub trait FromResidual { + pub trait FromResidual::Residual> { #[lang = "from_residual"] fn from_residual(residual: R) -> Self; } @@ -400,14 +404,66 @@ pub mod ops { impl Try for ControlFlow { type Output = C; - type Residual = ControlFlow; + type Residual = ControlFlow; fn from_output(output: Self::Output) -> Self {} fn branch(self) -> ControlFlow {} } impl FromResidual for ControlFlow { - fn from_residual(residual: ControlFlow) -> Self {} + fn from_residual(residual: ControlFlow) -> Self {} } + // region:option + impl Try for Option { + type Output = T; + type Residual = Option; + fn from_output(output: Self::Output) -> Self { + Some(output) + } + fn branch(self) -> ControlFlow { + match self { + Some(x) => ControlFlow::Continue(x), + None => ControlFlow::Break(None), + } + } + } + + impl FromResidual for Option { + fn from_residual(x: Option) -> Self { + match x { + None => None, + } + } + } + // endregion:option + // region:result + // region:from + use super::super::convert::From; + + impl Try for Result { + type Output = T; + type Residual = Result; + + fn from_output(output: Self::Output) -> Self { + Ok(output) + } + + fn branch(self) -> ControlFlow { + match self { + Ok(v) => ControlFlow::Continue(v), + Err(e) => ControlFlow::Break(Err(e)), + } + } + } + + impl> FromResidual> for Result { + fn from_residual(residual: Result) -> Self { + match residual { + Err(e) => Err(From::from(e)), + } + } + } + // endregion:from + // endregion:result } pub use self::try_::{ControlFlow, FromResidual, Try}; // endregion:try From 1b85b43e6f5283963e901597c67e89b82d90df01 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Wed, 8 Mar 2023 23:09:58 +0330 Subject: [PATCH 1183/2442] add mir-stats to analysis-stats --- .../rust-analyzer/src/cli/analysis_stats.rs | 23 +++++++++++++++++++ crates/rust-analyzer/src/cli/flags.rs | 3 +++ 2 files changed, 26 insertions(+) diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 6ce1de5d32bc..e1504743bfdb 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -2,6 +2,7 @@ //! errors. use std::{ + collections::HashMap, env, time::{SystemTime, UNIX_EPOCH}, }; @@ -153,6 +154,10 @@ impl flags::AnalysisStats { self.run_inference(&host, db, &vfs, &funcs, verbosity); } + if self.mir_stats { + self.lower_mir(db, &funcs); + } + let total_span = analysis_sw.elapsed(); eprintln!("{:<20} {total_span}", "Total:"); report_metric("total time", total_span.time.as_millis() as u64, "ms"); @@ -189,6 +194,24 @@ impl flags::AnalysisStats { Ok(()) } + fn lower_mir(&self, db: &RootDatabase, funcs: &[Function]) { + let all = funcs.len(); + let mut fail = 0; + let mut h: HashMap = HashMap::new(); + for f in funcs { + let f = FunctionId::from(*f); + let Err(e) = db.mir_body(f.into()) else { + continue; + }; + let es = format!("{:?}", e); + *h.entry(es).or_default() += 1; + fail += 1; + } + let h = h.into_iter().sorted_by_key(|x| x.1).collect::>(); + eprintln!("Mir failed reasons: {:#?}", h); + eprintln!("Mir failed bodies: {fail} ({}%)", fail * 100 / all); + } + fn run_inference( &self, host: &AnalysisHost, diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs index 770612cc9478..b085a0a892a5 100644 --- a/crates/rust-analyzer/src/cli/flags.rs +++ b/crates/rust-analyzer/src/cli/flags.rs @@ -66,6 +66,8 @@ xflags::xflags! { optional --memory-usage /// Print the total length of all source and macro files (whitespace is not counted). optional --source-stats + /// Print the number of bodies that fail to lower to mir, in addition to failed reasons. + optional --mir-stats /// Only analyze items matching this path. optional -o, --only path: String @@ -172,6 +174,7 @@ pub struct AnalysisStats { pub parallel: bool, pub memory_usage: bool, pub source_stats: bool, + pub mir_stats: bool, pub only: Option, pub with_deps: bool, pub no_sysroot: bool, From a063f000ff99989406abd1e6f58a9c2b576ba41a Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sat, 11 Mar 2023 21:43:53 +0330 Subject: [PATCH 1184/2442] Support function pointer MIR lowering --- crates/hir-expand/src/name.rs | 2 + crates/hir-ty/src/consteval/tests.rs | 102 ++++++ crates/hir-ty/src/infer.rs | 13 +- crates/hir-ty/src/infer/coerce.rs | 17 +- crates/hir-ty/src/infer/expr.rs | 35 +- crates/hir-ty/src/infer/unify.rs | 36 ++- crates/hir-ty/src/lib.rs | 6 +- crates/hir-ty/src/method_resolution.rs | 8 +- crates/hir-ty/src/mir/eval.rs | 299 ++++++++++++------ crates/hir-ty/src/mir/lower.rs | 46 +-- crates/hir-ty/src/mir/pretty.rs | 4 +- crates/hir-ty/src/tests/coercion.rs | 30 ++ crates/hir-ty/src/traits.rs | 9 + .../src/handlers/mutability_errors.rs | 25 ++ 14 files changed, 468 insertions(+), 164 deletions(-) diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index c3462beac73c..71eb35d9df8e 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -343,6 +343,8 @@ pub mod known { feature, // known methods of lang items call_once, + call_mut, + call, eq, ne, ge, diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 3bec2ee88bfa..8a9a5d254df8 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -906,6 +906,108 @@ fn or_pattern() { ); } +#[test] +fn function_pointer() { + check_number( + r#" + fn add2(x: u8) -> u8 { + x + 2 + } + const GOAL: u8 = { + let plus2 = add2; + plus2(3) + }; + "#, + 5, + ); + check_number( + r#" + fn add2(x: u8) -> u8 { + x + 2 + } + const GOAL: u8 = { + let plus2: fn(u8) -> u8 = add2; + plus2(3) + }; + "#, + 5, + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + fn add2(x: u8) -> u8 { + x + 2 + } + fn mult3(x: u8) -> u8 { + x * 3 + } + const GOAL: u8 = { + let x = [add2, mult3]; + x[0](1) + x[1](5) + }; + "#, + 18, + ); +} + +#[test] +fn function_traits() { + check_number( + r#" + //- minicore: fn + fn add2(x: u8) -> u8 { + x + 2 + } + fn call(f: impl Fn(u8) -> u8, x: u8) -> u8 { + f(x) + } + fn call_mut(mut f: impl FnMut(u8) -> u8, x: u8) -> u8 { + f(x) + } + fn call_once(f: impl FnOnce(u8) -> u8, x: u8) -> u8 { + f(x) + } + const GOAL: u8 = call(add2, 3) + call_mut(add2, 3) + call_once(add2, 3); + "#, + 15, + ); + check_number( + r#" + //- minicore: fn + fn add2(x: u8) -> u8 { + x + 2 + } + fn call(f: impl Fn(u8) -> u8, x: u8) -> u8 { + f(x) + } + fn call_mut(mut f: impl FnMut(u8) -> u8, x: u8) -> u8 { + f(x) + } + fn call_once(f: impl FnOnce(u8) -> u8, x: u8) -> u8 { + f(x) + } + const GOAL: u8 = { + let add2: fn(u8) -> u8 = add2; + call(add2, 3) + call_mut(add2, 3) + call_once(add2, 3) + }; + "#, + 15, + ); + check_number( + r#" + //- minicore: fn + fn add2(x: u8) -> u8 { + x + 2 + } + fn call(f: &&&&&impl Fn(u8) -> u8, x: u8) -> u8 { + f(x) + } + const GOAL: u8 = call(&&&&&add2, 3); + "#, + 5, + ); +} + #[test] fn array_and_index() { check_number( diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 00b5f7948ac4..06d74215fffb 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -38,9 +38,9 @@ use stdx::{always, never}; use crate::{ db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany, - lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal, - GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, Substitution, - TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, + lower::ImplTraitLoweringMode, static_lifetime, to_assoc_type_id, AliasEq, AliasTy, Const, + DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, + Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, }; // This lint has a false positive here. See the link below for details. @@ -273,6 +273,13 @@ pub struct Adjustment { pub target: Ty, } +impl Adjustment { + pub fn borrow(m: Mutability, ty: Ty) -> Self { + let ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner); + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty } + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Adjust { /// Go from ! to any type. diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs index 48c91530266d..6e899249b696 100644 --- a/crates/hir-ty/src/infer/coerce.rs +++ b/crates/hir-ty/src/infer/coerce.rs @@ -51,11 +51,12 @@ fn success( pub(super) struct CoerceMany { expected_ty: Ty, final_ty: Option, + expressions: Vec, } impl CoerceMany { pub(super) fn new(expected: Ty) -> Self { - CoerceMany { expected_ty: expected, final_ty: None } + CoerceMany { expected_ty: expected, final_ty: None, expressions: vec![] } } /// Returns the "expected type" with which this coercion was @@ -125,8 +126,15 @@ impl CoerceMany { let result1 = ctx.table.coerce_inner(self.merged_ty(), &target_ty); let result2 = ctx.table.coerce_inner(expr_ty.clone(), &target_ty); if let (Ok(result1), Ok(result2)) = (result1, result2) { - ctx.table.register_infer_ok(result1); - ctx.table.register_infer_ok(result2); + ctx.table.register_infer_ok(InferOk { value: (), goals: result1.goals }); + for &e in &self.expressions { + ctx.write_expr_adj(e, result1.value.0.clone()); + } + ctx.table.register_infer_ok(InferOk { value: (), goals: result2.goals }); + if let Some(expr) = expr { + ctx.write_expr_adj(expr, result2.value.0); + self.expressions.push(expr); + } return self.final_ty = Some(target_ty); } } @@ -148,6 +156,9 @@ impl CoerceMany { } cov_mark::hit!(coerce_merge_fail_fallback); } + if let Some(expr) = expr { + self.expressions.push(expr); + } } } diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 7bf227a27f28..ca285f2fec0a 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -34,6 +34,7 @@ use crate::{ method_resolution::{self, lang_items_for_bin_op, VisibleFromModule}, primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, + traits::FnTrait, utils::{generics, Generics}, Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, @@ -385,16 +386,32 @@ impl<'a> InferenceContext<'a> { || res.is_none(); let (param_tys, ret_ty) = match res { Some((func, params, ret_ty)) => { - let adjustments = auto_deref_adjust_steps(&derefs); - // FIXME: Handle call adjustments for Fn/FnMut - self.write_expr_adj(*callee, adjustments); - if let Some((trait_, func)) = func { - let subst = TyBuilder::subst_for_def(self.db, trait_, None) - .push(callee_ty.clone()) - .push(TyBuilder::tuple_with(params.iter().cloned())) - .build(); - self.write_method_resolution(tgt_expr, func, subst.clone()); + let mut adjustments = auto_deref_adjust_steps(&derefs); + if let Some(fn_x) = func { + match fn_x { + FnTrait::FnOnce => (), + FnTrait::FnMut => adjustments.push(Adjustment::borrow( + Mutability::Mut, + derefed_callee.clone(), + )), + FnTrait::Fn => adjustments.push(Adjustment::borrow( + Mutability::Not, + derefed_callee.clone(), + )), + } + let trait_ = fn_x + .get_id(self.db, self.trait_env.krate) + .expect("We just used it"); + let trait_data = self.db.trait_data(trait_); + if let Some(func) = trait_data.method_by_name(&fn_x.method_name()) { + let subst = TyBuilder::subst_for_def(self.db, trait_, None) + .push(callee_ty.clone()) + .push(TyBuilder::tuple_with(params.iter().cloned())) + .build(); + self.write_method_resolution(tgt_expr, func, subst.clone()); + } } + self.write_expr_adj(*callee, adjustments); (params, ret_ty) } None => { diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 504f0743aa94..2a07dd708c2a 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -8,16 +8,15 @@ use chalk_ir::{ }; use chalk_solve::infer::ParameterEnaVariableExt; use ena::unify::UnifyKey; -use hir_def::{FunctionId, TraitId}; use hir_expand::name; use stdx::never; use super::{InferOk, InferResult, InferenceContext, TypeError}; use crate::{ - db::HirDatabase, fold_tys, static_lifetime, traits::FnTrait, AliasEq, AliasTy, BoundVar, - Canonical, Const, DebruijnIndex, GenericArg, GenericArgData, Goal, Guidance, InEnvironment, - InferenceVar, Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution, - Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind, + db::HirDatabase, fold_tys, static_lifetime, to_chalk_trait_id, traits::FnTrait, AliasEq, + AliasTy, BoundVar, Canonical, Const, DebruijnIndex, GenericArg, GenericArgData, Goal, Guidance, + InEnvironment, InferenceVar, Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, + Scalar, Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind, }; impl<'a> InferenceContext<'a> { @@ -631,7 +630,7 @@ impl<'a> InferenceTable<'a> { &mut self, ty: &Ty, num_args: usize, - ) -> Option<(Option<(TraitId, FunctionId)>, Vec, Ty)> { + ) -> Option<(Option, Vec, Ty)> { match ty.callable_sig(self.db) { Some(sig) => Some((None, sig.params().to_vec(), sig.ret().clone())), None => self.callable_sig_from_fn_trait(ty, num_args), @@ -642,7 +641,7 @@ impl<'a> InferenceTable<'a> { &mut self, ty: &Ty, num_args: usize, - ) -> Option<(Option<(TraitId, FunctionId)>, Vec, Ty)> { + ) -> Option<(Option, Vec, Ty)> { let krate = self.trait_env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; let trait_data = self.db.trait_data(fn_once_trait); @@ -676,19 +675,28 @@ impl<'a> InferenceTable<'a> { }; let trait_env = self.trait_env.env.clone(); + let mut trait_ref = projection.trait_ref(self.db); let obligation = InEnvironment { - goal: projection.trait_ref(self.db).cast(Interner), - environment: trait_env, + goal: trait_ref.clone().cast(Interner), + environment: trait_env.clone(), }; let canonical = self.canonicalize(obligation.clone()); if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() { self.register_obligation(obligation.goal); let return_ty = self.normalize_projection_ty(projection); - Some(( - Some(fn_once_trait).zip(trait_data.method_by_name(&name!(call_once))), - arg_tys, - return_ty, - )) + for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { + let fn_x_trait = fn_x.get_id(self.db, krate)?; + trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); + let obligation: chalk_ir::InEnvironment> = InEnvironment { + goal: trait_ref.clone().cast(Interner), + environment: trait_env.clone(), + }; + let canonical = self.canonicalize(obligation.clone()); + if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() { + return Some((Some(fn_x), arg_tys, return_ty)); + } + } + unreachable!("It should at least implement FnOnce at this point"); } else { None } diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 9c63d67ab19a..782a8ab4aa2a 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -576,10 +576,14 @@ where } pub fn callable_sig_from_fnonce( - self_ty: &Ty, + mut self_ty: &Ty, env: Arc, db: &dyn HirDatabase, ) -> Option { + if let Some((ty, _, _)) = self_ty.as_reference() { + // This will happen when it implements fn or fn mut, since we add a autoborrow adjustment + self_ty = ty; + } let krate = env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index f3a27632bf54..f105c94086c9 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -20,7 +20,7 @@ use crate::{ autoderef::{self, AutoderefKind}, db::HirDatabase, from_chalk_trait_id, from_foreign_def_id, - infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast}, + infer::{unify::InferenceTable, Adjust, Adjustment, OverloadedDeref, PointerCast}, primitive::{FloatTy, IntTy, UintTy}, static_lifetime, to_chalk_trait_id, utils::all_super_traits, @@ -600,9 +600,9 @@ impl ReceiverAdjustments { } } if let Some(m) = self.autoref { - ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner); - adjust - .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty.clone() }); + let a = Adjustment::borrow(m, ty); + ty = a.target.clone(); + adjust.push(a); } if self.unsize_array { ty = 'x: { diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 1ff6e106021f..88ef92a4ae6c 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -11,7 +11,7 @@ use hir_def::{ builtin_type::BuiltinType, lang_item::{lang_attr, LangItem}, layout::{Layout, LayoutError, RustcEnumVariantIdx, TagEncoding, Variants}, - AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, Lookup, VariantId, + AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, VariantId, }; use intern::Interned; use la_arena::ArenaMap; @@ -24,8 +24,9 @@ use crate::{ layout::layout_of_ty, mapping::from_chalk, method_resolution::lookup_impl_method, - CallableDefId, Const, ConstScalar, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, - TyBuilder, TyExt, + traits::FnTrait, + CallableDefId, Const, ConstScalar, FnDefId, Interner, MemoryMap, Substitution, + TraitEnvironment, Ty, TyBuilder, TyExt, }; use super::{ @@ -33,11 +34,37 @@ use super::{ Operand, Place, ProjectionElem, Rvalue, StatementKind, Terminator, UnOp, }; +#[derive(Debug, Default)] +struct VTableMap { + ty_to_id: HashMap, + id_to_ty: Vec, +} + +impl VTableMap { + fn id(&mut self, ty: Ty) -> usize { + if let Some(x) = self.ty_to_id.get(&ty) { + return *x; + } + let id = self.id_to_ty.len(); + self.id_to_ty.push(ty.clone()); + self.ty_to_id.insert(ty, id); + id + } + + fn ty(&self, id: usize) -> Result<&Ty> { + self.id_to_ty.get(id).ok_or(MirEvalError::InvalidVTableId(id)) + } +} + pub struct Evaluator<'a> { db: &'a dyn HirDatabase, trait_env: Arc, stack: Vec, heap: Vec, + /// We don't really have function pointers, i.e. pointers to some assembly instructions that we can run. Instead, we + /// store the type as an interned id in place of function and vtable pointers, and we recover back the type at the + /// time of use. + vtable_map: VTableMap, crate_id: CrateId, // FIXME: This is a workaround, see the comment on `interpret_mir` assert_placeholder_ty_is_unused: bool, @@ -147,6 +174,7 @@ pub enum MirEvalError { ExecutionLimitExceeded, StackOverflow, TargetDataLayoutNotAvailable, + InvalidVTableId(usize), } impl std::fmt::Debug for MirEvalError { @@ -168,6 +196,7 @@ impl std::fmt::Debug for MirEvalError { Self::MirLowerError(arg0, arg1) => { f.debug_tuple("MirLowerError").field(arg0).field(arg1).finish() } + Self::InvalidVTableId(arg0) => f.debug_tuple("InvalidVTableId").field(arg0).finish(), Self::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(), Self::InvalidConst(arg0) => { let data = &arg0.data(Interner); @@ -240,6 +269,7 @@ impl Evaluator<'_> { Evaluator { stack: vec![0], heap: vec![0], + vtable_map: VTableMap::default(), db, trait_env, crate_id, @@ -461,108 +491,16 @@ impl Evaluator<'_> { } => { let fn_ty = self.operand_ty(func, &locals)?; match &fn_ty.data(Interner).kind { - TyKind::FnDef(def, generic_args) => { - let def: CallableDefId = from_chalk(self.db, *def); - let generic_args = self.subst_filler(generic_args, &locals); - match def { - CallableDefId::FunctionId(def) => { - let arg_bytes = args - .iter() - .map(|x| { - Ok(self - .eval_operand(x, &locals)? - .get(&self)? - .to_owned()) - }) - .collect::>>()? - .into_iter(); - let function_data = self.db.function_data(def); - let is_intrinsic = match &function_data.abi { - Some(abi) => *abi == Interned::new_str("rust-intrinsic"), - None => match def.lookup(self.db.upcast()).container { - hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db.upcast()).id; - id.item_tree(self.db.upcast())[id.value] - .abi - .as_deref() - == Some("rust-intrinsic") - } - _ => false, - }, - }; - let result = if is_intrinsic { - self.exec_intrinsic( - function_data - .name - .as_text() - .unwrap_or_default() - .as_str(), - arg_bytes, - generic_args, - &locals, - )? - } else if let Some(x) = self.detect_lang_function(def) { - self.exec_lang_item(x, arg_bytes)? - } else { - let (imp, generic_args) = lookup_impl_method( - self.db, - self.trait_env.clone(), - def, - generic_args.clone(), - ); - let generic_args = - self.subst_filler(&generic_args, &locals); - let def = imp.into(); - let mir_body = self - .db - .mir_body(def) - .map_err(|e| MirEvalError::MirLowerError(imp, e))?; - self.interpret_mir(&mir_body, arg_bytes, generic_args) - .map_err(|e| { - MirEvalError::InFunction(imp, Box::new(e)) - })? - }; - let dest_addr = self.place_addr(destination, &locals)?; - self.write_memory(dest_addr, &result)?; - } - CallableDefId::StructId(id) => { - let (size, variant_layout, tag) = self.layout_of_variant( - id.into(), - generic_args.clone(), - &locals, - )?; - let result = self.make_by_layout( - size, - &variant_layout, - tag, - args, - &locals, - )?; - let dest_addr = self.place_addr(destination, &locals)?; - self.write_memory(dest_addr, &result)?; - } - CallableDefId::EnumVariantId(id) => { - let (size, variant_layout, tag) = self.layout_of_variant( - id.into(), - generic_args.clone(), - &locals, - )?; - let result = self.make_by_layout( - size, - &variant_layout, - tag, - args, - &locals, - )?; - let dest_addr = self.place_addr(destination, &locals)?; - self.write_memory(dest_addr, &result)?; - } - } - current_block_idx = - target.expect("broken mir, function without target"); + TyKind::Function(_) => { + let bytes = self.eval_operand(func, &locals)?; + self.exec_fn_pointer(bytes, destination, args, &locals)?; } - _ => not_supported!("unknown function type"), + TyKind::FnDef(def, generic_args) => { + self.exec_fn_def(*def, generic_args, destination, args, &locals)?; + } + x => not_supported!("unknown function type {x:?}"), } + current_block_idx = target.expect("broken mir, function without target"); } Terminator::SwitchInt { discr, targets } => { let val = u128::from_le_bytes(pad16( @@ -808,6 +746,16 @@ impl Evaluator<'_> { not_supported!("creating pointer from exposed address") } CastKind::Pointer(cast) => match cast { + PointerCast::ReifyFnPointer => { + let current_ty = self.operand_ty(operand, locals)?; + if let TyKind::FnDef(_, _) = ¤t_ty.data(Interner).kind { + let id = self.vtable_map.id(current_ty); + let ptr_size = self.ptr_size(); + Owned(id.to_le_bytes()[0..ptr_size].to_vec()) + } else { + not_supported!("ReifyFnPointer cast of a non FnDef type"); + } + } PointerCast::Unsize => { let current_ty = self.operand_ty(operand, locals)?; match &target_ty.data(Interner).kind { @@ -920,7 +868,7 @@ impl Evaluator<'_> { size: usize, // Not neccessarily equal to variant_layout.size variant_layout: &Layout, tag: Option<(usize, usize, i128)>, - values: &Vec, + values: &[Operand], locals: &Locals<'_>, ) -> Result> { let mut result = vec![0; size]; @@ -1140,6 +1088,20 @@ impl Evaluator<'_> { None } + fn detect_fn_trait(&self, def: FunctionId) -> Option { + use LangItem::*; + let ItemContainerId::TraitId(parent) = self.db.lookup_intern_function(def).container else { + return None; + }; + let l = lang_attr(self.db.upcast(), parent)?; + match l { + FnOnce => Some(FnTrait::FnOnce), + FnMut => Some(FnTrait::FnMut), + Fn => Some(FnTrait::Fn), + _ => None, + } + } + fn create_memory_map(&self, bytes: &[u8], ty: &Ty, locals: &Locals<'_>) -> Result { // FIXME: support indirect references let mut mm = MemoryMap::default(); @@ -1228,7 +1190,134 @@ impl Evaluator<'_> { } } - pub(crate) fn exec_lang_item( + fn exec_fn_pointer( + &mut self, + bytes: Interval, + destination: &Place, + args: &[Operand], + locals: &Locals<'_>, + ) -> Result<()> { + let id = from_bytes!(usize, bytes.get(self)?); + let next_ty = self.vtable_map.ty(id)?.clone(); + if let TyKind::FnDef(def, generic_args) = &next_ty.data(Interner).kind { + self.exec_fn_def(*def, generic_args, destination, args, &locals)?; + } else { + return Err(MirEvalError::TypeError("function pointer to non function")); + } + Ok(()) + } + + fn exec_fn_def( + &mut self, + def: FnDefId, + generic_args: &Substitution, + destination: &Place, + args: &[Operand], + locals: &Locals<'_>, + ) -> Result<()> { + let def: CallableDefId = from_chalk(self.db, def); + let generic_args = self.subst_filler(generic_args, &locals); + match def { + CallableDefId::FunctionId(def) => { + let dest_addr = self.place_addr(destination, &locals)?; + if let Some(x) = self.detect_fn_trait(def) { + self.exec_fn_trait(x, &args, destination, locals)?; + return Ok(()); + } + let arg_bytes = args + .iter() + .map(|x| Ok(self.eval_operand(x, &locals)?.get(&self)?.to_owned())) + .collect::>>()? + .into_iter(); + let function_data = self.db.function_data(def); + let is_intrinsic = match &function_data.abi { + Some(abi) => *abi == Interned::new_str("rust-intrinsic"), + None => match def.lookup(self.db.upcast()).container { + hir_def::ItemContainerId::ExternBlockId(block) => { + let id = block.lookup(self.db.upcast()).id; + id.item_tree(self.db.upcast())[id.value].abi.as_deref() + == Some("rust-intrinsic") + } + _ => false, + }, + }; + let result = if is_intrinsic { + self.exec_intrinsic( + function_data.name.as_text().unwrap_or_default().as_str(), + arg_bytes, + generic_args, + &locals, + )? + } else if let Some(x) = self.detect_lang_function(def) { + self.exec_lang_item(x, arg_bytes)? + } else { + let (imp, generic_args) = lookup_impl_method( + self.db, + self.trait_env.clone(), + def, + generic_args.clone(), + ); + let generic_args = self.subst_filler(&generic_args, &locals); + let def = imp.into(); + let mir_body = + self.db.mir_body(def).map_err(|e| MirEvalError::MirLowerError(imp, e))?; + self.interpret_mir(&mir_body, arg_bytes, generic_args) + .map_err(|e| MirEvalError::InFunction(imp, Box::new(e)))? + }; + self.write_memory(dest_addr, &result)?; + } + CallableDefId::StructId(id) => { + let (size, variant_layout, tag) = + self.layout_of_variant(id.into(), generic_args.clone(), &locals)?; + let result = self.make_by_layout(size, &variant_layout, tag, args, &locals)?; + let dest_addr = self.place_addr(destination, &locals)?; + self.write_memory(dest_addr, &result)?; + } + CallableDefId::EnumVariantId(id) => { + let (size, variant_layout, tag) = + self.layout_of_variant(id.into(), generic_args.clone(), &locals)?; + let result = self.make_by_layout(size, &variant_layout, tag, args, &locals)?; + let dest_addr = self.place_addr(destination, &locals)?; + self.write_memory(dest_addr, &result)?; + } + } + Ok(()) + } + + fn exec_fn_trait( + &mut self, + ft: FnTrait, + args: &[Operand], + destination: &Place, + locals: &Locals<'_>, + ) -> Result<()> { + let func = args.get(0).ok_or(MirEvalError::TypeError("fn trait with no arg"))?; + let ref_func_ty = self.operand_ty(func, locals)?; + let func_ty = match ft { + FnTrait::FnOnce => ref_func_ty, + FnTrait::FnMut | FnTrait::Fn => match ref_func_ty.as_reference() { + Some(x) => x.0.clone(), + None => return Err(MirEvalError::TypeError("fn trait with non-reference arg")), + }, + }; + match &func_ty.data(Interner).kind { + TyKind::FnDef(def, subst) => { + self.exec_fn_def(*def, subst, destination, &args[1..], locals)?; + } + TyKind::Function(_) => { + let mut func_data = self.eval_operand(func, locals)?; + if let FnTrait::FnMut | FnTrait::Fn = ft { + let addr = Address::from_bytes(func_data.get(self)?)?; + func_data = Interval { addr, size: self.ptr_size() }; + } + self.exec_fn_pointer(func_data, destination, &args[1..], locals)?; + } + x => not_supported!("Call {ft:?} trait methods with type {x:?}"), + } + Ok(()) + } + + fn exec_lang_item( &self, x: LangItem, mut args: std::vec::IntoIter>, diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 3b9a31c772a5..7a5ca0894200 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -298,7 +298,7 @@ impl MirLowerCtx<'_> { ); Ok(Some(current)) } - ValueNs::StructId(_) => { + ValueNs::FunctionId(_) | ValueNs::StructId(_) => { // It's probably a unit struct or a zero sized function, so no action is needed. Ok(Some(current)) } @@ -445,36 +445,36 @@ impl MirLowerCtx<'_> { }) }, Expr::Call { callee, args, .. } => { + if let Some((func_id, generic_args)) = + self.infer.method_resolution(expr_id) { + let ty = chalk_ir::TyKind::FnDef( + CallableDefId::FunctionId(func_id).to_chalk(self.db), + generic_args, + ) + .intern(Interner); + let func = Operand::from_bytes(vec![], ty); + return self.lower_call_and_args( + func, + iter::once(*callee).chain(args.iter().copied()), + place, + current, + self.is_uninhabited(expr_id), + ); + } let callee_ty = self.expr_ty_after_adjustments(*callee); match &callee_ty.data(Interner).kind { chalk_ir::TyKind::FnDef(..) => { let func = Operand::from_bytes(vec![], callee_ty.clone()); self.lower_call_and_args(func, args.iter().copied(), place, current, self.is_uninhabited(expr_id)) } - TyKind::Scalar(_) - | TyKind::Tuple(_, _) - | TyKind::Array(_, _) - | TyKind::Adt(_, _) - | TyKind::Str - | TyKind::Foreign(_) - | TyKind::Slice(_) => { - return Err(MirLowerError::TypeError("function call on data type")) + chalk_ir::TyKind::Function(_) => { + let Some((func, current)) = self.lower_expr_to_some_operand(*callee, current)? else { + return Ok(None); + }; + self.lower_call_and_args(func, args.iter().copied(), place, current, self.is_uninhabited(expr_id)) } TyKind::Error => return Err(MirLowerError::MissingFunctionDefinition), - TyKind::AssociatedType(_, _) - | TyKind::Raw(_, _) - | TyKind::Ref(_, _, _) - | TyKind::OpaqueType(_, _) - | TyKind::Never - | TyKind::Closure(_, _) - | TyKind::Generator(_, _) - | TyKind::GeneratorWitness(_, _) - | TyKind::Placeholder(_) - | TyKind::Dyn(_) - | TyKind::Alias(_) - | TyKind::Function(_) - | TyKind::BoundVar(_) - | TyKind::InferenceVar(_, _) => not_supported!("dynamic function call"), + _ => return Err(MirLowerError::TypeError("function call on bad type")), } } Expr::MethodCall { receiver, args, .. } => { diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index 70364d088231..eb0002266dc5 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -301,9 +301,9 @@ impl<'a> MirPrettyCtx<'a> { w!(self, ")"); } Rvalue::Cast(ck, op, ty) => { - w!(self, "Discriminant({ck:?}"); + w!(self, "Cast({ck:?}, "); self.operand(op); - w!(self, "{})", ty.display(self.db)); + w!(self, ", {})", ty.display(self.db)); } Rvalue::CheckedBinaryOp(b, o1, o2) => { self.operand(o1); diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs index b524922b6cf4..696bdef03fcb 100644 --- a/crates/hir-ty/src/tests/coercion.rs +++ b/crates/hir-ty/src/tests/coercion.rs @@ -396,10 +396,40 @@ fn test() { ); } +#[test] +fn coerce_fn_item_to_fn_ptr_in_array() { + check_no_mismatches( + r" +fn foo(x: u32) -> isize { 1 } +fn bar(x: u32) -> isize { 1 } +fn test() { + let f = [foo, bar]; + // ^^^ adjustments: Pointer(ReifyFnPointer) +}", + ); +} + #[test] fn coerce_fn_items_in_match_arms() { cov_mark::check!(coerce_fn_reification); + check_no_mismatches( + r" +fn foo1(x: u32) -> isize { 1 } +fn foo2(x: u32) -> isize { 2 } +fn foo3(x: u32) -> isize { 3 } +fn test() { + let x = match 1 { + 1 => foo1, + // ^^^^ adjustments: Pointer(ReifyFnPointer) + 2 => foo2, + // ^^^^ adjustments: Pointer(ReifyFnPointer) + _ => foo3, + // ^^^^ adjustments: Pointer(ReifyFnPointer) + }; + x; +}", + ); check_types( r" fn foo1(x: u32) -> isize { 1 } diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index 3ab85c68f5b9..aebf59f31525 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -11,6 +11,7 @@ use hir_def::{ lang_item::{LangItem, LangItemTarget}, TraitId, }; +use hir_expand::name::{name, Name}; use stdx::panic_context; use crate::{ @@ -187,6 +188,14 @@ impl FnTrait { } } + pub fn method_name(&self) -> Name { + match self { + FnTrait::FnOnce => name!(call_once), + FnTrait::FnMut => name!(call_mut), + FnTrait::Fn => name!(call), + } + } + pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option { let target = db.lang_item(krate, self.lang_item())?; match target { diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 96470265d11d..03951ea2bf51 100644 --- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -631,6 +631,31 @@ fn f(inp: (Foo, Foo, Foo, Foo)) { ); } + #[test] + fn fn_traits() { + check_diagnostics( + r#" +//- minicore: fn +fn fn_ref(mut x: impl Fn(u8) -> u8) -> u8 { + //^^^^^ 💡 weak: variable does not need to be mutable + x(2) +} +fn fn_mut(x: impl FnMut(u8) -> u8) -> u8 { + x(2) + //^ 💡 error: cannot mutate immutable variable `x` +} +fn fn_borrow_mut(mut x: &mut impl FnMut(u8) -> u8) -> u8 { + //^^^^^ 💡 weak: variable does not need to be mutable + x(2) +} +fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 { + //^^^^^ 💡 weak: variable does not need to be mutable + x(2) +} +"#, + ); + } + #[test] fn respect_allow_unused_mut() { // FIXME: respect From 7525a38af5ebd9eef404b19a11cefe8a033f9d2d Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Tue, 14 Mar 2023 12:14:02 +0330 Subject: [PATCH 1185/2442] Support evaluating `dyn Trait` methods --- crates/hir-ty/src/consteval/tests.rs | 51 ++++++++ crates/hir-ty/src/method_resolution.rs | 39 +++++- crates/hir-ty/src/mir/eval.rs | 158 ++++++++++++++++--------- crates/hir-ty/src/mir/lower.rs | 9 +- 4 files changed, 197 insertions(+), 60 deletions(-) diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 8a9a5d254df8..f7914b578e43 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -1008,6 +1008,57 @@ fn function_traits() { ); } +#[test] +fn dyn_trait() { + check_number( + r#" + //- minicore: coerce_unsized, index, slice + trait Foo { + fn foo(&self) -> u8 { 10 } + } + struct S1; + struct S2; + struct S3; + impl Foo for S1 { + fn foo(&self) -> u8 { 1 } + } + impl Foo for S2 { + fn foo(&self) -> u8 { 2 } + } + impl Foo for S3 {} + const GOAL: u8 = { + let x: &[&dyn Foo] = &[&S1, &S2, &S3]; + x[0].foo() + x[1].foo() + x[2].foo() + }; + "#, + 13, + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + trait Foo { + fn foo(&self) -> i32 { 10 } + } + trait Bar { + fn bar(&self) -> i32 { 20 } + } + + struct S; + impl Foo for S { + fn foo(&self) -> i32 { 200 } + } + impl Bar for dyn Foo { + fn bar(&self) -> i32 { 700 } + } + const GOAL: i32 = { + let x: &dyn Foo = &S; + x.bar() + x.foo() + }; + "#, + 900, + ); +} + #[test] fn array_and_index() { check_number( diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index f105c94086c9..6244b98104fe 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -5,7 +5,7 @@ use std::{ops::ControlFlow, sync::Arc}; use base_db::{CrateId, Edition}; -use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex}; +use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause}; use hir_def::{ data::ImplData, item_scope::ItemScope, lang_item::LangItem, nameres::DefMap, AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, @@ -692,6 +692,38 @@ pub fn lookup_impl_const( .unwrap_or((const_id, subs)) } +/// Checks if the self parameter of `Trait` method is the `dyn Trait` and we should +/// call the method using the vtable. +pub fn is_dyn_method( + db: &dyn HirDatabase, + _env: Arc, + func: FunctionId, + fn_subst: Substitution, +) -> Option { + let ItemContainerId::TraitId(trait_id) = func.lookup(db.upcast()).container else { + return None; + }; + let trait_params = db.generic_params(trait_id.into()).type_or_consts.len(); + let fn_params = fn_subst.len(Interner) - trait_params; + let trait_ref = TraitRef { + trait_id: to_chalk_trait_id(trait_id), + substitution: Substitution::from_iter(Interner, fn_subst.iter(Interner).skip(fn_params)), + }; + let self_ty = trait_ref.self_type_parameter(Interner); + if let TyKind::Dyn(d) = self_ty.kind(Interner) { + let is_my_trait_in_bounds = d.bounds.skip_binders().as_slice(Interner).iter().any(|x| match x.skip_binders() { + // rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter + // what the generics are, we are sure that the method is come from the vtable. + WhereClause::Implemented(tr) => tr.trait_id == trait_ref.trait_id, + _ => false, + }); + if is_my_trait_in_bounds { + return Some(fn_params); + } + } + None +} + /// Looks up the impl method that actually runs for the trait method `func`. /// /// Returns `func` if it's not a method defined in a trait or the lookup failed. @@ -701,9 +733,8 @@ pub fn lookup_impl_method( func: FunctionId, fn_subst: Substitution, ) -> (FunctionId, Substitution) { - let trait_id = match func.lookup(db.upcast()).container { - ItemContainerId::TraitId(id) => id, - _ => return (func, fn_subst), + let ItemContainerId::TraitId(trait_id) = func.lookup(db.upcast()).container else { + return (func, fn_subst) }; let trait_params = db.generic_params(trait_id.into()).type_or_consts.len(); let fn_params = fn_subst.len(Interner) - trait_params; diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 88ef92a4ae6c..7293156a978f 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -23,10 +23,10 @@ use crate::{ infer::{normalize, PointerCast}, layout::layout_of_ty, mapping::from_chalk, - method_resolution::lookup_impl_method, + method_resolution::{is_dyn_method, lookup_impl_method}, traits::FnTrait, CallableDefId, Const, ConstScalar, FnDefId, Interner, MemoryMap, Substitution, - TraitEnvironment, Ty, TyBuilder, TyExt, + TraitEnvironment, Ty, TyBuilder, TyExt, GenericArgData, }; use super::{ @@ -34,6 +34,15 @@ use super::{ Operand, Place, ProjectionElem, Rvalue, StatementKind, Terminator, UnOp, }; +macro_rules! from_bytes { + ($ty:tt, $value:expr) => { + ($ty::from_le_bytes(match ($value).try_into() { + Ok(x) => x, + Err(_) => return Err(MirEvalError::TypeError("mismatched size")), + })) + }; +} + #[derive(Debug, Default)] struct VTableMap { ty_to_id: HashMap, @@ -54,6 +63,11 @@ impl VTableMap { fn ty(&self, id: usize) -> Result<&Ty> { self.id_to_ty.get(id).ok_or(MirEvalError::InvalidVTableId(id)) } + + fn ty_of_bytes(&self, bytes: &[u8]) -> Result<&Ty> { + let id = from_bytes!(usize, bytes); + self.ty(id) + } } pub struct Evaluator<'a> { @@ -110,15 +124,6 @@ impl IntervalOrOwned { } } -macro_rules! from_bytes { - ($ty:tt, $value:expr) => { - ($ty::from_le_bytes(match ($value).try_into() { - Ok(x) => x, - Err(_) => return Err(MirEvalError::TypeError("mismatched size")), - })) - }; -} - impl Address { fn from_bytes(x: &[u8]) -> Result { Ok(Address::from_usize(from_bytes!(usize, x))) @@ -781,7 +786,18 @@ impl Evaluator<'_> { } _ => not_supported!("slice unsizing from non pointers"), }, - TyKind::Dyn(_) => not_supported!("dyn pointer unsize cast"), + TyKind::Dyn(_) => match ¤t_ty.data(Interner).kind { + TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => { + let vtable = self.vtable_map.id(ty.clone()); + let addr = + self.eval_operand(operand, locals)?.get(&self)?; + let mut r = Vec::with_capacity(16); + r.extend(addr.iter().copied()); + r.extend(vtable.to_le_bytes().into_iter()); + Owned(r) + } + _ => not_supported!("dyn unsizing from non pointers"), + }, _ => not_supported!("unknown unsized cast"), } } @@ -1227,44 +1243,8 @@ impl Evaluator<'_> { let arg_bytes = args .iter() .map(|x| Ok(self.eval_operand(x, &locals)?.get(&self)?.to_owned())) - .collect::>>()? - .into_iter(); - let function_data = self.db.function_data(def); - let is_intrinsic = match &function_data.abi { - Some(abi) => *abi == Interned::new_str("rust-intrinsic"), - None => match def.lookup(self.db.upcast()).container { - hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db.upcast()).id; - id.item_tree(self.db.upcast())[id.value].abi.as_deref() - == Some("rust-intrinsic") - } - _ => false, - }, - }; - let result = if is_intrinsic { - self.exec_intrinsic( - function_data.name.as_text().unwrap_or_default().as_str(), - arg_bytes, - generic_args, - &locals, - )? - } else if let Some(x) = self.detect_lang_function(def) { - self.exec_lang_item(x, arg_bytes)? - } else { - let (imp, generic_args) = lookup_impl_method( - self.db, - self.trait_env.clone(), - def, - generic_args.clone(), - ); - let generic_args = self.subst_filler(&generic_args, &locals); - let def = imp.into(); - let mir_body = - self.db.mir_body(def).map_err(|e| MirEvalError::MirLowerError(imp, e))?; - self.interpret_mir(&mir_body, arg_bytes, generic_args) - .map_err(|e| MirEvalError::InFunction(imp, Box::new(e)))? - }; - self.write_memory(dest_addr, &result)?; + .collect::>>()?; + self.exec_fn_with_args(def, arg_bytes, generic_args, locals, dest_addr)?; } CallableDefId::StructId(id) => { let (size, variant_layout, tag) = @@ -1284,6 +1264,77 @@ impl Evaluator<'_> { Ok(()) } + fn exec_fn_with_args( + &mut self, + def: FunctionId, + arg_bytes: Vec>, + generic_args: Substitution, + locals: &Locals<'_>, + dest_addr: Address, + ) -> Result<()> { + let function_data = self.db.function_data(def); + let is_intrinsic = match &function_data.abi { + Some(abi) => *abi == Interned::new_str("rust-intrinsic"), + None => match def.lookup(self.db.upcast()).container { + hir_def::ItemContainerId::ExternBlockId(block) => { + let id = block.lookup(self.db.upcast()).id; + id.item_tree(self.db.upcast())[id.value].abi.as_deref() + == Some("rust-intrinsic") + } + _ => false, + }, + }; + let result = if is_intrinsic { + self.exec_intrinsic( + function_data.name.as_text().unwrap_or_default().as_str(), + arg_bytes.iter().cloned(), + generic_args, + &locals, + )? + } else if let Some(x) = self.detect_lang_function(def) { + self.exec_lang_item(x, &arg_bytes)? + } else { + if let Some(self_ty_idx) = + is_dyn_method(self.db, self.trait_env.clone(), def, generic_args.clone()) + { + // In the layout of current possible receiver, which at the moment of writing this code is one of + // `&T`, `&mut T`, `Box`, `Rc`, `Arc`, and `Pin

` where `P` is one of possible recievers, + // the vtable is exactly in the `[ptr_size..2*ptr_size]` bytes. So we can use it without branching on + // the type. + let ty = self + .vtable_map + .ty_of_bytes(&arg_bytes[0][self.ptr_size()..self.ptr_size() * 2])?; + let ty = GenericArgData::Ty(ty.clone()).intern(Interner); + let mut args_for_target = arg_bytes; + args_for_target[0] = args_for_target[0][0..self.ptr_size()].to_vec(); + let generics_for_target = Substitution::from_iter( + Interner, + generic_args + .iter(Interner) + .enumerate() + .map(|(i, x)| if i == self_ty_idx { &ty } else { x }) + ); + return self.exec_fn_with_args( + def, + args_for_target, + generics_for_target, + locals, + dest_addr, + ); + } + let (imp, generic_args) = + lookup_impl_method(self.db, self.trait_env.clone(), def, generic_args.clone()); + let generic_args = self.subst_filler(&generic_args, &locals); + let def = imp.into(); + let mir_body = + self.db.mir_body(def).map_err(|e| MirEvalError::MirLowerError(imp, e))?; + self.interpret_mir(&mir_body, arg_bytes.iter().cloned(), generic_args) + .map_err(|e| MirEvalError::InFunction(imp, Box::new(e)))? + }; + self.write_memory(dest_addr, &result)?; + Ok(()) + } + fn exec_fn_trait( &mut self, ft: FnTrait, @@ -1317,12 +1368,9 @@ impl Evaluator<'_> { Ok(()) } - fn exec_lang_item( - &self, - x: LangItem, - mut args: std::vec::IntoIter>, - ) -> Result> { + fn exec_lang_item(&self, x: LangItem, args: &[Vec]) -> Result> { use LangItem::*; + let mut args = args.iter(); match x { PanicFmt | BeginPanic => Err(MirEvalError::Panic), SliceLen => { diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 7a5ca0894200..4fc3c67a6e1e 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -230,7 +230,14 @@ impl MirLowerCtx<'_> { self.lower_const(c, current, place, expr_id.into())?; return Ok(Some(current)) }, - _ => not_supported!("associated functions and types"), + hir_def::AssocItemId::FunctionId(_) => { + // FnDefs are zero sized, no action is needed. + return Ok(Some(current)) + } + hir_def::AssocItemId::TypeAliasId(_) => { + // FIXME: If it is unreachable, use proper error instead of `not_supported`. + not_supported!("associated functions and types") + }, } } else if let Some(variant) = self .infer From 513e340bd344ee373847953baead3097f0b43815 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Tue, 14 Mar 2023 12:49:09 +0330 Subject: [PATCH 1186/2442] implement transmute intrinsic --- crates/hir-ty/src/mir/eval.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 7293156a978f..3001832d7953 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1187,7 +1187,7 @@ impl Evaluator<'_> { fn exec_intrinsic( &self, as_str: &str, - _arg_bytes: impl Iterator>, + mut arg_bytes: impl Iterator>, generic_args: Substitution, locals: &Locals<'_>, ) -> Result> { @@ -1202,6 +1202,12 @@ impl Evaluator<'_> { None => return Err(MirEvalError::TypeError("size_of arg is unsized")), } } + "transmute" => { + let Some(arg) = arg_bytes.next() else { + return Err(MirEvalError::TypeError("trasmute arg is not provided")); + }; + Ok(arg) + } _ => not_supported!("unknown intrinsic {as_str}"), } } From 051dae222164a04c703c5c0914a304d35206a62f Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Tue, 14 Mar 2023 17:02:38 +0330 Subject: [PATCH 1187/2442] Support record pattern MIR lowering --- crates/hir-ty/src/consteval/tests.rs | 41 +++++- crates/hir-ty/src/method_resolution.rs | 13 +- crates/hir-ty/src/mir/eval.rs | 15 +- crates/hir-ty/src/mir/lower.rs | 193 +++++++++++++++++++------ lib/la-arena/src/lib.rs | 2 +- 5 files changed, 201 insertions(+), 63 deletions(-) diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index f7914b578e43..1d298f96091a 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -555,6 +555,38 @@ fn structs() { "#, 17, ); + check_number( + r#" + struct Point { + x: i32, + y: i32, + } + + const GOAL: i32 = { + let p = Point { x: 5, y: 2 }; + let p2 = Point { x: 3, ..p }; + p.x * 1000 + p.y * 100 + p2.x * 10 + p2.y + }; + "#, + 5232, + ); + check_number( + r#" + struct Point { + x: i32, + y: i32, + } + + const GOAL: i32 = { + let p = Point { x: 5, y: 2 }; + let Point { x, y } = p; + let Point { x: x2, .. } = p; + let Point { y: y2, .. } = p; + x * 1000 + y * 100 + x2 * 10 + y2 + }; + "#, + 5252, + ); } #[test] @@ -599,13 +631,14 @@ fn tuples() { ); check_number( r#" - struct TupleLike(i32, u8, i64, u16); - const GOAL: u8 = { + struct TupleLike(i32, i64, u8, u16); + const GOAL: i64 = { let a = TupleLike(10, 20, 3, 15); - a.1 + let TupleLike(b, .., c) = a; + a.1 * 100 + b as i64 + c as i64 }; "#, - 20, + 2025, ); check_number( r#" diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 6244b98104fe..2003d24038b1 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -711,12 +711,13 @@ pub fn is_dyn_method( }; let self_ty = trait_ref.self_type_parameter(Interner); if let TyKind::Dyn(d) = self_ty.kind(Interner) { - let is_my_trait_in_bounds = d.bounds.skip_binders().as_slice(Interner).iter().any(|x| match x.skip_binders() { - // rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter - // what the generics are, we are sure that the method is come from the vtable. - WhereClause::Implemented(tr) => tr.trait_id == trait_ref.trait_id, - _ => false, - }); + let is_my_trait_in_bounds = + d.bounds.skip_binders().as_slice(Interner).iter().any(|x| match x.skip_binders() { + // rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter + // what the generics are, we are sure that the method is come from the vtable. + WhereClause::Implemented(tr) => tr.trait_id == trait_ref.trait_id, + _ => false, + }); if is_my_trait_in_bounds { return Some(fn_params); } diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 3001832d7953..787665bb637a 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -25,8 +25,8 @@ use crate::{ mapping::from_chalk, method_resolution::{is_dyn_method, lookup_impl_method}, traits::FnTrait, - CallableDefId, Const, ConstScalar, FnDefId, Interner, MemoryMap, Substitution, - TraitEnvironment, Ty, TyBuilder, TyExt, GenericArgData, + CallableDefId, Const, ConstScalar, FnDefId, GenericArgData, Interner, MemoryMap, Substitution, + TraitEnvironment, Ty, TyBuilder, TyExt, }; use super::{ @@ -1315,10 +1315,13 @@ impl Evaluator<'_> { args_for_target[0] = args_for_target[0][0..self.ptr_size()].to_vec(); let generics_for_target = Substitution::from_iter( Interner, - generic_args - .iter(Interner) - .enumerate() - .map(|(i, x)| if i == self_ty_idx { &ty } else { x }) + generic_args.iter(Interner).enumerate().map(|(i, x)| { + if i == self_ty_idx { + &ty + } else { + x + } + }), ); return self.exec_fn_with_args( def, diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 4fc3c67a6e1e..d36d9e946ca8 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -4,16 +4,17 @@ use std::{iter, mem, sync::Arc}; use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; use hir_def::{ + adt::VariantData, body::Body, expr::{ Array, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm, Pat, PatId, - RecordLitField, + RecordFieldPat, RecordLitField, }, lang_item::{LangItem, LangItemTarget}, layout::LayoutError, path::Path, resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, - DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, TraitId, + DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, LocalFieldId, TraitId, }; use hir_expand::name::Name; use la_arena::ArenaMap; @@ -106,6 +107,12 @@ impl MirLowerError { type Result = std::result::Result; +enum AdtPatternShape<'a> { + Tuple { args: &'a [PatId], ellipsis: Option }, + Record { args: &'a [RecordFieldPat] }, + Unit, +} + impl MirLowerCtx<'_> { fn temp(&mut self, ty: Ty) -> Result { if matches!(ty.kind(Interner), TyKind::Slice(_) | TyKind::Dyn(_)) { @@ -444,7 +451,8 @@ impl MirLowerCtx<'_> { current, pat.into(), Some(end), - &[pat], &None)?; + AdtPatternShape::Tuple { args: &[pat], ellipsis: None }, + )?; if let Some((_, block)) = this.lower_expr_as_place(current, body, true)? { this.set_goto(block, begin); } @@ -573,7 +581,17 @@ impl MirLowerCtx<'_> { Ok(None) } Expr::Yield { .. } => not_supported!("yield"), - Expr::RecordLit { fields, path, .. } => { + Expr::RecordLit { fields, path, spread, ellipsis: _, is_assignee_expr: _ } => { + let spread_place = match spread { + &Some(x) => { + let Some((p, c)) = self.lower_expr_as_place(current, x, true)? else { + return Ok(None); + }; + current = c; + Some(p) + }, + None => None, + }; let variant_id = self .infer .variant_resolution_for_expr(expr_id) @@ -603,9 +621,24 @@ impl MirLowerCtx<'_> { place, Rvalue::Aggregate( AggregateKind::Adt(variant_id, subst), - operands.into_iter().map(|x| x).collect::>().ok_or( - MirLowerError::TypeError("missing field in record literal"), - )?, + match spread_place { + Some(sp) => operands.into_iter().enumerate().map(|(i, x)| { + match x { + Some(x) => x, + None => { + let mut p = sp.clone(); + p.projection.push(ProjectionElem::Field(FieldId { + parent: variant_id, + local_id: LocalFieldId::from_raw(RawIdx::from(i as u32)), + })); + Operand::Copy(p) + }, + } + }).collect(), + None => operands.into_iter().map(|x| x).collect::>().ok_or( + MirLowerError::TypeError("missing field in record literal"), + )?, + }, ), expr_id.into(), ); @@ -1021,14 +1054,11 @@ impl MirLowerCtx<'_> { self.pattern_match_tuple_like( current, current_else, - args.iter().enumerate().map(|(i, x)| { - ( - PlaceElem::TupleField(i), - *x, - subst.at(Interner, i).assert_ty_ref(Interner).clone(), - ) - }), + args, *ellipsis, + subst.iter(Interner).enumerate().map(|(i, x)| { + (PlaceElem::TupleField(i), x.assert_ty_ref(Interner).clone()) + }), &cond_place, binding_mode, )? @@ -1062,7 +1092,21 @@ impl MirLowerCtx<'_> { } (then_target, current_else) } - Pat::Record { .. } => not_supported!("record pattern"), + Pat::Record { args, .. } => { + let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else { + not_supported!("unresolved variant"); + }; + self.pattern_matching_variant( + cond_ty, + binding_mode, + cond_place, + variant, + current, + pattern.into(), + current_else, + AdtPatternShape::Record { args: &*args }, + )? + } Pat::Range { .. } => not_supported!("range pattern"), Pat::Slice { .. } => not_supported!("slice pattern"), Pat::Path(_) => { @@ -1077,8 +1121,7 @@ impl MirLowerCtx<'_> { current, pattern.into(), current_else, - &[], - &None, + AdtPatternShape::Unit, )? } Pat::Lit(l) => { @@ -1160,8 +1203,7 @@ impl MirLowerCtx<'_> { current, pattern.into(), current_else, - args, - ellipsis, + AdtPatternShape::Tuple { args, ellipsis: *ellipsis }, )? } Pat::Ref { .. } => not_supported!("& pattern"), @@ -1179,15 +1221,13 @@ impl MirLowerCtx<'_> { current: BasicBlockId, span: MirSpan, current_else: Option, - args: &[PatId], - ellipsis: &Option, + shape: AdtPatternShape<'_>, ) -> Result<(BasicBlockId, Option)> { pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place); let subst = match cond_ty.kind(Interner) { TyKind::Adt(_, s) => s, _ => return Err(MirLowerError::TypeError("non adt type matched with tuple struct")), }; - let fields_type = self.db.field_types(variant); Ok(match variant { VariantId::EnumVariantId(v) => { let e = self.db.const_eval_discriminant(v)? as u128; @@ -1208,35 +1248,26 @@ impl MirLowerCtx<'_> { }, ); let enum_data = self.db.enum_data(v.parent); - let fields = - enum_data.variants[v.local_id].variant_data.fields().iter().map(|(x, _)| { - ( - PlaceElem::Field(FieldId { parent: v.into(), local_id: x }), - fields_type[x].clone().substitute(Interner, subst), - ) - }); - self.pattern_match_tuple_like( + self.pattern_matching_variant_fields( + shape, + &enum_data.variants[v.local_id].variant_data, + variant, + subst, next, Some(else_target), - args.iter().zip(fields).map(|(x, y)| (y.0, *x, y.1)), - *ellipsis, &cond_place, binding_mode, )? } VariantId::StructId(s) => { let struct_data = self.db.struct_data(s); - let fields = struct_data.variant_data.fields().iter().map(|(x, _)| { - ( - PlaceElem::Field(FieldId { parent: s.into(), local_id: x }), - fields_type[x].clone().substitute(Interner, subst), - ) - }); - self.pattern_match_tuple_like( + self.pattern_matching_variant_fields( + shape, + &struct_data.variant_data, + variant, + subst, current, current_else, - args.iter().zip(fields).map(|(x, y)| (y.0, *x, y.1)), - *ellipsis, &cond_place, binding_mode, )? @@ -1247,18 +1278,69 @@ impl MirLowerCtx<'_> { }) } - fn pattern_match_tuple_like( + fn pattern_matching_variant_fields( + &mut self, + shape: AdtPatternShape<'_>, + variant_data: &VariantData, + v: VariantId, + subst: &Substitution, + current: BasicBlockId, + current_else: Option, + cond_place: &Place, + binding_mode: BindingAnnotation, + ) -> Result<(BasicBlockId, Option)> { + let fields_type = self.db.field_types(v); + Ok(match shape { + AdtPatternShape::Record { args } => { + let it = args + .iter() + .map(|x| { + let field_id = + variant_data.field(&x.name).ok_or(MirLowerError::UnresolvedField)?; + Ok(( + PlaceElem::Field(FieldId { parent: v.into(), local_id: field_id }), + x.pat, + fields_type[field_id].clone().substitute(Interner, subst), + )) + }) + .collect::>>()?; + self.pattern_match_adt( + current, + current_else, + it.into_iter(), + cond_place, + binding_mode, + )? + } + AdtPatternShape::Tuple { args, ellipsis } => { + let fields = variant_data.fields().iter().map(|(x, _)| { + ( + PlaceElem::Field(FieldId { parent: v.into(), local_id: x }), + fields_type[x].clone().substitute(Interner, subst), + ) + }); + self.pattern_match_tuple_like( + current, + current_else, + args, + ellipsis, + fields, + cond_place, + binding_mode, + )? + } + AdtPatternShape::Unit => (current, current_else), + }) + } + + fn pattern_match_adt( &mut self, mut current: BasicBlockId, mut current_else: Option, args: impl Iterator, - ellipsis: Option, cond_place: &Place, binding_mode: BindingAnnotation, ) -> Result<(BasicBlockId, Option)> { - if ellipsis.is_some() { - not_supported!("tuple like pattern with ellipsis"); - } for (proj, arg, ty) in args { let mut cond_place = cond_place.clone(); cond_place.projection.push(proj); @@ -1268,6 +1350,25 @@ impl MirLowerCtx<'_> { Ok((current, current_else)) } + fn pattern_match_tuple_like( + &mut self, + current: BasicBlockId, + current_else: Option, + args: &[PatId], + ellipsis: Option, + fields: impl DoubleEndedIterator + Clone, + cond_place: &Place, + binding_mode: BindingAnnotation, + ) -> Result<(BasicBlockId, Option)> { + let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len())); + let it = al + .iter() + .zip(fields.clone()) + .chain(ar.iter().rev().zip(fields.rev())) + .map(|(x, y)| (y.0, *x, y.1)); + self.pattern_match_adt(current, current_else, it, cond_place, binding_mode) + } + fn discr_temp_place(&mut self) -> Place { match &self.discr_temp { Some(x) => x.clone(), diff --git a/lib/la-arena/src/lib.rs b/lib/la-arena/src/lib.rs index ccaaf3991769..f6597efd8fd2 100644 --- a/lib/la-arena/src/lib.rs +++ b/lib/la-arena/src/lib.rs @@ -295,7 +295,7 @@ impl Arena { /// ``` pub fn iter( &self, - ) -> impl Iterator, &T)> + ExactSizeIterator + DoubleEndedIterator { + ) -> impl Iterator, &T)> + ExactSizeIterator + DoubleEndedIterator + Clone { self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawIdx(idx as u32)), value)) } From 9564773d5e6dff6d430594028383315ca2e202ef Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Tue, 14 Mar 2023 23:01:46 +0330 Subject: [PATCH 1188/2442] Improve pattern matching MIR lowering --- crates/hir-def/src/body/lower.rs | 19 +- crates/hir-def/src/expr.rs | 10 + crates/hir-ty/src/consteval/tests.rs | 112 +++++ crates/hir-ty/src/mir/eval.rs | 10 +- crates/hir-ty/src/mir/lower.rs | 415 ++---------------- .../hir-ty/src/mir/lower/pattern_matching.rs | 399 +++++++++++++++++ crates/hir-ty/src/mir/pretty.rs | 14 +- crates/syntax/src/ast/generated/nodes.rs | 1 + crates/test-utils/src/minicore.rs | 5 +- 9 files changed, 590 insertions(+), 395 deletions(-) create mode 100644 crates/hir-ty/src/mir/lower/pattern_matching.rs diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 348b7589ff4f..7cce23b5316c 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -1030,9 +1030,16 @@ impl ExprCollector<'_> { .collect(), } } - ast::Pat::LiteralPat(lit) => { + ast::Pat::LiteralPat(lit) => 'b: { if let Some(ast_lit) = lit.literal() { - let expr = Expr::Literal(ast_lit.kind().into()); + let mut hir_lit: Literal = ast_lit.kind().into(); + if lit.minus_token().is_some() { + let Some(h) = hir_lit.negate() else { + break 'b Pat::Missing; + }; + hir_lit = h; + } + let expr = Expr::Literal(hir_lit); let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit)); let expr_id = self.alloc_expr(expr, expr_ptr); Pat::Lit(expr_id) @@ -1144,11 +1151,11 @@ impl From for Literal { FloatTypeWrapper::new(lit.float_value().unwrap_or(Default::default())), builtin, ) - } else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinInt::from_suffix) { - Literal::Int(lit.value().unwrap_or(0) as i128, builtin) - } else { - let builtin = lit.suffix().and_then(BuiltinUint::from_suffix); + } else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinUint::from_suffix) { Literal::Uint(lit.value().unwrap_or(0), builtin) + } else { + let builtin = lit.suffix().and_then(BuiltinInt::from_suffix); + Literal::Int(lit.value().unwrap_or(0) as i128, builtin) } } LiteralKind::FloatNumber(lit) => { diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs index 5b8758224371..8b1528f81e61 100644 --- a/crates/hir-def/src/expr.rs +++ b/crates/hir-def/src/expr.rs @@ -92,6 +92,16 @@ pub enum Literal { Float(FloatTypeWrapper, Option), } +impl Literal { + pub fn negate(self) -> Option { + if let Literal::Int(i, k) = self { + Some(Literal::Int(-i, k)) + } else { + None + } + } +} + #[derive(Debug, Clone, Eq, PartialEq)] pub enum Expr { /// This is produced if the syntax tree does not have a required expression piece. diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 1d298f96091a..ecc163a4151c 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -685,6 +685,36 @@ fn path_pattern_matching() { ); } +#[test] +fn pattern_matching_literal() { + check_number( + r#" + const fn f(x: i32) -> i32 { + match x { + -1 => 1, + 1 => 10, + _ => 100, + } + } + const GOAL: i32 = f(-1) + f(1) + f(0) + f(-5); + "#, + 211 + ); + check_number( + r#" + const fn f(x: &str) -> u8 { + match x { + "foo" => 1, + "bar" => 10, + _ => 100, + } + } + const GOAL: u8 = f("foo") + f("bar"); + "#, + 11 + ); +} + #[test] fn pattern_matching_ergonomics() { check_number( @@ -698,6 +728,16 @@ fn pattern_matching_ergonomics() { "#, 5, ); + check_number( + r#" + const GOAL: u8 = { + let a = &(2, 3); + let &(x, y) = a; + x + y + }; + "#, + 5, + ); } #[test] @@ -781,6 +821,33 @@ fn function_param_patterns() { ); } +#[test] +fn match_guards() { + check_number( + r#" + //- minicore: option, eq + impl PartialEq for Option { + fn eq(&self, other: &Rhs) -> bool { + match (self, other) { + (Some(x), Some(y)) => x == y, + (None, None) => true, + _ => false, + } + } + } + fn f(x: Option) -> i32 { + match x { + y if y == Some(42) => 42000, + Some(y) => y, + None => 10 + } + } + const GOAL: i32 = f(Some(42)) + f(Some(2)) + f(None); + "#, + 42012, + ); +} + #[test] fn options() { check_number( @@ -983,6 +1050,51 @@ fn function_pointer() { ); } +#[test] +fn enum_variant_as_function() { + check_number( + r#" + //- minicore: option + const GOAL: u8 = { + let f = Some; + f(3).unwrap_or(2) + }; + "#, + 3, + ); + check_number( + r#" + //- minicore: option + const GOAL: u8 = { + let f: fn(u8) -> Option = Some; + f(3).unwrap_or(2) + }; + "#, + 3, + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + enum Foo { + Add2(u8), + Mult3(u8), + } + use Foo::*; + const fn f(x: Foo) -> u8 { + match x { + Add2(x) => x + 2, + Mult3(x) => x * 3, + } + } + const GOAL: u8 = { + let x = [Add2, Mult3]; + f(x[0](1)) + f(x[1](5)) + }; + "#, + 18, + ); +} + #[test] fn function_traits() { check_number( diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 787665bb637a..450cd5404e5e 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -423,6 +423,7 @@ impl Evaluator<'_> { args: impl Iterator>, subst: Substitution, ) -> Result> { + dbg!(body.dbg(self.db)); if let Some(x) = self.stack_depth_limit.checked_sub(1) { self.stack_depth_limit = x; } else { @@ -581,7 +582,14 @@ impl Evaluator<'_> { let mut ty = self.operand_ty(lhs, locals)?; while let TyKind::Ref(_, _, z) = ty.kind(Interner) { ty = z.clone(); - let size = self.size_of_sized(&ty, locals, "operand of binary op")?; + let size = if ty.kind(Interner) == &TyKind::Str { + let ns = from_bytes!(usize, &lc[self.ptr_size()..self.ptr_size() * 2]); + lc = &lc[..self.ptr_size()]; + rc = &rc[..self.ptr_size()]; + ns + } else { + self.size_of_sized(&ty, locals, "operand of binary op")? + }; lc = self.read_memory(Address::from_bytes(lc)?, size)?; rc = self.read_memory(Address::from_bytes(rc)?, size)?; } diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index d36d9e946ca8..4da0f8760997 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -4,7 +4,7 @@ use std::{iter, mem, sync::Arc}; use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; use hir_def::{ - adt::VariantData, + adt::{VariantData, StructKind}, body::Body, expr::{ Array, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm, Pat, PatId, @@ -28,6 +28,9 @@ use crate::{ use super::*; mod as_place; +mod pattern_matching; + +use pattern_matching::AdtPatternShape; #[derive(Debug, Clone, Copy)] struct LoopBlocks { @@ -107,12 +110,6 @@ impl MirLowerError { type Result = std::result::Result; -enum AdtPatternShape<'a> { - Tuple { args: &'a [PatId], ellipsis: Option }, - Record { args: &'a [RecordFieldPat] }, - Unit, -} - impl MirLowerCtx<'_> { fn temp(&mut self, ty: Ty) -> Result { if matches!(ty.kind(Interner), TyKind::Slice(_) | TyKind::Dyn(_)) { @@ -275,15 +272,19 @@ impl MirLowerCtx<'_> { Ok(Some(current)) } ValueNs::EnumVariantId(variant_id) => { - let ty = self.infer.type_of_expr[expr_id].clone(); - let current = self.lower_enum_variant( - variant_id, - current, - place, - ty, - vec![], - expr_id.into(), - )?; + let variant_data = &self.db.enum_data(variant_id.parent).variants[variant_id.local_id]; + if variant_data.variant_data.kind() == StructKind::Unit { + let ty = self.infer.type_of_expr[expr_id].clone(); + current = self.lower_enum_variant( + variant_id, + current, + place, + ty, + vec![], + expr_id.into(), + )?; + } + // Otherwise its a tuple like enum, treated like a zero sized function, so no action is needed Ok(Some(current)) } ValueNs::GenericParam(p) => { @@ -517,10 +518,7 @@ impl MirLowerCtx<'_> { let cond_ty = self.expr_ty_after_adjustments(*expr); let mut end = None; for MatchArm { pat, guard, expr } in arms.iter() { - if guard.is_some() { - not_supported!("pattern matching with guard"); - } - let (then, otherwise) = self.pattern_match( + let (then, mut otherwise) = self.pattern_match( current, None, cond_place.clone(), @@ -528,6 +526,16 @@ impl MirLowerCtx<'_> { *pat, BindingAnnotation::Unannotated, )?; + let then = if let &Some(guard) = guard { + let next = self.new_basic_block(); + let o = otherwise.get_or_insert_with(|| self.new_basic_block()); + if let Some((discr, c)) = self.lower_expr_to_some_operand(guard, then)? { + self.set_terminator(c, Terminator::SwitchInt { discr, targets: SwitchTargets::static_if(1, next, *o) }); + } + next + } else { + then + }; if let Some(block) = self.lower_expr_to_place(*expr, place.clone(), then)? { let r = end.get_or_insert_with(|| self.new_basic_block()); self.set_goto(block, *r); @@ -922,7 +930,7 @@ impl MirLowerCtx<'_> { ) -> Result { let subst = match ty.kind(Interner) { TyKind::Adt(_, subst) => subst.clone(), - _ => not_supported!("Non ADT enum"), + _ => implementation_error!("Non ADT enum"), }; self.push_assignment( prev_block, @@ -1020,355 +1028,6 @@ impl MirLowerCtx<'_> { self.push_statement(block, StatementKind::Assign(place, rvalue).with_span(span)); } - /// It gets a `current` unterminated block, appends some statements and possibly a terminator to it to check if - /// the pattern matches and write bindings, and returns two unterminated blocks, one for the matched path (which - /// can be the `current` block) and one for the mismatched path. If the input pattern is irrefutable, the - /// mismatched path block is `None`. - /// - /// By default, it will create a new block for mismatched path. If you already have one, you can provide it with - /// `current_else` argument to save an unneccessary jump. If `current_else` isn't `None`, the result mismatched path - /// wouldn't be `None` as well. Note that this function will add jumps to the beginning of the `current_else` block, - /// so it should be an empty block. - fn pattern_match( - &mut self, - mut current: BasicBlockId, - mut current_else: Option, - mut cond_place: Place, - mut cond_ty: Ty, - pattern: PatId, - mut binding_mode: BindingAnnotation, - ) -> Result<(BasicBlockId, Option)> { - Ok(match &self.body.pats[pattern] { - Pat::Missing => return Err(MirLowerError::IncompleteExpr), - Pat::Wild => (current, current_else), - Pat::Tuple { args, ellipsis } => { - pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place); - let subst = match cond_ty.kind(Interner) { - TyKind::Tuple(_, s) => s, - _ => { - return Err(MirLowerError::TypeError( - "non tuple type matched with tuple pattern", - )) - } - }; - self.pattern_match_tuple_like( - current, - current_else, - args, - *ellipsis, - subst.iter(Interner).enumerate().map(|(i, x)| { - (PlaceElem::TupleField(i), x.assert_ty_ref(Interner).clone()) - }), - &cond_place, - binding_mode, - )? - } - Pat::Or(pats) => { - let then_target = self.new_basic_block(); - let mut finished = false; - for pat in &**pats { - let (next, next_else) = self.pattern_match( - current, - None, - cond_place.clone(), - cond_ty.clone(), - *pat, - binding_mode, - )?; - self.set_goto(next, then_target); - match next_else { - Some(t) => { - current = t; - } - None => { - finished = true; - break; - } - } - } - if !finished { - let ce = *current_else.get_or_insert_with(|| self.new_basic_block()); - self.set_goto(current, ce); - } - (then_target, current_else) - } - Pat::Record { args, .. } => { - let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else { - not_supported!("unresolved variant"); - }; - self.pattern_matching_variant( - cond_ty, - binding_mode, - cond_place, - variant, - current, - pattern.into(), - current_else, - AdtPatternShape::Record { args: &*args }, - )? - } - Pat::Range { .. } => not_supported!("range pattern"), - Pat::Slice { .. } => not_supported!("slice pattern"), - Pat::Path(_) => { - let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else { - not_supported!("unresolved variant"); - }; - self.pattern_matching_variant( - cond_ty, - binding_mode, - cond_place, - variant, - current, - pattern.into(), - current_else, - AdtPatternShape::Unit, - )? - } - Pat::Lit(l) => { - let then_target = self.new_basic_block(); - let else_target = current_else.unwrap_or_else(|| self.new_basic_block()); - match &self.body.exprs[*l] { - Expr::Literal(l) => match l { - hir_def::expr::Literal::Int(x, _) => { - self.set_terminator( - current, - Terminator::SwitchInt { - discr: Operand::Copy(cond_place), - targets: SwitchTargets::static_if( - *x as u128, - then_target, - else_target, - ), - }, - ); - } - hir_def::expr::Literal::Uint(x, _) => { - self.set_terminator( - current, - Terminator::SwitchInt { - discr: Operand::Copy(cond_place), - targets: SwitchTargets::static_if(*x, then_target, else_target), - }, - ); - } - _ => not_supported!("non int path literal"), - }, - _ => not_supported!("expression path literal"), - } - (then_target, Some(else_target)) - } - Pat::Bind { id, subpat } => { - let target_place = self.result.binding_locals[*id]; - let mode = self.body.bindings[*id].mode; - if let Some(subpat) = subpat { - (current, current_else) = self.pattern_match( - current, - current_else, - cond_place.clone(), - cond_ty, - *subpat, - binding_mode, - )? - } - if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) { - binding_mode = mode; - } - self.push_storage_live(*id, current); - self.push_assignment( - current, - target_place.into(), - match binding_mode { - BindingAnnotation::Unannotated | BindingAnnotation::Mutable => { - Operand::Copy(cond_place).into() - } - BindingAnnotation::Ref => Rvalue::Ref(BorrowKind::Shared, cond_place), - BindingAnnotation::RefMut => Rvalue::Ref( - BorrowKind::Mut { allow_two_phase_borrow: false }, - cond_place, - ), - }, - pattern.into(), - ); - (current, current_else) - } - Pat::TupleStruct { path: _, args, ellipsis } => { - let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else { - not_supported!("unresolved variant"); - }; - self.pattern_matching_variant( - cond_ty, - binding_mode, - cond_place, - variant, - current, - pattern.into(), - current_else, - AdtPatternShape::Tuple { args, ellipsis: *ellipsis }, - )? - } - Pat::Ref { .. } => not_supported!("& pattern"), - Pat::Box { .. } => not_supported!("box pattern"), - Pat::ConstBlock(_) => not_supported!("const block pattern"), - }) - } - - fn pattern_matching_variant( - &mut self, - mut cond_ty: Ty, - mut binding_mode: BindingAnnotation, - mut cond_place: Place, - variant: VariantId, - current: BasicBlockId, - span: MirSpan, - current_else: Option, - shape: AdtPatternShape<'_>, - ) -> Result<(BasicBlockId, Option)> { - pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place); - let subst = match cond_ty.kind(Interner) { - TyKind::Adt(_, s) => s, - _ => return Err(MirLowerError::TypeError("non adt type matched with tuple struct")), - }; - Ok(match variant { - VariantId::EnumVariantId(v) => { - let e = self.db.const_eval_discriminant(v)? as u128; - let next = self.new_basic_block(); - let tmp = self.discr_temp_place(); - self.push_assignment( - current, - tmp.clone(), - Rvalue::Discriminant(cond_place.clone()), - span, - ); - let else_target = current_else.unwrap_or_else(|| self.new_basic_block()); - self.set_terminator( - current, - Terminator::SwitchInt { - discr: Operand::Copy(tmp), - targets: SwitchTargets::static_if(e, next, else_target), - }, - ); - let enum_data = self.db.enum_data(v.parent); - self.pattern_matching_variant_fields( - shape, - &enum_data.variants[v.local_id].variant_data, - variant, - subst, - next, - Some(else_target), - &cond_place, - binding_mode, - )? - } - VariantId::StructId(s) => { - let struct_data = self.db.struct_data(s); - self.pattern_matching_variant_fields( - shape, - &struct_data.variant_data, - variant, - subst, - current, - current_else, - &cond_place, - binding_mode, - )? - } - VariantId::UnionId(_) => { - return Err(MirLowerError::TypeError("pattern matching on union")) - } - }) - } - - fn pattern_matching_variant_fields( - &mut self, - shape: AdtPatternShape<'_>, - variant_data: &VariantData, - v: VariantId, - subst: &Substitution, - current: BasicBlockId, - current_else: Option, - cond_place: &Place, - binding_mode: BindingAnnotation, - ) -> Result<(BasicBlockId, Option)> { - let fields_type = self.db.field_types(v); - Ok(match shape { - AdtPatternShape::Record { args } => { - let it = args - .iter() - .map(|x| { - let field_id = - variant_data.field(&x.name).ok_or(MirLowerError::UnresolvedField)?; - Ok(( - PlaceElem::Field(FieldId { parent: v.into(), local_id: field_id }), - x.pat, - fields_type[field_id].clone().substitute(Interner, subst), - )) - }) - .collect::>>()?; - self.pattern_match_adt( - current, - current_else, - it.into_iter(), - cond_place, - binding_mode, - )? - } - AdtPatternShape::Tuple { args, ellipsis } => { - let fields = variant_data.fields().iter().map(|(x, _)| { - ( - PlaceElem::Field(FieldId { parent: v.into(), local_id: x }), - fields_type[x].clone().substitute(Interner, subst), - ) - }); - self.pattern_match_tuple_like( - current, - current_else, - args, - ellipsis, - fields, - cond_place, - binding_mode, - )? - } - AdtPatternShape::Unit => (current, current_else), - }) - } - - fn pattern_match_adt( - &mut self, - mut current: BasicBlockId, - mut current_else: Option, - args: impl Iterator, - cond_place: &Place, - binding_mode: BindingAnnotation, - ) -> Result<(BasicBlockId, Option)> { - for (proj, arg, ty) in args { - let mut cond_place = cond_place.clone(); - cond_place.projection.push(proj); - (current, current_else) = - self.pattern_match(current, current_else, cond_place, ty, arg, binding_mode)?; - } - Ok((current, current_else)) - } - - fn pattern_match_tuple_like( - &mut self, - current: BasicBlockId, - current_else: Option, - args: &[PatId], - ellipsis: Option, - fields: impl DoubleEndedIterator + Clone, - cond_place: &Place, - binding_mode: BindingAnnotation, - ) -> Result<(BasicBlockId, Option)> { - let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len())); - let it = al - .iter() - .zip(fields.clone()) - .chain(ar.iter().rev().zip(fields.rev())) - .map(|(x, y)| (y.0, *x, y.1)); - self.pattern_match_adt(current, current_else, it, cond_place, binding_mode) - } - fn discr_temp_place(&mut self) -> Place { match &self.discr_temp { Some(x) => x.clone(), @@ -1546,22 +1205,6 @@ impl MirLowerCtx<'_> { } } -fn pattern_matching_dereference( - cond_ty: &mut Ty, - binding_mode: &mut BindingAnnotation, - cond_place: &mut Place, -) { - while let Some((ty, _, mu)) = cond_ty.as_reference() { - if mu == Mutability::Mut && *binding_mode != BindingAnnotation::Ref { - *binding_mode = BindingAnnotation::RefMut; - } else { - *binding_mode = BindingAnnotation::Ref; - } - *cond_ty = ty.clone(); - cond_place.projection.push(ProjectionElem::Deref); - } -} - fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result { Ok(match (source_ty.kind(Interner), target_ty.kind(Interner)) { (TyKind::Scalar(s), TyKind::Scalar(t)) => match (s, t) { diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs new file mode 100644 index 000000000000..c3ced82aab7b --- /dev/null +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -0,0 +1,399 @@ +//! MIR lowering for patterns + +use super::*; + +macro_rules! not_supported { + ($x: expr) => { + return Err(MirLowerError::NotSupported(format!($x))) + }; +} + +pub(super) enum AdtPatternShape<'a> { + Tuple { args: &'a [PatId], ellipsis: Option }, + Record { args: &'a [RecordFieldPat] }, + Unit, +} + +impl MirLowerCtx<'_> { + /// It gets a `current` unterminated block, appends some statements and possibly a terminator to it to check if + /// the pattern matches and write bindings, and returns two unterminated blocks, one for the matched path (which + /// can be the `current` block) and one for the mismatched path. If the input pattern is irrefutable, the + /// mismatched path block is `None`. + /// + /// By default, it will create a new block for mismatched path. If you already have one, you can provide it with + /// `current_else` argument to save an unneccessary jump. If `current_else` isn't `None`, the result mismatched path + /// wouldn't be `None` as well. Note that this function will add jumps to the beginning of the `current_else` block, + /// so it should be an empty block. + pub(super) fn pattern_match( + &mut self, + mut current: BasicBlockId, + mut current_else: Option, + mut cond_place: Place, + mut cond_ty: Ty, + pattern: PatId, + mut binding_mode: BindingAnnotation, + ) -> Result<(BasicBlockId, Option)> { + Ok(match &self.body.pats[pattern] { + Pat::Missing => return Err(MirLowerError::IncompleteExpr), + Pat::Wild => (current, current_else), + Pat::Tuple { args, ellipsis } => { + pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place); + let subst = match cond_ty.kind(Interner) { + TyKind::Tuple(_, s) => s, + _ => { + return Err(MirLowerError::TypeError( + "non tuple type matched with tuple pattern", + )) + } + }; + self.pattern_match_tuple_like( + current, + current_else, + args, + *ellipsis, + subst.iter(Interner).enumerate().map(|(i, x)| { + (PlaceElem::TupleField(i), x.assert_ty_ref(Interner).clone()) + }), + &cond_place, + binding_mode, + )? + } + Pat::Or(pats) => { + let then_target = self.new_basic_block(); + let mut finished = false; + for pat in &**pats { + let (next, next_else) = self.pattern_match( + current, + None, + cond_place.clone(), + cond_ty.clone(), + *pat, + binding_mode, + )?; + self.set_goto(next, then_target); + match next_else { + Some(t) => { + current = t; + } + None => { + finished = true; + break; + } + } + } + if !finished { + let ce = *current_else.get_or_insert_with(|| self.new_basic_block()); + self.set_goto(current, ce); + } + (then_target, current_else) + } + Pat::Record { args, .. } => { + let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else { + not_supported!("unresolved variant"); + }; + self.pattern_matching_variant( + cond_ty, + binding_mode, + cond_place, + variant, + current, + pattern.into(), + current_else, + AdtPatternShape::Record { args: &*args }, + )? + } + Pat::Range { .. } => not_supported!("range pattern"), + Pat::Slice { .. } => not_supported!("slice pattern"), + Pat::Path(_) => { + let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else { + not_supported!("unresolved variant"); + }; + self.pattern_matching_variant( + cond_ty, + binding_mode, + cond_place, + variant, + current, + pattern.into(), + current_else, + AdtPatternShape::Unit, + )? + } + Pat::Lit(l) => match &self.body.exprs[*l] { + Expr::Literal(l) => { + let c = self.lower_literal_to_operand(cond_ty, l)?; + self.pattern_match_const(current_else, current, c, cond_place, pattern)? + } + _ => not_supported!("expression path literal"), + }, + Pat::Bind { id, subpat } => { + let target_place = self.result.binding_locals[*id]; + let mode = self.body.bindings[*id].mode; + if let Some(subpat) = subpat { + (current, current_else) = self.pattern_match( + current, + current_else, + cond_place.clone(), + cond_ty, + *subpat, + binding_mode, + )? + } + if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) { + binding_mode = mode; + } + self.push_storage_live(*id, current); + self.push_assignment( + current, + target_place.into(), + match binding_mode { + BindingAnnotation::Unannotated | BindingAnnotation::Mutable => { + Operand::Copy(cond_place).into() + } + BindingAnnotation::Ref => Rvalue::Ref(BorrowKind::Shared, cond_place), + BindingAnnotation::RefMut => Rvalue::Ref( + BorrowKind::Mut { allow_two_phase_borrow: false }, + cond_place, + ), + }, + pattern.into(), + ); + (current, current_else) + } + Pat::TupleStruct { path: _, args, ellipsis } => { + let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else { + not_supported!("unresolved variant"); + }; + self.pattern_matching_variant( + cond_ty, + binding_mode, + cond_place, + variant, + current, + pattern.into(), + current_else, + AdtPatternShape::Tuple { args, ellipsis: *ellipsis }, + )? + } + Pat::Ref { pat, mutability: _ } => { + if let Some((ty, _, _)) = cond_ty.as_reference() { + cond_ty = ty.clone(); + cond_place.projection.push(ProjectionElem::Deref); + self.pattern_match( + current, + current_else, + cond_place, + cond_ty, + *pat, + binding_mode, + )? + } else { + return Err(MirLowerError::TypeError("& pattern for non reference")); + } + } + Pat::Box { .. } => not_supported!("box pattern"), + Pat::ConstBlock(_) => not_supported!("const block pattern"), + }) + } + + fn pattern_match_const( + &mut self, + current_else: Option, + current: BasicBlockId, + c: Operand, + cond_place: Place, + pattern: Idx, + ) -> Result<(BasicBlockId, Option)> { + let then_target = self.new_basic_block(); + let else_target = current_else.unwrap_or_else(|| self.new_basic_block()); + let discr: Place = self.temp(TyBuilder::bool())?.into(); + self.push_assignment( + current, + discr.clone(), + Rvalue::CheckedBinaryOp(BinOp::Eq, c, Operand::Copy(cond_place)), + pattern.into(), + ); + let discr = Operand::Copy(discr); + self.set_terminator( + current, + Terminator::SwitchInt { + discr, + targets: SwitchTargets::static_if(1, then_target, else_target), + }, + ); + Ok((then_target, Some(else_target))) + } + + pub(super) fn pattern_matching_variant( + &mut self, + mut cond_ty: Ty, + mut binding_mode: BindingAnnotation, + mut cond_place: Place, + variant: VariantId, + current: BasicBlockId, + span: MirSpan, + current_else: Option, + shape: AdtPatternShape<'_>, + ) -> Result<(BasicBlockId, Option)> { + pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place); + let subst = match cond_ty.kind(Interner) { + TyKind::Adt(_, s) => s, + _ => return Err(MirLowerError::TypeError("non adt type matched with tuple struct")), + }; + Ok(match variant { + VariantId::EnumVariantId(v) => { + let e = self.db.const_eval_discriminant(v)? as u128; + let next = self.new_basic_block(); + let tmp = self.discr_temp_place(); + self.push_assignment( + current, + tmp.clone(), + Rvalue::Discriminant(cond_place.clone()), + span, + ); + let else_target = current_else.unwrap_or_else(|| self.new_basic_block()); + self.set_terminator( + current, + Terminator::SwitchInt { + discr: Operand::Copy(tmp), + targets: SwitchTargets::static_if(e, next, else_target), + }, + ); + let enum_data = self.db.enum_data(v.parent); + self.pattern_matching_variant_fields( + shape, + &enum_data.variants[v.local_id].variant_data, + variant, + subst, + next, + Some(else_target), + &cond_place, + binding_mode, + )? + } + VariantId::StructId(s) => { + let struct_data = self.db.struct_data(s); + self.pattern_matching_variant_fields( + shape, + &struct_data.variant_data, + variant, + subst, + current, + current_else, + &cond_place, + binding_mode, + )? + } + VariantId::UnionId(_) => { + return Err(MirLowerError::TypeError("pattern matching on union")) + } + }) + } + + fn pattern_matching_variant_fields( + &mut self, + shape: AdtPatternShape<'_>, + variant_data: &VariantData, + v: VariantId, + subst: &Substitution, + current: BasicBlockId, + current_else: Option, + cond_place: &Place, + binding_mode: BindingAnnotation, + ) -> Result<(BasicBlockId, Option)> { + let fields_type = self.db.field_types(v); + Ok(match shape { + AdtPatternShape::Record { args } => { + let it = args + .iter() + .map(|x| { + let field_id = + variant_data.field(&x.name).ok_or(MirLowerError::UnresolvedField)?; + Ok(( + PlaceElem::Field(FieldId { parent: v.into(), local_id: field_id }), + x.pat, + fields_type[field_id].clone().substitute(Interner, subst), + )) + }) + .collect::>>()?; + self.pattern_match_adt( + current, + current_else, + it.into_iter(), + cond_place, + binding_mode, + )? + } + AdtPatternShape::Tuple { args, ellipsis } => { + let fields = variant_data.fields().iter().map(|(x, _)| { + ( + PlaceElem::Field(FieldId { parent: v.into(), local_id: x }), + fields_type[x].clone().substitute(Interner, subst), + ) + }); + self.pattern_match_tuple_like( + current, + current_else, + args, + ellipsis, + fields, + cond_place, + binding_mode, + )? + } + AdtPatternShape::Unit => (current, current_else), + }) + } + + fn pattern_match_adt( + &mut self, + mut current: BasicBlockId, + mut current_else: Option, + args: impl Iterator, + cond_place: &Place, + binding_mode: BindingAnnotation, + ) -> Result<(BasicBlockId, Option)> { + for (proj, arg, ty) in args { + let mut cond_place = cond_place.clone(); + cond_place.projection.push(proj); + (current, current_else) = + self.pattern_match(current, current_else, cond_place, ty, arg, binding_mode)?; + } + Ok((current, current_else)) + } + + fn pattern_match_tuple_like( + &mut self, + current: BasicBlockId, + current_else: Option, + args: &[PatId], + ellipsis: Option, + fields: impl DoubleEndedIterator + Clone, + cond_place: &Place, + binding_mode: BindingAnnotation, + ) -> Result<(BasicBlockId, Option)> { + let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len())); + let it = al + .iter() + .zip(fields.clone()) + .chain(ar.iter().rev().zip(fields.rev())) + .map(|(x, y)| (y.0, *x, y.1)); + self.pattern_match_adt(current, current_else, it, cond_place, binding_mode) + } +} + +fn pattern_matching_dereference( + cond_ty: &mut Ty, + binding_mode: &mut BindingAnnotation, + cond_place: &mut Place, +) { + while let Some((ty, _, mu)) = cond_ty.as_reference() { + if mu == Mutability::Mut && *binding_mode != BindingAnnotation::Ref { + *binding_mode = BindingAnnotation::RefMut; + } else { + *binding_mode = BindingAnnotation::Ref; + } + *cond_ty = ty.clone(); + cond_place.projection.push(ProjectionElem::Deref); + } +} diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index eb0002266dc5..ab3bb643e7a7 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -1,6 +1,6 @@ //! A pretty-printer for MIR. -use std::fmt::{Display, Write}; +use std::fmt::{Display, Write, Debug}; use hir_def::{body::Body, expr::BindingId}; use hir_expand::name::Name; @@ -23,6 +23,18 @@ impl MirBody { ctx.for_body(); ctx.result } + + // String with lines is rendered poorly in `dbg!` macros, which I use very much, so this + // function exists to solve that. + pub fn dbg(&self, db: &dyn HirDatabase) -> impl Debug { + struct StringDbg(String); + impl Debug for StringDbg { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.0) + } + } + StringDbg(self.pretty_print(db)) + } } struct MirPrettyCtx<'a> { diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index fe324845360d..a2124f3ac164 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -1376,6 +1376,7 @@ pub struct LiteralPat { } impl LiteralPat { pub fn literal(&self) -> Option { support::child(&self.syntax) } + pub fn minus_token(&self) -> Option { support::token(&self.syntax, T![-]) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 8dd9f306c8a6..bf592c1f7be8 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -597,7 +597,10 @@ pub mod option { loop {} } pub fn unwrap_or(self, default: T) -> T { - loop {} + match self { + Some(val) => val, + None => default, + } } // region:fn pub fn and_then(self, f: F) -> Option From eb4939e217960ee77d79ec436a39f3cead646de4 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Fri, 17 Mar 2023 14:02:55 +0330 Subject: [PATCH 1189/2442] Support overloaded deref MIR lowering --- crates/hir-def/src/body/lower.rs | 42 ++-- crates/hir-ty/src/consteval/tests.rs | 27 ++- crates/hir-ty/src/infer.rs | 3 + crates/hir-ty/src/infer/expr.rs | 47 ++++- crates/hir-ty/src/infer/mutability.rs | 182 ++++++++++++++++++ crates/hir-ty/src/mir/eval.rs | 33 ++-- crates/hir-ty/src/mir/lower.rs | 2 +- crates/hir-ty/src/mir/lower/as_place.rs | 26 ++- crates/hir-ty/src/mir/pretty.rs | 4 +- crates/hir-ty/src/tests/coercion.rs | 3 +- crates/hir-ty/src/tests/method_resolution.rs | 3 +- .../src/handlers/mutability_errors.rs | 31 ++- crates/ide/src/inlay_hints/chaining.rs | 12 +- crates/ide/src/syntax_highlighting/tests.rs | 2 +- crates/syntax/rust.ungram | 2 +- crates/syntax/src/ast/generated/nodes.rs | 2 +- crates/syntax/src/tests/sourcegen_ast.rs | 1 + crates/test-utils/src/minicore.rs | 62 ++++++ 18 files changed, 398 insertions(+), 86 deletions(-) create mode 100644 crates/hir-ty/src/infer/mutability.rs diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 7cce23b5316c..448821d3844a 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -609,21 +609,12 @@ impl ExprCollector<'_> { fn collect_try_operator(&mut self, syntax_ptr: AstPtr, e: ast::TryExpr) -> ExprId { let (try_branch, cf_continue, cf_break, try_from_residual) = 'if_chain: { if let Some(try_branch) = LangItem::TryTraitBranch.path(self.db, self.krate) { - if let Some(cf_continue) = - LangItem::ControlFlowContinue.path(self.db, self.krate) - { - if let Some(cf_break) = - LangItem::ControlFlowBreak.path(self.db, self.krate) - { + if let Some(cf_continue) = LangItem::ControlFlowContinue.path(self.db, self.krate) { + if let Some(cf_break) = LangItem::ControlFlowBreak.path(self.db, self.krate) { if let Some(try_from_residual) = LangItem::TryTraitFromResidual.path(self.db, self.krate) { - break 'if_chain ( - try_branch, - cf_continue, - cf_break, - try_from_residual, - ); + break 'if_chain (try_branch, cf_continue, cf_break, try_from_residual); } } } @@ -634,15 +625,10 @@ impl ExprCollector<'_> { let operand = self.collect_expr_opt(e.expr()); let try_branch = self.alloc_expr(Expr::Path(try_branch), syntax_ptr.clone()); let expr = self.alloc_expr( - Expr::Call { - callee: try_branch, - args: Box::new([operand]), - is_assignee_expr: false, - }, + Expr::Call { callee: try_branch, args: Box::new([operand]), is_assignee_expr: false }, syntax_ptr.clone(), ); - let continue_binding = - self.alloc_binding(name![v1], BindingAnnotation::Unannotated); + let continue_binding = self.alloc_binding(name![v1], BindingAnnotation::Unannotated); let continue_bpat = self.alloc_pat_desugared(Pat::Bind { id: continue_binding, subpat: None }); self.add_definition_to_binding(continue_binding, continue_bpat); @@ -656,8 +642,7 @@ impl ExprCollector<'_> { expr: self.alloc_expr(Expr::Path(Path::from(name![v1])), syntax_ptr.clone()), }; let break_binding = self.alloc_binding(name![v1], BindingAnnotation::Unannotated); - let break_bpat = - self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None }); + let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None }); self.add_definition_to_binding(break_binding, break_bpat); let break_arm = MatchArm { pat: self.alloc_pat_desugared(Pat::TupleStruct { @@ -667,10 +652,8 @@ impl ExprCollector<'_> { }), guard: None, expr: { - let x = - self.alloc_expr(Expr::Path(Path::from(name![v1])), syntax_ptr.clone()); - let callee = - self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr.clone()); + let x = self.alloc_expr(Expr::Path(Path::from(name![v1])), syntax_ptr.clone()); + let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr.clone()); let result = self.alloc_expr( Expr::Call { callee, args: Box::new([x]), is_assignee_expr: false }, syntax_ptr.clone(), @@ -1030,8 +1013,9 @@ impl ExprCollector<'_> { .collect(), } } - ast::Pat::LiteralPat(lit) => 'b: { - if let Some(ast_lit) = lit.literal() { + // FIXME: rustfmt removes this label if it is a block and not a loop + ast::Pat::LiteralPat(lit) => 'b: loop { + break if let Some(ast_lit) = lit.literal() { let mut hir_lit: Literal = ast_lit.kind().into(); if lit.minus_token().is_some() { let Some(h) = hir_lit.negate() else { @@ -1045,8 +1029,8 @@ impl ExprCollector<'_> { Pat::Lit(expr_id) } else { Pat::Missing - } - } + }; + }, ast::Pat::RestPat(_) => { // `RestPat` requires special handling and should not be mapped // to a Pat. Here we are using `Pat::Missing` as a fallback for diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index ecc163a4151c..a658bfa0c9a8 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -166,8 +166,7 @@ fn reference_autoderef() { #[test] fn overloaded_deref() { - // FIXME: We should support this. - check_fail( + check_number( r#" //- minicore: deref_mut struct Foo; @@ -185,9 +184,7 @@ fn overloaded_deref() { *y + *x }; "#, - ConstEvalError::MirLowerError(MirLowerError::NotSupported( - "explicit overloaded deref".into(), - )), + 10, ); } @@ -698,7 +695,7 @@ fn pattern_matching_literal() { } const GOAL: i32 = f(-1) + f(1) + f(0) + f(-5); "#, - 211 + 211, ); check_number( r#" @@ -711,7 +708,7 @@ fn pattern_matching_literal() { } const GOAL: u8 = f("foo") + f("bar"); "#, - 11 + 11, ); } @@ -1116,6 +1113,22 @@ fn function_traits() { "#, 15, ); + check_number( + r#" + //- minicore: coerce_unsized, fn + fn add2(x: u8) -> u8 { + x + 2 + } + fn call(f: &dyn Fn(u8) -> u8, x: u8) -> u8 { + f(x) + } + fn call_mut(f: &mut dyn FnMut(u8) -> u8, x: u8) -> u8 { + f(x) + } + const GOAL: u8 = call(&add2, 3) + call_mut(&mut add2, 3); + "#, + 10, + ); check_number( r#" //- minicore: fn diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 06d74215fffb..d1b9aff36d24 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -57,6 +57,7 @@ mod expr; mod pat; mod coerce; mod closure; +mod mutability; /// The entry point of type inference. pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { @@ -99,6 +100,8 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc InferenceContext<'a> { if let Some(fn_x) = func { match fn_x { FnTrait::FnOnce => (), - FnTrait::FnMut => adjustments.push(Adjustment::borrow( - Mutability::Mut, - derefed_callee.clone(), - )), - FnTrait::Fn => adjustments.push(Adjustment::borrow( - Mutability::Not, - derefed_callee.clone(), - )), + FnTrait::FnMut => { + if !matches!( + derefed_callee.kind(Interner), + TyKind::Ref(Mutability::Mut, _, _) + ) { + adjustments.push(Adjustment::borrow( + Mutability::Mut, + derefed_callee.clone(), + )); + } + } + FnTrait::Fn => { + if !matches!( + derefed_callee.kind(Interner), + TyKind::Ref(Mutability::Not, _, _) + ) { + adjustments.push(Adjustment::borrow( + Mutability::Not, + derefed_callee.clone(), + )); + } + } } let trait_ = fn_x .get_id(self.db, self.trait_env.krate) @@ -673,6 +687,23 @@ impl<'a> InferenceContext<'a> { // FIXME: Note down method resolution her match op { UnaryOp::Deref => { + if let Some(deref_trait) = self + .db + .lang_item(self.table.trait_env.krate, LangItem::Deref) + .and_then(|l| l.as_trait()) + { + if let Some(deref_fn) = + self.db.trait_data(deref_trait).method_by_name(&name![deref]) + { + // FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that + // the mutability is not wrong, and will be fixed in `self.infer_mut`). + self.write_method_resolution( + tgt_expr, + deref_fn, + Substitution::empty(Interner), + ); + } + } autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty()) } UnaryOp::Neg => { diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs new file mode 100644 index 000000000000..8e3d71788f2f --- /dev/null +++ b/crates/hir-ty/src/infer/mutability.rs @@ -0,0 +1,182 @@ +//! Finds if an expression is an immutable context or a mutable context, which is used in selecting +//! between `Deref` and `DerefMut` or `Index` and `IndexMut` or similar. + +use chalk_ir::Mutability; +use hir_def::{ + expr::{Array, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp}, + lang_item::LangItem, +}; +use hir_expand::name; + +use crate::{lower::lower_to_chalk_mutability, Adjust, AutoBorrow, OverloadedDeref}; + +use super::InferenceContext; + +impl<'a> InferenceContext<'a> { + pub(crate) fn infer_mut_body(&mut self) { + self.infer_mut_expr(self.body.body_expr, Mutability::Not); + } + + fn infer_mut_expr(&mut self, tgt_expr: ExprId, mut mutability: Mutability) { + let mut v = vec![]; + let adjustments = self.result.expr_adjustments.get_mut(&tgt_expr).unwrap_or(&mut v); + for adj in adjustments.iter_mut().rev() { + match &mut adj.kind { + Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => (), + Adjust::Deref(Some(d)) => *d = OverloadedDeref(Some(mutability)), + Adjust::Borrow(b) => match b { + AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m) => mutability = *m, + }, + } + } + self.infer_mut_expr_without_adjust(tgt_expr, mutability); + } + + fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) { + match &self.body[tgt_expr] { + Expr::Missing => (), + &Expr::If { condition, then_branch, else_branch } => { + self.infer_mut_expr(condition, Mutability::Not); + self.infer_mut_expr(then_branch, Mutability::Not); + if let Some(else_branch) = else_branch { + self.infer_mut_expr(else_branch, Mutability::Not); + } + } + Expr::Let { pat, expr } => self.infer_mut_expr(*expr, self.pat_bound_mutability(*pat)), + Expr::Block { id: _, statements, tail, label: _ } + | Expr::TryBlock { id: _, statements, tail } + | Expr::Async { id: _, statements, tail } + | Expr::Const { id: _, statements, tail } + | Expr::Unsafe { id: _, statements, tail } => { + for st in statements.iter() { + match st { + Statement::Let { pat, type_ref: _, initializer, else_branch } => { + if let Some(i) = initializer { + self.infer_mut_expr(*i, self.pat_bound_mutability(*pat)); + } + if let Some(e) = else_branch { + self.infer_mut_expr(*e, Mutability::Not); + } + } + Statement::Expr { expr, has_semi: _ } => { + self.infer_mut_expr(*expr, Mutability::Not); + } + } + } + if let Some(tail) = tail { + self.infer_mut_expr(*tail, Mutability::Not); + } + } + &Expr::For { iterable: c, pat: _, body, label: _ } + | &Expr::While { condition: c, body, label: _ } => { + self.infer_mut_expr(c, Mutability::Not); + self.infer_mut_expr(body, Mutability::Not); + } + Expr::MethodCall { receiver: x, method_name: _, args, generic_args: _ } + | Expr::Call { callee: x, args, is_assignee_expr: _ } => { + self.infer_mut_not_expr_iter(args.iter().copied().chain(Some(*x))); + } + Expr::Match { expr, arms } => { + let m = self.pat_iter_bound_mutability(arms.iter().map(|x| x.pat)); + self.infer_mut_expr(*expr, m); + for arm in arms.iter() { + self.infer_mut_expr(arm.expr, Mutability::Not); + } + } + Expr::Yield { expr } + | Expr::Yeet { expr } + | Expr::Return { expr } + | Expr::Break { expr, label: _ } => { + if let &Some(expr) = expr { + self.infer_mut_expr(expr, Mutability::Not); + } + } + Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => { + self.infer_mut_not_expr_iter(fields.iter().map(|x| x.expr).chain(*spread)) + } + &Expr::Index { base, index } => { + self.infer_mut_expr(base, mutability); + self.infer_mut_expr(index, Mutability::Not); + } + Expr::UnaryOp { expr, op: UnaryOp::Deref } => { + if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { + if mutability == Mutability::Mut { + if let Some(deref_trait) = self + .db + .lang_item(self.table.trait_env.krate, LangItem::DerefMut) + .and_then(|l| l.as_trait()) + { + if let Some(deref_fn) = + self.db.trait_data(deref_trait).method_by_name(&name![deref_mut]) + { + *f = deref_fn; + } + } + } + } + self.infer_mut_expr(*expr, mutability); + } + Expr::Field { expr, name: _ } => { + self.infer_mut_expr(*expr, mutability); + } + Expr::UnaryOp { expr, op: _ } + | Expr::Range { lhs: Some(expr), rhs: None, range_type: _ } + | Expr::Range { rhs: Some(expr), lhs: None, range_type: _ } + | Expr::Await { expr } + | Expr::Box { expr } + | Expr::Loop { body: expr, label: _ } + | Expr::Cast { expr, type_ref: _ } => { + self.infer_mut_expr(*expr, Mutability::Not); + } + Expr::Ref { expr, rawness: _, mutability } => { + let mutability = lower_to_chalk_mutability(*mutability); + self.infer_mut_expr(*expr, mutability); + } + Expr::Array(Array::Repeat { initializer: lhs, repeat: rhs }) + | Expr::BinaryOp { lhs, rhs, op: _ } + | Expr::Range { lhs: Some(lhs), rhs: Some(rhs), range_type: _ } => { + self.infer_mut_expr(*lhs, Mutability::Not); + self.infer_mut_expr(*rhs, Mutability::Not); + } + // not implemented + Expr::Closure { .. } => (), + Expr::Tuple { exprs, is_assignee_expr: _ } + | Expr::Array(Array::ElementList { elements: exprs, is_assignee_expr: _ }) => { + self.infer_mut_not_expr_iter(exprs.iter().copied()); + } + // These don't need any action, as they don't have sub expressions + Expr::Range { lhs: None, rhs: None, range_type: _ } + | Expr::Literal(_) + | Expr::Path(_) + | Expr::Continue { .. } + | Expr::Underscore => (), + } + } + + fn infer_mut_not_expr_iter(&mut self, exprs: impl Iterator) { + for expr in exprs { + self.infer_mut_expr(expr, Mutability::Not); + } + } + + fn pat_iter_bound_mutability(&self, mut pat: impl Iterator) -> Mutability { + if pat.any(|p| self.pat_bound_mutability(p) == Mutability::Mut) { + Mutability::Mut + } else { + Mutability::Not + } + } + + /// Checks if the pat contains a `ref mut` binding. Such paths makes the context of bounded expressions + /// mutable. For example in `let (ref mut x0, ref x1) = *x;` we need to use `DerefMut` for `*x` but in + /// `let (ref x0, ref x1) = *x;` we should use `Deref`. + fn pat_bound_mutability(&self, pat: PatId) -> Mutability { + let mut r = Mutability::Not; + self.body.walk_bindings_in_pat(pat, |b| { + if self.body.bindings[b].mode == BindingAnnotation::RefMut { + r = Mutability::Mut; + } + }); + r + } +} diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 450cd5404e5e..f8545e88ad54 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1,6 +1,6 @@ //! This module provides a MIR interpreter, which is used in const eval. -use std::{borrow::Cow, collections::HashMap, iter, sync::Arc}; +use std::{borrow::Cow, collections::HashMap, iter, ops::Range, sync::Arc}; use base_db::CrateId; use chalk_ir::{ @@ -109,6 +109,10 @@ impl Interval { fn get<'a>(&self, memory: &'a Evaluator<'a>) -> Result<&'a [u8]> { memory.read_memory(self.addr, self.size) } + + fn slice(self, range: Range) -> Interval { + Interval { addr: self.addr.offset(range.start), size: range.len() } + } } enum IntervalOrOwned { @@ -423,7 +427,6 @@ impl Evaluator<'_> { args: impl Iterator>, subst: Substitution, ) -> Result> { - dbg!(body.dbg(self.db)); if let Some(x) = self.stack_depth_limit.checked_sub(1) { self.stack_depth_limit = x; } else { @@ -1360,24 +1363,24 @@ impl Evaluator<'_> { locals: &Locals<'_>, ) -> Result<()> { let func = args.get(0).ok_or(MirEvalError::TypeError("fn trait with no arg"))?; - let ref_func_ty = self.operand_ty(func, locals)?; - let func_ty = match ft { - FnTrait::FnOnce => ref_func_ty, - FnTrait::FnMut | FnTrait::Fn => match ref_func_ty.as_reference() { - Some(x) => x.0.clone(), - None => return Err(MirEvalError::TypeError("fn trait with non-reference arg")), - }, - }; + let mut func_ty = self.operand_ty(func, locals)?; + let mut func_data = self.eval_operand(func, locals)?; + while let TyKind::Ref(_, _, z) = func_ty.kind(Interner) { + func_ty = z.clone(); + if matches!(func_ty.kind(Interner), TyKind::Dyn(_)) { + let id = + from_bytes!(usize, &func_data.get(self)?[self.ptr_size()..self.ptr_size() * 2]); + func_data = func_data.slice(0..self.ptr_size()); + func_ty = self.vtable_map.ty(id)?.clone(); + } + let size = self.size_of_sized(&func_ty, locals, "self type of fn trait")?; + func_data = Interval { addr: Address::from_bytes(func_data.get(self)?)?, size }; + } match &func_ty.data(Interner).kind { TyKind::FnDef(def, subst) => { self.exec_fn_def(*def, subst, destination, &args[1..], locals)?; } TyKind::Function(_) => { - let mut func_data = self.eval_operand(func, locals)?; - if let FnTrait::FnMut | FnTrait::Fn = ft { - let addr = Address::from_bytes(func_data.get(self)?)?; - func_data = Interval { addr, size: self.ptr_size() }; - } self.exec_fn_pointer(func_data, destination, &args[1..], locals)?; } x => not_supported!("Call {ft:?} trait methods with type {x:?}"), diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 4da0f8760997..04175fb4d956 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -4,7 +4,7 @@ use std::{iter, mem, sync::Arc}; use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; use hir_def::{ - adt::{VariantData, StructKind}, + adt::{StructKind, VariantData}, body::Body, expr::{ Array, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm, Pat, PatId, diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs index b683dd7f90d6..c6f4f66ada0e 100644 --- a/crates/hir-ty/src/mir/lower/as_place.rs +++ b/crates/hir-ty/src/mir/lower/as_place.rs @@ -145,10 +145,32 @@ impl MirLowerCtx<'_> { self.expr_ty(*expr).kind(Interner), TyKind::Ref(..) | TyKind::Raw(..) ) { - let Some(_) = self.lower_expr_as_place(current, *expr, true)? else { + let Some((p, current)) = self.lower_expr_as_place(current, *expr, true)? else { return Ok(None); }; - not_supported!("explicit overloaded deref"); + return self.lower_overloaded_deref( + current, + p, + self.expr_ty_after_adjustments(*expr), + self.expr_ty(expr_id), + expr_id.into(), + 'b: { + if let Some((f, _)) = self.infer.method_resolution(expr_id) { + if let Some(deref_trait) = + self.resolve_lang_item(LangItem::DerefMut)?.as_trait() + { + if let Some(deref_fn) = self + .db + .trait_data(deref_trait) + .method_by_name(&name![deref_mut]) + { + break 'b deref_fn == f; + } + } + } + false + }, + ); } let Some((mut r, current)) = self.lower_expr_as_place(current, *expr, true)? else { return Ok(None); diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index ab3bb643e7a7..9ec2913dce97 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -1,6 +1,6 @@ //! A pretty-printer for MIR. -use std::fmt::{Display, Write, Debug}; +use std::fmt::{Debug, Display, Write}; use hir_def::{body::Body, expr::BindingId}; use hir_expand::name::Name; @@ -24,7 +24,7 @@ impl MirBody { ctx.result } - // String with lines is rendered poorly in `dbg!` macros, which I use very much, so this + // String with lines is rendered poorly in `dbg` macros, which I use very much, so this // function exists to solve that. pub fn dbg(&self, db: &dyn HirDatabase) -> impl Debug { struct StringDbg(String); diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs index 696bdef03fcb..9f624cc32c0c 100644 --- a/crates/hir-ty/src/tests/coercion.rs +++ b/crates/hir-ty/src/tests/coercion.rs @@ -258,7 +258,6 @@ fn test() { #[test] fn coerce_autoderef_block() { - // FIXME: We should know mutability in overloaded deref check_no_mismatches( r#" //- minicore: deref @@ -268,7 +267,7 @@ fn takes_ref_str(x: &str) {} fn returns_string() -> String { loop {} } fn test() { takes_ref_str(&{ returns_string() }); - // ^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(None), Deref(Some(OverloadedDeref(None))), Borrow(Ref(Not)) + // ^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(None), Deref(Some(OverloadedDeref(Some(Not)))), Borrow(Ref(Not)) } "#, ); diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs index 378d47833610..f3ca93672d9f 100644 --- a/crates/hir-ty/src/tests/method_resolution.rs +++ b/crates/hir-ty/src/tests/method_resolution.rs @@ -1255,7 +1255,6 @@ fn foo(a: &T) { #[test] fn autoderef_visibility_field() { - // FIXME: We should know mutability in overloaded deref check( r#" //- minicore: deref @@ -1277,7 +1276,7 @@ mod a { mod b { fn foo() { let x = super::a::Bar::new().0; - // ^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(None))) + // ^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(Some(Not)))) // ^^^^^^^^^^^^^^^^^^^^^^ type: char } } diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 03951ea2bf51..83c61f73db63 100644 --- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -566,7 +566,6 @@ fn f(x: [(i32, u8); 10]) { #[test] fn overloaded_deref() { - // FIXME: check for false negative check_diagnostics( r#" //- minicore: deref_mut @@ -574,22 +573,36 @@ use core::ops::{Deref, DerefMut}; struct Foo; impl Deref for Foo { - type Target = i32; - fn deref(&self) -> &i32 { - &5 + type Target = (i32, u8); + fn deref(&self) -> &(i32, u8) { + &(5, 2) } } impl DerefMut for Foo { - fn deref_mut(&mut self) -> &mut i32 { - &mut 5 + fn deref_mut(&mut self) -> &mut (i32, u8) { + &mut (5, 2) } } fn f() { - let x = Foo; + let mut x = Foo; + //^^^^^ 💡 weak: variable does not need to be mutable let y = &*x; let x = Foo; - let mut x = Foo; - let y: &mut i32 = &mut x; + let y = &mut *x; + //^^ 💡 error: cannot mutate immutable variable `x` + let x = Foo; + let x = Foo; + let y: &mut (i32, u8) = &mut x; + //^^^^^^ 💡 error: cannot mutate immutable variable `x` + let ref mut y = *x; + //^^ 💡 error: cannot mutate immutable variable `x` + let (ref mut y, _) = *x; + //^^ 💡 error: cannot mutate immutable variable `x` + match *x { + //^^ 💡 error: cannot mutate immutable variable `x` + (ref y, _) => (), + (_, ref mut y) => (), + } } "#, ); diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index 1e1771259b1b..11e6dc05fa10 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -435,7 +435,7 @@ fn main() { file_id: FileId( 1, ), - range: 3415..3423, + range: 5805..5813, }, ), tooltip: "", @@ -448,7 +448,7 @@ fn main() { file_id: FileId( 1, ), - range: 3447..3451, + range: 5837..5841, }, ), tooltip: "", @@ -468,7 +468,7 @@ fn main() { file_id: FileId( 1, ), - range: 3415..3423, + range: 5805..5813, }, ), tooltip: "", @@ -481,7 +481,7 @@ fn main() { file_id: FileId( 1, ), - range: 3447..3451, + range: 5837..5841, }, ), tooltip: "", @@ -501,7 +501,7 @@ fn main() { file_id: FileId( 1, ), - range: 3415..3423, + range: 5805..5813, }, ), tooltip: "", @@ -514,7 +514,7 @@ fn main() { file_id: FileId( 1, ), - range: 3447..3451, + range: 5837..5841, }, ), tooltip: "", diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index ac9bd8e39dc0..5cc3bad04be1 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -1126,5 +1126,5 @@ fn benchmark_syntax_highlighting_parser() { .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function)) .count() }; - assert_eq!(hash, 1608); + assert_eq!(hash, 1170); } diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 548b5ba8b8b6..1c15a606f957 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -613,7 +613,7 @@ Pat = | ConstBlockPat LiteralPat = - Literal + '-'? Literal IdentPat = Attr* 'ref'? 'mut'? Name ('@' Pat)? diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index a2124f3ac164..0e84aca5c7d9 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -1375,8 +1375,8 @@ pub struct LiteralPat { pub(crate) syntax: SyntaxNode, } impl LiteralPat { - pub fn literal(&self) -> Option { support::child(&self.syntax) } pub fn minus_token(&self) -> Option { support::token(&self.syntax, T![-]) } + pub fn literal(&self) -> Option { support::child(&self.syntax) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs index e954b58251fa..77a8363a185c 100644 --- a/crates/syntax/src/tests/sourcegen_ast.rs +++ b/crates/syntax/src/tests/sourcegen_ast.rs @@ -535,6 +535,7 @@ impl Field { "!" => "excl", "*" => "star", "&" => "amp", + "-" => "minus", "_" => "underscore", "." => "dot", ".." => "dotdot", diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index bf592c1f7be8..118b9ad631bf 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -375,6 +375,68 @@ pub mod ops { type Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } + + mod impls { + use crate::marker::Tuple; + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const Fn for &F + where + F: ~const Fn, + { + extern "rust-call" fn call(&self, args: A) -> F::Output { + (**self).call(args) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const FnMut for &F + where + F: ~const Fn, + { + extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { + (**self).call(args) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const FnOnce for &F + where + F: ~const Fn, + { + type Output = F::Output; + + extern "rust-call" fn call_once(self, args: A) -> F::Output { + (*self).call(args) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const FnMut for &mut F + where + F: ~const FnMut, + { + extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { + (*self).call_mut(args) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl const FnOnce for &mut F + where + F: ~const FnMut, + { + type Output = F::Output; + extern "rust-call" fn call_once(self, args: A) -> F::Output { + (*self).call_mut(args) + } + } + } } pub use self::function::{Fn, FnMut, FnOnce}; // endregion:fn From 9ad83deeccd8cb3d375b5558eb7e3d339b1a4e0b Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Fri, 17 Mar 2023 19:10:25 +0330 Subject: [PATCH 1190/2442] Support overloaded index MIR lowering --- crates/hir-ty/src/consteval/tests.rs | 46 +++++++++++++- crates/hir-ty/src/infer/mutability.rs | 15 +++++ crates/hir-ty/src/mir/lower/as_place.rs | 63 ++++++++++++++++++- .../src/handlers/mutability_errors.rs | 48 ++++++++++++++ 4 files changed, 169 insertions(+), 3 deletions(-) diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index a658bfa0c9a8..944912b6c262 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -2,7 +2,8 @@ use base_db::fixture::WithFixture; use hir_def::db::DefDatabase; use crate::{ - consteval::try_const_usize, db::HirDatabase, test_db::TestDB, Const, ConstScalar, Interner, + consteval::try_const_usize, db::HirDatabase, mir::pad16, test_db::TestDB, Const, ConstScalar, + Interner, }; use super::{ @@ -30,7 +31,12 @@ fn check_number(ra_fixture: &str, answer: i128) { match &r.data(Interner).value { chalk_ir::ConstValue::Concrete(c) => match &c.interned { ConstScalar::Bytes(b, _) => { - assert_eq!(b, &answer.to_le_bytes()[0..b.len()]); + assert_eq!( + b, + &answer.to_le_bytes()[0..b.len()], + "Bytes differ. In decimal form: actual = {}, expected = {answer}", + i128::from_le_bytes(pad16(b, true)) + ); } x => panic!("Expected number but found {:?}", x), }, @@ -215,6 +221,42 @@ fn overloaded_deref_autoref() { ); } +#[test] +fn overloaded_index() { + check_number( + r#" + //- minicore: index + struct Foo; + + impl core::ops::Index for Foo { + type Output = i32; + fn index(&self, index: usize) -> &i32 { + if index == 7 { + &700 + } else { + &1000 + } + } + } + + impl core::ops::IndexMut for Foo { + fn index_mut(&mut self, index: usize) -> &mut i32 { + if index == 7 { + &mut 7 + } else { + &mut 10 + } + } + } + + const GOAL: i32 = { + (Foo[2]) + (Foo[7]) + (*&Foo[2]) + (*&Foo[7]) + (*&mut Foo[2]) + (*&mut Foo[7]) + }; + "#, + 3417, + ); +} + #[test] fn function_call() { check_number( diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs index 8e3d71788f2f..784725da9350 100644 --- a/crates/hir-ty/src/infer/mutability.rs +++ b/crates/hir-ty/src/infer/mutability.rs @@ -95,6 +95,21 @@ impl<'a> InferenceContext<'a> { self.infer_mut_not_expr_iter(fields.iter().map(|x| x.expr).chain(*spread)) } &Expr::Index { base, index } => { + if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { + if mutability == Mutability::Mut { + if let Some(index_trait) = self + .db + .lang_item(self.table.trait_env.krate, LangItem::IndexMut) + .and_then(|l| l.as_trait()) + { + if let Some(index_fn) = + self.db.trait_data(index_trait).method_by_name(&name![index_mut]) + { + *f = index_fn; + } + } + } + } self.infer_mut_expr(base, mutability); self.infer_mut_expr(index, Mutability::Not); } diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs index c6f4f66ada0e..425904850ba8 100644 --- a/crates/hir-ty/src/mir/lower/as_place.rs +++ b/crates/hir-ty/src/mir/lower/as_place.rs @@ -1,6 +1,7 @@ //! MIR lowering for places use super::*; +use hir_def::FunctionId; use hir_expand::name; macro_rules! not_supported { @@ -193,7 +194,24 @@ impl MirLowerCtx<'_> { if index_ty != TyBuilder::usize() || !matches!(base_ty.kind(Interner), TyKind::Array(..) | TyKind::Slice(..)) { - not_supported!("overloaded index"); + let Some(index_fn) = self.infer.method_resolution(expr_id) else { + return Err(MirLowerError::UnresolvedMethod); + }; + let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else { + return Ok(None); + }; + let Some((index_operand, current)) = self.lower_expr_to_some_operand(*index, current)? else { + return Ok(None); + }; + return self.lower_overloaded_index( + current, + base_place, + self.expr_ty_after_adjustments(*base), + self.expr_ty(expr_id), + index_operand, + expr_id.into(), + index_fn, + ); } let Some((mut p_base, current)) = self.lower_expr_as_place(current, *base, true)? else { @@ -210,6 +228,49 @@ impl MirLowerCtx<'_> { } } + fn lower_overloaded_index( + &mut self, + current: BasicBlockId, + place: Place, + base_ty: Ty, + result_ty: Ty, + index_operand: Operand, + span: MirSpan, + index_fn: (FunctionId, Substitution), + ) -> Result> { + let is_mutable = 'b: { + if let Some(index_mut_trait) = self.resolve_lang_item(LangItem::IndexMut)?.as_trait() { + if let Some(index_mut_fn) = + self.db.trait_data(index_mut_trait).method_by_name(&name![index_mut]) + { + break 'b index_mut_fn == index_fn.0; + } + } + false + }; + let (mutability, borrow_kind) = match is_mutable { + true => (Mutability::Mut, BorrowKind::Mut { allow_two_phase_borrow: false }), + false => (Mutability::Not, BorrowKind::Shared), + }; + let base_ref = TyKind::Ref(mutability, static_lifetime(), base_ty).intern(Interner); + let result_ref = TyKind::Ref(mutability, static_lifetime(), result_ty).intern(Interner); + let ref_place: Place = self.temp(base_ref)?.into(); + self.push_assignment(current, ref_place.clone(), Rvalue::Ref(borrow_kind, place), span); + let mut result: Place = self.temp(result_ref)?.into(); + let index_fn_op = Operand::const_zst( + TyKind::FnDef( + self.db.intern_callable_def(CallableDefId::FunctionId(index_fn.0)).into(), + index_fn.1, + ) + .intern(Interner), + ); + let Some(current) = self.lower_call(index_fn_op, vec![Operand::Copy(ref_place), index_operand], result.clone(), current, false)? else { + return Ok(None); + }; + result.projection.push(ProjectionElem::Deref); + Ok(Some((result, current))) + } + fn lower_overloaded_deref( &mut self, current: BasicBlockId, diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 83c61f73db63..17a70f5701bc 100644 --- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -564,6 +564,54 @@ fn f(x: [(i32, u8); 10]) { ); } + #[test] + fn overloaded_index() { + check_diagnostics( + r#" +//- minicore: index +use core::ops::{Index, IndexMut}; + +struct Foo; +impl Index for Foo { + type Output = (i32, u8); + fn index(&self, index: usize) -> &(i32, u8) { + &(5, 2) + } +} +impl IndexMut for Foo { + fn index_mut(&mut self, index: usize) -> &mut (i32, u8) { + &mut (5, 2) + } +} +fn f() { + let mut x = Foo; + //^^^^^ 💡 weak: variable does not need to be mutable + let y = &x[2]; + let x = Foo; + let y = &mut x[2]; + //^^^^ 💡 error: cannot mutate immutable variable `x` + let mut x = &mut Foo; + //^^^^^ 💡 weak: variable does not need to be mutable + let y: &mut (i32, u8) = &mut x[2]; + let x = Foo; + let ref mut y = x[7]; + //^^^^ 💡 error: cannot mutate immutable variable `x` + let (ref mut y, _) = x[3]; + //^^^^ 💡 error: cannot mutate immutable variable `x` + match x[10] { + //^^^^^ 💡 error: cannot mutate immutable variable `x` + (ref y, _) => (), + (_, ref mut y) => (), + } + let mut x = Foo; + let mut i = 5; + //^^^^^ 💡 weak: variable does not need to be mutable + let y = &mut x[i]; +} +"#, + ); + } + #[test] fn overloaded_deref() { check_diagnostics( From 453ae2e00e2f3bcd96a2fa78626296e14641dae8 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sat, 18 Mar 2023 02:06:36 +0330 Subject: [PATCH 1191/2442] Support range MIR lowering --- crates/hir-ty/src/consteval/tests.rs | 12 +++++++ crates/hir-ty/src/infer/unify.rs | 9 ++++-- crates/hir-ty/src/mir/lower.rs | 48 ++++++++++++++++++++++++++-- crates/hir-ty/src/traits.rs | 4 +-- 4 files changed, 65 insertions(+), 8 deletions(-) diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 944912b6c262..97c8d62860c6 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -561,6 +561,18 @@ fn for_loops() { ); } +#[test] +fn ranges() { + check_number( + r#" + //- minicore: range + const GOAL: i32 = (1..2).start + (20..10).end + (100..=200).start + (2000..=1000).end + + (10000..).start + (..100000).end + (..=1000000).end; + "#, + 1111111, + ); +} + #[test] fn recursion() { check_number( diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 2a07dd708c2a..0e516b9399a6 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -633,7 +633,10 @@ impl<'a> InferenceTable<'a> { ) -> Option<(Option, Vec, Ty)> { match ty.callable_sig(self.db) { Some(sig) => Some((None, sig.params().to_vec(), sig.ret().clone())), - None => self.callable_sig_from_fn_trait(ty, num_args), + None => { + let (f, args_ty, return_ty) = self.callable_sig_from_fn_trait(ty, num_args)?; + Some((Some(f), args_ty, return_ty)) + } } } @@ -641,7 +644,7 @@ impl<'a> InferenceTable<'a> { &mut self, ty: &Ty, num_args: usize, - ) -> Option<(Option, Vec, Ty)> { + ) -> Option<(FnTrait, Vec, Ty)> { let krate = self.trait_env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; let trait_data = self.db.trait_data(fn_once_trait); @@ -693,7 +696,7 @@ impl<'a> InferenceTable<'a> { }; let canonical = self.canonicalize(obligation.clone()); if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() { - return Some((Some(fn_x), arg_tys, return_ty)); + return Some((fn_x, arg_tys, return_ty)); } } unreachable!("It should at least implement FnOnce at this point"); diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 04175fb4d956..4b43e44a8ec3 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -14,7 +14,7 @@ use hir_def::{ layout::LayoutError, path::Path, resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, - DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, LocalFieldId, TraitId, + AdtId, DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, LocalFieldId, TraitId, }; use hir_expand::name::Name; use la_arena::ArenaMap; @@ -643,7 +643,7 @@ impl MirLowerCtx<'_> { }, } }).collect(), - None => operands.into_iter().map(|x| x).collect::>().ok_or( + None => operands.into_iter().collect::>().ok_or( MirLowerError::TypeError("missing field in record literal"), )?, }, @@ -761,7 +761,49 @@ impl MirLowerCtx<'_> { ); Ok(Some(current)) } - Expr::Range { .. } => not_supported!("range"), + &Expr::Range { lhs, rhs, range_type: _ } => { + let ty = self.expr_ty(expr_id); + let Some((adt, subst)) = ty.as_adt() else { + return Err(MirLowerError::TypeError("Range type is not adt")); + }; + let AdtId::StructId(st) = adt else { + return Err(MirLowerError::TypeError("Range type is not struct")); + }; + let mut lp = None; + let mut rp = None; + if let Some(x) = lhs { + let Some((o, c)) = self.lower_expr_to_some_operand(x, current)? else { + return Ok(None); + }; + lp = Some(o); + current = c; + } + if let Some(x) = rhs { + let Some((o, c)) = self.lower_expr_to_some_operand(x, current)? else { + return Ok(None); + }; + rp = Some(o); + current = c; + } + self.push_assignment( + current, + place, + Rvalue::Aggregate( + AggregateKind::Adt(st.into(), subst.clone()), + self.db.struct_data(st).variant_data.fields().iter().map(|x| { + let o = match x.1.name.as_str() { + Some("start") => lp.take(), + Some("end") => rp.take(), + Some("exhausted") => Some(Operand::from_bytes(vec![0], TyBuilder::bool())), + _ => None, + }; + o.ok_or(MirLowerError::UnresolvedField) + }).collect::>()?, + ), + expr_id.into(), + ); + Ok(Some(current)) + }, Expr::Closure { .. } => not_supported!("closure"), Expr::Tuple { exprs, is_assignee_expr: _ } => { let Some(values) = exprs diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index aebf59f31525..e7fffc4cc7d7 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -188,7 +188,7 @@ impl FnTrait { } } - pub fn method_name(&self) -> Name { + pub fn method_name(self) -> Name { match self { FnTrait::FnOnce => name!(call_once), FnTrait::FnMut => name!(call_mut), @@ -196,7 +196,7 @@ impl FnTrait { } } - pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option { + pub fn get_id(self, db: &dyn HirDatabase, krate: CrateId) -> Option { let target = db.lang_item(krate, self.lang_item())?; match target { LangItemTarget::Trait(t) => Some(t), From f7113685b563f2b20e770ee1e901b2b93ccbc990 Mon Sep 17 00:00:00 2001 From: feniljain Date: Sat, 18 Mar 2023 11:43:45 +0530 Subject: [PATCH 1192/2442] fix: make tests valid rust code --- crates/ide-completion/src/tests/record.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/ide-completion/src/tests/record.rs b/crates/ide-completion/src/tests/record.rs index 2de42e8435e4..65cefdb0856d 100644 --- a/crates/ide-completion/src/tests/record.rs +++ b/crates/ide-completion/src/tests/record.rs @@ -81,6 +81,7 @@ fn foo(baz: Baz) { enum Baz { Foo, Bar } fn foo(baz: Baz) { + use Baz::*; match baz { Foo => (), $0 @@ -91,12 +92,14 @@ fn foo(baz: Baz) { en Baz en Result md core + ev Bar ev Err + ev Foo ev Ok - bn Baz::Bar Baz::Bar$0 - bn Baz::Foo Baz::Foo$0 - bn Err(…) Err($1)$0 - bn Ok(…) Ok($1)$0 + bn Bar Bar$0 + bn Err(…) Err($1)$0 + bn Foo Foo$0 + bn Ok(…) Ok($1)$0 kw mut kw ref "#]], From a79a76a94274c22676e2047039cf68ca199c07dd Mon Sep 17 00:00:00 2001 From: feniljain Date: Sat, 18 Mar 2023 11:43:57 +0530 Subject: [PATCH 1193/2442] refactor: pass is_variant_missing as args to build_completion --- crates/ide-completion/src/render.rs | 13 +----------- crates/ide-completion/src/render/pattern.rs | 23 +++++++++++++-------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index eb2df395c4d5..86302cb0678f 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -32,22 +32,11 @@ pub(crate) struct RenderContext<'a> { completion: &'a CompletionContext<'a>, is_private_editable: bool, import_to_add: Option, - // For variants which are missing - // in match completion context - // - // Option -> only applicable for enums - // bool -> is enum variant missing or not? - is_variant_missing: Option, } impl<'a> RenderContext<'a> { pub(crate) fn new(completion: &'a CompletionContext<'a>) -> RenderContext<'a> { - RenderContext { - completion, - is_private_editable: false, - import_to_add: None, - is_variant_missing: None, - } + RenderContext { completion, is_private_editable: false, import_to_add: None } } pub(crate) fn private_editable(mut self, private_editable: bool) -> Self { diff --git a/crates/ide-completion/src/render/pattern.rs b/crates/ide-completion/src/render/pattern.rs index d70f02127d5c..fcc78998153b 100644 --- a/crates/ide-completion/src/render/pattern.rs +++ b/crates/ide-completion/src/render/pattern.rs @@ -39,11 +39,11 @@ pub(crate) fn render_struct_pat( let db = ctx.db(); - Some(build_completion(ctx, label, lookup, pat, strukt, strukt.ty(db))) + Some(build_completion(ctx, label, lookup, pat, strukt, strukt.ty(db), false)) } pub(crate) fn render_variant_pat( - mut ctx: RenderContext<'_>, + ctx: RenderContext<'_>, pattern_ctx: &PatternContext, path_ctx: Option<&PathCompletionCtx>, variant: hir::Variant, @@ -56,11 +56,6 @@ pub(crate) fn render_variant_pat( let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?; let enum_ty = variant.parent_enum(ctx.db()).ty(ctx.db()); - // Missing in context of match statement completions - if pattern_ctx.missing_variants.contains(&variant) { - ctx.is_variant_missing = Some(true); - } - let (name, escaped_name) = match path { Some(path) => (path.unescaped().to_string().into(), path.to_string().into()), None => { @@ -89,7 +84,15 @@ pub(crate) fn render_variant_pat( } }; - Some(build_completion(ctx, label, lookup, pat, variant, enum_ty)) + Some(build_completion( + ctx, + label, + lookup, + pat, + variant, + enum_ty, + pattern_ctx.missing_variants.contains(&variant), + )) } fn build_completion( @@ -99,10 +102,12 @@ fn build_completion( pat: String, def: impl HasAttrs + Copy, adt_ty: hir::Type, + // Missing in context of match statement completions + is_variant_missing: bool, ) -> CompletionItem { let mut relevance = ctx.completion_relevance(); - if let Some(true) = ctx.is_variant_missing { + if is_variant_missing { relevance.type_match = super::compute_type_match(ctx.completion, &adt_ty); } From 1d1a86f3508581b5867df202c87016520fd221a5 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Sun, 19 Mar 2023 16:45:26 +0900 Subject: [PATCH 1194/2442] Bump chalk to 0.89 --- Cargo.lock | 16 ++++++++-------- crates/hir-ty/Cargo.toml | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc77515b63bf..25242c6028a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -169,9 +169,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chalk-derive" -version = "0.88.0" +version = "0.89.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df80a3fbc1f0e59f560eeeebca94bf655566a8ad3023c210a109deb6056455a" +checksum = "ea176c50987dc4765961aa165001e8eb5a722a26308c5797a47303ea91686aab" dependencies = [ "proc-macro2", "quote", @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.88.0" +version = "0.89.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f39e5272016916956298cceea5147006f897972c274a768ed4d6e074efe5d3fb" +checksum = "473b480241695428c14e8f84f1c9a47ef232450a50faf3a4041e5c9dc11e0a3b" dependencies = [ "bitflags", "chalk-derive", @@ -192,9 +192,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.88.0" +version = "0.89.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d60b42ad7478d3e027e2f9ea4e99fbbb8fdee0c8c3cf068be269f57e603618" +checksum = "6764b4fe67cac3a3758185084efbfbd39bf0352795824ba849ddd2b64cd4bb28" dependencies = [ "chalk-derive", "chalk-ir", @@ -205,9 +205,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.88.0" +version = "0.89.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab30620ea5b36819525eaab2204f4b8e1842fc7ee36826424a28bef59ae7fecf" +checksum = "55a7e6160966eceb6e7dcc2f479a2af4c477aaf5bccbc640d82515995ab1a6cc" dependencies = [ "chalk-derive", "chalk-ir", diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index 4572e33486f0..9b3296df2508 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -22,10 +22,10 @@ either = "1.7.0" tracing = "0.1.35" rustc-hash = "1.1.0" scoped-tls = "1.0.0" -chalk-solve = { version = "0.88.0", default-features = false } -chalk-ir = "0.88.0" -chalk-recursive = { version = "0.88.0", default-features = false } -chalk-derive = "0.88.0" +chalk-solve = { version = "0.89.0", default-features = false } +chalk-ir = "0.89.0" +chalk-recursive = { version = "0.89.0", default-features = false } +chalk-derive = "0.89.0" la-arena = { version = "0.3.0", path = "../../lib/la-arena" } once_cell = "1.17.0" typed-arena = "2.0.1" From e12460bbca48ec354c40caf51603ddc9f97c17a5 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Sun, 19 Mar 2023 16:58:10 +0900 Subject: [PATCH 1195/2442] Add regression test so that we can catch regressions when we move away from chalk. --- crates/hir-ty/src/tests/regression.rs | 32 +++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index e6b4f13c8d11..689f0da44f68 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -1756,3 +1756,35 @@ const C: usize = 2 + 2; "#, ); } + +#[test] +fn regression_14164() { + check_types( + r#" +trait Rec { + type K; + type Rebind: Rec; +} + +trait Expr { + type Part: Rec; + fn foo(_: ::Rebind) {} +} + +struct Head(K); +impl Rec for Head { + type K = K; + type Rebind = Head; +} + +fn test() +where + E: Expr>, +{ + let head; + //^^^^ Head + E::foo(head); +} +"#, + ); +} From 8e73ea52537fe5189fac5cd02380592563fe7f0c Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sun, 19 Mar 2023 13:02:51 +0330 Subject: [PATCH 1196/2442] Desugar try blocks --- crates/hir-def/src/body/lower.rs | 87 +++++++++++++++++++++++---- crates/hir-def/src/body/pretty.rs | 3 - crates/hir-def/src/body/scope.rs | 3 +- crates/hir-def/src/expr.rs | 6 -- crates/hir-expand/src/name.rs | 14 ++++- crates/hir-ty/src/consteval/tests.rs | 54 +++++++++++++++++ crates/hir-ty/src/infer.rs | 4 -- crates/hir-ty/src/infer/expr.rs | 20 ------ crates/hir-ty/src/infer/mutability.rs | 1 - crates/hir-ty/src/mir/lower.rs | 87 ++++++++++++++++++--------- crates/hir-ty/src/tests/traits.rs | 20 ++++-- 11 files changed, 215 insertions(+), 84 deletions(-) diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 448821d3844a..a93fcb3b1dc2 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -19,7 +19,7 @@ use rustc_hash::FxHashMap; use smallvec::SmallVec; use syntax::{ ast::{ - self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind, + self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasLoopBody, HasName, LiteralKind, SlicePatComponents, }, AstNode, AstPtr, SyntaxNodePtr, @@ -100,6 +100,7 @@ pub(super) fn lower( _c: Count::new(), }, expander, + current_try_block: None, is_lowering_assignee_expr: false, is_lowering_generator: false, } @@ -113,6 +114,7 @@ struct ExprCollector<'a> { body: Body, krate: CrateId, source_map: BodySourceMap, + current_try_block: Option, is_lowering_assignee_expr: bool, is_lowering_generator: bool, } @@ -222,6 +224,10 @@ impl ExprCollector<'_> { self.source_map.label_map.insert(src, id); id } + // FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow. + fn alloc_label_desugared(&mut self, label: Label) -> LabelId { + self.body.labels.alloc(label) + } fn make_label(&mut self, label: Label, src: LabelSource) -> LabelId { let id = self.body.labels.alloc(label); self.source_map.label_map_back.insert(id, src); @@ -259,13 +265,7 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr) } ast::Expr::BlockExpr(e) => match e.modifier() { - Some(ast::BlockModifier::Try(_)) => { - self.collect_block_(e, |id, statements, tail| Expr::TryBlock { - id, - statements, - tail, - }) - } + Some(ast::BlockModifier::Try(_)) => self.collect_try_block(e), Some(ast::BlockModifier::Unsafe(_)) => { self.collect_block_(e, |id, statements, tail| Expr::Unsafe { id, @@ -606,6 +606,59 @@ impl ExprCollector<'_> { }) } + /// Desugar `try { ; }` into `': { ; ::std::ops::Try::from_output() }`, + /// `try { ; }` into `': { ; ::std::ops::Try::from_output(()) }` + /// and save the `` to use it as a break target for desugaring of the `?` operator. + fn collect_try_block(&mut self, e: BlockExpr) -> ExprId { + let Some(try_from_output) = LangItem::TryTraitFromOutput.path(self.db, self.krate) else { + return self.alloc_expr_desugared(Expr::Missing); + }; + let prev_try_block = self.current_try_block.take(); + self.current_try_block = + Some(self.alloc_label_desugared(Label { name: Name::generate_new_name() })); + let expr_id = self.collect_block(e); + let callee = self.alloc_expr_desugared(Expr::Path(try_from_output)); + let Expr::Block { label, tail, .. } = &mut self.body.exprs[expr_id] else { + unreachable!("It is the output of collect block"); + }; + *label = self.current_try_block; + let next_tail = match *tail { + Some(tail) => self.alloc_expr_desugared(Expr::Call { + callee, + args: Box::new([tail]), + is_assignee_expr: false, + }), + None => { + let unit = self.alloc_expr_desugared(Expr::Tuple { + exprs: Box::new([]), + is_assignee_expr: false, + }); + self.alloc_expr_desugared(Expr::Call { + callee, + args: Box::new([unit]), + is_assignee_expr: false, + }) + } + }; + let Expr::Block { tail, .. } = &mut self.body.exprs[expr_id] else { + unreachable!("It is the output of collect block"); + }; + *tail = Some(next_tail); + self.current_try_block = prev_try_block; + expr_id + } + + /// Desugar `ast::TryExpr` from: `?` into: + /// ```ignore (pseudo-rust) + /// match Try::branch() { + /// ControlFlow::Continue(val) => val, + /// ControlFlow::Break(residual) => + /// // If there is an enclosing `try {...}`: + /// break 'catch_target Try::from_residual(residual), + /// // Otherwise: + /// return Try::from_residual(residual), + /// } + /// ``` fn collect_try_operator(&mut self, syntax_ptr: AstPtr, e: ast::TryExpr) -> ExprId { let (try_branch, cf_continue, cf_break, try_from_residual) = 'if_chain: { if let Some(try_branch) = LangItem::TryTraitBranch.path(self.db, self.krate) { @@ -628,7 +681,9 @@ impl ExprCollector<'_> { Expr::Call { callee: try_branch, args: Box::new([operand]), is_assignee_expr: false }, syntax_ptr.clone(), ); - let continue_binding = self.alloc_binding(name![v1], BindingAnnotation::Unannotated); + let continue_name = Name::generate_new_name(); + let continue_binding = + self.alloc_binding(continue_name.clone(), BindingAnnotation::Unannotated); let continue_bpat = self.alloc_pat_desugared(Pat::Bind { id: continue_binding, subpat: None }); self.add_definition_to_binding(continue_binding, continue_bpat); @@ -639,9 +694,10 @@ impl ExprCollector<'_> { ellipsis: None, }), guard: None, - expr: self.alloc_expr(Expr::Path(Path::from(name![v1])), syntax_ptr.clone()), + expr: self.alloc_expr(Expr::Path(Path::from(continue_name)), syntax_ptr.clone()), }; - let break_binding = self.alloc_binding(name![v1], BindingAnnotation::Unannotated); + let break_name = Name::generate_new_name(); + let break_binding = self.alloc_binding(break_name.clone(), BindingAnnotation::Unannotated); let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None }); self.add_definition_to_binding(break_binding, break_bpat); let break_arm = MatchArm { @@ -652,13 +708,18 @@ impl ExprCollector<'_> { }), guard: None, expr: { - let x = self.alloc_expr(Expr::Path(Path::from(name![v1])), syntax_ptr.clone()); + let x = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr.clone()); let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr.clone()); let result = self.alloc_expr( Expr::Call { callee, args: Box::new([x]), is_assignee_expr: false }, syntax_ptr.clone(), ); - self.alloc_expr(Expr::Return { expr: Some(result) }, syntax_ptr.clone()) + if let Some(label) = self.current_try_block { + let label = Some(self.body.labels[label].name.clone()); + self.alloc_expr(Expr::Break { expr: Some(result), label }, syntax_ptr.clone()) + } else { + self.alloc_expr(Expr::Return { expr: Some(result) }, syntax_ptr.clone()) + } }, }; let arms = Box::new([continue_arm, break_arm]); diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index c091ad0d150f..8c9d77620e18 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -420,9 +420,6 @@ impl<'a> Printer<'a> { Expr::Unsafe { id: _, statements, tail } => { self.print_block(Some("unsafe "), statements, tail); } - Expr::TryBlock { id: _, statements, tail } => { - self.print_block(Some("try "), statements, tail); - } Expr::Async { id: _, statements, tail } => { self.print_block(Some("async "), statements, tail); } diff --git a/crates/hir-def/src/body/scope.rs b/crates/hir-def/src/body/scope.rs index 12fc1f116d7d..8ddb89a4725d 100644 --- a/crates/hir-def/src/body/scope.rs +++ b/crates/hir-def/src/body/scope.rs @@ -202,8 +202,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope } Expr::Unsafe { id, statements, tail } | Expr::Async { id, statements, tail } - | Expr::Const { id, statements, tail } - | Expr::TryBlock { id, statements, tail } => { + | Expr::Const { id, statements, tail } => { let mut scope = scopes.new_block_scope(*scope, *id, None); // Overwrite the old scope for the block expr, so that every block scope can be found // via the block itself (important for blocks that only contain items, no expressions). diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs index 8b1528f81e61..7ede19cc3c2b 100644 --- a/crates/hir-def/src/expr.rs +++ b/crates/hir-def/src/expr.rs @@ -122,11 +122,6 @@ pub enum Expr { tail: Option, label: Option, }, - TryBlock { - id: BlockId, - statements: Box<[Statement]>, - tail: Option, - }, Async { id: BlockId, statements: Box<[Statement]>, @@ -310,7 +305,6 @@ impl Expr { f(*expr); } Expr::Block { statements, tail, .. } - | Expr::TryBlock { statements, tail, .. } | Expr::Unsafe { statements, tail, .. } | Expr::Async { statements, tail, .. } | Expr::Const { statements, tail, .. } => { diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 71eb35d9df8e..8099c20b027c 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -78,7 +78,7 @@ impl Name { Self::new_text(lt.text().into()) } - /// Shortcut to create inline plain text name + /// Shortcut to create inline plain text name. Panics if `text.len() > 22` const fn new_inline(text: &str) -> Name { Name::new_text(SmolStr::new_inline(text)) } @@ -112,6 +112,18 @@ impl Name { Name::new_inline("[missing name]") } + /// Generates a new name which is only equal to itself, by incrementing a counter. Due + /// its implementation, it should not be used in things that salsa considers, like + /// type names or field names, and it should be only used in names of local variables + /// and labels and similar things. + pub fn generate_new_name() -> Name { + use std::sync::atomic::{AtomicUsize, Ordering}; + static CNT: AtomicUsize = AtomicUsize::new(0); + let c = CNT.fetch_add(1, Ordering::Relaxed); + // FIXME: Currently a `__RA_generated_name` in user code will break our analysis + Name::new_text(format!("__RA_geneated_name_{c}").into()) + } + /// Returns the tuple index this name represents if it is a tuple field. pub fn as_tuple_index(&self) -> Option { match self.0 { diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 97c8d62860c6..2ba0cbd5db4f 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -522,6 +522,42 @@ fn loops() { "#, 4, ); + check_number( + r#" + const GOAL: u8 = { + let mut x = 0; + loop { + x = x + 1; + if x == 5 { + break x + 2; + } + } + }; + "#, + 7, + ); + check_number( + r#" + const GOAL: u8 = { + 'a: loop { + let x = 'b: loop { + let x = 'c: loop { + let x = 'd: loop { + let x = 'e: loop { + break 'd 1; + }; + break 2 + x; + }; + break 3 + x; + }; + break 'a 4 + x; + }; + break 5 + x; + } + }; + "#, + 8, + ); } #[test] @@ -1019,6 +1055,24 @@ fn try_operator() { ); } +#[test] +fn try_block() { + check_number( + r#" + //- minicore: option, try + const fn g(x: Option, y: Option) -> i32 { + let r = try { x? * y? }; + match r { + Some(k) => k, + None => 5, + } + } + const GOAL: i32 = g(Some(10), Some(20)) + g(Some(30), None) + g(None, Some(40)) + g(None, None); + "#, + 215, + ); +} + #[test] fn or_pattern() { check_number( diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index d1b9aff36d24..38b7dee75fd5 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -1025,10 +1025,6 @@ impl<'a> InferenceContext<'a> { self.resolve_lang_item(lang)?.as_trait() } - fn resolve_ops_try_output(&self) -> Option { - self.resolve_output_on(self.resolve_lang_trait(LangItem::Try)?) - } - fn resolve_ops_neg_output(&self) -> Option { self.resolve_output_on(self.resolve_lang_trait(LangItem::Neg)?) } diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 82119c97ec21..6d2aa59ea359 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -159,26 +159,6 @@ impl<'a> InferenceContext<'a> { }) .1 } - Expr::TryBlock { id: _, statements, tail } => { - // The type that is returned from the try block - let try_ty = self.table.new_type_var(); - if let Some(ty) = expected.only_has_type(&mut self.table) { - self.unify(&try_ty, &ty); - } - - // The ok-ish type that is expected from the last expression - let ok_ty = - self.resolve_associated_type(try_ty.clone(), self.resolve_ops_try_output()); - - self.infer_block( - tgt_expr, - statements, - *tail, - None, - &Expectation::has_type(ok_ty.clone()), - ); - try_ty - } Expr::Async { id: _, statements, tail } => { let ret_ty = self.table.new_type_var(); let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs index 784725da9350..7ed21d230c7f 100644 --- a/crates/hir-ty/src/infer/mutability.rs +++ b/crates/hir-ty/src/infer/mutability.rs @@ -44,7 +44,6 @@ impl<'a> InferenceContext<'a> { } Expr::Let { pat, expr } => self.infer_mut_expr(*expr, self.pat_bound_mutability(*pat)), Expr::Block { id: _, statements, tail, label: _ } - | Expr::TryBlock { id: _, statements, tail } | Expr::Async { id: _, statements, tail } | Expr::Const { id: _, statements, tail } | Expr::Unsafe { id: _, statements, tail } => { diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 4b43e44a8ec3..5d9ae320726f 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -18,6 +18,7 @@ use hir_def::{ }; use hir_expand::name::Name; use la_arena::ArenaMap; +use rustc_hash::FxHashMap; use crate::{ consteval::ConstEvalError, db::HirDatabase, display::HirDisplay, infer::TypeMismatch, @@ -32,17 +33,21 @@ mod pattern_matching; use pattern_matching::AdtPatternShape; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] struct LoopBlocks { begin: BasicBlockId, /// `None` for loops that are not terminating end: Option, + place: Place, } struct MirLowerCtx<'a> { result: MirBody, owner: DefWithBodyId, current_loop_blocks: Option, + // FIXME: we should resolve labels in HIR lowering and always work with label id here, not + // with raw names. + labeled_loop_blocks: FxHashMap, discr_temp: Option, db: &'a dyn HirDatabase, body: &'a Body, @@ -72,6 +77,7 @@ pub enum MirLowerError { ImplementationError(&'static str), LangItemNotFound(LangItem), MutatingRvalue, + UnresolvedLabel, } macro_rules! not_supported { @@ -375,19 +381,29 @@ impl MirLowerCtx<'_> { Ok(self.merge_blocks(Some(then_target), else_target)) } Expr::Unsafe { id: _, statements, tail } => { - self.lower_block_to_place(None, statements, current, *tail, place) + self.lower_block_to_place(statements, current, *tail, place) } Expr::Block { id: _, statements, tail, label } => { - self.lower_block_to_place(*label, statements, current, *tail, place) + if let Some(label) = label { + self.lower_loop(current, place.clone(), Some(*label), |this, begin| { + if let Some(block) = this.lower_block_to_place(statements, begin, *tail, place)? { + let end = this.current_loop_end()?; + this.set_goto(block, end); + } + Ok(()) + }) + } else { + self.lower_block_to_place(statements, current, *tail, place) + } } - Expr::Loop { body, label } => self.lower_loop(current, *label, |this, begin| { + Expr::Loop { body, label } => self.lower_loop(current, place, *label, |this, begin| { if let Some((_, block)) = this.lower_expr_as_place(begin, *body, true)? { this.set_goto(block, begin); } Ok(()) }), Expr::While { condition, body, label } => { - self.lower_loop(current, *label, |this, begin| { + self.lower_loop(current, place, *label, |this, begin| { let Some((discr, to_switch)) = this.lower_expr_to_some_operand(*condition, begin)? else { return Ok(()); }; @@ -438,7 +454,7 @@ impl MirLowerCtx<'_> { return Ok(None); }; self.push_assignment(current, ref_mut_iterator_place.clone(), Rvalue::Ref(BorrowKind::Mut { allow_two_phase_borrow: false }, iterator_place), expr_id.into()); - self.lower_loop(current, label, |this, begin| { + self.lower_loop(current, place, label, |this, begin| { let Some(current) = this.lower_call(iter_next_fn_op, vec![Operand::Copy(ref_mut_iterator_place)], option_item_place.clone(), begin, false)? else { return Ok(()); @@ -558,24 +574,28 @@ impl MirLowerCtx<'_> { Some(_) => not_supported!("continue with label"), None => { let loop_data = - self.current_loop_blocks.ok_or(MirLowerError::ContinueWithoutLoop)?; + self.current_loop_blocks.as_ref().ok_or(MirLowerError::ContinueWithoutLoop)?; self.set_goto(current, loop_data.begin); Ok(None) } }, Expr::Break { expr, label } => { - if expr.is_some() { - not_supported!("break with value"); - } - match label { - Some(_) => not_supported!("break with label"), - None => { - let end = - self.current_loop_end()?; - self.set_goto(current, end); - Ok(None) - } + if let Some(expr) = expr { + let loop_data = match label { + Some(l) => self.labeled_loop_blocks.get(l).ok_or(MirLowerError::UnresolvedLabel)?, + None => self.current_loop_blocks.as_ref().ok_or(MirLowerError::BreakWithoutLoop)?, + }; + let Some(c) = self.lower_expr_to_place(*expr, loop_data.place.clone(), current)? else { + return Ok(None); + }; + current = c; } + let end = match label { + Some(l) => self.labeled_loop_blocks.get(l).ok_or(MirLowerError::UnresolvedLabel)?.end.expect("We always generate end for labeled loops"), + None => self.current_loop_end()?, + }; + self.set_goto(current, end); + Ok(None) } Expr::Return { expr } => { if let Some(expr) = expr { @@ -668,7 +688,6 @@ impl MirLowerCtx<'_> { } Expr::Await { .. } => not_supported!("await"), Expr::Yeet { .. } => not_supported!("yeet"), - Expr::TryBlock { .. } => not_supported!("try block"), Expr::Async { .. } => not_supported!("async block"), Expr::Const { .. } => not_supported!("anonymous const block"), Expr::Cast { expr, type_ref: _ } => { @@ -1085,19 +1104,34 @@ impl MirLowerCtx<'_> { fn lower_loop( &mut self, prev_block: BasicBlockId, + place: Place, label: Option, f: impl FnOnce(&mut MirLowerCtx<'_>, BasicBlockId) -> Result<()>, ) -> Result> { - if label.is_some() { - not_supported!("loop with label"); - } let begin = self.new_basic_block(); - let prev = - mem::replace(&mut self.current_loop_blocks, Some(LoopBlocks { begin, end: None })); + let prev = mem::replace( + &mut self.current_loop_blocks, + Some(LoopBlocks { begin, end: None, place }), + ); + let prev_label = if let Some(label) = label { + // We should generate the end now, to make sure that it wouldn't change later. It is + // bad as we may emit end (unneccessary unreachable block) for unterminating loop, but + // it should not affect correctness. + self.current_loop_end()?; + self.labeled_loop_blocks.insert( + self.body.labels[label].name.clone(), + self.current_loop_blocks.as_ref().unwrap().clone(), + ) + } else { + None + }; self.set_goto(prev_block, begin); f(self, begin)?; let my = mem::replace(&mut self.current_loop_blocks, prev) .ok_or(MirLowerError::ImplementationError("current_loop_blocks is corrupt"))?; + if let Some(prev) = prev_label { + self.labeled_loop_blocks.insert(self.body.labels[label.unwrap()].name.clone(), prev); + } Ok(my.end) } @@ -1185,15 +1219,11 @@ impl MirLowerCtx<'_> { fn lower_block_to_place( &mut self, - label: Option, statements: &[hir_def::expr::Statement], mut current: BasicBlockId, tail: Option, place: Place, ) -> Result>> { - if label.is_some() { - not_supported!("block with label"); - } for statement in statements.iter() { match statement { hir_def::expr::Statement::Let { pat, initializer, else_branch, type_ref: _ } => { @@ -1355,6 +1385,7 @@ pub fn lower_to_mir( body, owner, current_loop_blocks: None, + labeled_loop_blocks: Default::default(), discr_temp: None, }; let mut current = start_block; diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index da76d7fd83f7..97ec1bb871d4 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -206,19 +206,27 @@ fn test() { fn infer_try_trait() { check_types( r#" -//- minicore: try, result +//- minicore: try, result, from fn test() { let r: Result = Result::Ok(1); let v = r?; v; } //^ i32 - -impl core::ops::Try for Result { - type Output = O; - type Error = Result; +"#, + ); } -impl> core::ops::FromResidual> for Result {} +#[test] +fn infer_try_block() { + // FIXME: We should test more cases, but it currently doesn't work, since + // our labeled block type inference is broken. + check_types( + r#" +//- minicore: try, option +fn test() { + let x: Option<_> = try { Some(2)?; }; + //^ Option<()> +} "#, ); } From 3303a6eff5f759d5bc6f9a2e891bddab0d1f21e7 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Mon, 20 Mar 2023 21:48:01 +0330 Subject: [PATCH 1197/2442] Implement some intrinsics --- crates/hir-ty/src/consteval/tests.rs | 70 +++- .../hir-ty/src/consteval/tests/intrinsics.rs | 162 ++++++++ crates/hir-ty/src/infer/expr.rs | 11 +- crates/hir-ty/src/mir/eval.rs | 383 +++++++++++++----- crates/hir-ty/src/mir/lower.rs | 5 + crates/hir-ty/src/tests/simple.rs | 34 +- crates/ide/src/hover/render.rs | 1 - 7 files changed, 521 insertions(+), 145 deletions(-) create mode 100644 crates/hir-ty/src/consteval/tests/intrinsics.rs diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 2ba0cbd5db4f..47ef26fc5860 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -11,6 +11,8 @@ use super::{ ConstEvalError, }; +mod intrinsics; + fn simplify(e: ConstEvalError) -> ConstEvalError { match e { ConstEvalError::MirEvalError(MirEvalError::InFunction(_, e)) => { @@ -82,6 +84,49 @@ fn bit_op() { check_number(r#"const GOAL: i8 = 1 << 8"#, 0); } +#[test] +fn casts() { + check_number(r#"const GOAL: usize = 12 as *const i32 as usize"#, 12); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + const GOAL: i32 = { + let a = [10, 20, 3, 15]; + let x: &[i32] = &a; + let y: *const [i32] = x; + let z = y as *const i32; + unsafe { *z } + }; + "#, + 10, + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + const GOAL: i16 = { + let a = &mut 5; + let z = a as *mut _; + unsafe { *z } + }; + "#, + 5, + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice + const GOAL: usize = { + let a = [10, 20, 3, 15]; + let x: &[i32] = &a; + let y: *const [i32] = x; + let z = y as *const [u8]; // slice fat pointer cast don't touch metadata + let w = unsafe { &*z }; + w.len() + }; + "#, + 4, + ); +} + #[test] fn locals() { check_number( @@ -279,20 +324,6 @@ fn function_call() { ); } -#[test] -fn intrinsics() { - check_number( - r#" - extern "rust-intrinsic" { - pub fn size_of() -> usize; - } - - const GOAL: usize = size_of::(); - "#, - 4, - ); -} - #[test] fn trait_basic() { check_number( @@ -1353,6 +1384,17 @@ fn array_and_index() { check_number( r#" //- minicore: coerce_unsized, index, slice + const GOAL: usize = { + let a = [1, 2, 3]; + let x: &[i32] = &a; + let y = &*x; + y.len() + };"#, + 3, + ); + check_number( + r#" + //- minicore: coerce_unsized, index, slice const GOAL: usize = [1, 2, 3, 4, 5].len();"#, 5, ); diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs new file mode 100644 index 000000000000..371d5cab3378 --- /dev/null +++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -0,0 +1,162 @@ +use super::*; + +#[test] +fn size_of() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn size_of() -> usize; + } + + const GOAL: usize = size_of::(); + "#, + 4, + ); +} + +#[test] +fn transmute() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn transmute(e: T) -> U; + } + + const GOAL: i32 = transmute((1i16, 1i16)); + "#, + 0x00010001, + ); +} + +#[test] +fn const_eval_select() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn const_eval_select(arg: ARG, called_in_const: F, called_at_rt: G) -> RET + where + G: FnOnce, + F: FnOnce; + } + + const fn in_const(x: i32, y: i32) -> i32 { + x + y + } + + fn in_rt(x: i32, y: i32) -> i32 { + x + y + } + + const GOAL: i32 = const_eval_select((2, 3), in_const, in_rt); + "#, + 5, + ); +} + +#[test] +fn wrapping_add() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn wrapping_add(a: T, b: T) -> T; + } + + const GOAL: u8 = wrapping_add(10, 250); + "#, + 4, + ); +} + +#[test] +fn offset() { + check_number( + r#" + //- minicore: coerce_unsized, index, slice + extern "rust-intrinsic" { + pub fn offset(dst: *const T, offset: isize) -> *const T; + } + + const GOAL: u8 = unsafe { + let ar: &[(u8, u8, u8)] = &[ + (10, 11, 12), + (20, 21, 22), + (30, 31, 32), + (40, 41, 42), + (50, 51, 52), + ]; + let ar: *const [(u8, u8, u8)] = ar; + let ar = ar as *const (u8, u8, u8); + let element = offset(ar, 2); + element.1 + }; + "#, + 31, + ); +} + +#[test] +fn arith_offset() { + check_number( + r#" + //- minicore: coerce_unsized, index, slice + extern "rust-intrinsic" { + pub fn arith_offset(dst: *const T, offset: isize) -> *const T; + } + + const GOAL: u8 = unsafe { + let ar: &[(u8, u8, u8)] = &[ + (10, 11, 12), + (20, 21, 22), + (30, 31, 32), + (40, 41, 42), + (50, 51, 52), + ]; + let ar: *const [(u8, u8, u8)] = ar; + let ar = ar as *const (u8, u8, u8); + let element = arith_offset(arith_offset(ar, 102), -100); + element.1 + }; + "#, + 31, + ); +} + +#[test] +fn copy_nonoverlapping() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); + } + + const GOAL: u8 = unsafe { + let mut x = 2; + let y = 5; + copy_nonoverlapping(&y, &mut x, 1); + x + }; + "#, + 5, + ); +} + +#[test] +fn copy() { + check_number( + r#" + //- minicore: coerce_unsized, index, slice + extern "rust-intrinsic" { + pub fn copy(src: *const T, dst: *mut T, count: usize); + } + + const GOAL: i32 = unsafe { + let mut x = [1i32, 2, 3, 4, 5]; + let y = (&mut x as *mut _) as *mut i32; + let z = (y as usize + 4) as *const i32; + copy(z, y, 4); + x[0] + x[1] + x[2] + x[3] + x[4] + }; + "#, + 19, + ); +} diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 6d2aa59ea359..d14b3f7140e4 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -630,8 +630,15 @@ impl<'a> InferenceContext<'a> { Expr::Cast { expr, type_ref } => { let cast_ty = self.make_ty(type_ref); // FIXME: propagate the "castable to" expectation - let _inner_ty = self.infer_expr_no_expect(*expr); - // FIXME check the cast... + let inner_ty = self.infer_expr_no_expect(*expr); + match (inner_ty.kind(Interner), cast_ty.kind(Interner)) { + (TyKind::Ref(_, _, inner), TyKind::Raw(_, cast)) => { + // FIXME: record invalid cast diagnostic in case of mismatch + self.unify(inner, cast); + } + // FIXME check the other kinds of cast... + _ => (), + } cast_ty } Expr::Ref { expr, rawness, mutability } => { diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index f8545e88ad54..26bf877cf0b0 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -96,11 +96,18 @@ enum Address { use Address::*; +#[derive(Debug, Clone, Copy)] struct Interval { addr: Address, size: usize, } +#[derive(Debug, Clone)] +struct IntervalAndTy { + interval: Interval, + ty: Ty, +} + impl Interval { fn new(addr: Address, size: usize) -> Self { Self { addr, size } @@ -110,11 +117,37 @@ impl Interval { memory.read_memory(self.addr, self.size) } + fn write_from_bytes(&self, memory: &mut Evaluator<'_>, bytes: &[u8]) -> Result<()> { + memory.write_memory(self.addr, bytes) + } + + fn write_from_interval(&self, memory: &mut Evaluator<'_>, interval: Interval) -> Result<()> { + // FIXME: this could be more efficent + let bytes = &interval.get(memory)?.to_vec(); + memory.write_memory(self.addr, bytes) + } + fn slice(self, range: Range) -> Interval { Interval { addr: self.addr.offset(range.start), size: range.len() } } } +impl IntervalAndTy { + fn get<'a>(&self, memory: &'a Evaluator<'a>) -> Result<&'a [u8]> { + memory.read_memory(self.interval.addr, self.interval.size) + } + + fn new( + addr: Address, + ty: Ty, + evaluator: &Evaluator<'_>, + locals: &Locals<'_>, + ) -> Result { + let size = evaluator.size_of_sized(&ty, locals, "type of interval")?; + Ok(IntervalAndTy { interval: Interval { addr, size }, ty }) + } +} + enum IntervalOrOwned { Owned(Vec), Borrowed(Interval), @@ -135,7 +168,7 @@ impl Address { fn from_usize(x: usize) -> Self { if x > usize::MAX / 2 { - Stack(usize::MAX - x) + Stack(x - usize::MAX / 2) } else { Heap(x) } @@ -147,7 +180,7 @@ impl Address { fn to_usize(&self) -> usize { let as_num = match self { - Stack(x) => usize::MAX - *x, + Stack(x) => *x + usize::MAX / 2, Heap(x) => *x, }; as_num @@ -174,7 +207,7 @@ pub enum MirEvalError { /// Means that code had undefined behavior. We don't try to actively detect UB, but if it was detected /// then use this type of error. UndefinedBehavior(&'static str), - Panic, + Panic(String), MirLowerError(FunctionId, MirLowerError), TypeIsUnsized(Ty, &'static str), NotSupported(String), @@ -197,7 +230,7 @@ impl std::fmt::Debug for MirEvalError { Self::UndefinedBehavior(arg0) => { f.debug_tuple("UndefinedBehavior").field(arg0).finish() } - Self::Panic => write!(f, "Panic"), + Self::Panic(msg) => write!(f, "Panic with message:\n{msg:?}"), Self::TargetDataLayoutNotAvailable => write!(f, "TargetDataLayoutNotAvailable"), Self::TypeIsUnsized(ty, it) => write!(f, "{ty:?} is unsized. {it} should be sized."), Self::ExecutionLimitExceeded => write!(f, "execution limit exceeded"), @@ -289,7 +322,19 @@ impl Evaluator<'_> { } fn place_addr(&self, p: &Place, locals: &Locals<'_>) -> Result

{ - Ok(self.place_addr_and_ty(p, locals)?.0) + Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0) + } + + fn place_interval(&self, p: &Place, locals: &Locals<'_>) -> Result { + let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?; + Ok(Interval { + addr: place_addr_and_ty.0, + size: self.size_of_sized( + &place_addr_and_ty.1, + locals, + "Type of place that we need its interval", + )?, + }) } fn ptr_size(&self) -> usize { @@ -299,10 +344,15 @@ impl Evaluator<'_> { } } - fn place_addr_and_ty<'a>(&'a self, p: &Place, locals: &'a Locals<'a>) -> Result<(Address, Ty)> { + fn place_addr_and_ty_and_metadata<'a>( + &'a self, + p: &Place, + locals: &'a Locals<'a>, + ) -> Result<(Address, Ty, Option)> { let mut addr = locals.ptr[p.local]; let mut ty: Ty = self.ty_filler(&locals.body.locals[p.local].ty, locals.subst, locals.body.owner)?; + let mut metadata = None; // locals are always sized for proj in &p.projection { match proj { ProjectionElem::Deref => { @@ -314,12 +364,18 @@ impl Evaluator<'_> { )) } }; + metadata = if self.size_of(&ty, locals)?.is_none() { + Some(Interval { addr: addr.offset(self.ptr_size()), size: self.ptr_size() }) + } else { + None + }; let x = from_bytes!(usize, self.read_memory(addr, self.ptr_size())?); addr = Address::from_usize(x); } ProjectionElem::Index(op) => { let offset = from_bytes!(usize, self.read_memory(locals.ptr[*op], self.ptr_size())?); + metadata = None; // Result of index is always sized match &ty.data(Interner).kind { TyKind::Ref(_, _, inner) => match &inner.data(Interner).kind { TyKind::Slice(inner) => { @@ -357,6 +413,7 @@ impl Evaluator<'_> { .clone(); let offset = layout.fields.offset(f).bytes_usize(); addr = addr.offset(offset); + metadata = None; // tuple field is always sized } _ => return Err(MirEvalError::TypeError("Only tuple has tuple fields")), }, @@ -386,6 +443,8 @@ impl Evaluator<'_> { .offset(u32::from(f.local_id.into_raw()) as usize) .bytes_usize(); addr = addr.offset(offset); + // FIXME: support structs with unsized fields + metadata = None; } _ => return Err(MirEvalError::TypeError("Only adt has fields")), }, @@ -396,7 +455,7 @@ impl Evaluator<'_> { ProjectionElem::OpaqueCast(_) => not_supported!("opaque cast"), } } - Ok((addr, ty)) + Ok((addr, ty, metadata)) } fn layout(&self, ty: &Ty) -> Result { @@ -411,16 +470,23 @@ impl Evaluator<'_> { } fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals<'a>) -> Result { - Ok(self.place_addr_and_ty(p, locals)?.1) + Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1) } - fn operand_ty<'a>(&'a self, o: &'a Operand, locals: &'a Locals<'a>) -> Result { + fn operand_ty(&self, o: &Operand, locals: &Locals<'_>) -> Result { Ok(match o { Operand::Copy(p) | Operand::Move(p) => self.place_ty(p, locals)?, Operand::Constant(c) => c.data(Interner).ty.clone(), }) } + fn operand_ty_and_eval(&mut self, o: &Operand, locals: &Locals<'_>) -> Result { + Ok(IntervalAndTy { + interval: self.eval_operand(o, locals)?, + ty: self.operand_ty(o, locals)?, + }) + } + fn interpret_mir( &mut self, body: &MirBody, @@ -498,14 +564,19 @@ impl Evaluator<'_> { cleanup: _, from_hir_call: _, } => { + let destination = self.place_interval(destination, &locals)?; let fn_ty = self.operand_ty(func, &locals)?; + let args = args + .iter() + .map(|x| self.operand_ty_and_eval(x, &locals)) + .collect::>>()?; match &fn_ty.data(Interner).kind { TyKind::Function(_) => { let bytes = self.eval_operand(func, &locals)?; - self.exec_fn_pointer(bytes, destination, args, &locals)?; + self.exec_fn_pointer(bytes, destination, &args, &locals)?; } TyKind::FnDef(def, generic_args) => { - self.exec_fn_def(*def, generic_args, destination, args, &locals)?; + self.exec_fn_def(*def, generic_args, destination, &args, &locals)?; } x => not_supported!("unknown function type {x:?}"), } @@ -545,8 +616,12 @@ impl Evaluator<'_> { Ok(match r { Rvalue::Use(x) => Borrowed(self.eval_operand(x, locals)?), Rvalue::Ref(_, p) => { - let addr = self.place_addr(p, locals)?; - Owned(addr.to_bytes()) + let (addr, _, metadata) = self.place_addr_and_ty_and_metadata(p, locals)?; + let mut r = addr.to_bytes(); + if let Some(metadata) = metadata { + r.extend(metadata.get(self)?); + } + Owned(r) } Rvalue::Len(_) => not_supported!("rvalue len"), Rvalue::UnaryOp(op, val) => { @@ -624,8 +699,12 @@ impl Evaluator<'_> { let r = match op { BinOp::Add => l128.overflowing_add(r128).0, BinOp::Mul => l128.overflowing_mul(r128).0, - BinOp::Div => l128.checked_div(r128).ok_or(MirEvalError::Panic)?, - BinOp::Rem => l128.checked_rem(r128).ok_or(MirEvalError::Panic)?, + BinOp::Div => l128.checked_div(r128).ok_or_else(|| { + MirEvalError::Panic(format!("Overflow in {op:?}")) + })?, + BinOp::Rem => l128.checked_rem(r128).ok_or_else(|| { + MirEvalError::Panic(format!("Overflow in {op:?}")) + })?, BinOp::Sub => l128.overflowing_sub(r128).0, BinOp::BitAnd => l128 & r128, BinOp::BitOr => l128 | r128, @@ -635,16 +714,16 @@ impl Evaluator<'_> { let r = r.to_le_bytes(); for &k in &r[lc.len()..] { if k != 0 && (k != 255 || !is_signed) { - return Err(MirEvalError::Panic); + return Err(MirEvalError::Panic(format!("Overflow in {op:?}"))); } } Owned(r[0..lc.len()].into()) } BinOp::Shl | BinOp::Shr => { let shift_amout = if r128 < 0 { - return Err(MirEvalError::Panic); + return Err(MirEvalError::Panic(format!("Overflow in {op:?}"))); } else if r128 > 128 { - return Err(MirEvalError::Panic); + return Err(MirEvalError::Panic(format!("Overflow in {op:?}"))); } else { r128 as u8 }; @@ -720,47 +799,54 @@ impl Evaluator<'_> { } Rvalue::ShallowInitBox(_, _) => not_supported!("shallow init box"), Rvalue::CopyForDeref(_) => not_supported!("copy for deref"), - Rvalue::Aggregate(kind, values) => match kind { - AggregateKind::Array(_) => { - let mut r = vec![]; - for x in values { - let value = self.eval_operand(x, locals)?.get(&self)?; - r.extend(value); + Rvalue::Aggregate(kind, values) => { + let values = values + .iter() + .map(|x| self.eval_operand(x, locals)) + .collect::>>()?; + match kind { + AggregateKind::Array(_) => { + let mut r = vec![]; + for x in values { + let value = x.get(&self)?; + r.extend(value); + } + Owned(r) + } + AggregateKind::Tuple(ty) => { + let layout = self.layout(&ty)?; + Owned(self.make_by_layout( + layout.size.bytes_usize(), + &layout, + None, + values.iter().copied(), + )?) + } + AggregateKind::Union(x, f) => { + let layout = self.layout_adt((*x).into(), Substitution::empty(Interner))?; + let offset = layout + .fields + .offset(u32::from(f.local_id.into_raw()) as usize) + .bytes_usize(); + let op = values[0].get(&self)?; + let mut result = vec![0; layout.size.bytes_usize()]; + result[offset..offset + op.len()].copy_from_slice(op); + Owned(result) + } + AggregateKind::Adt(x, subst) => { + let subst = self.subst_filler(subst, locals); + let (size, variant_layout, tag) = + self.layout_of_variant(*x, subst, locals)?; + Owned(self.make_by_layout( + size, + &variant_layout, + tag, + values.iter().copied(), + )?) } - Owned(r) } - AggregateKind::Tuple(ty) => { - let layout = self.layout(&ty)?; - Owned(self.make_by_layout( - layout.size.bytes_usize(), - &layout, - None, - values, - locals, - )?) - } - AggregateKind::Union(x, f) => { - let layout = self.layout_adt((*x).into(), Substitution::empty(Interner))?; - let offset = layout - .fields - .offset(u32::from(f.local_id.into_raw()) as usize) - .bytes_usize(); - let op = self.eval_operand(&values[0], locals)?.get(&self)?; - let mut result = vec![0; layout.size.bytes_usize()]; - result[offset..offset + op.len()].copy_from_slice(op); - Owned(result) - } - AggregateKind::Adt(x, subst) => { - let subst = self.subst_filler(subst, locals); - let (size, variant_layout, tag) = self.layout_of_variant(*x, subst, locals)?; - Owned(self.make_by_layout(size, &variant_layout, tag, values, locals)?) - } - }, + } Rvalue::Cast(kind, operand, target_ty) => match kind { - CastKind::PointerExposeAddress => not_supported!("exposing pointer address"), - CastKind::PointerFromExposedAddress => { - not_supported!("creating pointer from exposed address") - } CastKind::Pointer(cast) => match cast { PointerCast::ReifyFnPointer => { let current_ty = self.operand_ty(operand, locals)?; @@ -818,7 +904,9 @@ impl Evaluator<'_> { x => not_supported!("pointer cast {x:?}"), }, CastKind::DynStar => not_supported!("dyn star cast"), - CastKind::IntToInt => { + CastKind::IntToInt + | CastKind::PointerExposeAddress + | CastKind::PointerFromExposedAddress => { // FIXME: handle signed cast let current = pad16(self.eval_operand(operand, locals)?.get(&self)?, false); let dest_size = @@ -828,7 +916,12 @@ impl Evaluator<'_> { CastKind::FloatToInt => not_supported!("float to int cast"), CastKind::FloatToFloat => not_supported!("float to float cast"), CastKind::IntToFloat => not_supported!("float to int cast"), - CastKind::PtrToPtr => not_supported!("ptr to ptr cast"), + CastKind::PtrToPtr => { + let current = pad16(self.eval_operand(operand, locals)?.get(&self)?, false); + let dest_size = + self.size_of_sized(target_ty, locals, "destination of ptr to ptr cast")?; + Owned(current[0..dest_size].to_vec()) + } CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"), }, }) @@ -895,16 +988,15 @@ impl Evaluator<'_> { size: usize, // Not neccessarily equal to variant_layout.size variant_layout: &Layout, tag: Option<(usize, usize, i128)>, - values: &[Operand], - locals: &Locals<'_>, + values: impl Iterator, ) -> Result> { let mut result = vec![0; size]; if let Some((offset, size, value)) = tag { result[offset..offset + size].copy_from_slice(&value.to_le_bytes()[0..size]); } - for (i, op) in values.iter().enumerate() { + for (i, op) in values.enumerate() { let offset = variant_layout.fields.offset(i).bytes_usize(); - let op = self.eval_operand(op, locals)?.get(&self)?; + let op = op.get(&self)?; result[offset..offset + op.len()].copy_from_slice(op); } Ok(result) @@ -1196,28 +1288,89 @@ impl Evaluator<'_> { } fn exec_intrinsic( - &self, + &mut self, as_str: &str, - mut arg_bytes: impl Iterator>, + args: &[IntervalAndTy], generic_args: Substitution, + destination: Interval, locals: &Locals<'_>, - ) -> Result> { + ) -> Result<()> { match as_str { "size_of" => { let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { return Err(MirEvalError::TypeError("size_of generic arg is not provided")); }; - let size = self.size_of(ty, locals)?; - match size { - Some(x) => Ok(x.to_le_bytes().to_vec()), - None => return Err(MirEvalError::TypeError("size_of arg is unsized")), - } + let size = self.size_of_sized(ty, locals, "size_of arg")?; + destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size]) + } + "wrapping_add" => { + let [lhs, rhs] = args else { + return Err(MirEvalError::TypeError("const_eval_select args are not provided")); + }; + let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false)); + let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false)); + let ans = lhs.wrapping_add(rhs); + destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]) + } + "copy" | "copy_nonoverlapping" => { + let [src, dst, offset] = args else { + return Err(MirEvalError::TypeError("copy_nonoverlapping args are not provided")); + }; + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + return Err(MirEvalError::TypeError("copy_nonoverlapping generic arg is not provided")); + }; + let src = Address::from_bytes(src.get(self)?)?; + let dst = Address::from_bytes(dst.get(self)?)?; + let offset = from_bytes!(usize, offset.get(self)?); + let size = self.size_of_sized(ty, locals, "copy_nonoverlapping ptr type")?; + let size = offset * size; + let src = Interval { addr: src, size }; + let dst = Interval { addr: dst, size }; + dst.write_from_interval(self, src) + } + "offset" | "arith_offset" => { + let [ptr, offset] = args else { + return Err(MirEvalError::TypeError("offset args are not provided")); + }; + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + return Err(MirEvalError::TypeError("offset generic arg is not provided")); + }; + let ptr = u128::from_le_bytes(pad16(ptr.get(self)?, false)); + let offset = u128::from_le_bytes(pad16(offset.get(self)?, false)); + let size = self.size_of_sized(ty, locals, "offset ptr type")? as u128; + let ans = ptr + offset * size; + destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]) + } + "assert_inhabited" | "assert_zero_valid" | "assert_uninit_valid" => { + // FIXME: We should actually implement these checks + Ok(()) + } + "forget" => { + // We don't call any drop glue yet, so there is nothing here + Ok(()) } "transmute" => { - let Some(arg) = arg_bytes.next() else { + let [arg] = args else { return Err(MirEvalError::TypeError("trasmute arg is not provided")); }; - Ok(arg) + destination.write_from_interval(self, arg.interval) + } + "const_eval_select" => { + let [tuple, const_fn, _] = args else { + return Err(MirEvalError::TypeError("const_eval_select args are not provided")); + }; + let mut args = vec![const_fn.clone()]; + let TyKind::Tuple(_, fields) = tuple.ty.kind(Interner) else { + return Err(MirEvalError::TypeError("const_eval_select arg[0] is not a tuple")); + }; + let layout = self.layout(&tuple.ty)?; + for (i, field) in fields.iter(Interner).enumerate() { + let field = field.assert_ty_ref(Interner).clone(); + let offset = layout.fields.offset(i).bytes_usize(); + let addr = tuple.interval.addr.offset(offset); + args.push(IntervalAndTy::new(addr, field, self, locals)?); + } + self.exec_fn_trait(&args, destination, locals) } _ => not_supported!("unknown intrinsic {as_str}"), } @@ -1226,8 +1379,8 @@ impl Evaluator<'_> { fn exec_fn_pointer( &mut self, bytes: Interval, - destination: &Place, - args: &[Operand], + destination: Interval, + args: &[IntervalAndTy], locals: &Locals<'_>, ) -> Result<()> { let id = from_bytes!(usize, bytes.get(self)?); @@ -1244,38 +1397,41 @@ impl Evaluator<'_> { &mut self, def: FnDefId, generic_args: &Substitution, - destination: &Place, - args: &[Operand], + destination: Interval, + args: &[IntervalAndTy], locals: &Locals<'_>, ) -> Result<()> { let def: CallableDefId = from_chalk(self.db, def); let generic_args = self.subst_filler(generic_args, &locals); match def { CallableDefId::FunctionId(def) => { - let dest_addr = self.place_addr(destination, &locals)?; - if let Some(x) = self.detect_fn_trait(def) { - self.exec_fn_trait(x, &args, destination, locals)?; + if let Some(_) = self.detect_fn_trait(def) { + self.exec_fn_trait(&args, destination, locals)?; return Ok(()); } - let arg_bytes = args - .iter() - .map(|x| Ok(self.eval_operand(x, &locals)?.get(&self)?.to_owned())) - .collect::>>()?; - self.exec_fn_with_args(def, arg_bytes, generic_args, locals, dest_addr)?; + self.exec_fn_with_args(def, args, generic_args, locals, destination)?; } CallableDefId::StructId(id) => { let (size, variant_layout, tag) = self.layout_of_variant(id.into(), generic_args.clone(), &locals)?; - let result = self.make_by_layout(size, &variant_layout, tag, args, &locals)?; - let dest_addr = self.place_addr(destination, &locals)?; - self.write_memory(dest_addr, &result)?; + let result = self.make_by_layout( + size, + &variant_layout, + tag, + args.iter().map(|x| x.interval), + )?; + destination.write_from_bytes(self, &result)?; } CallableDefId::EnumVariantId(id) => { let (size, variant_layout, tag) = self.layout_of_variant(id.into(), generic_args.clone(), &locals)?; - let result = self.make_by_layout(size, &variant_layout, tag, args, &locals)?; - let dest_addr = self.place_addr(destination, &locals)?; - self.write_memory(dest_addr, &result)?; + let result = self.make_by_layout( + size, + &variant_layout, + tag, + args.iter().map(|x| x.interval), + )?; + destination.write_from_bytes(self, &result)?; } } Ok(()) @@ -1284,10 +1440,10 @@ impl Evaluator<'_> { fn exec_fn_with_args( &mut self, def: FunctionId, - arg_bytes: Vec>, + args: &[IntervalAndTy], generic_args: Substitution, locals: &Locals<'_>, - dest_addr: Address, + destination: Interval, ) -> Result<()> { let function_data = self.db.function_data(def); let is_intrinsic = match &function_data.abi { @@ -1301,14 +1457,18 @@ impl Evaluator<'_> { _ => false, }, }; - let result = if is_intrinsic { - self.exec_intrinsic( + if is_intrinsic { + return self.exec_intrinsic( function_data.name.as_text().unwrap_or_default().as_str(), - arg_bytes.iter().cloned(), + args, generic_args, + destination, &locals, - )? - } else if let Some(x) = self.detect_lang_function(def) { + ); + } + let arg_bytes = + args.iter().map(|x| Ok(x.get(&self)?.to_owned())).collect::>>()?; + let result = if let Some(x) = self.detect_lang_function(def) { self.exec_lang_item(x, &arg_bytes)? } else { if let Some(self_ty_idx) = @@ -1321,9 +1481,12 @@ impl Evaluator<'_> { let ty = self .vtable_map .ty_of_bytes(&arg_bytes[0][self.ptr_size()..self.ptr_size() * 2])?; + let mut args_for_target = args.to_vec(); + args_for_target[0] = IntervalAndTy { + interval: args_for_target[0].interval.slice(0..self.ptr_size()), + ty: ty.clone(), + }; let ty = GenericArgData::Ty(ty.clone()).intern(Interner); - let mut args_for_target = arg_bytes; - args_for_target[0] = args_for_target[0][0..self.ptr_size()].to_vec(); let generics_for_target = Substitution::from_iter( Interner, generic_args.iter(Interner).enumerate().map(|(i, x)| { @@ -1336,10 +1499,10 @@ impl Evaluator<'_> { ); return self.exec_fn_with_args( def, - args_for_target, + &args_for_target, generics_for_target, locals, - dest_addr, + destination, ); } let (imp, generic_args) = @@ -1351,20 +1514,19 @@ impl Evaluator<'_> { self.interpret_mir(&mir_body, arg_bytes.iter().cloned(), generic_args) .map_err(|e| MirEvalError::InFunction(imp, Box::new(e)))? }; - self.write_memory(dest_addr, &result)?; + destination.write_from_bytes(self, &result)?; Ok(()) } fn exec_fn_trait( &mut self, - ft: FnTrait, - args: &[Operand], - destination: &Place, + args: &[IntervalAndTy], + destination: Interval, locals: &Locals<'_>, ) -> Result<()> { let func = args.get(0).ok_or(MirEvalError::TypeError("fn trait with no arg"))?; - let mut func_ty = self.operand_ty(func, locals)?; - let mut func_data = self.eval_operand(func, locals)?; + let mut func_ty = func.ty.clone(); + let mut func_data = func.interval; while let TyKind::Ref(_, _, z) = func_ty.kind(Interner) { func_ty = z.clone(); if matches!(func_ty.kind(Interner), TyKind::Dyn(_)) { @@ -1383,7 +1545,7 @@ impl Evaluator<'_> { TyKind::Function(_) => { self.exec_fn_pointer(func_data, destination, &args[1..], locals)?; } - x => not_supported!("Call {ft:?} trait methods with type {x:?}"), + x => not_supported!("Call FnTrait methods with type {x:?}"), } Ok(()) } @@ -1392,7 +1554,10 @@ impl Evaluator<'_> { use LangItem::*; let mut args = args.iter(); match x { - PanicFmt | BeginPanic => Err(MirEvalError::Panic), + // FIXME: we want to find the panic message from arguments, but it wouldn't work + // currently even if we do that, since macro expansion of panic related macros + // is dummy. + PanicFmt | BeginPanic => Err(MirEvalError::Panic("".to_string())), SliceLen => { let arg = args .next() diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 5d9ae320726f..65e3348b2189 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -1285,6 +1285,11 @@ fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result { (_, chalk_ir::Scalar::Float(_)) => CastKind::IntToFloat, (_, _) => CastKind::IntToInt, }, + (TyKind::Scalar(_), TyKind::Raw(..)) => CastKind::PointerFromExposedAddress, + (TyKind::Raw(..), TyKind::Scalar(_)) => CastKind::PointerExposeAddress, + (TyKind::Raw(..) | TyKind::Ref(..), TyKind::Raw(..) | TyKind::Ref(..)) => { + CastKind::PtrToPtr + } // Enum to int casts (TyKind::Scalar(_), TyKind::Adt(..)) | (TyKind::Adt(..), TyKind::Scalar(_)) => { CastKind::IntToInt diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index 13cc3fea52d1..8322b9e1ca64 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -2696,6 +2696,21 @@ fn f() { ) } +#[test] +fn infer_ref_to_raw_cast() { + check_types( + r#" +struct S; + +fn f() { + let s = &mut S; + let s = s as *mut _; + //^ *mut S +} + "#, + ); +} + #[test] fn infer_missing_type() { check_types( @@ -3258,25 +3273,6 @@ fn f(t: Ark) { ); } -// FIXME -#[test] -fn castable_to2() { - check_infer( - r#" -fn func() { - let x = &0u32 as *const _; -} -"#, - expect![[r#" - 10..44 '{ ...t _; }': () - 20..21 'x': *const {unknown} - 24..29 '&0u32': &u32 - 24..41 '&0u32 ...onst _': *const {unknown} - 25..29 '0u32': u32 - "#]], - ); -} - #[test] fn issue_14275() { // FIXME: evaluate const generic diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index da725ce502b8..fb7b15e05d81 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -409,7 +409,6 @@ pub(super) fn definition( } match it.eval(db) { Ok(()) => Some("pass".into()), - Err(MirEvalError::Panic) => Some("fail".into()), Err(MirEvalError::MirLowerError(f, e)) => { let name = &db.function_data(f).name; Some(format!("error: fail to lower {name} due {e:?}")) From 8a3ad7c3d592adac72b1fce6bc208cdf7a40c8ad Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Tue, 21 Mar 2023 02:20:30 +0330 Subject: [PATCH 1198/2442] Support evaluating inherent associated constants with generics --- crates/hir-ty/src/consteval.rs | 10 ++++++---- crates/hir-ty/src/consteval/tests.rs | 8 ++++---- crates/hir-ty/src/db.rs | 2 +- crates/hir-ty/src/infer/expr.rs | 15 --------------- crates/hir-ty/src/mir/eval.rs | 5 +++-- crates/hir-ty/src/mir/lower.rs | 11 ++++++----- crates/hir/src/lib.rs | 4 ++-- 7 files changed, 22 insertions(+), 33 deletions(-) diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index fcb3445a5427..7e69971fee78 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -15,7 +15,7 @@ use stdx::never; use crate::{ db::HirDatabase, infer::InferenceContext, layout::layout_of_ty, lower::ParamLoweringMode, to_placeholder_idx, utils::Generics, Const, ConstData, ConstScalar, ConstValue, GenericArg, - Interner, MemoryMap, Ty, TyBuilder, + Interner, MemoryMap, Substitution, Ty, TyBuilder, }; use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError}; @@ -169,6 +169,7 @@ pub(crate) fn const_eval_recover( _: &dyn HirDatabase, _: &[String], _: &ConstId, + _: &Substitution, ) -> Result { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } @@ -184,10 +185,11 @@ pub(crate) fn const_eval_discriminant_recover( pub(crate) fn const_eval_query( db: &dyn HirDatabase, const_id: ConstId, + subst: Substitution, ) -> Result { let def = const_id.into(); let body = db.mir_body(def)?; - let c = interpret_mir(db, &body, false)?; + let c = interpret_mir(db, &body, subst, false)?; Ok(c) } @@ -210,7 +212,7 @@ pub(crate) fn const_eval_discriminant_variant( return Ok(value); } let mir_body = db.mir_body(def)?; - let c = interpret_mir(db, &mir_body, false)?; + let c = interpret_mir(db, &mir_body, Substitution::empty(Interner), false)?; let c = try_const_usize(&c).unwrap() as i128; Ok(c) } @@ -234,7 +236,7 @@ pub(crate) fn eval_to_const( } let infer = ctx.clone().resolve_all(); if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, &ctx.body, &infer, expr) { - if let Ok(result) = interpret_mir(db, &mir_body, true) { + if let Ok(result) = interpret_mir(db, &mir_body, Substitution::empty(Interner), true) { return result; } } diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 47ef26fc5860..a0efc7541e3f 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -1,4 +1,5 @@ use base_db::fixture::WithFixture; +use chalk_ir::Substitution; use hir_def::db::DefDatabase; use crate::{ @@ -64,7 +65,7 @@ fn eval_goal(ra_fixture: &str) -> Result { _ => None, }) .unwrap(); - db.const_eval(const_id) + db.const_eval(const_id, Substitution::empty(Interner)) } #[test] @@ -1519,8 +1520,7 @@ fn const_generic_subst_fn() { #[test] fn const_generic_subst_assoc_const_impl() { - // FIXME: this should evaluate to 5 - check_fail( + check_number( r#" struct Adder; impl Adder { @@ -1528,7 +1528,7 @@ fn const_generic_subst_assoc_const_impl() { } const GOAL: usize = Adder::<2, 3>::VAL; "#, - ConstEvalError::MirEvalError(MirEvalError::TypeError("missing generic arg")), + 5, ); } diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 8f1af4c2f8e2..000944e0b5b0 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -57,7 +57,7 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::consteval::const_eval_query)] #[salsa::cycle(crate::consteval::const_eval_recover)] - fn const_eval(&self, def: ConstId) -> Result; + fn const_eval(&self, def: ConstId, subst: Substitution) -> Result; #[salsa::invoke(crate::consteval::const_eval_discriminant_variant)] #[salsa::cycle(crate::consteval::const_eval_discriminant_recover)] diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index d14b3f7140e4..d52188bb284a 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -612,21 +612,6 @@ impl<'a> InferenceContext<'a> { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); self.resolve_associated_type(inner_ty, self.resolve_future_future_output()) } - // Expr::Try { expr } => { - // let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); - // if let Some(trait_) = self.resolve_lang_trait(LangItem::Try) { - // if let Some(func) = self.db.trait_data(trait_).method_by_name(&name!(branch)) { - // let subst = TyBuilder::subst_for_def(self.db, trait_, None) - // .push(inner_ty.clone()) - // .build(); - // self.write_method_resolution(tgt_expr, func, subst.clone()); - // } - // let try_output = self.resolve_output_on(trait_); - // self.resolve_associated_type(inner_ty, try_output) - // } else { - // self.err_ty() - // } - // } Expr::Cast { expr, type_ref } => { let cast_ty = self.make_ty(type_ref); // FIXME: propagate the "castable to" expectation diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 26bf877cf0b0..7b83645faef7 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -282,6 +282,7 @@ struct Locals<'a> { pub fn interpret_mir( db: &dyn HirDatabase, body: &MirBody, + subst: Substitution, // FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now // they share their body with their parent, so in MIR lowering we have locals of the parent body, which // might have placeholders. With this argument, we (wrongly) assume that every placeholder type has @@ -291,11 +292,11 @@ pub fn interpret_mir( ) -> Result { let ty = body.locals[return_slot()].ty.clone(); let mut evaluator = Evaluator::new(db, body, assert_placeholder_ty_is_unused); - let bytes = evaluator.interpret_mir_with_no_arg(&body)?; + let bytes = evaluator.interpret_mir(&body, None.into_iter(), subst.clone())?; let memory_map = evaluator.create_memory_map( &bytes, &ty, - &Locals { ptr: &ArenaMap::new(), body: &body, subst: &Substitution::empty(Interner) }, + &Locals { ptr: &ArenaMap::new(), body: &body, subst: &subst }, )?; return Ok(intern_const_scalar(ConstScalar::Bytes(bytes, memory_map), ty)); } diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 65e3348b2189..1821796be33c 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -231,13 +231,13 @@ impl MirLowerCtx<'_> { let pr = match pr { ResolveValueResult::ValueNs(v) => v, ResolveValueResult::Partial(..) => { - if let Some(assoc) = self + if let Some((assoc, subst)) = self .infer .assoc_resolutions_for_expr(expr_id) { - match assoc.0 { + match assoc { hir_def::AssocItemId::ConstId(c) => { - self.lower_const(c, current, place, expr_id.into())?; + self.lower_const(c, current, place, subst, expr_id.into())?; return Ok(Some(current)) }, hir_def::AssocItemId::FunctionId(_) => { @@ -274,7 +274,7 @@ impl MirLowerCtx<'_> { Ok(Some(current)) } ValueNs::ConstId(const_id) => { - self.lower_const(const_id, current, place, expr_id.into())?; + self.lower_const(const_id, current, place, Substitution::empty(Interner), expr_id.into())?; Ok(Some(current)) } ValueNs::EnumVariantId(variant_id) => { @@ -951,9 +951,10 @@ impl MirLowerCtx<'_> { const_id: hir_def::ConstId, prev_block: BasicBlockId, place: Place, + subst: Substitution, span: MirSpan, ) -> Result<()> { - let c = self.db.const_eval(const_id)?; + let c = self.db.const_eval(const_id, subst)?; self.write_const_to_place(c, prev_block, place, span) } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 35424feec8b2..dbf618afa6fe 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1801,7 +1801,7 @@ impl Function { let body = db .mir_body(self.id.into()) .map_err(|e| MirEvalError::MirLowerError(self.id.into(), e))?; - interpret_mir(db, &body, false)?; + interpret_mir(db, &body, Substitution::empty(Interner), false)?; Ok(()) } } @@ -1947,7 +1947,7 @@ impl Const { } pub fn render_eval(self, db: &dyn HirDatabase) -> Result { - let c = db.const_eval(self.id)?; + let c = db.const_eval(self.id, Substitution::empty(Interner))?; let r = format!("{}", HexifiedConst(c).display(db)); // We want to see things like `` and `` as they are probably bug in our // implementation, but there is no need to show things like `` or `` to From 9745a25d57fbd9a73aec1306554ac87936a63e7d Mon Sep 17 00:00:00 2001 From: x2cf Date: Tue, 21 Mar 2023 14:56:07 +0800 Subject: [PATCH 1199/2442] Fix VS Code status message formatting error --- editors/code/src/ctx.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index c2dca733df8f..85579453a63d 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -383,7 +383,7 @@ export class Ctx { ); statusBar.tooltip.appendMarkdown("\n\n[Open logs](command:rust-analyzer.openLogs)"); statusBar.tooltip.appendMarkdown("\n\n[Restart server](command:rust-analyzer.startServer)"); - statusBar.tooltip.appendMarkdown("[Stop server](command:rust-analyzer.stopServer)"); + statusBar.tooltip.appendMarkdown("\n\n[Stop server](command:rust-analyzer.stopServer)"); if (!status.quiescent) icon = "$(sync~spin) "; statusBar.text = `${icon}rust-analyzer`; } From 28225cc33d60615aaa140dc4b0d32e2a1c21462c Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sat, 18 Mar 2023 11:41:38 -0400 Subject: [PATCH 1200/2442] internal: Coalesce adjacent Indels --- crates/text-edit/src/lib.rs | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/crates/text-edit/src/lib.rs b/crates/text-edit/src/lib.rs index 9bb4271b65f7..4705d18187af 100644 --- a/crates/text-edit/src/lib.rs +++ b/crates/text-edit/src/lib.rs @@ -176,6 +176,7 @@ impl TextEditBuilder { pub fn finish(self) -> TextEdit { let mut indels = self.indels; assert_disjoint_or_equal(&mut indels); + indels = coalesce_indels(indels); TextEdit { indels } } pub fn invalidates_offset(&self, offset: TextSize) -> bool { @@ -205,6 +206,21 @@ where indels.clone().zip(indels.skip(1)).all(|(l, r)| l.delete.end() <= r.delete.start() || l == r) } +fn coalesce_indels(indels: Vec) -> Vec { + indels + .into_iter() + .coalesce(|mut a, b| { + if a.delete.end() == b.delete.start() { + a.insert.push_str(&b.insert); + a.delete = TextRange::new(a.delete.start(), b.delete.end()); + Ok(a) + } else { + Err((a, b)) + } + }) + .collect_vec() +} + #[cfg(test)] mod tests { use super::{TextEdit, TextEditBuilder, TextRange}; @@ -261,4 +277,40 @@ mod tests { let edit2 = TextEdit::delete(range(9, 13)); assert!(edit1.union(edit2).is_err()); } + + #[test] + fn test_coalesce_disjoint() { + let mut builder = TextEditBuilder::default(); + builder.replace(range(1, 3), "aa".into()); + builder.replace(range(5, 7), "bb".into()); + let edit = builder.finish(); + + assert_eq!(edit.indels.len(), 2); + } + + #[test] + fn test_coalesce_adjacent() { + let mut builder = TextEditBuilder::default(); + builder.replace(range(1, 3), "aa".into()); + builder.replace(range(3, 5), "bb".into()); + + let edit = builder.finish(); + assert_eq!(edit.indels.len(), 1); + assert_eq!(edit.indels[0].insert, "aabb"); + assert_eq!(edit.indels[0].delete, range(1, 5)); + } + + #[test] + fn test_coalesce_adjacent_series() { + let mut builder = TextEditBuilder::default(); + builder.replace(range(1, 3), "au".into()); + builder.replace(range(3, 5), "www".into()); + builder.replace(range(5, 8), "".into()); + builder.replace(range(8, 9), "ub".into()); + + let edit = builder.finish(); + assert_eq!(edit.indels.len(), 1); + assert_eq!(edit.indels[0].insert, "auwwwub"); + assert_eq!(edit.indels[0].delete, range(1, 9)); + } } From 3622fb645632fcf81af82919259be4b0012a3939 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 20 Mar 2023 21:24:53 +0100 Subject: [PATCH 1201/2442] Fix lints --- editors/code/src/client.ts | 75 ++++++++++++++++++-------------------- editors/code/src/ctx.ts | 4 +- 2 files changed, 37 insertions(+), 42 deletions(-) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 2a1c757dfefd..4ca6601a6aad 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -121,59 +121,54 @@ export async function createClient( const preview = config.previewRustcOutput; const errorCode = config.useRustcErrorCode; diagnosticList.forEach((diag, idx) => { - let value = + const value = typeof diag.code === "string" || typeof diag.code === "number" ? diag.code : diag.code?.value; if (value === "unlinked-file" && !unlinkedFiles.includes(uri)) { - let config = vscode.workspace.getConfiguration("rust-analyzer"); + const config = vscode.workspace.getConfiguration("rust-analyzer"); if (config.get("showUnlinkedFileNotification")) { unlinkedFiles.push(uri); - let folder = vscode.workspace.getWorkspaceFolder(uri)?.uri.fsPath; + const folder = vscode.workspace.getWorkspaceFolder(uri)?.uri.fsPath; if (folder) { - let parent_backslash = uri.fsPath.lastIndexOf( + const parentBackslash = uri.fsPath.lastIndexOf( pathSeparator + "src" ); - let parent = uri.fsPath.substring(0, parent_backslash); + const parent = uri.fsPath.substring(0, parentBackslash); if (parent.startsWith(folder)) { - let path = vscode.Uri.file( + const path = vscode.Uri.file( parent + pathSeparator + "Cargo.toml" ); - void vscode.workspace.fs.stat(path).then(() => { - vscode.window - .showInformationMessage( - `This rust file does not belong to a loaded cargo project. It looks like it might belong to the workspace at ${path}, do you want to add it to the linked Projects?`, - "Yes", - "No", - "Don't show this again" - ) - .then((choice) => { - switch (choice) { - case "Yes": - break; - case "No": - config.update( - "linkedProjects", - config - .get("linkedProjects") - ?.concat( - path.fsPath.substring( - folder!.length - ) - ), - false - ); - break; - case "Don't show this again": - config.update( - "showUnlinkedFileNotification", - false, - false - ); - break; - } - }); + void vscode.workspace.fs.stat(path).then(async () => { + const choice = await vscode.window.showInformationMessage( + `This rust file does not belong to a loaded cargo project. It looks like it might belong to the workspace at ${path}, do you want to add it to the linked Projects?`, + "Yes", + "No", + "Don't show this again" + ); + switch (choice) { + case "Yes": + break; + case "No": + await config.update( + "linkedProjects", + config + .get("linkedProjects") + ?.concat( + path.fsPath.substring(folder.length) + ), + false + ); + break; + case "Don't show this again": + await config.update( + "showUnlinkedFileNotification", + false, + false + ); + break; + } }); } } diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 5515921ed149..8a0f4ea47732 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -95,7 +95,6 @@ export class Ctx { ) { extCtx.subscriptions.push(this); this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); - this.statusBar.show(); this.workspace = workspace; this.clientSubscriptions = []; this.commandDisposables = []; @@ -338,6 +337,7 @@ export class Ctx { setServerStatus(status: ServerStatusParams | { health: "stopped" }) { let icon = ""; const statusBar = this.statusBar; + statusBar.show(); statusBar.tooltip = new vscode.MarkdownString("", true); statusBar.tooltip.isTrusted = true; switch (status.health) { @@ -386,7 +386,7 @@ export class Ctx { ); statusBar.tooltip.appendMarkdown("\n\n[Open logs](command:rust-analyzer.openLogs)"); statusBar.tooltip.appendMarkdown("\n\n[Restart server](command:rust-analyzer.startServer)"); - statusBar.tooltip.appendMarkdown("[Stop server](command:rust-analyzer.stopServer)"); + statusBar.tooltip.appendMarkdown("\n\n[Stop server](command:rust-analyzer.stopServer)"); if (!status.quiescent) icon = "$(sync~spin) "; statusBar.text = `${icon}rust-analyzer`; } From c01ba4a3101e343464093603b12bb5327d8a320f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 25 Mar 2023 14:22:05 +0100 Subject: [PATCH 1202/2442] Reject symlinks in project-json --- crates/project-model/src/workspace.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index d1e53e12eebb..2158485a3306 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -4,7 +4,7 @@ use std::{collections::VecDeque, fmt, fs, process::Command, sync::Arc}; -use anyhow::{format_err, Context, Result}; +use anyhow::{bail, format_err, Context, Result}; use base_db::{ CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, FileId, LangCrateOrigin, ProcMacroLoadResult, TargetLayoutLoadResult, @@ -154,6 +154,12 @@ impl ProjectWorkspace { ) -> Result { let res = match manifest { ProjectManifest::ProjectJson(project_json) => { + let metadata = fs::symlink_metadata(&project_json).with_context(|| { + format!("Failed to read json file {}", project_json.display()) + })?; + if metadata.is_symlink() { + bail!("The project-json may not currently point to a symlink"); + } let file = fs::read_to_string(&project_json).with_context(|| { format!("Failed to read json file {}", project_json.display()) })?; From 39e86e78c3e3a8fb35b93ac5e658b3379e1f9e6e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 25 Mar 2023 14:43:08 +0100 Subject: [PATCH 1203/2442] Bump Cargo.lock --- Cargo.lock | 257 +++++++++++++++---------------- Cargo.toml | 4 + crates/flycheck/Cargo.toml | 4 +- crates/paths/Cargo.toml | 2 +- crates/proc-macro-api/Cargo.toml | 4 +- crates/profile/Cargo.toml | 2 +- crates/project-model/Cargo.toml | 4 +- crates/rust-analyzer/Cargo.toml | 14 +- crates/syntax/Cargo.toml | 2 +- lib/lsp-server/Cargo.toml | 4 +- 10 files changed, 150 insertions(+), 147 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 25242c6028a4..f97591411ee0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,9 +28,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" [[package]] name = "anymap" @@ -40,9 +40,9 @@ checksum = "8f1f8f5a6f3d50d89e3797d7593a50f96bb2aaa20ca0cc7be1fb673232c91d72" [[package]] name = "arbitrary" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0224938f92e7aef515fac2ff2d18bd1115c1394ddf4a092e0c87e8be9499ee5" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" [[package]] name = "arrayvec" @@ -111,9 +111,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "camino" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055" +checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" dependencies = [ "serde", ] @@ -129,9 +129,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a" +checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" dependencies = [ "camino", "cargo-platform", @@ -143,9 +143,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg" @@ -221,9 +221,9 @@ dependencies = [ [[package]] name = "command-group" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "026c3922235f9f7d78f21251a026f3acdeb7cce3deba107fe09a4bfa63d850a2" +checksum = "5080df6b0f0ecb76cab30808f00d937ba725cebe266a3da8cd89dff92f2a9916" dependencies = [ "nix", "winapi", @@ -257,9 +257,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -267,9 +267,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -278,22 +278,22 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.7.1", + "memoffset", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] @@ -313,9 +313,9 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf460bbff5f571bfc762da5102729f59f338be7db17a21fade44c5c4f5005350" +checksum = "f3cdeb9ec472d588e539a818b2dee436825730da08ad0017c4b1a17676bdc8b7" dependencies = [ "proc-macro2", "quote", @@ -342,24 +342,24 @@ checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "ena" -version = "0.14.0" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" dependencies = [ "log", ] [[package]] name = "expect-test" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d4661aca38d826eb7c72fe128e4238220616de4c0cc00db7bfc38e2e1364dd3" +checksum = "30d9eafeadd538e68fb28016364c9732d78e420b9ff8853fa5e4058861e9f8d3" dependencies = [ "dissimilar", "once_cell", @@ -419,12 +419,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs_extra" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" - [[package]] name = "fsevent-sys" version = "4.1.0" @@ -442,9 +436,9 @@ checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "hashbrown" @@ -774,9 +768,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", @@ -832,9 +826,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "jod-thread" @@ -874,9 +868,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" [[package]] name = "libloading" @@ -977,27 +971,18 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] [[package]] name = "memoffset" -version = "0.6.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" dependencies = [ "autocfg", ] @@ -1055,9 +1040,9 @@ dependencies = [ [[package]] name = "notify" -version = "5.0.0" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2c66da08abae1c024c01d635253e402341b4060a12e99b31c7594063bf490a" +checksum = "58ea850aa68a06e48fdb069c0ec44d0d64c8dbffa49bf3b6f7f0a901fdea1ba9" dependencies = [ "bitflags", "crossbeam-channel", @@ -1068,7 +1053,7 @@ dependencies = [ "libc", "mio", "walkdir", - "winapi", + "windows-sys", ] [[package]] @@ -1093,18 +1078,18 @@ dependencies = [ [[package]] name = "object" -version = "0.30.2" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8c786513eb403643f2a88c244c2aaa270ef2153f55094587d0c48a3cf22a83" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "oorandom" @@ -1180,9 +1165,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "paths" @@ -1282,9 +1267,9 @@ version = "0.0.0" [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" dependencies = [ "unicode-ident", ] @@ -1366,18 +1351,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ "either", "rayon-core", @@ -1385,9 +1370,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -1406,9 +1391,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "regex-syntax", ] @@ -1424,19 +1409,19 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "rowan" -version = "0.15.10" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5811547e7ba31e903fe48c8ceab10d40d70a101f3d15523c847cce91aa71f332" +checksum = "64449cfef9483a475ed56ae30e2da5ee96448789fb2aa240a04beb6a055078bf" dependencies = [ "countme", "hashbrown", - "memoffset 0.6.5", + "memoffset", "rustc-hash", "text-size", ] @@ -1451,6 +1436,7 @@ dependencies = [ "crossbeam-channel", "dissimilar", "expect-test", + "filetime", "flycheck", "hir", "hir-def", @@ -1464,9 +1450,11 @@ dependencies = [ "lsp-types", "mbe", "mimalloc", + "mio", "num_cpus", "oorandom", "parking_lot 0.12.1", + "parking_lot_core 0.9.6", "proc-macro-api", "proc-macro-srv", "profile", @@ -1476,10 +1464,12 @@ dependencies = [ "scip", "serde", "serde_json", + "serde_repr", "sourcegen", "stdx", "syntax", "test-utils", + "thiserror", "threadpool", "tikv-jemallocator", "toolchain", @@ -1506,9 +1496,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" [[package]] name = "rustc-hash" @@ -1518,9 +1508,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "salsa" @@ -1583,27 +1573,27 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.152" +version = "1.0.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" dependencies = [ "proc-macro2", "quote", @@ -1612,9 +1602,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" dependencies = [ "indexmap", "itoa", @@ -1624,9 +1614,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e" +checksum = "395627de918015623b32e7669714206363a7fc00382bf477e72c1f7533e8eafc" dependencies = [ "proc-macro2", "quote", @@ -1650,9 +1640,9 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "smol_str" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7475118a28b7e3a2e157ce0131ba8c5526ea96e90ee601d9f6bb2e286a35ab44" +checksum = "fad6c857cbab2627dcf01ec85a623ca4e7dcb5691cbaa3d7fb7653671f0d09c9" dependencies = [ "serde", ] @@ -1689,9 +1679,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -1763,18 +1753,18 @@ checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a" [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" dependencies = [ "proc-macro2", "quote", @@ -1783,10 +1773,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -1812,12 +1803,11 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.2+5.3.0-patched" +version = "0.5.3+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" +checksum = "a678df20055b43e57ef8cddde41cdfda9a3c1a060b67f4c5836dfb1d78543ba8" dependencies = [ "cc", - "fs_extra", "libc", ] @@ -1833,9 +1823,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ "serde", "time-core", @@ -1858,9 +1848,9 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toolchain" @@ -1973,15 +1963,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.10" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" @@ -1994,9 +1984,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-xid" @@ -2054,12 +2044,11 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] @@ -2117,45 +2106,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "write-json" diff --git a/Cargo.toml b/Cargo.toml index 333f03ce2ffe..511cb24a61ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,5 +74,9 @@ toolchain = { path = "./crates/toolchain", version = "0.0.0" } tt = { path = "./crates/tt", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } + # non-local crates smallvec = { version = "1.10.0", features = ["const_new", "union", "const_generics"] } +# the following crates are pinned to prevent us from pulling in syn 2 until all our dependencies have moved +serde = { version = "=1.0.156", features = ["derive"] } +serde_json = "1.0.94" diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index 609d18c4eea3..1e0b3605b165 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml @@ -16,8 +16,8 @@ crossbeam-channel = "0.5.5" tracing = "0.1.37" cargo_metadata = "0.15.0" rustc-hash = "1.1.0" -serde = { version = "1.0.137", features = ["derive"] } -serde_json = "1.0.86" +serde_json.workspace = true +serde.workspace = true jod-thread = "0.1.2" command-group = "2.0.1" diff --git a/crates/paths/Cargo.toml b/crates/paths/Cargo.toml index e24e6eceffbd..28b54be5212f 100644 --- a/crates/paths/Cargo.toml +++ b/crates/paths/Cargo.toml @@ -15,4 +15,4 @@ doctest = false # Adding this dep sadly puts a lot of rust-analyzer crates after the # serde-derive crate. Even though we don't activate the derive feature here, # someone else in the crate graph certainly does! -# serde = "1" +# serde.workspace = true diff --git a/crates/proc-macro-api/Cargo.toml b/crates/proc-macro-api/Cargo.toml index 28469b832468..e748421f6dd9 100644 --- a/crates/proc-macro-api/Cargo.toml +++ b/crates/proc-macro-api/Cargo.toml @@ -19,8 +19,8 @@ object = { version = "0.30.2", default-features = false, features = [ "macho", "pe", ] } -serde = { version = "1.0.137", features = ["derive"] } -serde_json = { version = "1.0.81", features = ["unbounded_depth"] } +serde.workspace = true +serde_json = { workspace = true, features = ["unbounded_depth"] } tracing = "0.1.37" memmap2 = "0.5.4" snap = "1.1.0" diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index 6273ea51db83..602e74275106 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml @@ -20,7 +20,7 @@ countme = { version = "3.0.1", features = ["enable"] } jemalloc-ctl = { version = "0.5.0", package = "tikv-jemalloc-ctl", optional = true } [target.'cfg(target_os = "linux")'.dependencies] -perf-event = "0.4.7" +perf-event = "=0.4.7" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.9", features = ["processthreadsapi", "psapi"] } diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml index 22d6a6e78957..080b224e8627 100644 --- a/crates/project-model/Cargo.toml +++ b/crates/project-model/Cargo.toml @@ -16,8 +16,8 @@ tracing = "0.1.35" rustc-hash = "1.1.0" cargo_metadata = "0.15.0" semver = "1.0.14" -serde = { version = "1.0.137", features = ["derive"] } -serde_json = "1.0.86" +serde_json.workspace = true +serde.workspace = true anyhow = "1.0.62" la-arena = { version = "0.3.0", path = "../../lib/la-arena" } diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index f0f1900c78c5..1a4155d3bbb3 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -29,8 +29,8 @@ parking_lot = "0.12.1" xflags = "0.3.0" oorandom = "11.1.3" rustc-hash = "1.1.0" -serde = { version = "1.0.137", features = ["derive"] } -serde_json = { version = "1.0.81", features = ["preserve_order"] } +serde_json = { workspace = true, features = ["preserve_order"] } +serde.workspace = true threadpool = "1.8.1" rayon = "1.6.1" num_cpus = "1.15.0" @@ -47,6 +47,16 @@ tracing-log = "0.1.3" tracing-tree = "0.2.1" always-assert = "0.1.2" +# These dependencies are unused, but we pin them to a version here to restrict them for our transitive dependencies +# so that we don't pull in duplicates of their depdendenceies like windows-sys and syn 1 vs 2 +# these would pull in serde 2 +thiserror = "=1.0.39" +serde_repr = "=0.1.11" +# these would pull in windows-sys 0.45.0 +mio = "=0.8.5" +filetime = "=0.2.19" +parking_lot_core = "=0.9.6" + cfg.workspace = true flycheck.workspace = true hir-def.workspace = true diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 305cf2d394b4..7200df0a5736 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -16,7 +16,7 @@ doctest = false cov-mark = "2.0.0-pre.1" either = "1.7.0" itertools = "0.10.5" -rowan = "0.15.10" +rowan = "0.15.11" rustc_lexer = { version = "727.0.0", package = "rustc-ap-rustc_lexer" } rustc-hash = "1.1.0" once_cell = "1.17.0" diff --git a/lib/lsp-server/Cargo.toml b/lib/lsp-server/Cargo.toml index 6e32e3960526..e78a9d2eb167 100644 --- a/lib/lsp-server/Cargo.toml +++ b/lib/lsp-server/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] log = "0.4.17" -serde_json = "1.0.86" -serde = { version = "1.0.144", features = ["derive"] } +serde_json.workspace = true +serde.workspace = true crossbeam-channel = "0.5.6" [dev-dependencies] From 3ae9bfe2661c4a3542a5b44cb1f9700cb17d8f30 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 25 Mar 2023 15:43:58 +0100 Subject: [PATCH 1204/2442] Remove client side proc-macro version check --- crates/proc-macro-api/src/lib.rs | 14 ++------------ crates/rust-analyzer/src/reload.rs | 3 +-- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index 90d06967e8fc..4525d9dfdd72 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -54,18 +54,8 @@ pub struct MacroDylib { } impl MacroDylib { - // FIXME: this is buggy due to TOCTOU, we should check the version in the - // macro process instead. - pub fn new(path: AbsPathBuf) -> io::Result { - let _p = profile::span("MacroDylib::new"); - - let info = version::read_dylib_info(&path)?; - if info.version.0 < 1 || info.version.1 < 47 { - let msg = format!("proc-macro {} built by {info:#?} is not supported by rust-analyzer, please update your Rust version.", path.display()); - return Err(io::Error::new(io::ErrorKind::InvalidData, msg)); - } - - Ok(MacroDylib { path }) + pub fn new(path: AbsPathBuf) -> MacroDylib { + MacroDylib { path } } } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 1a6e1af2eb7e..138b8446b908 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -648,8 +648,7 @@ pub(crate) fn load_proc_macro( ) -> ProcMacroLoadResult { let server = server.map_err(ToOwned::to_owned)?; let res: Result, String> = (|| { - let dylib = MacroDylib::new(path.to_path_buf()) - .map_err(|io| format!("Proc-macro dylib loading failed: {io}"))?; + let dylib = MacroDylib::new(path.to_path_buf()); let vec = server.load_dylib(dylib).map_err(|e| format!("{e}"))?; if vec.is_empty() { return Err("proc macro library returned no proc macros".to_string()); From d154ea88f90e570b9d88dba021050f9030238c79 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 25 Mar 2023 16:42:52 +0100 Subject: [PATCH 1205/2442] Split out proc-macros from the CrateGraph --- crates/base-db/src/change.rs | 10 ++- crates/base-db/src/fixture.rs | 17 ++-- crates/base-db/src/input.rs | 24 +++-- crates/base-db/src/lib.rs | 6 +- crates/hir-def/src/nameres/collector.rs | 46 ++++++---- crates/hir-expand/src/proc_macro.rs | 9 +- crates/ide/src/lib.rs | 1 - crates/ide/src/shuffle_crate_graph.rs | 7 +- crates/project-model/src/tests.rs | 100 +++------------------ crates/project-model/src/workspace.rs | 66 ++++++++------ crates/rust-analyzer/src/cli/load_cargo.rs | 18 +++- crates/rust-analyzer/src/reload.rs | 13 +-- 12 files changed, 141 insertions(+), 176 deletions(-) diff --git a/crates/base-db/src/change.rs b/crates/base-db/src/change.rs index b57f2345767d..b906511dbcfe 100644 --- a/crates/base-db/src/change.rs +++ b/crates/base-db/src/change.rs @@ -6,7 +6,7 @@ use std::{fmt, sync::Arc}; use salsa::Durability; use vfs::FileId; -use crate::{CrateGraph, SourceDatabaseExt, SourceRoot, SourceRootId}; +use crate::{CrateGraph, ProcMacros, SourceDatabaseExt, SourceRoot, SourceRootId}; /// Encapsulate a bunch of raw `.set` calls on the database. #[derive(Default)] @@ -14,6 +14,7 @@ pub struct Change { pub roots: Option>, pub files_changed: Vec<(FileId, Option>)>, pub crate_graph: Option, + pub proc_macros: Option, } impl fmt::Debug for Change { @@ -49,6 +50,10 @@ impl Change { self.crate_graph = Some(graph); } + pub fn set_proc_macros(&mut self, proc_macros: ProcMacros) { + self.proc_macros = Some(proc_macros); + } + pub fn apply(self, db: &mut dyn SourceDatabaseExt) { let _p = profile::span("RootDatabase::apply_change"); if let Some(roots) = self.roots { @@ -73,6 +78,9 @@ impl Change { if let Some(crate_graph) = self.crate_graph { db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) } + if let Some(proc_macros) = self.proc_macros { + db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH) + } } } diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs index 8a7e9dfadfed..7269180a5d61 100644 --- a/crates/base-db/src/fixture.rs +++ b/crates/base-db/src/fixture.rs @@ -12,8 +12,8 @@ use vfs::{file_set::FileSet, VfsPath}; use crate::{ input::{CrateName, CrateOrigin, LangCrateOrigin}, Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition, - FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, SourceDatabaseExt, - SourceRoot, SourceRootId, + FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacros, + SourceDatabaseExt, SourceRoot, SourceRootId, }; pub const WORKSPACE: SourceRootId = SourceRootId(0); @@ -100,7 +100,7 @@ impl ChangeFixture { pub fn parse_with_proc_macros( ra_fixture: &str, - mut proc_macros: Vec<(String, ProcMacro)>, + mut proc_macro_defs: Vec<(String, ProcMacro)>, ) -> ChangeFixture { let (mini_core, proc_macro_names, fixture) = Fixture::parse(ra_fixture); let mut change = Change::new(); @@ -160,7 +160,6 @@ impl ChangeFixture { meta.cfg.clone(), meta.cfg, meta.env, - Ok(Vec::new()), false, origin, meta.target_data_layout @@ -200,7 +199,6 @@ impl ChangeFixture { default_cfg.clone(), default_cfg, Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, name: None }, default_target_data_layout @@ -244,7 +242,6 @@ impl ChangeFixture { CfgOptions::default(), CfgOptions::default(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::Lang(LangCrateOrigin::Core), target_layout.clone(), @@ -257,12 +254,13 @@ impl ChangeFixture { } } + let mut proc_macros = ProcMacros::default(); if !proc_macro_names.is_empty() { let proc_lib_file = file_id; file_id.0 += 1; - proc_macros.extend(default_test_proc_macros()); - let (proc_macro, source) = filter_test_proc_macros(&proc_macro_names, proc_macros); + proc_macro_defs.extend(default_test_proc_macros()); + let (proc_macro, source) = filter_test_proc_macros(&proc_macro_names, proc_macro_defs); let mut fs = FileSet::default(); fs.insert( proc_lib_file, @@ -282,11 +280,11 @@ impl ChangeFixture { CfgOptions::default(), CfgOptions::default(), Env::default(), - Ok(proc_macro), true, CrateOrigin::CratesIo { repo: None, name: None }, target_layout, ); + proc_macros.insert(proc_macros_crate, Ok(proc_macro)); for krate in all_crates { crate_graph @@ -305,6 +303,7 @@ impl ChangeFixture { roots.push(root); change.set_roots(roots); change.set_crate_graph(crate_graph); + change.set_proc_macros(proc_macros); ChangeFixture { file_position, files, change } } diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 43388e915b5d..41a2abd803a6 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -15,6 +15,8 @@ use syntax::SmolStr; use tt::token_id::Subtree; use vfs::{file_set::FileSet, AnchoredPath, FileId, VfsPath}; +pub type ProcMacros = FxHashMap; + /// Files are grouped into source roots. A source root is a directory on the /// file systems which is watched for changes. Typically it corresponds to a /// Rust crate. Source roots *might* be nested: in this case, a file belongs to @@ -269,7 +271,6 @@ pub struct CrateData { pub target_layout: TargetLayoutLoadResult, pub env: Env, pub dependencies: Vec, - pub proc_macro: ProcMacroLoadResult, pub origin: CrateOrigin, pub is_proc_macro: bool, } @@ -322,7 +323,6 @@ impl CrateGraph { cfg_options: CfgOptions, potential_cfg_options: CfgOptions, env: Env, - proc_macro: ProcMacroLoadResult, is_proc_macro: bool, origin: CrateOrigin, target_layout: Result, Arc>, @@ -335,7 +335,6 @@ impl CrateGraph { cfg_options, potential_cfg_options, env, - proc_macro, dependencies: Vec::new(), origin, target_layout, @@ -460,7 +459,12 @@ impl CrateGraph { /// /// The ids of the crates in the `other` graph are shifted by the return /// amount. - pub fn extend(&mut self, other: CrateGraph) -> u32 { + pub fn extend( + &mut self, + other: CrateGraph, + proc_macros: &mut ProcMacros, + other_proc_macros: ProcMacros, + ) -> u32 { let start = self.arena.len() as u32; self.arena.extend(other.arena.into_iter().map(|(id, mut data)| { let new_id = id.shift(start); @@ -469,6 +473,8 @@ impl CrateGraph { } (new_id, data) })); + proc_macros + .extend(other_proc_macros.into_iter().map(|(id, macros)| (id.shift(start), macros))); start } @@ -645,7 +651,6 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, name: None }, Err("".into()), @@ -658,7 +663,6 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, name: None }, Err("".into()), @@ -671,7 +675,6 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, name: None }, Err("".into()), @@ -698,7 +701,6 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, name: None }, Err("".into()), @@ -711,7 +713,6 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, name: None }, Err("".into()), @@ -735,7 +736,6 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, name: None }, Err("".into()), @@ -748,7 +748,6 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, name: None }, Err("".into()), @@ -761,7 +760,6 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, name: None }, Err("".into()), @@ -785,7 +783,6 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, name: None }, Err("".into()), @@ -798,7 +795,6 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, name: None }, Err("".into()), diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 9720db9d8ace..7ab9aa8709c0 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -16,7 +16,7 @@ pub use crate::{ input::{ CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, - ProcMacroId, ProcMacroKind, ProcMacroLoadResult, SourceRoot, SourceRootId, + ProcMacroId, ProcMacroKind, ProcMacroLoadResult, ProcMacros, SourceRoot, SourceRootId, TargetLayoutLoadResult, }, }; @@ -73,6 +73,10 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug { /// The crate graph. #[salsa::input] fn crate_graph(&self) -> Arc; + + /// The crate graph. + #[salsa::input] + fn proc_macros(&self) -> Arc; } fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse { diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index ddcee77ec4cc..b3ce913d9ab5 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -78,25 +78,35 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T } let cfg_options = &krate.cfg_options; - let proc_macros = match &krate.proc_macro { - Ok(proc_macros) => { - proc_macros - .iter() - .enumerate() - .map(|(idx, it)| { - // FIXME: a hacky way to create a Name from string. - let name = - tt::Ident { text: it.name.clone(), span: tt::TokenId::unspecified() }; - (name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32))) - }) - .collect() - } - Err(e) => { - def_map.proc_macro_loading_error = Some(e.clone().into_boxed_str()); - Vec::new() - } - }; + let is_proc_macro = krate.is_proc_macro; + let proc_macros = if is_proc_macro { + match db.proc_macros().get(&def_map.krate) { + Some(Ok(proc_macros)) => { + proc_macros + .iter() + .enumerate() + .map(|(idx, it)| { + // FIXME: a hacky way to create a Name from string. + let name = + tt::Ident { text: it.name.clone(), span: tt::TokenId::unspecified() }; + (name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32))) + }) + .collect() + } + Some(Err(e)) => { + def_map.proc_macro_loading_error = Some(e.clone().into_boxed_str()); + Vec::new() + } + None => { + def_map.proc_macro_loading_error = + Some("No proc-macros present for crate".to_owned().into_boxed_str()); + Vec::new() + } + } + } else { + vec![] + }; let mut collector = DefCollector { db, diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs index d758e9302cd8..ad9893587406 100644 --- a/crates/hir-expand/src/proc_macro.rs +++ b/crates/hir-expand/src/proc_macro.rs @@ -33,10 +33,10 @@ impl ProcMacroExpander { ) -> ExpandResult { match self.proc_macro_id { Some(id) => { - let krate_graph = db.crate_graph(); - let proc_macros = match &krate_graph[def_crate].proc_macro { - Ok(proc_macros) => proc_macros, - Err(_) => { + let proc_macros = db.proc_macros(); + let proc_macros = match proc_macros.get(&def_crate) { + Some(Ok(proc_macros)) => proc_macros, + Some(Err(_)) | None => { never!("Non-dummy expander even though there are no proc macros"); return ExpandResult::with_err( tt::Subtree::empty(), @@ -59,6 +59,7 @@ impl ProcMacroExpander { } }; + let krate_graph = db.crate_graph(); // Proc macros have access to the environment variables of the invoking crate. let env = &krate_graph[calling_crate].env; match proc_macro.expander.expand(tt, attr_arg, env) { diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 078b66dd3955..8477a8e6228d 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -235,7 +235,6 @@ impl Analysis { cfg_options.clone(), cfg_options, Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, name: None }, Err("Analysis::from_single_file has no target layout".into()), diff --git a/crates/ide/src/shuffle_crate_graph.rs b/crates/ide/src/shuffle_crate_graph.rs index e606072a8237..471c36dfecf5 100644 --- a/crates/ide/src/shuffle_crate_graph.rs +++ b/crates/ide/src/shuffle_crate_graph.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use ide_db::{ - base_db::{salsa::Durability, CrateGraph, SourceDatabase}, + base_db::{salsa::Durability, CrateGraph, ProcMacros, SourceDatabase}, FxHashMap, RootDatabase, }; @@ -16,6 +16,7 @@ use ide_db::{ // |=== pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { let crate_graph = db.crate_graph(); + let proc_macros = db.proc_macros(); let mut shuffled_ids = crate_graph.iter().collect::>(); @@ -23,6 +24,7 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { stdx::rand::shuffle(&mut shuffled_ids, |i| rng.rand_range(0..i as u32) as usize); let mut new_graph = CrateGraph::default(); + let mut new_proc_macros = ProcMacros::default(); let mut map = FxHashMap::default(); for old_id in shuffled_ids.iter().copied() { @@ -35,11 +37,11 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { data.cfg_options.clone(), data.potential_cfg_options.clone(), data.env.clone(), - data.proc_macro.clone(), data.is_proc_macro, data.origin.clone(), data.target_layout.clone(), ); + new_proc_macros.insert(new_id, proc_macros[&old_id].clone()); map.insert(old_id, new_id); } @@ -53,4 +55,5 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { } db.set_crate_graph_with_durability(Arc::new(new_graph), Durability::HIGH); + db.set_proc_macros_with_durability(Arc::new(new_proc_macros), Durability::HIGH); } diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index 3754accbb03d..ed78d71a1a57 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -3,7 +3,7 @@ use std::{ path::{Path, PathBuf}, }; -use base_db::{CrateGraph, FileId}; +use base_db::{CrateGraph, FileId, ProcMacros}; use cfg::{CfgAtom, CfgDiff}; use expect_test::{expect, Expect}; use paths::{AbsPath, AbsPathBuf}; @@ -14,11 +14,11 @@ use crate::{ WorkspaceBuildScripts, }; -fn load_cargo(file: &str) -> CrateGraph { +fn load_cargo(file: &str) -> (CrateGraph, ProcMacros) { load_cargo_with_overrides(file, CfgOverrides::default()) } -fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGraph { +fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> (CrateGraph, ProcMacros) { let meta = get_test_json_file(file); let cargo_workspace = CargoWorkspace::new(meta); let project_workspace = ProjectWorkspace::Cargo { @@ -34,7 +34,7 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGr to_crate_graph(project_workspace) } -fn load_rust_project(file: &str) -> CrateGraph { +fn load_rust_project(file: &str) -> (CrateGraph, ProcMacros) { let data = get_test_json_file(file); let project = rooted_project_json(data); let sysroot = Ok(get_fake_sysroot()); @@ -92,7 +92,7 @@ fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { ProjectJson::new(base, data) } -fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph { +fn to_crate_graph(project_workspace: ProjectWorkspace) -> (CrateGraph, ProcMacros) { project_workspace.to_crate_graph( &mut |_, _| Ok(Vec::new()), &mut { @@ -117,7 +117,8 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { let cfg_overrides = CfgOverrides::Wildcard( CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(), ); - let crate_graph = load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); + let (crate_graph, _proc_macros) = + load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); check_crate_graph( crate_graph, expect![[r#" @@ -184,9 +185,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { prelude: true, }, ], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: None, name: Some( @@ -265,9 +263,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { prelude: true, }, ], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: None, name: Some( @@ -346,9 +341,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { prelude: true, }, ], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: None, name: Some( @@ -427,9 +419,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { prelude: true, }, ], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: None, name: Some( @@ -498,9 +487,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { }, }, dependencies: [], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: Some( "https://github.com/rust-lang/libc", @@ -527,7 +513,8 @@ fn cargo_hello_world_project_model_with_selective_overrides() { .collect(), ) }; - let crate_graph = load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); + let (crate_graph, _proc_macros) = + load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); check_crate_graph( crate_graph, expect![[r#" @@ -596,9 +583,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() { prelude: true, }, ], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: None, name: Some( @@ -679,9 +663,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() { prelude: true, }, ], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: None, name: Some( @@ -762,9 +743,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() { prelude: true, }, ], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: None, name: Some( @@ -845,9 +823,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() { prelude: true, }, ], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: None, name: Some( @@ -916,9 +891,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() { }, }, dependencies: [], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: Some( "https://github.com/rust-lang/libc", @@ -936,7 +908,7 @@ fn cargo_hello_world_project_model_with_selective_overrides() { #[test] fn cargo_hello_world_project_model() { - let crate_graph = load_cargo("hello-world-metadata.json"); + let (crate_graph, _proc_macros) = load_cargo("hello-world-metadata.json"); check_crate_graph( crate_graph, expect![[r#" @@ -1005,9 +977,6 @@ fn cargo_hello_world_project_model() { prelude: true, }, ], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: None, name: Some( @@ -1088,9 +1057,6 @@ fn cargo_hello_world_project_model() { prelude: true, }, ], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: None, name: Some( @@ -1171,9 +1137,6 @@ fn cargo_hello_world_project_model() { prelude: true, }, ], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: None, name: Some( @@ -1254,9 +1217,6 @@ fn cargo_hello_world_project_model() { prelude: true, }, ], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: None, name: Some( @@ -1325,9 +1285,6 @@ fn cargo_hello_world_project_model() { }, }, dependencies: [], - proc_macro: Err( - "crate has not (yet) been built", - ), origin: CratesIo { repo: Some( "https://github.com/rust-lang/libc", @@ -1345,7 +1302,7 @@ fn cargo_hello_world_project_model() { #[test] fn rust_project_hello_world_project_model() { - let crate_graph = load_rust_project("hello-world-project.json"); + let (crate_graph, _proc_macros) = load_rust_project("hello-world-project.json"); check_crate_graph( crate_graph, expect![[r#" @@ -1390,9 +1347,6 @@ fn rust_project_hello_world_project_model() { prelude: true, }, ], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), origin: Lang( Alloc, ), @@ -1427,9 +1381,6 @@ fn rust_project_hello_world_project_model() { entries: {}, }, dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), origin: Lang( Core, ), @@ -1464,9 +1415,6 @@ fn rust_project_hello_world_project_model() { entries: {}, }, dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), origin: Lang( Other, ), @@ -1501,9 +1449,6 @@ fn rust_project_hello_world_project_model() { entries: {}, }, dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), origin: Lang( Other, ), @@ -1557,9 +1502,6 @@ fn rust_project_hello_world_project_model() { prelude: true, }, ], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), origin: Lang( Other, ), @@ -1594,9 +1536,6 @@ fn rust_project_hello_world_project_model() { entries: {}, }, dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), origin: Lang( Other, ), @@ -1704,9 +1643,6 @@ fn rust_project_hello_world_project_model() { prelude: true, }, ], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), origin: Lang( Std, ), @@ -1741,9 +1677,6 @@ fn rust_project_hello_world_project_model() { entries: {}, }, dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), origin: Lang( Other, ), @@ -1778,9 +1711,6 @@ fn rust_project_hello_world_project_model() { entries: {}, }, dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), origin: Lang( Test, ), @@ -1815,9 +1745,6 @@ fn rust_project_hello_world_project_model() { entries: {}, }, dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), origin: Lang( Other, ), @@ -1889,9 +1816,6 @@ fn rust_project_hello_world_project_model() { prelude: false, }, ], - proc_macro: Err( - "no proc macro dylib present", - ), origin: CratesIo { repo: None, name: Some( @@ -1907,7 +1831,7 @@ fn rust_project_hello_world_project_model() { #[test] fn rust_project_is_proc_macro_has_proc_macro_dep() { - let crate_graph = load_rust_project("is-proc-macro-project.json"); + let (crate_graph, _proc_macros) = load_rust_project("is-proc-macro-project.json"); // Since the project only defines one crate (outside the sysroot crates), // it should be the one with the biggest Id. let crate_id = crate_graph.iter().max().unwrap(); diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 2158485a3306..5766859143b2 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, process::Command, sync::Arc}; use anyhow::{bail, format_err, Context, Result}; use base_db::{ CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, - FileId, LangCrateOrigin, ProcMacroLoadResult, TargetLayoutLoadResult, + FileId, LangCrateOrigin, ProcMacroLoadResult, ProcMacros, TargetLayoutLoadResult, }; use cfg::{CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; @@ -579,10 +579,10 @@ impl ProjectWorkspace { load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, extra_env: &FxHashMap, - ) -> CrateGraph { + ) -> (CrateGraph, ProcMacros) { let _p = profile::span("ProjectWorkspace::to_crate_graph"); - let mut crate_graph = match self { + let (mut crate_graph, proc_macros) = match self { ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph( rustc_cfg.clone(), load_proc_macro, @@ -630,7 +630,7 @@ impl ProjectWorkspace { } else { tracing::debug!("Did not patch std to depend on cfg-if") } - crate_graph + (crate_graph, proc_macros) } pub fn eq_ignore_build_data(&self, other: &Self) -> bool { @@ -685,8 +685,9 @@ fn project_json_to_crate_graph( sysroot: Option<&Sysroot>, extra_env: &FxHashMap, target_layout: TargetLayoutLoadResult, -) -> CrateGraph { +) -> (CrateGraph, ProcMacros) { let mut crate_graph = CrateGraph::default(); + let mut proc_macros = FxHashMap::<_, _>::default(); let sysroot_deps = sysroot.as_ref().map(|sysroot| { sysroot_to_crate_graph( &mut crate_graph, @@ -707,13 +708,15 @@ fn project_json_to_crate_graph( }) .map(|(crate_id, krate, file_id)| { let env = krate.env.clone().into_iter().collect(); - let proc_macro = match krate.proc_macro_dylib_path.clone() { - Some(it) => load_proc_macro( - krate.display_name.as_ref().map(|it| it.canonical_name()).unwrap_or(""), - &it, - ), - None => Err("no proc macro dylib present".into()), - }; + if let Some(it) = krate.proc_macro_dylib_path.clone() { + proc_macros.insert( + crate_id, + load_proc_macro( + krate.display_name.as_ref().map(|it| it.canonical_name()).unwrap_or(""), + &it, + ), + ); + } let target_cfgs = match krate.target.as_deref() { Some(target) => cfg_cache @@ -734,7 +737,6 @@ fn project_json_to_crate_graph( cfg_options.clone(), cfg_options, env, - proc_macro, krate.is_proc_macro, if krate.display_name.is_some() { CrateOrigin::CratesIo { @@ -776,7 +778,7 @@ fn project_json_to_crate_graph( } } } - crate_graph + (crate_graph, proc_macros) } fn cargo_to_crate_graph( @@ -789,9 +791,10 @@ fn cargo_to_crate_graph( override_cfg: &CfgOverrides, build_scripts: &WorkspaceBuildScripts, target_layout: TargetLayoutLoadResult, -) -> CrateGraph { +) -> (CrateGraph, ProcMacros) { let _p = profile::span("cargo_to_crate_graph"); let mut crate_graph = CrateGraph::default(); + let mut proc_macros = FxHashMap::default(); let (public_deps, libproc_macro) = match sysroot { Some(sysroot) => sysroot_to_crate_graph( &mut crate_graph, @@ -855,6 +858,7 @@ fn cargo_to_crate_graph( if let Some(file_id) = load(&cargo[tgt].root) { let crate_id = add_target_crate_root( &mut crate_graph, + &mut proc_macros, &cargo[pkg], build_scripts.get_output(pkg), cfg_options.clone(), @@ -931,6 +935,7 @@ fn cargo_to_crate_graph( if let Some((rustc_workspace, rustc_build_scripts)) = rustc { handle_rustc_crates( &mut crate_graph, + &mut proc_macros, &mut pkg_to_lib_crate, load, load_proc_macro, @@ -952,7 +957,7 @@ fn cargo_to_crate_graph( ); } } - crate_graph + (crate_graph, proc_macros) } fn detached_files_to_crate_graph( @@ -961,7 +966,7 @@ fn detached_files_to_crate_graph( detached_files: &[AbsPathBuf], sysroot: Option<&Sysroot>, target_layout: TargetLayoutLoadResult, -) -> CrateGraph { +) -> (CrateGraph, ProcMacros) { let _p = profile::span("detached_files_to_crate_graph"); let mut crate_graph = CrateGraph::default(); let (public_deps, _libproc_macro) = match sysroot { @@ -998,7 +1003,6 @@ fn detached_files_to_crate_graph( cfg_options.clone(), cfg_options.clone(), Env::default(), - Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None, @@ -1009,11 +1013,12 @@ fn detached_files_to_crate_graph( public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate); } - crate_graph + (crate_graph, FxHashMap::default()) } fn handle_rustc_crates( crate_graph: &mut CrateGraph, + proc_macros: &mut ProcMacros, pkg_to_lib_crate: &mut FxHashMap, load: &mut dyn FnMut(&AbsPath) -> Option, load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, @@ -1075,6 +1080,7 @@ fn handle_rustc_crates( if let Some(file_id) = load(&rustc_workspace[tgt].root) { let crate_id = add_target_crate_root( crate_graph, + proc_macros, &rustc_workspace[pkg], build_scripts.get_output(pkg), cfg_options.clone(), @@ -1140,6 +1146,7 @@ fn handle_rustc_crates( fn add_target_crate_root( crate_graph: &mut CrateGraph, + proc_macros: &mut ProcMacros, pkg: &PackageData, build_data: Option<&BuildScriptOutput>, cfg_options: CfgOptions, @@ -1176,14 +1183,8 @@ fn add_target_crate_root( } } - let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) { - Some(Some(it)) => load_proc_macro(it), - Some(None) => Err("no proc macro dylib present".into()), - None => Err("crate has not (yet) been built".into()), - }; - let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string()); - crate_graph.add_crate_root( + let crate_id = crate_graph.add_crate_root( file_id, edition, Some(display_name), @@ -1191,11 +1192,19 @@ fn add_target_crate_root( cfg_options, potential_cfg_options, env, - proc_macro, is_proc_macro, CrateOrigin::CratesIo { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) }, target_layout, - ) + ); + let proc_macro = match build_data.as_ref().map(|it| &it.proc_macro_dylib_path) { + Some(it) => it.as_deref().map(load_proc_macro), + None => Some(Err("crate has not (yet) been built".into())), + }; + if let Some(proc_macro) = proc_macro { + proc_macros.insert(crate_id, proc_macro); + } + + crate_id } #[derive(Default)] @@ -1237,7 +1246,6 @@ fn sysroot_to_crate_graph( cfg_options.clone(), cfg_options.clone(), env, - Err("no proc macro loaded for sysroot crate".into()), false, CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)), target_layout.clone(), diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 5a958d963e4b..2d15d673edb0 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -6,7 +6,10 @@ use anyhow::Result; use crossbeam_channel::{unbounded, Receiver}; use hir::db::DefDatabase; use ide::{AnalysisHost, Change}; -use ide_db::{base_db::CrateGraph, FxHashMap}; +use ide_db::{ + base_db::{CrateGraph, ProcMacros}, + FxHashMap, +}; use proc_macro_api::ProcMacroServer; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace}; use vfs::{loader::Handle, AbsPath, AbsPathBuf}; @@ -79,7 +82,7 @@ pub fn load_workspace( ProcMacroServerChoice::None => Err("proc macro server disabled".to_owned()), }; - let crate_graph = ws.to_crate_graph( + let (crate_graph, proc_macros) = ws.to_crate_graph( &mut |_, path: &AbsPath| { load_proc_macro(proc_macro_client.as_ref().map_err(|e| &**e), path, &[]) }, @@ -100,8 +103,13 @@ pub fn load_workspace( }); tracing::debug!("crate graph: {:?}", crate_graph); - let host = - load_crate_graph(crate_graph, project_folders.source_root_config, &mut vfs, &receiver); + let host = load_crate_graph( + crate_graph, + proc_macros, + project_folders.source_root_config, + &mut vfs, + &receiver, + ); if load_config.prefill_caches { host.analysis().parallel_prime_caches(1, |_| {})?; @@ -111,6 +119,7 @@ pub fn load_workspace( fn load_crate_graph( crate_graph: CrateGraph, + proc_macros: ProcMacros, source_root_config: SourceRootConfig, vfs: &mut vfs::Vfs, receiver: &Receiver, @@ -149,6 +158,7 @@ fn load_crate_graph( analysis_change.set_roots(source_roots); analysis_change.set_crate_graph(crate_graph); + analysis_change.set_proc_macros(proc_macros); host.apply_change(analysis_change); host diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 138b8446b908..65758419deac 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -20,7 +20,7 @@ use ide::Change; use ide_db::{ base_db::{ CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, - ProcMacroLoadResult, SourceRoot, VfsPath, + ProcMacroLoadResult, ProcMacros, SourceRoot, VfsPath, }, FxHashMap, }; @@ -355,7 +355,7 @@ impl GlobalState { }); // Create crate graph from all the workspaces - let crate_graph = { + let (crate_graph, proc_macros) = { let dummy_replacements = self.config.dummy_replacements(); let vfs = &mut self.vfs.write().0; @@ -376,6 +376,7 @@ impl GlobalState { }; let mut crate_graph = CrateGraph::default(); + let mut proc_macros = ProcMacros::default(); for (idx, ws) in self.workspaces.iter().enumerate() { let proc_macro_client = match self.proc_macro_clients.get(idx) { Some(res) => res.as_ref().map_err(|e| &**e), @@ -388,15 +389,17 @@ impl GlobalState { dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(), ) }; - crate_graph.extend(ws.to_crate_graph( + let (other, other_proc_macros) = ws.to_crate_graph( &mut load_proc_macro, &mut load, &self.config.cargo().extra_env, - )); + ); + crate_graph.extend(other, &mut proc_macros, other_proc_macros); } - crate_graph + (crate_graph, proc_macros) }; change.set_crate_graph(crate_graph); + change.set_proc_macros(proc_macros); self.source_root_config = project_folders.source_root_config; From e9fb2ffe4572471588b6bd602521a1421baf4dc3 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 25 Mar 2023 16:47:41 +0100 Subject: [PATCH 1206/2442] Add lsp command for rebuilding proc macros --- crates/rust-analyzer/src/handlers.rs | 8 ++++++++ crates/rust-analyzer/src/lsp_ext.rs | 8 ++++++++ crates/rust-analyzer/src/main_loop.rs | 1 + editors/code/src/commands.ts | 4 ++++ editors/code/src/ctx.ts | 5 ++++- editors/code/src/lsp_ext.ts | 1 + editors/code/src/main.ts | 1 + 7 files changed, 27 insertions(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 2fca2ab851d4..a56c245dca57 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -52,6 +52,14 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result< Ok(()) } +pub(crate) fn handle_proc_macros_reload(state: &mut GlobalState, _: ()) -> Result<()> { + state.proc_macro_clients.clear(); + state.proc_macro_changed = false; + + state.fetch_build_data_queue.request_op("reload proc macros request".to_string()); + Ok(()) +} + pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> Result<()> { let _p = profile::span("handle_stop_flycheck"); state.flycheck.iter().for_each(|flycheck| flycheck.cancel()); diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index c7b513db981e..2f8829ec7386 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -51,6 +51,14 @@ impl Request for ReloadWorkspace { const METHOD: &'static str = "rust-analyzer/reloadWorkspace"; } +pub enum ReloadProcMacros {} + +impl Request for ReloadProcMacros { + type Params = (); + type Result = (); + const METHOD: &'static str = "rust-analyzer/reloadProcMacros"; +} + pub enum SyntaxTree {} impl Request for SyntaxTree { diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 67a54cde68c6..ae7457e3473e 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -633,6 +633,7 @@ impl GlobalState { dispatcher .on_sync_mut::(handlers::handle_workspace_reload) + .on_sync_mut::(handlers::handle_proc_macros_reload) .on_sync_mut::(handlers::handle_memory_usage) .on_sync_mut::(handlers::handle_shuffle_crate_graph) .on_sync::(handlers::handle_join_lines) diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 8a953577e99d..8ce3466ed440 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -749,6 +749,10 @@ export function reloadWorkspace(ctx: CtxInit): Cmd { return async () => ctx.client.sendRequest(ra.reloadWorkspace); } +export function reloadProcMacros(ctx: CtxInit): Cmd { + return async () => ctx.client.sendRequest(ra.reloadProcMacros); +} + export function addProject(ctx: CtxInit): Cmd { return async () => { const discoverProjectCommand = ctx.config.discoverProjectCommand; diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 85579453a63d..8da8b0d63a15 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -378,10 +378,13 @@ export class Ctx { if (statusBar.tooltip.value) { statusBar.tooltip.appendText("\n\n"); } + statusBar.tooltip.appendMarkdown("\n\n[Open logs](command:rust-analyzer.openLogs)"); statusBar.tooltip.appendMarkdown( "\n\n[Reload Workspace](command:rust-analyzer.reloadWorkspace)" ); - statusBar.tooltip.appendMarkdown("\n\n[Open logs](command:rust-analyzer.openLogs)"); + statusBar.tooltip.appendMarkdown( + "\n\n[Rebuild Proc Macros](command:rust-analyzer.reloadProcMacros)" + ); statusBar.tooltip.appendMarkdown("\n\n[Restart server](command:rust-analyzer.startServer)"); statusBar.tooltip.appendMarkdown("\n\n[Stop server](command:rust-analyzer.stopServer)"); if (!status.quiescent) icon = "$(sync~spin) "; diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index 872d7199b838..a03777d1c0af 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -43,6 +43,7 @@ export const relatedTests = new lc.RequestType("rust-analyzer/reloadWorkspace"); +export const reloadProcMacros = new lc.RequestType0("rust-analyzer/reloadProcMacros"); export const runFlycheck = new lc.NotificationType<{ textDocument: lc.TextDocumentIdentifier | null; diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index d5de00561b12..7079f235cab1 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -153,6 +153,7 @@ function createCommands(): Record { memoryUsage: { enabled: commands.memoryUsage }, shuffleCrateGraph: { enabled: commands.shuffleCrateGraph }, reloadWorkspace: { enabled: commands.reloadWorkspace }, + reloadProcMacros: { enabled: commands.reloadProcMacros }, addProject: { enabled: commands.addProject }, matchingBrace: { enabled: commands.matchingBrace }, joinLines: { enabled: commands.joinLines }, From 607375dc206259955a386c48d88c45529c316145 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 25 Mar 2023 18:06:06 +0100 Subject: [PATCH 1207/2442] Load proc-macros asynchronously --- crates/base-db/src/input.rs | 21 ++--- crates/base-db/src/lib.rs | 4 +- crates/project-model/src/tests.rs | 14 +-- crates/project-model/src/workspace.rs | 41 +++----- crates/rust-analyzer/src/cli/load_cargo.rs | 22 ++++- crates/rust-analyzer/src/global_state.rs | 10 +- crates/rust-analyzer/src/handlers.rs | 5 +- crates/rust-analyzer/src/main_loop.rs | 18 +++- crates/rust-analyzer/src/reload.rs | 105 +++++++++++++++------ docs/dev/lsp-extensions.md | 2 +- 10 files changed, 154 insertions(+), 88 deletions(-) diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 41a2abd803a6..9580b76faa22 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -6,15 +6,16 @@ //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how //! actual IO is done and lowered to input. -use std::{fmt, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc}; +use std::{fmt, mem, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc}; use cfg::CfgOptions; use rustc_hash::FxHashMap; use stdx::hash::{NoHashHashMap, NoHashHashSet}; use syntax::SmolStr; use tt::token_id::Subtree; -use vfs::{file_set::FileSet, AnchoredPath, FileId, VfsPath}; +use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath}; +pub type ProcMacroPaths = FxHashMap, AbsPathBuf), String>>; pub type ProcMacros = FxHashMap; /// Files are grouped into source roots. A source root is a directory on the @@ -455,16 +456,11 @@ impl CrateGraph { } /// Extends this crate graph by adding a complete disjoint second crate - /// graph. + /// graph and adjust the ids in the [`ProcMacroPaths`] accordingly. /// /// The ids of the crates in the `other` graph are shifted by the return /// amount. - pub fn extend( - &mut self, - other: CrateGraph, - proc_macros: &mut ProcMacros, - other_proc_macros: ProcMacros, - ) -> u32 { + pub fn extend(&mut self, other: CrateGraph, proc_macros: &mut ProcMacroPaths) -> u32 { let start = self.arena.len() as u32; self.arena.extend(other.arena.into_iter().map(|(id, mut data)| { let new_id = id.shift(start); @@ -473,8 +469,11 @@ impl CrateGraph { } (new_id, data) })); - proc_macros - .extend(other_proc_macros.into_iter().map(|(id, macros)| (id.shift(start), macros))); + + *proc_macros = mem::take(proc_macros) + .into_iter() + .map(|(id, macros)| (id.shift(start), macros)) + .collect(); start } diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 7ab9aa8709c0..f6975f2fbd75 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -16,8 +16,8 @@ pub use crate::{ input::{ CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, - ProcMacroId, ProcMacroKind, ProcMacroLoadResult, ProcMacros, SourceRoot, SourceRootId, - TargetLayoutLoadResult, + ProcMacroId, ProcMacroKind, ProcMacroLoadResult, ProcMacroPaths, ProcMacros, SourceRoot, + SourceRootId, TargetLayoutLoadResult, }, }; pub use salsa::{self, Cancelled}; diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index ed78d71a1a57..26c4c89f7646 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -3,7 +3,7 @@ use std::{ path::{Path, PathBuf}, }; -use base_db::{CrateGraph, FileId, ProcMacros}; +use base_db::{CrateGraph, FileId, ProcMacroPaths}; use cfg::{CfgAtom, CfgDiff}; use expect_test::{expect, Expect}; use paths::{AbsPath, AbsPathBuf}; @@ -14,11 +14,14 @@ use crate::{ WorkspaceBuildScripts, }; -fn load_cargo(file: &str) -> (CrateGraph, ProcMacros) { +fn load_cargo(file: &str) -> (CrateGraph, ProcMacroPaths) { load_cargo_with_overrides(file, CfgOverrides::default()) } -fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> (CrateGraph, ProcMacros) { +fn load_cargo_with_overrides( + file: &str, + cfg_overrides: CfgOverrides, +) -> (CrateGraph, ProcMacroPaths) { let meta = get_test_json_file(file); let cargo_workspace = CargoWorkspace::new(meta); let project_workspace = ProjectWorkspace::Cargo { @@ -34,7 +37,7 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> (CrateG to_crate_graph(project_workspace) } -fn load_rust_project(file: &str) -> (CrateGraph, ProcMacros) { +fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) { let data = get_test_json_file(file); let project = rooted_project_json(data); let sysroot = Ok(get_fake_sysroot()); @@ -92,9 +95,8 @@ fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { ProjectJson::new(base, data) } -fn to_crate_graph(project_workspace: ProjectWorkspace) -> (CrateGraph, ProcMacros) { +fn to_crate_graph(project_workspace: ProjectWorkspace) -> (CrateGraph, ProcMacroPaths) { project_workspace.to_crate_graph( - &mut |_, _| Ok(Vec::new()), &mut { let mut counter = 0; move |_path| { diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 5766859143b2..1fd7c681938e 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, process::Command, sync::Arc}; use anyhow::{bail, format_err, Context, Result}; use base_db::{ CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, - FileId, LangCrateOrigin, ProcMacroLoadResult, ProcMacros, TargetLayoutLoadResult, + FileId, LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult, }; use cfg::{CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; @@ -576,16 +576,14 @@ impl ProjectWorkspace { pub fn to_crate_graph( &self, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, extra_env: &FxHashMap, - ) -> (CrateGraph, ProcMacros) { + ) -> (CrateGraph, ProcMacroPaths) { let _p = profile::span("ProjectWorkspace::to_crate_graph"); let (mut crate_graph, proc_macros) = match self { ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph( rustc_cfg.clone(), - load_proc_macro, load, project, sysroot.as_ref().ok(), @@ -602,7 +600,6 @@ impl ProjectWorkspace { toolchain: _, target_layout, } => cargo_to_crate_graph( - load_proc_macro, load, rustc.as_ref().ok(), cargo, @@ -679,15 +676,14 @@ impl ProjectWorkspace { fn project_json_to_crate_graph( rustc_cfg: Vec, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, project: &ProjectJson, sysroot: Option<&Sysroot>, extra_env: &FxHashMap, target_layout: TargetLayoutLoadResult, -) -> (CrateGraph, ProcMacros) { +) -> (CrateGraph, ProcMacroPaths) { let mut crate_graph = CrateGraph::default(); - let mut proc_macros = FxHashMap::<_, _>::default(); + let mut proc_macros = FxHashMap::default(); let sysroot_deps = sysroot.as_ref().map(|sysroot| { sysroot_to_crate_graph( &mut crate_graph, @@ -708,16 +704,15 @@ fn project_json_to_crate_graph( }) .map(|(crate_id, krate, file_id)| { let env = krate.env.clone().into_iter().collect(); - if let Some(it) = krate.proc_macro_dylib_path.clone() { + if let Some(path) = krate.proc_macro_dylib_path.clone() { proc_macros.insert( crate_id, - load_proc_macro( - krate.display_name.as_ref().map(|it| it.canonical_name()).unwrap_or(""), - &it, - ), + Ok(( + krate.display_name.as_ref().map(|it| it.canonical_name().to_owned()), + path, + )), ); } - let target_cfgs = match krate.target.as_deref() { Some(target) => cfg_cache .entry(target) @@ -782,7 +777,6 @@ fn project_json_to_crate_graph( } fn cargo_to_crate_graph( - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, rustc: Option<&(CargoWorkspace, WorkspaceBuildScripts)>, cargo: &CargoWorkspace, @@ -791,7 +785,7 @@ fn cargo_to_crate_graph( override_cfg: &CfgOverrides, build_scripts: &WorkspaceBuildScripts, target_layout: TargetLayoutLoadResult, -) -> (CrateGraph, ProcMacros) { +) -> (CrateGraph, ProcMacroPaths) { let _p = profile::span("cargo_to_crate_graph"); let mut crate_graph = CrateGraph::default(); let mut proc_macros = FxHashMap::default(); @@ -862,7 +856,6 @@ fn cargo_to_crate_graph( &cargo[pkg], build_scripts.get_output(pkg), cfg_options.clone(), - &mut |path| load_proc_macro(&cargo[tgt].name, path), file_id, &cargo[tgt].name, cargo[tgt].is_proc_macro, @@ -938,7 +931,6 @@ fn cargo_to_crate_graph( &mut proc_macros, &mut pkg_to_lib_crate, load, - load_proc_macro, rustc_workspace, cargo, &public_deps, @@ -966,7 +958,7 @@ fn detached_files_to_crate_graph( detached_files: &[AbsPathBuf], sysroot: Option<&Sysroot>, target_layout: TargetLayoutLoadResult, -) -> (CrateGraph, ProcMacros) { +) -> (CrateGraph, ProcMacroPaths) { let _p = profile::span("detached_files_to_crate_graph"); let mut crate_graph = CrateGraph::default(); let (public_deps, _libproc_macro) = match sysroot { @@ -1018,10 +1010,9 @@ fn detached_files_to_crate_graph( fn handle_rustc_crates( crate_graph: &mut CrateGraph, - proc_macros: &mut ProcMacros, + proc_macros: &mut ProcMacroPaths, pkg_to_lib_crate: &mut FxHashMap, load: &mut dyn FnMut(&AbsPath) -> Option, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, rustc_workspace: &CargoWorkspace, cargo: &CargoWorkspace, public_deps: &SysrootPublicDeps, @@ -1084,7 +1075,6 @@ fn handle_rustc_crates( &rustc_workspace[pkg], build_scripts.get_output(pkg), cfg_options.clone(), - &mut |path| load_proc_macro(&rustc_workspace[tgt].name, path), file_id, &rustc_workspace[tgt].name, rustc_workspace[tgt].is_proc_macro, @@ -1146,11 +1136,10 @@ fn handle_rustc_crates( fn add_target_crate_root( crate_graph: &mut CrateGraph, - proc_macros: &mut ProcMacros, + proc_macros: &mut ProcMacroPaths, pkg: &PackageData, build_data: Option<&BuildScriptOutput>, cfg_options: CfgOptions, - load_proc_macro: &mut dyn FnMut(&AbsPath) -> ProcMacroLoadResult, file_id: FileId, cargo_name: &str, is_proc_macro: bool, @@ -1197,11 +1186,11 @@ fn add_target_crate_root( target_layout, ); let proc_macro = match build_data.as_ref().map(|it| &it.proc_macro_dylib_path) { - Some(it) => it.as_deref().map(load_proc_macro), + Some(it) => it.clone().map(Ok), None => Some(Err("crate has not (yet) been built".into())), }; if let Some(proc_macro) = proc_macro { - proc_macros.insert(crate_id, proc_macro); + proc_macros.insert(crate_id, proc_macro.map(|path| (Some(cargo_name.to_owned()), path))); } crate_id diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 2d15d673edb0..f5bc3c12c149 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -69,7 +69,7 @@ pub fn load_workspace( Box::new(loader) }; - let proc_macro_client = match &load_config.with_proc_macro_server { + let proc_macro_server = match &load_config.with_proc_macro_server { ProcMacroServerChoice::Sysroot => ws .find_sysroot_proc_macro_srv() .ok_or_else(|| "failed to find sysroot proc-macro server".to_owned()) @@ -83,9 +83,6 @@ pub fn load_workspace( }; let (crate_graph, proc_macros) = ws.to_crate_graph( - &mut |_, path: &AbsPath| { - load_proc_macro(proc_macro_client.as_ref().map_err(|e| &**e), path, &[]) - }, &mut |path: &AbsPath| { let contents = loader.load_sync(path); let path = vfs::VfsPath::from(path.to_path_buf()); @@ -94,6 +91,21 @@ pub fn load_workspace( }, extra_env, ); + let proc_macros = { + let proc_macro_server = match &proc_macro_server { + Ok(it) => Ok(it), + Err(e) => Err(e.as_str()), + }; + proc_macros + .into_iter() + .map(|(crate_id, path)| { + ( + crate_id, + path.and_then(|(_, path)| load_proc_macro(proc_macro_server, &path, &[])), + ) + }) + .collect() + }; let project_folders = ProjectFolders::new(&[ws], &[]); loader.set_config(vfs::loader::Config { @@ -114,7 +126,7 @@ pub fn load_workspace( if load_config.prefill_caches { host.analysis().parallel_prime_caches(1, |_| {})?; } - Ok((host, vfs, proc_macro_client.ok())) + Ok((host, vfs, proc_macro_server.ok())) } fn load_crate_graph( diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index aca6c9235707..d02714ad1ead 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -59,10 +59,11 @@ pub(crate) struct GlobalState { pub(crate) mem_docs: MemDocs, pub(crate) semantic_tokens_cache: Arc>>, pub(crate) shutdown_requested: bool, - pub(crate) proc_macro_changed: bool, pub(crate) last_reported_status: Option, pub(crate) source_root_config: SourceRootConfig, - pub(crate) proc_macro_clients: Vec>, + + pub(crate) proc_macro_changed: bool, + pub(crate) proc_macro_clients: Arc<[Result]>, pub(crate) flycheck: Arc<[FlycheckHandle]>, pub(crate) flycheck_sender: Sender, @@ -151,10 +152,11 @@ impl GlobalState { mem_docs: MemDocs::default(), semantic_tokens_cache: Arc::new(Default::default()), shutdown_requested: false, - proc_macro_changed: false, last_reported_status: None, source_root_config: SourceRootConfig::default(), - proc_macro_clients: vec![], + + proc_macro_changed: false, + proc_macro_clients: Arc::new([]), flycheck: Arc::new([]), flycheck_sender, diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index a56c245dca57..8866515bb94d 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -5,6 +5,7 @@ use std::{ io::Write as _, process::{self, Stdio}, + sync::Arc, }; use anyhow::Context; @@ -44,7 +45,7 @@ use crate::{ }; pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<()> { - state.proc_macro_clients.clear(); + state.proc_macro_clients = Arc::new([]); state.proc_macro_changed = false; state.fetch_workspaces_queue.request_op("reload workspace request".to_string()); @@ -53,7 +54,7 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result< } pub(crate) fn handle_proc_macros_reload(state: &mut GlobalState, _: ()) -> Result<()> { - state.proc_macro_clients.clear(); + state.proc_macro_clients = Arc::new([]); state.proc_macro_changed = false; state.fetch_build_data_queue.request_op("reload proc macros request".to_string()); diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index ae7457e3473e..8db526e0b76d 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -24,7 +24,7 @@ use crate::{ handlers, lsp_ext, lsp_utils::{apply_document_changes, notification_is, Progress}, mem_docs::DocumentData, - reload::{self, BuildDataProgress, ProjectWorkspaceProgress}, + reload::{self, BuildDataProgress, ProcMacroProgress, ProjectWorkspaceProgress}, Result, }; @@ -68,6 +68,7 @@ pub(crate) enum Task { PrimeCaches(PrimeCachesProgress), FetchWorkspace(ProjectWorkspaceProgress), FetchBuildData(BuildDataProgress), + LoadProcMacros(ProcMacroProgress), } #[derive(Debug)] @@ -487,6 +488,21 @@ impl GlobalState { } }; + if let Some(state) = state { + self.report_progress("Building", state, msg, None, None); + } + } + Task::LoadProcMacros(progress) => { + let (state, msg) = match progress { + ProcMacroProgress::Begin => (Some(Progress::Begin), None), + ProcMacroProgress::Report(msg) => (Some(Progress::Report), Some(msg)), + ProcMacroProgress::End(proc_macro_load_result) => { + self.set_proc_macros(proc_macro_load_result); + + (Some(Progress::End), None) + } + }; + if let Some(state) = state { self.report_progress("Loading", state, msg, None, None); } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 65758419deac..f8f2cb093220 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -12,7 +12,7 @@ //! correct. Instead, we try to provide a best-effort service. Even if the //! project is currently loading and we don't have a full project model, we //! still want to respond to various requests. -use std::{collections::hash_map::Entry, mem, sync::Arc}; +use std::{collections::hash_map::Entry, iter, mem, sync::Arc}; use flycheck::{FlycheckConfig, FlycheckHandle}; use hir::db::DefDatabase; @@ -20,7 +20,7 @@ use ide::Change; use ide_db::{ base_db::{ CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, - ProcMacroLoadResult, ProcMacros, SourceRoot, VfsPath, + ProcMacroLoadResult, ProcMacroPaths, ProcMacros, SourceRoot, VfsPath, }, FxHashMap, }; @@ -54,6 +54,13 @@ pub(crate) enum BuildDataProgress { End((Arc>, Vec>)), } +#[derive(Debug)] +pub(crate) enum ProcMacroProgress { + Begin, + Report(String), + End(ProcMacros), +} + impl GlobalState { pub(crate) fn is_quiescent(&self) -> bool { !(self.last_reported_status.is_none() @@ -216,6 +223,59 @@ impl GlobalState { }); } + pub(crate) fn load_proc_macros(&mut self, paths: Vec) { + tracing::info!("will load proc macros"); + let dummy_replacements = self.config.dummy_replacements().clone(); + let proc_macro_clients = self.proc_macro_clients.clone(); + + self.task_pool.handle.spawn_with_sender(move |sender| { + sender.send(Task::LoadProcMacros(ProcMacroProgress::Begin)).unwrap(); + + let dummy_replacements = &dummy_replacements; + let progress = { + let sender = sender.clone(); + &move |msg| { + sender.send(Task::LoadProcMacros(ProcMacroProgress::Report(msg))).unwrap() + } + }; + + let mut res = FxHashMap::default(); + for (client, paths) in proc_macro_clients + .iter() + .map(|res| res.as_ref().map_err(|e| &**e)) + .chain(iter::repeat_with(|| Err("Proc macros are disabled"))) + .zip(paths) + { + res.extend(paths.into_iter().map(move |(crate_id, res)| { + ( + crate_id, + res.and_then(|(crate_name, path)| { + progress(path.display().to_string()); + load_proc_macro( + client, + &path, + crate_name + .as_deref() + .and_then(|crate_name| { + dummy_replacements.get(crate_name).map(|v| &**v) + }) + .unwrap_or_default(), + ) + }), + ) + })); + } + + sender.send(Task::LoadProcMacros(ProcMacroProgress::End(res))).unwrap(); + }); + } + + pub(crate) fn set_proc_macros(&mut self, proc_macros: ProcMacros) { + let mut change = Change::new(); + change.set_proc_macros(proc_macros); + self.analysis_host.apply_change(change); + } + pub(crate) fn switch_workspaces(&mut self, cause: Cause) { let _p = profile::span("GlobalState::switch_workspaces"); tracing::info!(%cause, "will switch workspaces"); @@ -303,8 +363,6 @@ impl GlobalState { ); } - let mut change = Change::new(); - let files_config = self.config.files(); let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude); @@ -353,11 +411,10 @@ impl GlobalState { watch, version: self.vfs_config_version, }); + self.source_root_config = project_folders.source_root_config; // Create crate graph from all the workspaces - let (crate_graph, proc_macros) = { - let dummy_replacements = self.config.dummy_replacements(); - + let (crate_graph, proc_macro_paths) = { let vfs = &mut self.vfs.write().0; let loader = &mut self.loader; let mem_docs = &self.mem_docs; @@ -376,34 +433,22 @@ impl GlobalState { }; let mut crate_graph = CrateGraph::default(); - let mut proc_macros = ProcMacros::default(); - for (idx, ws) in self.workspaces.iter().enumerate() { - let proc_macro_client = match self.proc_macro_clients.get(idx) { - Some(res) => res.as_ref().map_err(|e| &**e), - None => Err("Proc macros are disabled"), - }; - let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| { - load_proc_macro( - proc_macro_client, - path, - dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(), - ) - }; - let (other, other_proc_macros) = ws.to_crate_graph( - &mut load_proc_macro, - &mut load, - &self.config.cargo().extra_env, - ); - crate_graph.extend(other, &mut proc_macros, other_proc_macros); + let mut proc_macros = Vec::default(); + for ws in &**self.workspaces { + let (other, mut crate_proc_macros) = + ws.to_crate_graph(&mut load, &self.config.cargo().extra_env); + crate_graph.extend(other, &mut crate_proc_macros); + proc_macros.push(crate_proc_macros); } (crate_graph, proc_macros) }; + let mut change = Change::new(); change.set_crate_graph(crate_graph); - change.set_proc_macros(proc_macros); - - self.source_root_config = project_folders.source_root_config; - self.analysis_host.apply_change(change); + + if same_workspaces { + self.load_proc_macros(proc_macro_paths); + } self.process_changes(); self.reload_flycheck(); tracing::info!("did switch workspaces"); diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index de1422032088..11eda94f5bb6 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ src/main.rs:6:11 - | -6 | foo::("".to_string()); - | ^^^ explicit generic argument not allowed - -``` - -However it would compile if `explicit_generic_args_with_impl_trait` is enabled. - -Note that the synthetic type parameters from `impl Trait` are still implicit and you -cannot explicitly specify these: - -```rust,compile_fail -#![feature(explicit_generic_args_with_impl_trait)] - -fn foo(_f: impl AsRef) {} -fn bar>(_f: F) {} - -fn main() { - bar::("".to_string()); // Okay - bar::("".to_string()); // Okay - - foo::("".to_string()); // Okay - foo::("".to_string()); // Error, you cannot specify `impl Trait` explicitly -} -``` +This feature adds the possibility of using `sysv64`, `win64` or `efiapi` calling +conventions on functions with varargs. "##, }, Lint { @@ -2243,7 +2338,7 @@ See Also: [`unboxed_closures`](../language-features/unboxed-closures.md) The `fn_traits` feature allows for implementation of the [`Fn*`] traits for creating custom closure-like types. -[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html +[`Fn*`]: ../../std/ops/trait.Fn.html ```rust #![feature(unboxed_closures)] @@ -2518,80 +2613,35 @@ does. "##, }, Lint { - label: "half_open_range_patterns", - description: r##"# `half_open_range_patterns` + label: "half_open_range_patterns_in_slices", + description: r##"# `half_open_range_patterns_in_slices` The tracking issue for this feature is: [#67264] -It is part of the `#![exclusive_range_pattern]` feature, +It is part of the `exclusive_range_pattern` feature, tracked at [#37854]. [#67264]: https://github.com/rust-lang/rust/issues/67264 [#37854]: https://github.com/rust-lang/rust/issues/37854 ----- -The `half_open_range_patterns` feature allows RangeTo patterns -(`..10`) to be used in appropriate pattern matching contexts. -This requires also enabling the `exclusive_range_pattern` feature. - -It also enabled RangeFrom patterns but that has since been -stabilized. +This feature allow using top-level half-open range patterns in slices. ```rust -#![feature(half_open_range_patterns)] +#![feature(half_open_range_patterns_in_slices)] #![feature(exclusive_range_pattern)] - let x = 5; - match x { - ..0 => println!("negative!"), // "RangeTo" pattern. Unstable. - 0 => println!("zero!"), - 1.. => println!("positive!"), // "RangeFrom" pattern. Stable. - } -``` -"##, - }, - Lint { - label: "infer_static_outlives_requirements", - description: r##"# `infer_static_outlives_requirements` -The tracking issue for this feature is: [#54185] - -[#54185]: https://github.com/rust-lang/rust/issues/54185 - ------------------------- -The `infer_static_outlives_requirements` feature indicates that certain -`'static` outlives requirements can be inferred by the compiler rather than -stating them explicitly. - -Note: It is an accompanying feature to `infer_outlives_requirements`, -which must be enabled to infer outlives requirements. - -For example, currently generic struct definitions that contain -references, require where-clauses of the form T: 'static. By using -this feature the outlives predicates will be inferred, although -they may still be written explicitly. - -```rust,ignore (pseudo-Rust) -struct Foo where U: 'static { // <-- currently required - bar: Bar -} -struct Bar { - x: T, +fn main() { + let xs = [13, 1, 5, 2, 3, 1, 21, 8]; + let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs else { return; }; } ``` +Note that this feature is not required if the patterns are wrapped between parenthesis. -## Examples: - -```rust,ignore (pseudo-Rust) -#![feature(infer_outlives_requirements)] -#![feature(infer_static_outlives_requirements)] - -#[rustc_outlives] -// Implicitly infer U: 'static -struct Foo { - bar: Bar -} -struct Bar { - x: T, +```rust +fn main() { + let xs = [13, 1]; + let [(a @ 3..), c] = xs else { return; }; } ``` "##, @@ -2658,15 +2708,6 @@ match some_int { ``` [#76001]: https://github.com/rust-lang/rust/issues/76001 -"##, - }, - Lint { - label: "int_error_internals", - description: r##"# `int_error_internals` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- "##, }, Lint { @@ -2718,12 +2759,13 @@ via a declaration like ```rust #![feature(intrinsics)] +#![allow(internal_features)] # fn main() {} extern "rust-intrinsic" { fn transmute(x: T) -> U; - fn offset(dst: *const T, offset: isize) -> *const T; + fn arith_offset(dst: *const T, offset: isize) -> *const T; } ``` @@ -2758,290 +2800,110 @@ functionality that isn't hard-coded into the language, but is implemented in libraries, with a special marker to tell the compiler it exists. The marker is the attribute `#[lang = "..."]` and there are various different values of `...`, i.e. various different 'lang -items'. +items'. Most of them can only be defined once. -For example, `Box` pointers require two lang items, one for allocation -and one for deallocation. A freestanding program that uses the `Box` -sugar for dynamic allocations via `malloc` and `free`: +Lang items are loaded lazily by the compiler; e.g. if one never uses `Box` +then there is no need to define a function for `exchange_malloc`. +`rustc` will emit an error when an item is needed but not found in the current +crate or any that it depends on. + +Some features provided by lang items: + +- overloadable operators via traits: the traits corresponding to the + `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all + marked with lang items; those specific four are `eq`, `partial_ord`, + `deref`/`deref_mut`, and `add` respectively. +- panicking: the `panic` and `panic_impl` lang items, among others. +- stack unwinding: the lang item `eh_personality` is a function used by the + failure mechanisms of the compiler. This is often mapped to GCC's personality + function (see the [`std` implementation][personality] for more information), + but programs which don't trigger a panic can be assured that this function is + never called. Additionally, a `eh_catch_typeinfo` static is needed for certain + targets which implement Rust panics on top of C++ exceptions. +- the traits in `core::marker` used to indicate types of + various kinds; e.g. lang items `sized`, `sync` and `copy`. +- memory allocation, see below. + +Most lang items are defined by `core`, but if you're trying to build +an executable without the `std` crate, you might run into the need +for lang item definitions. + +[personality]: https://github.com/rust-lang/rust/blob/master/library/std/src/sys/personality/gcc.rs + +## Example: Implementing a `Box` + +`Box` pointers require two lang items: one for the type itself and one for +allocation. A freestanding program that uses the `Box` sugar for dynamic +allocations via `malloc` and `free`: ```rust,ignore (libc-is-finicky) -#![feature(lang_items, box_syntax, start, libc, core_intrinsics, rustc_private)] +#![feature(lang_items, start, core_intrinsics, rustc_private, panic_unwind, rustc_attrs)] +#![allow(internal_features)] #![no_std] -use core::intrinsics; -use core::panic::PanicInfo; extern crate libc; +extern crate unwind; + +use core::ffi::c_void; +use core::intrinsics; +use core::panic::PanicInfo; +use core::ptr::NonNull; + +pub struct Global; // the global allocator +struct Unique(NonNull); #[lang = "owned_box"] -pub struct Box(*mut T); +pub struct Box(Unique, A); + +impl Box { + pub fn new(x: T) -> Self { + #[rustc_box] + Box::new(x) + } +} + +impl Drop for Box { + fn drop(&mut self) { + unsafe { + libc::free(self.0.0.as_ptr() as *mut c_void); + } + } +} #[lang = "exchange_malloc"] unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { - let p = libc::malloc(size as libc::size_t) as *mut u8; + let p = libc::malloc(size) as *mut u8; // Check if `malloc` failed: - if p as usize == 0 { + if p.is_null() { intrinsics::abort(); } p } -#[lang = "box_free"] -unsafe fn box_free(ptr: *mut T) { - libc::free(ptr as *mut libc::c_void) -} - #[start] fn main(_argc: isize, _argv: *const *const u8) -> isize { - let _x = box 1; + let _x = Box::new(1); 0 } -#[lang = "eh_personality"] extern fn rust_eh_personality() {} -#[lang = "panic_impl"] extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } } -#[no_mangle] pub extern fn rust_eh_register_frames () {} -#[no_mangle] pub extern fn rust_eh_unregister_frames () {} +#[lang = "eh_personality"] +fn rust_eh_personality() {} + +#[panic_handler] +fn panic_handler(_info: &PanicInfo) -> ! { intrinsics::abort() } ``` Note the use of `abort`: the `exchange_malloc` lang item is assumed to return a valid pointer, and so needs to do the check internally. -Other features provided by lang items include: - -- overloadable operators via traits: the traits corresponding to the - `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all - marked with lang items; those specific four are `eq`, `ord`, - `deref`, and `add` respectively. -- stack unwinding and general failure; the `eh_personality`, - `panic` and `panic_bounds_check` lang items. -- the traits in `std::marker` used to indicate types of - various kinds; lang items `send`, `sync` and `copy`. -- the marker types and variance indicators found in - `std::marker`; lang items `covariant_type`, - `contravariant_lifetime`, etc. - -Lang items are loaded lazily by the compiler; e.g. if one never uses -`Box` then there is no need to define functions for `exchange_malloc` -and `box_free`. `rustc` will emit an error when an item is needed -but not found in the current crate or any that it depends on. - -Most lang items are defined by `libcore`, but if you're trying to build -an executable without the standard library, you'll run into the need -for lang items. The rest of this page focuses on this use-case, even though -lang items are a bit broader than that. - -### Using libc - -In order to build a `#[no_std]` executable we will need libc as a dependency. -We can specify this using our `Cargo.toml` file: - -```toml -[dependencies] -libc = { version = "0.2.14", default-features = false } -``` - -Note that the default features have been disabled. This is a critical step - -**the default features of libc include the standard library and so must be -disabled.** - -### Writing an executable without stdlib - -Controlling the entry point is possible in two ways: the `#[start]` attribute, -or overriding the default shim for the C `main` function with your own. - -The function marked `#[start]` is passed the command line parameters -in the same format as C: - -```rust,ignore (libc-is-finicky) -#![feature(lang_items, core_intrinsics, rustc_private)] -#![feature(start)] -#![no_std] -use core::intrinsics; -use core::panic::PanicInfo; - -// Pull in the system libc library for what crt0.o likely requires. -extern crate libc; - -// Entry point for this program. -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { - 0 -} - -// These functions are used by the compiler, but not -// for a bare-bones hello world. These are normally -// provided by libstd. -#[lang = "eh_personality"] -#[no_mangle] -pub extern fn rust_eh_personality() { -} - -#[lang = "panic_impl"] -#[no_mangle] -pub extern fn rust_begin_panic(info: &PanicInfo) -> ! { - unsafe { intrinsics::abort() } -} -``` - -To override the compiler-inserted `main` shim, one has to disable it -with `#![no_main]` and then create the appropriate symbol with the -correct ABI and the correct name, which requires overriding the -compiler's name mangling too: - -```rust,ignore (libc-is-finicky) -#![feature(lang_items, core_intrinsics, rustc_private)] -#![feature(start)] -#![no_std] -#![no_main] -use core::intrinsics; -use core::panic::PanicInfo; - -// Pull in the system libc library for what crt0.o likely requires. -extern crate libc; - -// Entry point for this program. -#[no_mangle] // ensure that this symbol is called `main` in the output -pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 { - 0 -} - -// These functions are used by the compiler, but not -// for a bare-bones hello world. These are normally -// provided by libstd. -#[lang = "eh_personality"] -#[no_mangle] -pub extern fn rust_eh_personality() { -} - -#[lang = "panic_impl"] -#[no_mangle] -pub extern fn rust_begin_panic(info: &PanicInfo) -> ! { - unsafe { intrinsics::abort() } -} -``` - -In many cases, you may need to manually link to the `compiler_builtins` crate -when building a `no_std` binary. You may observe this via linker error messages -such as "```undefined reference to `__rust_probestack'```". - -## More about the language items - -The compiler currently makes a few assumptions about symbols which are -available in the executable to call. Normally these functions are provided by -the standard library, but without it you must define your own. These symbols -are called "language items", and they each have an internal name, and then a -signature that an implementation must conform to. - -The first of these functions, `rust_eh_personality`, is used by the failure -mechanisms of the compiler. This is often mapped to GCC's personality function -(see the [libstd implementation][unwind] for more information), but crates -which do not trigger a panic can be assured that this function is never -called. The language item's name is `eh_personality`. - -[unwind]: https://github.com/rust-lang/rust/blob/master/library/panic_unwind/src/gcc.rs - -The second function, `rust_begin_panic`, is also used by the failure mechanisms of the -compiler. When a panic happens, this controls the message that's displayed on -the screen. While the language item's name is `panic_impl`, the symbol name is -`rust_begin_panic`. - -Finally, a `eh_catch_typeinfo` static is needed for certain targets which -implement Rust panics on top of C++ exceptions. - ## List of all language items -This is a list of all language items in Rust along with where they are located in -the source code. +An up-to-date list of all language items can be found [here] in the compiler code. -- Primitives - - `i8`: `libcore/num/mod.rs` - - `i16`: `libcore/num/mod.rs` - - `i32`: `libcore/num/mod.rs` - - `i64`: `libcore/num/mod.rs` - - `i128`: `libcore/num/mod.rs` - - `isize`: `libcore/num/mod.rs` - - `u8`: `libcore/num/mod.rs` - - `u16`: `libcore/num/mod.rs` - - `u32`: `libcore/num/mod.rs` - - `u64`: `libcore/num/mod.rs` - - `u128`: `libcore/num/mod.rs` - - `usize`: `libcore/num/mod.rs` - - `f32`: `libstd/f32.rs` - - `f64`: `libstd/f64.rs` - - `char`: `libcore/char.rs` - - `slice`: `liballoc/slice.rs` - - `str`: `liballoc/str.rs` - - `const_ptr`: `libcore/ptr.rs` - - `mut_ptr`: `libcore/ptr.rs` - - `unsafe_cell`: `libcore/cell.rs` -- Runtime - - `start`: `libstd/rt.rs` - - `eh_personality`: `libpanic_unwind/emcc.rs` (EMCC) - - `eh_personality`: `libpanic_unwind/gcc.rs` (GNU) - - `eh_personality`: `libpanic_unwind/seh.rs` (SEH) - - `eh_catch_typeinfo`: `libpanic_unwind/emcc.rs` (EMCC) - - `panic`: `libcore/panicking.rs` - - `panic_bounds_check`: `libcore/panicking.rs` - - `panic_impl`: `libcore/panicking.rs` - - `panic_impl`: `libstd/panicking.rs` -- Allocations - - `owned_box`: `liballoc/boxed.rs` - - `exchange_malloc`: `liballoc/heap.rs` - - `box_free`: `liballoc/heap.rs` -- Operands - - `not`: `libcore/ops/bit.rs` - - `bitand`: `libcore/ops/bit.rs` - - `bitor`: `libcore/ops/bit.rs` - - `bitxor`: `libcore/ops/bit.rs` - - `shl`: `libcore/ops/bit.rs` - - `shr`: `libcore/ops/bit.rs` - - `bitand_assign`: `libcore/ops/bit.rs` - - `bitor_assign`: `libcore/ops/bit.rs` - - `bitxor_assign`: `libcore/ops/bit.rs` - - `shl_assign`: `libcore/ops/bit.rs` - - `shr_assign`: `libcore/ops/bit.rs` - - `deref`: `libcore/ops/deref.rs` - - `deref_mut`: `libcore/ops/deref.rs` - - `index`: `libcore/ops/index.rs` - - `index_mut`: `libcore/ops/index.rs` - - `add`: `libcore/ops/arith.rs` - - `sub`: `libcore/ops/arith.rs` - - `mul`: `libcore/ops/arith.rs` - - `div`: `libcore/ops/arith.rs` - - `rem`: `libcore/ops/arith.rs` - - `neg`: `libcore/ops/arith.rs` - - `add_assign`: `libcore/ops/arith.rs` - - `sub_assign`: `libcore/ops/arith.rs` - - `mul_assign`: `libcore/ops/arith.rs` - - `div_assign`: `libcore/ops/arith.rs` - - `rem_assign`: `libcore/ops/arith.rs` - - `eq`: `libcore/cmp.rs` - - `ord`: `libcore/cmp.rs` -- Functions - - `fn`: `libcore/ops/function.rs` - - `fn_mut`: `libcore/ops/function.rs` - - `fn_once`: `libcore/ops/function.rs` - - `generator_state`: `libcore/ops/generator.rs` - - `generator`: `libcore/ops/generator.rs` -- Other - - `coerce_unsized`: `libcore/ops/unsize.rs` - - `drop`: `libcore/ops/drop.rs` - - `drop_in_place`: `libcore/ptr.rs` - - `clone`: `libcore/clone.rs` - - `copy`: `libcore/marker.rs` - - `send`: `libcore/marker.rs` - - `sized`: `libcore/marker.rs` - - `unsize`: `libcore/marker.rs` - - `sync`: `libcore/marker.rs` - - `phantom_data`: `libcore/marker.rs` - - `discriminant_kind`: `libcore/marker.rs` - - `freeze`: `libcore/marker.rs` - - `debug_trait`: `libcore/fmt/mod.rs` - - `non_zero`: `libcore/nonzero.rs` - - `arc`: `liballoc/sync.rs` - - `rc`: `liballoc/rc.rs` +[here]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_hir/src/lang_items.rs "##, }, Lint { @@ -3050,15 +2912,6 @@ the source code. This feature is internal to the Rust compiler and is not intended for general use. ------------------------- -"##, - }, - Lint { - label: "libstd_thread_internals", - description: r##"# `libstd_thread_internals` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------ "##, }, @@ -3069,200 +2922,6 @@ This feature is internal to the Rust compiler and is not intended for general us This feature is internal to the Rust compiler and is not intended for general use. ------------------------ -"##, - }, - Lint { - label: "llvm_asm", - description: r##"# `llvm_asm` - -The tracking issue for this feature is: [#70173] - -[#70173]: https://github.com/rust-lang/rust/issues/70173 - ------------------------- - -For extremely low-level manipulations and performance reasons, one -might wish to control the CPU directly. Rust supports using inline -assembly to do this via the `llvm_asm!` macro. - -```rust,ignore (pseudo-code) -llvm_asm!(assembly template - : output operands - : input operands - : clobbers - : options - ); -``` - -Any use of `llvm_asm` is feature gated (requires `#![feature(llvm_asm)]` on the -crate to allow) and of course requires an `unsafe` block. - -> **Note**: the examples here are given in x86/x86-64 assembly, but -> all platforms are supported. - -## Assembly template - -The `assembly template` is the only required parameter and must be a -literal string (i.e. `""`) - -```rust -#![feature(llvm_asm)] - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn foo() { - unsafe { - llvm_asm!("NOP"); - } -} - -// Other platforms: -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -fn foo() { /* ... */ } - -fn main() { - // ... - foo(); - // ... -} -``` - -(The `feature(llvm_asm)` and `#[cfg]`s are omitted from now on.) - -Output operands, input operands, clobbers and options are all optional -but you must add the right number of `:` if you skip them: - -```rust -# #![feature(llvm_asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { unsafe { -llvm_asm!("xor %eax, %eax" - : - : - : "eax" - ); -# } } -# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -# fn main() {} -``` - -Whitespace also doesn't matter: - -```rust -# #![feature(llvm_asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { unsafe { -llvm_asm!("xor %eax, %eax" ::: "eax"); -# } } -# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -# fn main() {} -``` - -## Operands - -Input and output operands follow the same format: `: -"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand -expressions must be mutable place, or not yet assigned: - -```rust -# #![feature(llvm_asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn add(a: i32, b: i32) -> i32 { - let c: i32; - unsafe { - llvm_asm!("add $2, $0" - : "=r"(c) - : "0"(a), "r"(b) - ); - } - c -} -# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -# fn add(a: i32, b: i32) -> i32 { a + b } - -fn main() { - assert_eq!(add(3, 14159), 14162) -} -``` - -If you would like to use real operands in this position, however, -you are required to put curly braces `{}` around the register that -you want, and you are required to put the specific size of the -operand. This is useful for very low level programming, where -which register you use is important: - -```rust -# #![feature(llvm_asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# unsafe fn read_byte_in(port: u16) -> u8 { -let result: u8; -llvm_asm!("in %dx, %al" : "={al}"(result) : "{dx}"(port)); -result -# } -``` - -## Clobbers - -Some instructions modify registers which might otherwise have held -different values so we use the clobbers list to indicate to the -compiler not to assume any values loaded into those registers will -stay valid. - -```rust -# #![feature(llvm_asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { unsafe { -// Put the value 0x200 in eax: -llvm_asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax"); -# } } -# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -# fn main() {} -``` - -Input and output registers need not be listed since that information -is already communicated by the given constraints. Otherwise, any other -registers used either implicitly or explicitly should be listed. - -If the assembly changes the condition code register `cc` should be -specified as one of the clobbers. Similarly, if the assembly modifies -memory, `memory` should also be specified. - -## Options - -The last section, `options` is specific to Rust. The format is comma -separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to -specify some extra info about the inline assembly: - -Current valid options are: - -1. `volatile` - specifying this is analogous to - `__asm__ __volatile__ (...)` in gcc/clang. -2. `alignstack` - certain instructions expect the stack to be - aligned a certain way (i.e. SSE) and specifying this indicates to - the compiler to insert its usual stack alignment code -3. `intel` - use intel syntax instead of the default AT&T. - -```rust -# #![feature(llvm_asm)] -# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -# fn main() { -let result: i32; -unsafe { - llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel") -} -println!("eax is currently {}", result); -# } -# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -# fn main() {} -``` - -## More Information - -The current implementation of the `llvm_asm!` macro is a direct binding to [LLVM's -inline assembler expressions][llvm-docs], so be sure to check out [their -documentation as well][llvm-docs] for more information about clobbers, -constraints, etc. - -[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions "##, }, Lint { @@ -3335,21 +2994,6 @@ impl A for Foo { type Assoc = StructStruct; } ``` -"##, - }, - Lint { - label: "native_link_modifiers", - description: r##"# `native_link_modifiers` - -The tracking issue for this feature is: [#81490] - -[#81490]: https://github.com/rust-lang/rust/issues/81490 - ------------------------- - -The `native_link_modifiers` feature allows you to use the `modifiers` syntax with the `#[link(..)]` attribute. - -Modifiers are specified as a comma-delimited string with each modifier prefixed with either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively. The last boolean value specified for a given modifier wins. "##, }, Lint { @@ -3372,75 +3016,6 @@ This modifier translates to `--as-needed` for ld-like linkers, and to `-dead_str The modifier does nothing for linkers that don't support it (e.g. `link.exe`). The default for this modifier is unclear, some targets currently specify it as `+as-needed`, some do not. We may want to try making `+as-needed` a default for all targets. -"##, - }, - Lint { - label: "native_link_modifiers_bundle", - description: r##"# `native_link_modifiers_bundle` - -The tracking issue for this feature is: [#81490] - -[#81490]: https://github.com/rust-lang/rust/issues/81490 - ------------------------- - -The `native_link_modifiers_bundle` feature allows you to use the `bundle` modifier. - -Only compatible with the `static` linking kind. Using any other kind will result in a compiler error. - -`+bundle` means objects from the static library are bundled into the produced crate (a rlib, for example) and are used from this crate later during linking of the final binary. - -`-bundle` means the static library is included into the produced rlib "by name" and object files from it are included only during linking of the final binary, the file search by that name is also performed during final linking. - -This modifier is supposed to supersede the `static-nobundle` linking kind defined by [RFC 1717](https://github.com/rust-lang/rfcs/pull/1717). - -The default for this modifier is currently `+bundle`, but it could be changed later on some future edition boundary. -"##, - }, - Lint { - label: "native_link_modifiers_verbatim", - description: r##"# `native_link_modifiers_verbatim` - -The tracking issue for this feature is: [#81490] - -[#81490]: https://github.com/rust-lang/rust/issues/81490 - ------------------------- - -The `native_link_modifiers_verbatim` feature allows you to use the `verbatim` modifier. - -`+verbatim` means that rustc itself won't add any target-specified library prefixes or suffixes (like `lib` or `.a`) to the library name, and will try its best to ask for the same thing from the linker. - -For `ld`-like linkers rustc will use the `-l:filename` syntax (note the colon) when passing the library, so the linker won't add any prefixes or suffixes as well. -See [`-l namespec`](https://sourceware.org/binutils/docs/ld/Options.html) in ld documentation for more details. -For linkers not supporting any verbatim modifiers (e.g. `link.exe` or `ld64`) the library name will be passed as is. - -The default for this modifier is `-verbatim`. - -This RFC changes the behavior of `raw-dylib` linking kind specified by [RFC 2627](https://github.com/rust-lang/rfcs/pull/2627). The `.dll` suffix (or other target-specified suffixes for other targets) is now added automatically. -If your DLL doesn't have the `.dll` suffix, it can be specified with `+verbatim`. -"##, - }, - Lint { - label: "native_link_modifiers_whole_archive", - description: r##"# `native_link_modifiers_whole_archive` - -The tracking issue for this feature is: [#81490] - -[#81490]: https://github.com/rust-lang/rust/issues/81490 - ------------------------- - -The `native_link_modifiers_whole_archive` feature allows you to use the `whole-archive` modifier. - -Only compatible with the `static` linking kind. Using any other kind will result in a compiler error. - -`+whole-archive` means that the static library is linked as a whole archive without throwing any object files away. - -This modifier translates to `--whole-archive` for `ld`-like linkers, to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`. -The modifier does nothing for linkers that don't support it. - -The default for this modifier is `-whole-archive`. "##, }, Lint { @@ -3502,40 +3077,6 @@ This serves two purposes: * For proving the correctness of unsafe code, we can use that impl as evidence that no `DerefMut` or `Clone` impl exists. * It prevents downstream crates from creating such impls. -"##, - }, - Lint { - label: "coverage", - description: r##"# `coverage` - -The tracking issue for this feature is: [#84605] - -[#84605]: https://github.com/rust-lang/rust/issues/84605 - ---- - -The `coverage` attribute can be used to selectively disable coverage -instrumentation in an annotated function. This might be useful to: - -- Avoid instrumentation overhead in a performance critical function -- Avoid generating coverage for a function that is not meant to be executed, - but still target 100% coverage for the rest of the program. - -## Example - -```rust -#![feature(coverage)] - -// `foo()` will get coverage instrumentation (by default) -fn foo() { - // ... -} - -#[coverage(off)] -fn bar() { - // ... -} -``` "##, }, Lint { @@ -3612,7 +3153,7 @@ additional checks for code style, safety, etc. Now let's write a plugin that warns about any item named `lintme`. ```rust,ignore (requires-stage-2) -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] extern crate rustc_ast; @@ -3643,7 +3184,7 @@ impl EarlyLintPass for Pass { #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&TEST_LINT]); - reg.lint_store.register_early_pass(|| box Pass); + reg.lint_store.register_early_pass(|| Box::new(Pass)); } ``` @@ -3677,7 +3218,7 @@ The components of a lint plugin are: Lint passes are syntax traversals, but they run at a late stage of compilation where type information is available. `rustc`'s [built-in -lints](https://github.com/rust-lang/rust/blob/master/src/librustc_session/lint/builtin.rs) +lints](https://github.com/rust-lang/rust/blob/master/compiler/rustc_lint_defs/src/builtin.rs) mostly use the same infrastructure as lint plugins, and provide examples of how to access type information. @@ -3716,44 +3257,6 @@ The tracking issue for this feature is: [#42524](https://github.com/rust-lang/ru This feature is internal to the Rust compiler and is not intended for general use. ------------------------ -"##, - }, - Lint { - label: "raw_dylib", - description: r##"# `raw_dylib` - -The tracking issue for this feature is: [#58713] - -[#58713]: https://github.com/rust-lang/rust/issues/58713 - ------------------------- - -The `raw_dylib` feature allows you to link against the implementations of functions in an `extern` -block without, on Windows, linking against an import library. - -```rust,ignore (partial-example) -#![feature(raw_dylib)] - -#[link(name="library", kind="raw-dylib")] -extern { - fn extern_function(x: i32); -} - -fn main() { - unsafe { - extern_function(14); - } -} -``` - -## Limitations - -Currently, this feature is only supported on `-windows-msvc` targets. Non-Windows platforms don't have import -libraries, and an incompatibility between LLVM and the BFD linker means that it is not currently supported on -`-windows-gnu` targets. - -On the `i686-pc-windows-msvc` target, this feature supports only the `cdecl`, `stdcall`, `system`, and `fastcall` -calling conventions. "##, }, Lint { @@ -3851,6 +3354,69 @@ error: aborting due to 2 previous errors This feature is internal to the Rust compiler and is not intended for general use. ------------------------ +"##, + }, + Lint { + label: "start", + description: r##"# `start` + +The tracking issue for this feature is: [#29633] + +[#29633]: https://github.com/rust-lang/rust/issues/29633 + +------------------------ + +Allows you to mark a function as the entry point of the executable, which is +necessary in `#![no_std]` environments. + +The function marked `#[start]` is passed the command line parameters in the same +format as the C main function (aside from the integer types being used). +It has to be non-generic and have the following signature: + +```rust,ignore (only-for-syntax-highlight) +# let _: +fn(isize, *const *const u8) -> isize +# ; +``` + +This feature should not be confused with the `start` *lang item* which is +defined by the `std` crate and is written `#[lang = "start"]`. + +## Usage together with the `std` crate + +`#[start]` can be used in combination with the `std` crate, in which case the +normal `main` function (which would get called from the `std` crate) won't be +used as an entry point. +The initialization code in `std` will be skipped this way. + +Example: + +```rust +#![feature(start)] + +#[start] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} +``` + +Unwinding the stack past the `#[start]` function is currently considered +Undefined Behavior (for any unwinding implementation): + +```rust,ignore (UB) +#![feature(start)] + +#[start] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + std::panic::catch_unwind(|| { + panic!(); // panic safely gets caught or safely aborts execution + }); + + panic!(); // UB! + + 0 +} +``` "##, }, Lint { @@ -3860,6 +3426,32 @@ This feature is internal to the Rust compiler and is not intended for general us This feature is internal to the Rust compiler and is not intended for general use. ------------------------ +"##, + }, + Lint { + label: "strict_provenance", + description: r##"# `strict_provenance` + +The tracking issue for this feature is: [#95228] + +[#95228]: https://github.com/rust-lang/rust/issues/95228 +----- + +The `strict_provenance` feature allows to enable the `fuzzy_provenance_casts` and `lossy_provenance_casts` lints. +These lint on casts between integers and pointers, that are recommended against or invalid in the strict provenance model. +The same feature gate is also used for the experimental strict provenance API in `std` (actually `core`). + +## Example + +```rust +#![feature(strict_provenance)] +#![warn(fuzzy_provenance_casts)] + +fn main() { + let _dangling = 16_usize as *const u8; + //~^ WARNING: strict provenance disallows casting integer `usize` to pointer `*const u8` +} +``` "##, }, Lint { @@ -4319,7 +3911,7 @@ The `unboxed_closures` feature allows you to write functions using the `"rust-ca required for implementing the [`Fn*`] family of traits. `"rust-call"` functions must have exactly one (non self) argument, a tuple representing the argument list. -[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html +[`Fn*`]: ../../std/ops/trait.Fn.html ```rust #![feature(unboxed_closures)] @@ -4330,6 +3922,72 @@ extern "rust-call" fn add_args(args: (u32, u32)) -> u32 { fn main() {} ``` +"##, + }, + Lint { + label: "unix_sigpipe", + description: r##"# `unix_sigpipe` + +The tracking issue for this feature is: [#97889] + +[#97889]: https://github.com/rust-lang/rust/issues/97889 + +--- + +The `#[unix_sigpipe = "..."]` attribute on `fn main()` can be used to specify how libstd shall setup `SIGPIPE` on Unix platforms before invoking `fn main()`. This attribute is ignored on non-Unix targets. There are three variants: +* `#[unix_sigpipe = "inherit"]` +* `#[unix_sigpipe = "sig_dfl"]` +* `#[unix_sigpipe = "sig_ign"]` + +## `#[unix_sigpipe = "inherit"]` + +Leave `SIGPIPE` untouched before entering `fn main()`. Unless the parent process has changed the default `SIGPIPE` handler from `SIG_DFL` to something else, this will behave the same as `#[unix_sigpipe = "sig_dfl"]`. + +## `#[unix_sigpipe = "sig_dfl"]` + +Set the `SIGPIPE` handler to `SIG_DFL`. This will result in your program getting killed if it tries to write to a closed pipe. This is normally what you want if your program produces textual output. + +### Example + +```rust,no_run +#![feature(unix_sigpipe)] +#[unix_sigpipe = "sig_dfl"] +fn main() { loop { println!("hello world"); } } +``` + +```bash +% ./main | head -n 1 +hello world +``` + +## `#[unix_sigpipe = "sig_ign"]` + +Set the `SIGPIPE` handler to `SIG_IGN` before invoking `fn main()`. This will result in `ErrorKind::BrokenPipe` errors if you program tries to write to a closed pipe. This is normally what you want if you for example write socket servers, socket clients, or pipe peers. + +This is what libstd has done by default since 2014. (However, see the note on child processes below.) + +### Example + +```rust,no_run +#![feature(unix_sigpipe)] +#[unix_sigpipe = "sig_ign"] +fn main() { loop { println!("hello world"); } } +``` + +```bash +% ./main | head -n 1 +hello world +thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)', library/std/src/io/stdio.rs:1016:9 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +``` + +### Note on child processes + +When spawning child processes, the legacy Rust behavior if `#[unix_sigpipe]` is not specified is to +reset `SIGPIPE` to `SIG_DFL`. + +If `#[unix_sigpipe = "..."]` is specified, no matter what its value is, the signal disposition of +`SIGPIPE` is no longer reset. This means that the child inherits the parent's `SIGPIPE` behavior. "##, }, Lint { @@ -4585,17 +4243,78 @@ This feature is internal to the Rust compiler and is not intended for general us This feature is internal to the Rust compiler and is not intended for general use. ------------------------ +"##, + }, + Lint { + label: "yeet_expr", + description: r##"# `yeet_expr` + +The tracking issue for this feature is: [#96373] + +[#96373]: https://github.com/rust-lang/rust/issues/96373 + +------------------------ + +The `yeet_expr` feature adds support for `do yeet` expressions, +which can be used to early-exit from a function or `try` block. + +These are highly experimental, thus the placeholder syntax. + +```rust,edition2021 +#![feature(yeet_expr)] + +fn foo() -> Result { + do yeet 4; +} +assert_eq!(foo(), Err(4)); + +fn bar() -> Option { + do yeet; +} +assert_eq!(bar(), None); +``` "##, }, ]; pub const CLIPPY_LINTS: &[Lint] = &[ + Lint { + label: "clippy::absolute_paths", + description: r##"Checks for usage of items through absolute paths, like `std::env::current_dir`."##, + }, Lint { label: "clippy::absurd_extreme_comparisons", description: r##"Checks for comparisons where one side of the relation is either the minimum or maximum value for its type and warns if it involves a case that is always true or always false. Only integer and boolean types are checked."##, + }, + Lint { + label: "clippy::alloc_instead_of_core", + description: r##"Finds items imported through `alloc` when available through `core`."##, + }, + Lint { + label: "clippy::allow_attributes", + description: r##"Checks for usage of the `#[allow]` attribute and suggests replacing it with +the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) + +The expect attribute is still unstable and requires the `lint_reasons` +on nightly. It can be enabled by adding `#![feature(lint_reasons)]` to +the crate root. + +This lint only warns outer attributes (`#[allow]`), as inner attributes +(`#![allow]`) are usually used to enable or disable lints on a global scale."##, + }, + Lint { + label: "clippy::allow_attributes_without_reason", + description: r##"Checks for attributes that allow lints without a reason. + +(This requires the `lint_reasons` feature)"##, + }, + Lint { + label: "clippy::almost_complete_range", + description: r##"Checks for ranges which almost include the entire range of letters from 'a' to 'z' +or digits from '0' to '9', but don't because they're a half open range."##, }, Lint { label: "clippy::almost_swapped", @@ -4609,6 +4328,22 @@ constants which are defined in or [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), respectively, suggesting to use the predefined constant."##, + }, + Lint { + label: "clippy::arc_with_non_send_sync", + description: r##". +This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`."##, + }, + Lint { + label: "clippy::arithmetic_side_effects", + description: r##"Checks any kind of arithmetic operation of any type. + +Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust +Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), +or can panic (`/`, `%`). + +Known safe built-in types like `Wrapping` or `Saturating`, floats, operations in constant +environments, allowed types and non-constant operations that won't overflow are ignored."##, }, Lint { label: "clippy::as_conversions", @@ -4617,15 +4352,27 @@ respectively, suggesting to use the predefined constant."##, Note that this lint is specialized in linting *every single* use of `as` regardless of whether good alternatives exist or not. If you want more precise lints for `as`, please consider using these separate lints: -`unnecessary_cast`, `cast_lossless/possible_truncation/possible_wrap/precision_loss/sign_loss`, +`unnecessary_cast`, `cast_lossless/cast_possible_truncation/cast_possible_wrap/cast_precision_loss/cast_sign_loss`, `fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`. There is a good explanation the reason why this lint should work in this way and how it is useful [in this issue](https://github.com/rust-lang/rust-clippy/issues/5122)."##, }, + Lint { + label: "clippy::as_ptr_cast_mut", + description: r##"Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer"##, + }, + Lint { + label: "clippy::as_underscore", + description: r##"Checks for the usage of `as _` conversion using inferred type."##, + }, Lint { label: "clippy::assertions_on_constants", description: r##"Checks for `assert!(true)` and `assert!(false)` calls."##, }, + Lint { + label: "clippy::assertions_on_result_states", + description: r##"Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls."##, + }, Lint { label: "clippy::assign_op_pattern", description: r##"Checks for `a = a op b` or `a = b commutative_op a` @@ -4639,16 +4386,19 @@ patterns."##, label: "clippy::async_yields_async", description: r##"Checks for async blocks that yield values of types that can themselves be awaited."##, + }, + Lint { + label: "clippy::await_holding_invalid_type", + description: r##"Allows users to configure types which should not be held across `await` +suspension points."##, }, Lint { label: "clippy::await_holding_lock", - description: r##"Checks for calls to await while holding a -non-async-aware MutexGuard."##, + description: r##"Checks for calls to await while holding a non-async-aware MutexGuard."##, }, Lint { label: "clippy::await_holding_refcell_ref", - description: r##"Checks for calls to await while holding a -`RefCell` `Ref` or `RefMut`."##, + description: r##"Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`."##, }, Lint { label: "clippy::bad_bit_mask", @@ -4659,24 +4409,23 @@ The formula for detecting if an expression of the type `_ m {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following table: -|Comparison |Bit Op|Example |is always|Formula | -|------------|------|------------|---------|----------------------| -|`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | -|`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | -|`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | -|`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | -|`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | -|`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` |"##, +|Comparison |Bit Op|Example |is always|Formula | +|------------|------|-------------|---------|----------------------| +|`==` or `!=`| `&` |`x & 2 == 3` |`false` |`c & m != c` | +|`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | +|`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | +|`==` or `!=`| `\\|` |`x \\| 1 == 0`|`false` |`c \\| m != c` | +|`<` or `>=`| `\\|` |`x \\| 1 < 1` |`false` |`m >= c` | +|`<=` or `>` | `\\|` |`x \\| 1 > 0` |`true` |`m > c` |"##, + }, + Lint { + label: "clippy::big_endian_bytes", + description: r##"Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`."##, }, Lint { label: "clippy::bind_instead_of_map", description: r##"Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or `_.or_else(|x| Err(y))`."##, - }, - Lint { - label: "clippy::blacklisted_name", - description: r##"Checks for usage of blacklisted names for variables, such -as `foo`."##, }, Lint { label: "clippy::blanket_clippy_restriction_lints", @@ -4697,6 +4446,18 @@ expression, statements or conditions that use closures with blocks."##, `x != true` and order comparisons such as `x < true` (or vice versa) and suggest using the variable directly."##, }, + Lint { + label: "clippy::bool_to_int_with_if", + description: r##"Instead of using an if statement to convert a bool to an int, +this lint suggests using a `from()` function or an `as` coercion."##, + }, + Lint { + label: "clippy::borrow_as_ptr", + description: r##"Checks for the usage of `&expr as *const T` or +`&mut expr as *mut T`, and suggest using `ptr::addr_of` or +`ptr::addr_of_mut` instead."##, + }, + Lint { label: "clippy::borrow_deref_ref", description: r##"Checks for `&*(&T)`."## }, Lint { label: "clippy::borrow_interior_mutable_const", description: r##"Checks if `const` items which is interior mutable (e.g., @@ -4704,13 +4465,18 @@ contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly."##, }, Lint { label: "clippy::borrowed_box", - description: r##"Checks for use of `&Box` anywhere in the code. + description: r##"Checks for usage of `&Box` anywhere in the code. Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information."##, }, Lint { label: "clippy::box_collection", - description: r##"Checks for use of `Box` where T is a collection such as Vec anywhere in the code. + description: r##"Checks for usage of `Box` where T is a collection such as Vec anywhere in the code. Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information."##, + }, + Lint { + label: "clippy::box_default", + description: r##"checks for `Box::new(T::default())`, which is better written as +`Box::::default()`."##, }, Lint { label: "clippy::boxed_local", @@ -4726,6 +4492,11 @@ moved out of the blocks."##, label: "clippy::builtin_type_shadow", description: r##"Warns if a generic shadows a built-in type."##, }, + Lint { + label: "clippy::bytes_count_to_len", + description: r##"It checks for `str::bytes().count()` and suggests replacing it with +`str::len()`."##, + }, Lint { label: "clippy::bytes_nth", description: r##"Checks for the use of `.bytes().nth()`."##, @@ -4739,24 +4510,43 @@ moved out of the blocks."##, label: "clippy::case_sensitive_file_extension_comparisons", description: r##"Checks for calls to `ends_with` with possible file extensions and suggests to use a case-insensitive approach instead."##, + }, + Lint { + label: "clippy::cast_abs_to_unsigned", + description: r##"Checks for usage of the `abs()` method that cast the result to unsigned."##, + }, + Lint { + label: "clippy::cast_enum_constructor", + description: r##"Checks for casts from an enum tuple constructor to an integer."##, + }, + Lint { + label: "clippy::cast_enum_truncation", + description: r##"Checks for casts from an enum type to an integral type which will definitely truncate the +value."##, }, Lint { label: "clippy::cast_lossless", description: r##"Checks for casts between numerical types that may be replaced by safe conversion functions."##, }, + Lint { + label: "clippy::cast_nan_to_int", + description: r##"Checks for a known NaN float being cast to an integer"##, + }, Lint { label: "clippy::cast_possible_truncation", description: r##"Checks for casts between numerical types that may truncate large values. This is expected behavior, so the cast is `Allow` by -default."##, +default. It suggests user either explicitly ignore the lint, +or use `try_from()` and handle the truncation, default, or panic explicitly."##, }, Lint { label: "clippy::cast_possible_wrap", description: r##"Checks for casts from an unsigned type to a signed type of -the same size. Performing such a cast is a 'no-op' for the compiler, -i.e., nothing is changed at the bit level, and the binary representation of -the value is reinterpreted. This can cause wrapping if the value is too big +the same size, or possibly smaller due to target dependent integers. +Performing such a cast is a 'no-op' for the compiler, i.e., nothing is +changed at the bit level, and the binary representation of the value is +reinterpreted. This can cause wrapping if the value is too big for the target signed type. However, the cast works as defined, so this lint is `Allow` by default."##, }, @@ -4775,10 +4565,6 @@ or any 64-bit integer to `f64`."##, description: r##"Checks for casts, using `as` or `pointer::cast`, from a less-strictly-aligned pointer to a more-strictly-aligned pointer"##, }, - Lint { - label: "clippy::cast_ref_to_mut", - description: r##"Checks for casts of `&T` to `&mut T` anywhere in the code."##, - }, Lint { label: "clippy::cast_sign_loss", description: r##"Checks for casts from a signed to an unsigned numerical @@ -4786,6 +4572,14 @@ type. In this case, negative values wrap around to large positive values, which can be quite surprising in practice. However, as the cast works as defined, this lint is `Allow` by default."##, }, + Lint { + label: "clippy::cast_slice_different_sizes", + description: r##"Checks for `as` casts between raw pointers to slices with differently sized elements."##, + }, + Lint { + label: "clippy::cast_slice_from_raw_parts", + description: r##"Checks for a raw slice being cast to a slice pointer"##, + }, Lint { label: "clippy::char_lit_as_u8", description: r##"Checks for expressions where a character literal is cast @@ -4806,8 +4600,8 @@ if it starts with a given char."##, description: r##"Checks for explicit bounds checking when casting."##, }, Lint { - label: "clippy::clone_double_ref", - description: r##"Checks for usage of `.clone()` on an `&&T`."##, + label: "clippy::clear_with_drain", + description: r##"Checks for usage of `.drain(..)` for the sole purpose of clearing a container."##, }, Lint { label: "clippy::clone_on_copy", @@ -4821,10 +4615,9 @@ function syntax instead (e.g., `Rc::clone(foo)`)."##, }, Lint { label: "clippy::cloned_instead_of_copied", - description: r##"Checks for usages of `cloned()` on an `Iterator` or `Option` where + description: r##"Checks for usage of `cloned()` on an `Iterator` or `Option` where `copied()` could be used instead."##, }, - Lint { label: "clippy::cmp_nan", description: r##"Checks for comparisons to NaN."## }, Lint { label: "clippy::cmp_null", description: r##"This lint checks for equality comparisons with `ptr::null`"##, @@ -4856,6 +4649,15 @@ without adding any branches. Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only cases where merging would most likely make the code more readable."##, }, + Lint { + label: "clippy::collapsible_str_replace", + description: r##"Checks for consecutive calls to `str::replace` (2 or more) +that can be collapsed into a single call."##, + }, + Lint { + label: "clippy::collection_is_never_read", + description: r##"Checks for collections that are never queried."##, + }, Lint { label: "clippy::comparison_chain", description: r##"Checks comparison chains written with `if` that can be @@ -4871,6 +4673,10 @@ and suggests using `.is_empty()` where applicable."##, description: r##"Checks for types that implement `Copy` as well as `Iterator`."##, }, + Lint { + label: "clippy::crate_in_macro_def", + description: r##"Checks for usage of `crate` as opposed to `$crate` in a macro definition."##, + }, Lint { label: "clippy::create_dir", description: r##"Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead."##, @@ -4879,7 +4685,10 @@ and suggests using `.is_empty()` where applicable."##, label: "clippy::crosspointer_transmute", description: r##"Checks for transmutes between a type `T` and `*T`."##, }, - Lint { label: "clippy::dbg_macro", description: r##"Checks for usage of dbg!() macro."## }, + Lint { + label: "clippy::dbg_macro", + description: r##"Checks for usage of the [`dbg!`](https://doc.rust-lang.org/std/macro.dbg.html) macro."##, + }, Lint { label: "clippy::debug_assert_with_mut_call", description: r##"Checks for function/method calls with a mutable @@ -4893,6 +4702,15 @@ parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros." label: "clippy::declare_interior_mutable_const", description: r##"Checks for declaration of `const` items which is interior mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.)."##, + }, + Lint { + label: "clippy::default_constructed_unit_structs", + description: r##"Checks for construction on unit struct using `default`."##, + }, + Lint { + label: "clippy::default_instead_of_iter_empty", + description: r##"It checks for `std::iter::Empty::default()` and suggests replacing it with +`std::iter::empty()`."##, }, Lint { label: "clippy::default_numeric_fallback", @@ -4909,6 +4727,10 @@ See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-in label: "clippy::default_trait_access", description: r##"Checks for literal calls to `Default::default()`."##, }, + Lint { + label: "clippy::default_union_representation", + description: r##"Displays a warning when a union is declared with the default representation (without a `#[repr(C)]` attribute)."##, + }, Lint { label: "clippy::deprecated_cfg_attr", description: r##"Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it @@ -4923,23 +4745,47 @@ field that is not a valid semantic version."##, label: "clippy::deref_addrof", description: r##"Checks for usage of `*&` and `*&mut` in expressions."##, }, + Lint { + label: "clippy::deref_by_slicing", + description: r##"Checks for slicing expressions which are equivalent to dereferencing the +value."##, + }, Lint { label: "clippy::derivable_impls", description: r##"Detects manual `std::default::Default` implementations that are identical to a derived implementation."##, }, Lint { - label: "clippy::derive_hash_xor_eq", - description: r##"Checks for deriving `Hash` but implementing `PartialEq` -explicitly or vice versa."##, + label: "clippy::derive_ord_xor_partial_ord", + description: r##"Lints against manual `PartialOrd` and `Ord` implementations for types with a derived `Ord` +or `PartialOrd` implementation."##, }, Lint { - label: "clippy::derive_ord_xor_partial_ord", - description: r##"Checks for deriving `Ord` but implementing `PartialOrd` -explicitly or vice versa."##, + label: "clippy::derive_partial_eq_without_eq", + description: r##"Checks for types that derive `PartialEq` and could implement `Eq`."##, + }, + Lint { + label: "clippy::derived_hash_with_manual_eq", + description: r##"Lints against manual `PartialEq` implementations for types with a derived `Hash` +implementation."##, + }, + Lint { + label: "clippy::disallowed_macros", + description: r##"Denies the configured macros in clippy.toml + +Note: Even though this lint is warn-by-default, it will only trigger if +macros are defined in the clippy.toml file."##, }, Lint { label: "clippy::disallowed_methods", - description: r##"Denies the configured methods and functions in clippy.toml"##, + description: r##"Denies the configured methods and functions in clippy.toml + +Note: Even though this lint is warn-by-default, it will only trigger if +methods are defined in the clippy.toml file."##, + }, + Lint { + label: "clippy::disallowed_names", + description: r##"Checks for usage of disallowed names for variables, such +as `foo`."##, }, Lint { label: "clippy::disallowed_script_idents", @@ -4958,12 +4804,20 @@ See also: [`non_ascii_idents`]. }, Lint { label: "clippy::disallowed_types", - description: r##"Denies the configured types in clippy.toml."##, + description: r##"Denies the configured types in clippy.toml. + +Note: Even though this lint is warn-by-default, it will only trigger if +types are defined in the clippy.toml file."##, }, Lint { label: "clippy::diverging_sub_expression", description: r##"Checks for diverging calls that are not match arms or statements."##, + }, + Lint { + label: "clippy::doc_link_with_quotes", + description: r##"Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks) +outside of code blocks"##, }, Lint { label: "clippy::doc_markdown", @@ -4989,14 +4843,19 @@ marked as `#[must_use]`."##, description: r##"Checks for unnecessary double parentheses."##, }, Lint { - label: "clippy::drop_copy", - description: r##"Checks for calls to `std::mem::drop` with a value -that derives the Copy trait"##, + label: "clippy::drain_collect", + description: r##"Checks for calls to `.drain()` that clear the collection, immediately followed by a call to `.collect()`. + +> Collection in this context refers to any type with a `drain` method: +> `Vec`, `VecDeque`, `BinaryHeap`, `HashSet`,`HashMap`, `String`"##, }, Lint { - label: "clippy::drop_ref", - description: r##"Checks for calls to `std::mem::drop` with a reference -instead of an owned value."##, + label: "clippy::drop_non_drop", + description: r##"Checks for calls to `std::mem::drop` with a value that does not implement `Drop`."##, + }, + Lint { + label: "clippy::duplicate_mod", + description: r##"Checks for files that are included as modules multiple times."##, }, Lint { label: "clippy::duplicate_underscore_argument", @@ -5013,6 +4872,10 @@ from other `Duration` methods."##, description: r##"Checks for usage of if expressions with an `else if` branch, but without a final `else` branch."##, }, + Lint { + label: "clippy::empty_drop", + description: r##"Checks for empty `Drop` implementations."##, + }, Lint { label: "clippy::empty_enum", description: r##"Checks for `enum`s with no variants. @@ -5021,11 +4884,19 @@ As of this writing, the `never_type` is still a nightly-only experimental API. Therefore, this lint is only triggered if the `never_type` is enabled."##, }, + Lint { + label: "clippy::empty_line_after_doc_comments", + description: r##"Checks for empty lines after documenation comments."##, + }, Lint { label: "clippy::empty_line_after_outer_attr", description: r##"Checks for empty lines after outer attributes"##, }, Lint { label: "clippy::empty_loop", description: r##"Checks for empty `loop` expressions."## }, + Lint { + label: "clippy::empty_structs_with_brackets", + description: r##"Finds structs without fields (a so-called empty struct) that are declared with brackets."##, + }, Lint { label: "clippy::enum_clike_unportable_variant", description: r##"Checks for C-like enumerations that are @@ -5052,10 +4923,18 @@ bitwise, difference and division binary operators (`==`, `>`, etc., `&&`, description: r##"Checks for erasing operations, e.g., `x * 0`."##, }, Lint { - label: "clippy::eval_order_dependence", - description: r##"Checks for a read and a write to the same variable where -whether the read occurs before or after the write depends on the evaluation -order of sub-expressions."##, + label: "clippy::err_expect", + description: r##"Checks for `.err().expect()` calls on the `Result` type."##, + }, + Lint { + label: "clippy::error_impl_error", + description: r##"Checks for types named `Error` that implement `Error`."##, + }, + Lint { + label: "clippy::excessive_nesting", + description: r##"Checks for blocks which are nested beyond a certain threshold. + +Note: Even though this lint is warn-by-default, it will only trigger if a maximum nesting level is defined in the clippy.toml file."##, }, Lint { label: "clippy::excessive_precision", @@ -5072,8 +4951,7 @@ than that supported by the underlying type."##, }, Lint { label: "clippy::exit", - description: r##"`exit()` terminates the program and doesn't provide a -stack trace."##, + description: r##"Detects calls to the `exit()` function which terminates the program."##, }, Lint { label: "clippy::expect_fun_call", @@ -5082,13 +4960,17 @@ etc., and suggests to use `unwrap_or_else` instead"##, }, Lint { label: "clippy::expect_used", - description: r##"Checks for `.expect()` calls on `Option`s and `Result`s."##, + description: r##"Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s."##, }, Lint { label: "clippy::expl_impl_clone_on_copy", description: r##"Checks for explicit `Clone` implementations for `Copy` types."##, }, + Lint { + label: "clippy::explicit_auto_deref", + description: r##"Checks for dereferencing expressions which would be covered by auto-deref."##, + }, Lint { label: "clippy::explicit_counter_loop", description: r##"Checks `for` loops over slices with an explicit counter @@ -5126,6 +5008,10 @@ replaced with `(e)print!()` / `(e)println!()`"##, description: r##"Checks for lifetimes in generics that are never used anywhere else."##, }, + Lint { + label: "clippy::extra_unused_type_parameters", + description: r##"Checks for type parameters in generics that are never used anywhere else."##, + }, Lint { label: "clippy::fallible_impl_from", description: r##"Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`"##, @@ -5143,6 +5029,10 @@ with Default::default()."##, label: "clippy::filter_map", description: r##"Nothing. This lint has been deprecated."##, }, + Lint { + label: "clippy::filter_map_bool_then", + description: r##"Checks for usage of `bool::then` in `Iterator::filter_map`."##, + }, Lint { label: "clippy::filter_map_identity", description: r##"Checks for usage of `filter_map(|x| x)`."##, @@ -5162,7 +5052,7 @@ with Default::default()."##, }, Lint { label: "clippy::flat_map_option", - description: r##"Checks for usages of `Iterator::flat_map()` where `filter_map()` could be + description: r##"Checks for usage of `Iterator::flat_map()` where `filter_map()` could be used instead."##, }, Lint { label: "clippy::float_arithmetic", description: r##"Checks for float arithmetic."## }, @@ -5211,18 +5101,12 @@ store address."##, ignoring either the keys or values."##, }, Lint { - label: "clippy::for_loops_over_fallibles", - description: r##"Checks for `for` loops over `Option` or `Result` values."##, + label: "clippy::forget_non_drop", + description: r##"Checks for calls to `std::mem::forget` with a value that does not implement `Drop`."##, }, Lint { - label: "clippy::forget_copy", - description: r##"Checks for calls to `std::mem::forget` with a value that -derives the Copy trait"##, - }, - Lint { - label: "clippy::forget_ref", - description: r##"Checks for calls to `std::mem::forget` with a reference -instead of an owned value."##, + label: "clippy::format_collect", + description: r##"Checks for usage of `.map(|_| format!(..)).collect::()`."##, }, Lint { label: "clippy::format_in_format_args", @@ -5230,6 +5114,15 @@ instead of an owned value."##, formatting such as `format!` itself, `write!` or `println!`. Suggests inlining the `format!` call."##, }, + Lint { + label: "clippy::format_push_string", + description: r##"Detects cases where the result of a `format!` call is +appended to an existing `String`."##, + }, + Lint { + label: "clippy::four_forward_slashes", + description: r##"Checks for outer doc comments written with 4 forward slashes (`////`)."##, + }, Lint { label: "clippy::from_iter_instead_of_collect", description: r##"Checks for `from_iter()` function calls on types that implement the `FromIterator` @@ -5239,6 +5132,10 @@ trait."##, label: "clippy::from_over_into", description: r##"Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead."##, }, + Lint { + label: "clippy::from_raw_with_void_ptr", + description: r##"Checks if we're passing a `c_void` raw pointer to `{Box,Rc,Arc,Weak}::from_raw(_)`"##, + }, Lint { label: "clippy::from_str_radix_10", description: r##"Checks for function invocations of the form `primitive::from_str_radix(s, 10)`"##, @@ -5249,17 +5146,26 @@ trait."##, functions and methods to implement the `Send` marker trait. It is mostly used by library authors (public and internal) that target an audience where multithreaded executors are likely to be used for running these Futures."##, + }, + Lint { + label: "clippy::get_first", + description: r##"Checks for usage of `x.get(0)` instead of +`x.first()`."##, }, Lint { label: "clippy::get_last_with_len", - description: r##"Checks for using `x.get(x.len() - 1)` instead of + description: r##"Checks for usage of `x.get(x.len() - 1)` instead of `x.last()`."##, }, Lint { label: "clippy::get_unwrap", - description: r##"Checks for use of `.get().unwrap()` (or + description: r##"Checks for usage of `.get().unwrap()` (or `.get_mut().unwrap`) on a standard library type which implements `Index`"##, }, + Lint { + label: "clippy::host_endian_bytes", + description: r##"Checks for the usage of the `to_ne_bytes` method and/or the function `from_ne_bytes`."##, + }, Lint { label: "clippy::identity_op", description: r##"Checks for identity operations, e.g., `x + 0`."##, @@ -5285,12 +5191,20 @@ and the *else* part."##, }, Lint { label: "clippy::if_then_some_else_none", - description: r##"Checks for if-else that could be written to `bool::then`."##, + description: r##"Checks for if-else that could be written using either `bool::then` or `bool::then_some`."##, }, Lint { label: "clippy::ifs_same_cond", description: r##"Checks for consecutive `if`s with the same condition."##, }, + Lint { + label: "clippy::ignored_unit_patterns", + description: r##"Checks for usage of `_` in patterns of type `()`."##, + }, + Lint { + label: "clippy::impl_trait_in_params", + description: r##"Lints when `impl Trait` is being used in a function's parameters."##, + }, Lint { label: "clippy::implicit_clone", description: r##"Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer."##, @@ -5305,10 +5219,25 @@ algorithm (`SipHash`)."##, label: "clippy::implicit_return", description: r##"Checks for missing return statements at the end of a block."##, }, + Lint { + label: "clippy::implicit_saturating_add", + description: r##"Checks for implicit saturating addition."##, + }, Lint { label: "clippy::implicit_saturating_sub", description: r##"Checks for implicit saturating subtraction."##, }, + Lint { + label: "clippy::implied_bounds_in_impls", + description: r##"Looks for bounds in `impl Trait` in return position that are implied by other bounds. +This can happen when a trait is specified that another trait already has as a supertrait +(e.g. `fn() -> impl Deref + DerefMut` has an unnecessary `Deref` bound, +because `Deref` is a supertrait of `DerefMut`)"##, + }, + Lint { + label: "clippy::impossible_comparisons", + description: r##"Checks for double comparisons that can never succeed"##, + }, Lint { label: "clippy::imprecise_flops", description: r##"Looks for floating-point expressions that @@ -5343,10 +5272,10 @@ lint on constant `usize` indexing on arrays because that is handled by rustc's ` without changing the outcome. The basic structure can be seen in the following table: -|Comparison| Bit Op |Example |equals | -|----------|---------|-----------|-------| -|`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`| -|`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|"##, +|Comparison| Bit Op |Example |equals | +|----------|----------|------------|-------| +|`>` / `<=`|`\\|` / `^`|`x \\| 2 > 3`|`x > 3`| +|`<` / `>=`|`\\|` / `^`|`x ^ 1 < 4` |`x < 4`|"##, }, Lint { label: "clippy::inefficient_to_string", @@ -5370,6 +5299,12 @@ or tuple struct where a `let` will suffice."##, label: "clippy::inherent_to_string_shadow_display", description: r##"Checks for the definition of inherent methods with a signature of `to_string(&self) -> String` and if the type implementing this method also implements the `Display` trait."##, }, + Lint { + label: "clippy::init_numbered_fields", + description: r##"Checks for tuple structs initialized with field syntax. +It will however not lint if a base initializer is present. +The lint will also ignore code in macros."##, + }, Lint { label: "clippy::inline_always", description: r##"Checks for items annotated with `#[inline(always)]`, @@ -5395,16 +5330,6 @@ unless the annotated function is empty or simply panics."##, label: "clippy::int_plus_one", description: r##"Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block"##, }, - Lint { - label: "clippy::integer_arithmetic", - description: r##"Checks for integer arithmetic operations which could overflow or panic. - -Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable -of overflowing according to the [Rust -Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), -or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is -attempted."##, - }, Lint { label: "clippy::integer_division", description: r##"Checks for division of integers"## }, Lint { label: "clippy::into_iter_on_ref", @@ -5431,10 +5356,20 @@ necessary. Only integer types are checked."##, label: "clippy::invisible_characters", description: r##"Checks for invisible Unicode characters in the code."##, }, + Lint { + label: "clippy::is_digit_ascii_radix", + description: r##"Finds usages of [`char::is_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit) that +can be replaced with [`is_ascii_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_digit) or +[`is_ascii_hexdigit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_hexdigit)."##, + }, Lint { label: "clippy::items_after_statements", description: r##"Checks for items declared after some statement in a block."##, }, + Lint { + label: "clippy::items_after_test_module", + description: r##"Triggers if an item is declared after the testing module marked with `#[cfg(test)]`."##, + }, Lint { label: "clippy::iter_cloned_collect", description: r##"Checks for the use of `.cloned().collect()` on slice to @@ -5444,6 +5379,11 @@ create a `Vec`."##, label: "clippy::iter_count", description: r##"Checks for the use of `.iter().count()`."##, }, + Lint { + label: "clippy::iter_kv_map", + description: r##"Checks for iterating a map (`HashMap` or `BTreeMap`) and +ignoring either the keys or values."##, + }, Lint { label: "clippy::iter_next_loop", description: r##"Checks for loops on `x.next()`."## }, Lint { label: "clippy::iter_next_slice", @@ -5455,16 +5395,41 @@ create a `Vec`."##, }, Lint { label: "clippy::iter_nth", - description: r##"Checks for use of `.iter().nth()` (and the related + description: r##"Checks for usage of `.iter().nth()` (and the related `.iter_mut().nth()`) on standard library types with *O*(1) element access."##, }, Lint { label: "clippy::iter_nth_zero", description: r##"Checks for the use of `iter.nth(0)`."##, }, + Lint { + label: "clippy::iter_on_empty_collections", + description: r##"Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections"##, + }, + Lint { + label: "clippy::iter_on_single_items", + description: r##"Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item"##, + }, + Lint { + label: "clippy::iter_out_of_bounds", + description: r##"Looks for iterator combinator calls such as `.take(x)` or `.skip(x)` +where `x` is greater than the amount of items that an iterator will produce."##, + }, + Lint { + label: "clippy::iter_overeager_cloned", + description: r##"Checks for usage of `_.cloned().()` where call to `.cloned()` can be postponed."##, + }, Lint { label: "clippy::iter_skip_next", - description: r##"Checks for use of `.skip(x).next()` on iterators."##, + description: r##"Checks for usage of `.skip(x).next()` on iterators."##, + }, + Lint { + label: "clippy::iter_skip_zero", + description: r##"Checks for usage of `.skip(0)` on iterators."##, + }, + Lint { + label: "clippy::iter_with_drain", + description: r##"Checks for usage of `.drain(..)` on `Vec` and `VecDeque` for iteration."##, }, Lint { label: "clippy::iterator_step_by_zero", @@ -5490,11 +5455,30 @@ are too large."##, label: "clippy::large_enum_variant", description: r##"Checks for large size differences between variants on `enum`s."##, + }, + Lint { + label: "clippy::large_futures", + description: r##"It checks for the size of a `Future` created by `async fn` or `async {}`."##, + }, + Lint { + label: "clippy::large_include_file", + description: r##"Checks for the inclusion of large files via `include_bytes!()` +and `include_str!()`"##, }, Lint { label: "clippy::large_stack_arrays", description: r##"Checks for local arrays that may be too large."##, }, + Lint { + label: "clippy::large_stack_frames", + description: r##"Checks for functions that use a lot of stack space. + +This often happens when constructing a large type, such as an array with a lot of elements, +or constructing *many* smaller-but-still-large structs, or copying around a lot of large types. + +This lint is a more general version of [`large_stack_arrays`](https://rust-lang.github.io/rust-clippy/master/#large_stack_arrays) +that is intended to look at functions as a whole instead of only individual array expressions inside of a function."##, + }, Lint { label: "clippy::large_types_passed_by_value", description: r##"Checks for functions taking arguments by value, where @@ -5519,29 +5503,42 @@ just to compare to zero, and suggests using `.is_empty()` where applicable."##, returned."##, }, Lint { - label: "clippy::let_underscore_drop", - description: r##"Checks for `let _ = ` -where expr has a type that implements `Drop`"##, + label: "clippy::let_underscore_future", + description: r##"Checks for `let _ = ` where the resulting type of expr implements `Future`"##, }, Lint { label: "clippy::let_underscore_lock", - description: r##"Checks for `let _ = sync_lock`. -This supports `mutex` and `rwlock` in `std::sync` and `parking_lot`."##, + description: r##"Checks for `let _ = sync_lock`. This supports `mutex` and `rwlock` in +`parking_lot`. For `std` locks see the `rustc` lint +[`let_underscore_lock`](https://doc.rust-lang.org/nightly/rustc/lints/listing/deny-by-default.html#let-underscore-lock)"##, }, Lint { label: "clippy::let_underscore_must_use", description: r##"Checks for `let _ = ` where expr is `#[must_use]`"##, }, + Lint { + label: "clippy::let_underscore_untyped", + description: r##"Checks for `let _ = ` without a type annotation, and suggests to either provide one, +or remove the `let` keyword altogether."##, + }, Lint { label: "clippy::let_unit_value", description: r##"Checks for binding a unit value."## }, + Lint { + label: "clippy::let_with_type_underscore", + description: r##"Detects when a variable is declared with an explicit type of `_`."##, + }, + Lint { + label: "clippy::lines_filter_map_ok", + description: r##"Checks for usage of `lines.filter_map(Result::ok)` or `lines.flat_map(Result::ok)` +when `lines` has type `std::io::Lines`."##, + }, Lint { label: "clippy::linkedlist", description: r##"Checks for usage of any `LinkedList`, suggesting to use a `Vec` or a `VecDeque` (formerly called `RingBuf`)."##, }, Lint { - label: "clippy::logic_bug", - description: r##"Checks for boolean expressions that contain terminals that -can be eliminated."##, + label: "clippy::little_endian_bytes", + description: r##"Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`."##, }, Lint { label: "clippy::lossy_float_literal", @@ -5564,11 +5561,28 @@ cannot be represented as the underlying type without loss."##, label: "clippy::manual_async_fn", description: r##"It checks for manual implementations of `async` functions."##, }, + Lint { + label: "clippy::manual_bits", + description: r##"Checks for usage of `std::mem::size_of::() * 8` when +`T::BITS` is available."##, + }, + Lint { + label: "clippy::manual_clamp", + description: r##"Identifies good opportunities for a clamp function from std or core, and suggests using it."##, + }, + Lint { + label: "clippy::manual_filter", + description: r##"Checks for usage of `match` which could be implemented using `filter`"##, + }, Lint { label: "clippy::manual_filter_map", description: r##"Checks for usage of `_.filter(_).map(_)` that can be written more simply as `filter_map(_)`."##, }, + Lint { + label: "clippy::manual_find", + description: r##"Checks for manual implementations of Iterator::find"##, + }, Lint { label: "clippy::manual_find_map", description: r##"Checks for usage of `_.find(_).map(_)` that can be written more simply @@ -5576,18 +5590,56 @@ as `find_map(_)`."##, }, Lint { label: "clippy::manual_flatten", - description: r##"Check for unnecessary `if let` usage in a for loop + description: r##"Checks for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the iterator element is used."##, + }, + Lint { + label: "clippy::manual_hash_one", + description: r##"Checks for cases where [`BuildHasher::hash_one`] can be used. + +[`BuildHasher::hash_one`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html#method.hash_one"##, + }, + Lint { + label: "clippy::manual_instant_elapsed", + description: r##"Lints subtraction between `Instant::now()` and another `Instant`."##, + }, + Lint { + label: "clippy::manual_is_ascii_check", + description: r##"Suggests to use dedicated built-in methods, +`is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range"##, + }, + Lint { + label: "clippy::manual_is_finite", + description: r##"Checks for manual `is_finite` reimplementations +(i.e., `x != ::INFINITY && x != ::NEG_INFINITY`)."##, + }, + Lint { + label: "clippy::manual_is_infinite", + description: r##"Checks for manual `is_infinite` reimplementations +(i.e., `x == ::INFINITY || x == ::NEG_INFINITY`)."##, + }, + Lint { + label: "clippy::manual_let_else", + description: r##"Warn of cases where `let...else` could be used"##, + }, + Lint { + label: "clippy::manual_main_separator_str", + description: r##"Checks for references on `std::path::MAIN_SEPARATOR.to_string()` used +to build a `&str`."##, }, Lint { label: "clippy::manual_map", - description: r##"Checks for usages of `match` which could be implemented using `map`"##, + description: r##"Checks for usage of `match` which could be implemented using `map`"##, }, Lint { label: "clippy::manual_memcpy", description: r##"Checks for for-loops that manually copy items between slices that could be optimized by having a memcpy."##, }, + Lint { + label: "clippy::manual_next_back", + description: r##"Checks for `.rev().next()` on a `DoubleEndedIterator`"##, + }, Lint { label: "clippy::manual_non_exhaustive", description: r##"Checks for manual implementations of the non-exhaustive pattern."##, @@ -5601,28 +5653,66 @@ slices that could be optimized by having a memcpy."##, description: r##"Checks for expressions like `x >= 3 && x < 8` that could be more readably expressed as `(3..8).contains(x)`."##, }, + Lint { + label: "clippy::manual_range_patterns", + description: r##"Looks for combined OR patterns that are all contained in a specific range, +e.g. `6 | 4 | 5 | 9 | 7 | 8` can be rewritten as `4..=9`."##, + }, + Lint { + label: "clippy::manual_rem_euclid", + description: r##"Checks for an expression like `((x % 4) + 4) % 4` which is a common manual reimplementation +of `x.rem_euclid(4)`."##, + }, + Lint { + label: "clippy::manual_retain", + description: r##"Checks for code to be replaced by `.retain()`."##, + }, Lint { label: "clippy::manual_saturating_arithmetic", description: r##"Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`."##, }, + Lint { + label: "clippy::manual_slice_size_calculation", + description: r##"When `a` is `&[T]`, detect `a.len() * size_of::()` and suggest `size_of_val(a)` +instead."##, + }, Lint { label: "clippy::manual_split_once", - description: r##"Checks for usages of `str::splitn(2, _)`"##, + description: r##"Checks for usage of `str::splitn(2, _)`"##, }, Lint { label: "clippy::manual_str_repeat", description: r##"Checks for manual implementations of `str::repeat`"##, }, + Lint { + label: "clippy::manual_string_new", + description: r##"Checks for usage of `` to create a `String`, such as `.to_string()`, `.to_owned()`, +`String::from()` and others."##, + }, Lint { label: "clippy::manual_strip", description: r##"Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using the pattern's length."##, }, - Lint { label: "clippy::manual_swap", description: r##"Checks for manual swapping."## }, + Lint { + label: "clippy::manual_swap", + description: r##"Checks for manual swapping. + +Note that the lint will not be emitted in const blocks, as the suggestion would not be applicable."##, + }, + Lint { + label: "clippy::manual_try_fold", + description: r##"Checks for usage of `Iterator::fold` with a type that implements `Try`."##, + }, Lint { label: "clippy::manual_unwrap_or", description: r##"Finds patterns that reimplement `Option::unwrap_or` or `Result::unwrap_or`."##, }, + Lint { + label: "clippy::manual_while_let_some", + description: r##"Looks for loops that check for emptiness of a `Vec` in the condition and pop an element +in the body as a separate operation."##, + }, Lint { label: "clippy::many_single_char_names", description: r##"Checks for too many variables whose name consists of a @@ -5640,7 +5730,7 @@ and suggests `cloned()` or `copied()` instead"##, }, Lint { label: "clippy::map_entry", - description: r##"Checks for uses of `contains_key` + `insert` on `HashMap` + description: r##"Checks for usage of `contains_key` + `insert` on `HashMap` or `BTreeMap`."##, }, Lint { @@ -5695,7 +5785,10 @@ instead. It also checks for `if let &foo = bar` blocks."##, }, Lint { label: "clippy::match_same_arms", - description: r##"Checks for `match` with identical arm bodies."##, + description: r##"Checks for `match` with identical arm bodies. + +Note: Does not lint on wildcards if the `non_exhaustive_omitted_patterns_lint` feature is +enabled and disallowed."##, }, Lint { label: "clippy::match_single_binding", @@ -5718,10 +5811,15 @@ and take drastic actions like `panic!`."##, label: "clippy::maybe_infinite_iter", description: r##"Checks for iteration that may be infinite."##, }, + Lint { + label: "clippy::maybe_misused_cfg", + description: r##"Checks for `#[cfg(features = ...)]` and suggests to replace it with +`#[cfg(feature = ...)]`."##, + }, Lint { label: "clippy::mem_forget", description: r##"Checks for usage of `std::mem::forget(t)` where `t` is -`Drop`."##, +`Drop` or has a field that implements `Drop`."##, }, Lint { label: "clippy::mem_replace_option_with_none", @@ -5737,6 +5835,13 @@ and take drastic actions like `panic!`."##, label: "clippy::mem_replace_with_uninit", description: r##"Checks for `mem::replace(&mut _, mem::uninitialized())` and `mem::replace(&mut _, mem::zeroed())`."##, + }, + Lint { + label: "clippy::min_ident_chars", + description: r##"Checks for idents which comprise of a single letter. + +Note: This lint can be very noisy when enabled; it may be desirable to only enable it +temporarily."##, }, Lint { label: "clippy::min_max", @@ -5751,18 +5856,38 @@ used to clamp values, but switched so that the result is constant."##, label: "clippy::mismatched_target_os", description: r##"Checks for cfg attributes having operating systems used in target family position."##, }, + Lint { + label: "clippy::mismatching_type_param_order", + description: r##"Checks for type parameters which are positioned inconsistently between +a type definition and impl block. Specifically, a parameter in an impl +block which has the same name as a parameter in the type def, but is in +a different place."##, + }, + Lint { + label: "clippy::misnamed_getters", + description: r##"Checks for getter methods that return a field that doesn't correspond +to the name of the method, when there is a field's whose name matches that of the method."##, + }, Lint { label: "clippy::misrefactored_assign_op", description: r##"Checks for `a op= a op b` or `a op= b op a` patterns."##, }, + Lint { + label: "clippy::missing_assert_message", + description: r##"Checks assertions without a custom panic message."##, + }, + Lint { + label: "clippy::missing_asserts_for_indexing", + description: r##"Checks for repeated slice indexing without asserting beforehand that the length +is greater than the largest index used to index into the slice."##, + }, Lint { label: "clippy::missing_const_for_fn", description: r##"Suggests the use of `const` in functions and methods where possible."##, }, Lint { label: "clippy::missing_docs_in_private_items", - description: r##"Warns if there is missing doc for any documentable item -(public or private)."##, + description: r##"Warns if there is missing doc for any private documentable item"##, }, Lint { label: "clippy::missing_enforced_import_renames", @@ -5774,6 +5899,10 @@ in the `enforce-import-renames` config option."##, description: r##"Checks the doc comments of publicly visible functions that return a `Result` type and warns if there is no `# Errors` section."##, }, + Lint { + label: "clippy::missing_fields_in_debug", + description: r##"Checks for manual [`core::fmt::Debug`](https://doc.rust-lang.org/core/fmt/trait.Debug.html) implementations that do not use all fields."##, + }, Lint { label: "clippy::missing_inline_in_public_items", description: r##"It lints if an exported function, method, trait method with default impl, @@ -5788,6 +5917,17 @@ may panic and warns if there is no `# Panics` section."##, label: "clippy::missing_safety_doc", description: r##"Checks for the doc comments of publicly visible unsafe functions and warns if there is no `# Safety` section."##, + }, + Lint { label: "clippy::missing_spin_loop", description: r##"Checks for empty spin loops"## }, + Lint { + label: "clippy::missing_trait_methods", + description: r##"Checks if a provided method is used implicitly by a trait +implementation. A usage example would be a wrapper where every method +should perform some operation before delegating to the inner type's +implementation. + +This lint should typically be enabled on a specific trait `impl` item +rather than globally."##, }, Lint { label: "clippy::mistyped_literal_suffixes", @@ -5797,10 +5937,16 @@ unsafe functions and warns if there is no `# Safety` section."##, label: "clippy::mixed_case_hex_literals", description: r##"Warns on hexadecimal literals with mixed-case letter digits."##, + }, + Lint { + label: "clippy::mixed_read_write_in_expression", + description: r##"Checks for a read and a write to the same variable where +whether the read occurs before or after the write depends on the evaluation +order of sub-expressions."##, }, Lint { label: "clippy::mod_module_files", - description: r##"Checks that module layout uses only self named module files, bans mod.rs files."##, + description: r##"Checks that module layout uses only self named module files, bans `mod.rs` files."##, }, Lint { label: "clippy::module_inception", @@ -5818,6 +5964,7 @@ containing module's name."##, description: r##"Checks for getting the remainder of a division by one or minus one."##, }, + Lint { label: "clippy::multi_assignments", description: r##"Checks for nested assignments."## }, Lint { label: "clippy::multiple_crate_versions", description: r##"Checks to see if multiple versions of a crate are being @@ -5827,6 +5974,10 @@ used."##, label: "clippy::multiple_inherent_impl", description: r##"Checks for multiple inherent implementations of a struct"##, }, + Lint { + label: "clippy::multiple_unsafe_ops_per_block", + description: r##"Checks for `unsafe` blocks that contain more than one unsafe operation."##, + }, Lint { label: "clippy::must_use_candidate", description: r##"Checks for public functions that have no @@ -5840,8 +5991,12 @@ unit-returning functions and methods."##, }, Lint { label: "clippy::mut_from_ref", - description: r##"This lint checks for functions that take immutable -references and return mutable ones."##, + description: r##"This lint checks for functions that take immutable references and return +mutable ones. This will not trigger if no unsafe code exists as there +are multiple safe functions which will do this transformation + +To be on the conservative side, if there's at least one mutable +reference with the output lifetime, this lint will not trigger."##, }, Lint { label: "clippy::mut_mut", @@ -5861,11 +6016,11 @@ references and return mutable ones."##, }, Lint { label: "clippy::mutex_atomic", - description: r##"Checks for usages of `Mutex` where an atomic will do."##, + description: r##"Checks for usage of `Mutex` where an atomic will do."##, }, Lint { label: "clippy::mutex_integer", - description: r##"Checks for usages of `Mutex` where `X` is an integral + description: r##"Checks for usage of `Mutex` where `X` is an integral type."##, }, Lint { label: "clippy::naive_bytecount", description: r##"Checks for naive byte counts"## }, @@ -5876,13 +6031,19 @@ specify the `Self`-type explicitly"##, }, Lint { label: "clippy::needless_bitwise_bool", - description: r##"Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using + description: r##"Checks for usage of bitwise and/or operators between booleans, where performance may be improved by using a lazy and."##, }, Lint { label: "clippy::needless_bool", description: r##"Checks for expressions of the form `if c { true } else { false }` (or vice versa) and suggests using the condition directly."##, + }, + Lint { + label: "clippy::needless_bool_assign", + description: r##"Checks for expressions of the form `if c { x = true } else { x = false }` +(or vice versa) and suggest assigning the variable directly from the +condition."##, }, Lint { label: "clippy::needless_borrow", @@ -5891,8 +6052,13 @@ be dereferenced immediately by the compiler."##, }, Lint { label: "clippy::needless_borrowed_reference", - description: r##"Checks for bindings that destructure a reference and borrow the inner + description: r##"Checks for bindings that needlessly destructure a reference and borrow the inner value with `&ref`."##, + }, + Lint { + label: "clippy::needless_borrows_for_generic_args", + description: r##"Checks for borrow operations (`&`) that used as a generic argument to a +function when the borrowed value could be used."##, }, Lint { label: "clippy::needless_collect", @@ -5910,11 +6076,16 @@ rearrangement of code can make the code easier to understand."##, label: "clippy::needless_doctest_main", description: r##"Checks for `fn main() { .. }` in doctests"##, }, + Lint { label: "clippy::needless_else", description: r##"Checks for empty `else` branches."## }, Lint { label: "clippy::needless_for_each", description: r##"Checks for usage of `for_each` that would be more simply written as a `for` loop."##, }, + Lint { + label: "clippy::needless_if", + description: r##"Checks for empty `if` branches with no else branch."##, + }, Lint { label: "clippy::needless_late_init", description: r##"Checks for late initializations that can be replaced by a `let` statement @@ -5924,11 +6095,32 @@ with an initializer."##, label: "clippy::needless_lifetimes", description: r##"Checks for lifetime annotations which can be removed by relying on lifetime elision."##, + }, + Lint { + label: "clippy::needless_match", + description: r##"Checks for unnecessary `match` or match-like `if let` returns for `Option` and `Result` +when function signatures are the same."##, }, Lint { label: "clippy::needless_option_as_deref", - description: r##"Checks for no-op uses of Option::{as_deref,as_deref_mut}, + description: r##"Checks for no-op uses of `Option::{as_deref, as_deref_mut}`, for example, `Option<&T>::as_deref()` returns the same type."##, + }, + Lint { + label: "clippy::needless_option_take", + description: r##"Checks for calling `take` function after `as_ref`."##, + }, + Lint { + label: "clippy::needless_parens_on_range_literals", + description: r##"The lint checks for parenthesis on literals in range statements that are +superfluous."##, + }, + Lint { + label: "clippy::needless_pass_by_ref_mut", + description: r##"Check if a `&mut` function argument is actually used mutably. + +Be careful if the function is publicly reexported as it would break compatibility with +users of this function."##, }, Lint { label: "clippy::needless_pass_by_value", @@ -5936,6 +6128,10 @@ for example, `Option<&T>::as_deref()` returns the same type."##, consuming them in its body."##, }, + Lint { + label: "clippy::needless_pub_self", + description: r##"Checks for usage of `pub(self)` and `pub(in self)`."##, + }, Lint { label: "clippy::needless_question_mark", description: r##"Suggests alternatives for useless applications of `?` in terminating expressions"##, @@ -5945,13 +6141,25 @@ body."##, description: r##"Checks for looping over the range of `0..len` of some collection just to get the values by index."##, }, + Lint { + label: "clippy::needless_raw_string_hashes", + description: r##"Checks for raw string literals with an unnecessary amount of hashes around them."##, + }, + Lint { + label: "clippy::needless_raw_strings", + description: r##"Checks for raw string literals where a string literal can be used instead."##, + }, Lint { label: "clippy::needless_return", description: r##"Checks for return statements at the end of a block."##, }, + Lint { + label: "clippy::needless_return_with_question_mark", + description: r##"Checks for return statements on `Err` paired with the `?` operator."##, + }, Lint { label: "clippy::needless_splitn", - description: r##"Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same."##, + description: r##"Checks for usage of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same."##, }, Lint { label: "clippy::needless_update", @@ -5985,7 +6193,7 @@ This lint is not applied to structs marked with }, Lint { label: "clippy::new_without_default", - description: r##"Checks for types with a `fn new() -> Self` method and no + description: r##"Checks for public types with a `pub fn new() -> Self` method and no implementation of [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)."##, }, @@ -5993,14 +6201,34 @@ implementation of label: "clippy::no_effect", description: r##"Checks for statements which have no effect."##, }, + Lint { + label: "clippy::no_effect_replace", + description: r##"Checks for `replace` statements which have no effect."##, + }, Lint { label: "clippy::no_effect_underscore_binding", description: r##"Checks for binding to underscore prefixed variable without side-effects."##, }, + Lint { + label: "clippy::no_mangle_with_rust_abi", + description: r##"Checks for Rust ABI functions with the `#[no_mangle]` attribute."##, + }, Lint { label: "clippy::non_ascii_literal", description: r##"Checks for non-ASCII characters in string and char literals."##, }, + Lint { + label: "clippy::non_canonical_clone_impl", + description: r##"Checks for non-canonical implementations of `Clone` when `Copy` is already implemented."##, + }, + Lint { + label: "clippy::non_canonical_partial_ord_impl", + description: r##"Checks for non-canonical implementations of `PartialOrd` when `Ord` is already implemented."##, + }, + Lint { + label: "clippy::non_minimal_cfg", + description: r##"Checks for `any` and `all` combinators in `cfg` with only one condition."##, + }, Lint { label: "clippy::non_octal_unix_permissions", description: r##"Checks for non-octal values used to set Unix file permissions."##, @@ -6032,12 +6260,20 @@ that make no sense."##, description: r##"Checks for public functions that dereference raw pointer arguments but are not marked `unsafe`."##, }, + Lint { + label: "clippy::obfuscated_if_else", + description: r##"Checks for usage of `.then_some(..).unwrap_or(..)`"##, + }, Lint { label: "clippy::octal_escapes", description: r##"Checks for `\\0` escapes in string and byte literals that look like octal character escapes in C."##, }, Lint { label: "clippy::ok_expect", description: r##"Checks for usage of `ok().expect(..)`."## }, + Lint { + label: "clippy::only_used_in_recursion", + description: r##"Checks for arguments that are only used in recursion with no side-effects."##, + }, Lint { label: "clippy::op_ref", description: r##"Checks for arguments to `==` which have their address @@ -6046,7 +6282,7 @@ and suggests to dereference the other argument instead"##, }, Lint { label: "clippy::option_as_ref_deref", - description: r##"Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str)."##, + description: r##"Checks for usage of `_.as_ref().map(Deref::deref)` or its aliases (such as String::as_str)."##, }, Lint { label: "clippy::option_env_unwrap", @@ -6059,7 +6295,8 @@ suggests usage of the `env!` macro."##, }, Lint { label: "clippy::option_if_let_else", - description: r##"Lints usage of `if let Some(v) = ... { y } else { x }` which is more + description: r##"Lints usage of `if let Some(v) = ... { y } else { x }` and +`match .. { Some(v) => y, None/_ => x }` which are more idiomatically done with `Option::map_or` (if the else bit is a pure expression) or `Option::map_or_else` (if the else bit is an impure expression)."##, @@ -6075,14 +6312,19 @@ or closure that returns the unit type `()`."##, }, Lint { label: "clippy::option_option", - description: r##"Checks for use of `Option>` in function signatures and type + description: r##"Checks for usage of `Option>` in function signatures and type definitions"##, }, Lint { label: "clippy::or_fun_call", description: r##"Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, -etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or -`unwrap_or_default` instead."##, +`.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`, +`.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()` +etc. instead."##, + }, + Lint { + label: "clippy::or_then_unwrap", + description: r##"Checks for `.or(…).unwrap()` calls to Options and Results."##, }, Lint { label: "clippy::out_of_bounds_indexing", @@ -6093,23 +6335,47 @@ index."##, label: "clippy::overflow_check_conditional", description: r##"Detects classic underflow/overflow checks."##, }, + Lint { + label: "clippy::overly_complex_bool_expr", + description: r##"Checks for boolean expressions that contain terminals that +can be eliminated."##, + }, Lint { label: "clippy::panic", description: r##"Checks for usage of `panic!`."## }, Lint { label: "clippy::panic_in_result_fn", - description: r##"Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result."##, + description: r##"Checks for usage of `panic!` or assertions in a function of type result."##, }, Lint { label: "clippy::panicking_unwrap", description: r##"Checks for calls of `unwrap[_err]()` that will always fail."##, }, + Lint { + label: "clippy::partial_pub_fields", + description: r##"Checks whether partial fields of a struct are public. + +Either make all fields of a type public, or make none of them public"##, + }, Lint { label: "clippy::partialeq_ne_impl", description: r##"Checks for manual re-implementations of `PartialEq::ne`."##, }, + Lint { + label: "clippy::partialeq_to_none", + description: r##"Checks for binary comparisons to a literal `Option::None`."##, + }, Lint { label: "clippy::path_buf_push_overwrite", description: r##"* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) calls on `PathBuf` that can cause overwrites."##, + }, + Lint { + label: "clippy::path_ends_with_ext", + description: r##"Looks for calls to `Path::ends_with` calls where the argument looks like a file extension. + +By default, Clippy has a short list of known filenames that start with a dot +but aren't necessarily file extensions (e.g. the `.git` folder), which are allowed by default. +The `allowed-dotfiles` configuration can be used to allow additional +file extensions that Clippy should not lint."##, }, Lint { label: "clippy::pattern_type_mismatch", @@ -6132,6 +6398,10 @@ in a general way even outside of the various pattern matching mechanics. Of cour this lint can still be used to highlight areas of interest and ensure a good understanding of ownership semantics."##, }, + Lint { + label: "clippy::permissions_set_readonly_false", + description: r##"Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`."##, + }, Lint { label: "clippy::possible_missing_comma", description: r##"Checks for possible missing comma in an array. It lints if @@ -6146,6 +6416,11 @@ parentheses * a negative numeric literal (which is really a unary `-` followed by a numeric literal) followed by a method call"##, + }, + Lint { + label: "clippy::print_in_format_impl", + description: r##"Checks for usage of `println`, `print`, `eprintln` or `eprint` in an +implementation of a formatting trait."##, }, Lint { label: "clippy::print_literal", @@ -6173,15 +6448,19 @@ print a newline."##, }, Lint { label: "clippy::ptr_arg", - description: r##"This lint checks for function arguments of type `&String` -or `&Vec` unless the references are mutable. It will also suggest you -replace `.clone()` calls with the appropriate `.to_owned()`/`to_string()` -calls."##, + description: r##"This lint checks for function arguments of type `&String`, `&Vec`, +`&PathBuf`, and `Cow<_>`. It will also suggest you replace `.clone()` calls +with the appropriate `.to_owned()`/`to_string()` calls."##, }, Lint { label: "clippy::ptr_as_ptr", description: r##"Checks for `as` casts between raw pointers without changing its mutability, namely `*const T` to `*const U` and `*mut T` to `*mut U`."##, + }, + Lint { + label: "clippy::ptr_cast_constness", + description: r##"Checks for `as` casts between raw pointers which change its constness, namely `*const T` to +`*mut T` and `*mut T` to `*const T`."##, }, Lint { label: "clippy::ptr_eq", description: r##"Use `std::ptr::eq` when applicable"## }, Lint { @@ -6193,10 +6472,26 @@ namely `*const T` to `*const U` and `*mut T` to `*mut U`."##, label: "clippy::pub_enum_variant_names", description: r##"Nothing. This lint has been deprecated."##, }, + Lint { label: "clippy::pub_use", description: r##"Restricts the usage of `pub use ...`"## }, + Lint { + label: "clippy::pub_with_shorthand", + description: r##"Checks for usage of `pub()` with `in`."##, + }, + Lint { + label: "clippy::pub_without_shorthand", + description: r##"Checks for usage of `pub()` without `in`. + +Note: As you cannot write a module's path in `pub()`, this will only trigger on +`pub(super)` and the like."##, + }, Lint { label: "clippy::question_mark", description: r##"Checks for expressions that could be replaced by the question mark operator."##, }, + Lint { + label: "clippy::question_mark_used", + description: r##"Checks for expressions that use the question mark operator and rejects them."##, + }, Lint { label: "clippy::range_minus_one", description: r##"Checks for inclusive ranges where 1 is subtracted from @@ -6220,10 +6515,49 @@ upper bound, e.g., `x..(y+1)`."##, label: "clippy::rc_buffer", description: r##"Checks for `Rc` and `Arc` when `T` is a mutable buffer type such as `String` or `Vec`."##, }, + Lint { + label: "clippy::rc_clone_in_vec_init", + description: r##"Checks for reference-counted pointers (`Arc`, `Rc`, `rc::Weak`, and `sync::Weak`) +in `vec![elem; len]`"##, + }, Lint { label: "clippy::rc_mutex", description: r##"Checks for `Rc>`."## }, + Lint { + label: "clippy::read_line_without_trim", + description: r##"Looks for calls to [`Stdin::read_line`] to read a line from the standard input +into a string, then later attempting to parse this string into a type without first trimming it, which will +always fail because the string has a trailing newline in it."##, + }, + Lint { + label: "clippy::read_zero_byte_vec", + description: r##"This lint catches reads into a zero-length `Vec`. +Especially in the case of a call to `with_capacity`, this lint warns that read +gets the number of bytes from the `Vec`'s length, not its capacity."##, + }, + Lint { + label: "clippy::readonly_write_lock", + description: r##"Looks for calls to `RwLock::write` where the lock is only used for reading."##, + }, + Lint { + label: "clippy::recursive_format_impl", + description: r##"Checks for format trait implementations (e.g. `Display`) with a recursive call to itself +which uses `self` as a parameter. +This is typically done indirectly with the `write!` macro or with `to_string()`."##, + }, Lint { label: "clippy::redundant_allocation", - description: r##"Checks for use of redundant allocations anywhere in the code."##, + description: r##"Checks for usage of redundant allocations anywhere in the code."##, + }, + Lint { + label: "clippy::redundant_as_str", + description: r##"Checks for usage of `as_str()` on a `String`` chained with a method available on the `String` itself."##, + }, + Lint { + label: "clippy::redundant_async_block", + description: r##"Checks for `async` block that only returns `await` on a future."##, + }, + Lint { + label: "clippy::redundant_at_rest_pattern", + description: r##"Checks for `[all @ ..]` patterns."##, }, Lint { label: "clippy::redundant_clone", @@ -6246,6 +6580,10 @@ are defined."##, description: r##"Checks for closures which only invoke a method on the closure argument and can be replaced by referencing the method directly."##, }, + Lint { + label: "clippy::redundant_comparisons", + description: r##"Checks for ineffective double comparisons against constants."##, + }, Lint { label: "clippy::redundant_else", description: r##"Checks for `else` blocks that can be removed without changing semantics."##, @@ -6259,6 +6597,14 @@ argument and can be replaced by referencing the method directly."##, description: r##"Checks for fields in struct literals where shorthands could be used."##, }, + Lint { + label: "clippy::redundant_guards", + description: r##"Checks for unnecessary guards in match expressions."##, + }, + Lint { + label: "clippy::redundant_locals", + description: r##"Checks for redundant redefinitions of local bindings."##, + }, Lint { label: "clippy::redundant_pattern", description: r##"Checks for patterns in the form `name @ _`."##, @@ -6282,19 +6628,22 @@ do not change the type."##, label: "clippy::redundant_static_lifetimes", description: r##"Checks for constants and statics with an explicit `'static` lifetime."##, }, + Lint { + label: "clippy::redundant_type_annotations", + description: r##"Warns about needless / redundant type annotations."##, + }, Lint { label: "clippy::ref_binding_to_reference", description: r##"Checks for `ref` bindings which create a reference to a reference."##, }, - Lint { - label: "clippy::ref_in_deref", - description: r##"Checks for references in expressions that use -auto dereference."##, - }, Lint { label: "clippy::ref_option_ref", description: r##"Checks for usage of `&Option<&T>`."##, }, + Lint { + label: "clippy::ref_patterns", + description: r##"Checks for usages of the `ref` keyword."##, + }, Lint { label: "clippy::regex_macro", description: r##"Nothing. This lint has been deprecated."##, @@ -6313,10 +6662,19 @@ they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://gi label: "clippy::replace_consts", description: r##"Nothing. This lint has been deprecated."##, }, + Lint { + label: "clippy::reserve_after_initialization", + description: r##"Informs the user about a more concise way to create a vector with a known capacity."##, + }, Lint { label: "clippy::rest_pat_in_fully_bound_structs", description: r##"Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched."##, }, + Lint { + label: "clippy::result_large_err", + description: r##"Checks for functions that return `Result` with an unusually large +`Err`-variant."##, + }, Lint { label: "clippy::result_map_or_into_option", description: r##"Checks for usage of `_.map_or(None, Some)`."##, @@ -6339,7 +6697,7 @@ implements `std::error::Error`."##, Lint { label: "clippy::reversed_empty_ranges", description: r##"Checks for range expressions `x..y` where both `x` and `y` -are constant and `x` is greater or equal to `y`."##, +are constant and `x` is greater to `y`. Also triggers if `x` is equal to `y` when they are conditions to a `for` loop."##, }, Lint { label: "clippy::same_functions_in_if_condition", @@ -6359,6 +6717,16 @@ one from a trait, another not from trait."##, label: "clippy::search_is_some", description: r##"Checks for an iterator or string search (such as `find()`, `position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`."##, + }, + Lint { + label: "clippy::seek_from_current", + description: r##"Checks an argument of `seek` method of `Seek` trait +and if it start seek from `SeekFrom::Current(0)`, suggests `stream_position` instead."##, + }, + Lint { + label: "clippy::seek_to_start_instead_of_rewind", + description: r##"Checks for jumps to the start of a stream that implements `Seek` +and uses the `seek` method providing `Start` as parameter."##, }, Lint { label: "clippy::self_assignment", @@ -6370,13 +6738,22 @@ one from a trait, another not from trait."##, }, Lint { label: "clippy::self_named_module_files", - description: r##"Checks that module layout uses only mod.rs files."##, + description: r##"Checks that module layout uses only `mod.rs` files."##, }, Lint { label: "clippy::semicolon_if_nothing_returned", description: r##"Looks for blocks of expressions and fires if the last expression returns `()` but is not followed by a semicolon."##, }, + Lint { + label: "clippy::semicolon_inside_block", + description: r##"Suggests moving the semicolon after a block to the inside of the block, after its last +expression."##, + }, + Lint { + label: "clippy::semicolon_outside_block", + description: r##"Suggests moving the semicolon from a block's final expression outside of the block."##, + }, Lint { label: "clippy::separated_literal_suffix", description: r##"Warns if literal suffixes are separated by an underscore. @@ -6419,15 +6796,43 @@ statement."##, implementation of a `std` trait (see [llogiq's blog post](http://llogiq.github.io/2015/07/30/traits.html) for further information) instead of an inherent implementation."##, + }, + Lint { + label: "clippy::should_panic_without_expect", + description: r##"Checks for `#[should_panic]` attributes without specifying the expected panic message."##, + }, + Lint { + label: "clippy::significant_drop_in_scrutinee", + description: r##"Checks for temporaries returned from function calls in a match scrutinee that have the +`clippy::has_significant_drop` attribute."##, + }, + Lint { + label: "clippy::significant_drop_tightening", + description: r##"Searches for elements marked with `#[clippy::has_significant_drop]` that could be early +dropped but are in fact dropped at the end of their scopes. In other words, enforces the +tightening of their possible lifetimes."##, }, Lint { label: "clippy::similar_names", - description: r##"Checks for names that are very similar and thus confusing."##, + description: r##"Checks for names that are very similar and thus confusing. + +Note: this lint looks for similar names throughout each +scope. To allow it, you need to allow it on the scope +level, not on the name that is reported."##, + }, + Lint { + label: "clippy::single_call_fn", + description: r##"Checks for functions that are only used once. Does not lint tests."##, }, Lint { label: "clippy::single_char_add_str", description: r##"Warns when using `push_str`/`insert_str` with a single-character string literal where `push`/`insert` with a `char` would work fine."##, + }, + Lint { + label: "clippy::single_char_lifetime_names", + description: r##"Checks for lifetimes with names which are one character +long."##, }, Lint { label: "clippy::single_char_pattern", @@ -6445,18 +6850,32 @@ where `push`/`insert` with a `char` would work fine."##, Lint { label: "clippy::single_match", description: r##"Checks for matches with a single arm where an `if let` -will usually suffice."##, +will usually suffice. + +This intentionally does not lint if there are comments +inside of the other arm, so as to allow the user to document +why having another explicit pattern with an empty body is necessary, +or because the comments need to be preserved for other reasons."##, }, Lint { label: "clippy::single_match_else", description: r##"Checks for matches with two arms where an `if let else` will usually suffice."##, }, + Lint { + label: "clippy::single_range_in_vec_init", + description: r##"Checks for `Vec` or array initializations that contain only one range."##, + }, Lint { label: "clippy::size_of_in_element_count", description: r##"Detects expressions where `size_of::` or `size_of_val::` is used as a count of elements of type `T`"##, + }, + Lint { + label: "clippy::size_of_ref", + description: r##"Checks for calls to `std::mem::size_of_val()` where the argument is +a reference to a reference."##, }, Lint { label: "clippy::skip_while_next", @@ -6469,9 +6888,17 @@ count of elements of type `T`"##, Lint { label: "clippy::stable_sort_primitive", description: r##"When sorting primitive values (integers, bools, chars, as well -as arrays, slices, and tuples of such items), it is better to +as arrays, slices, and tuples of such items), it is typically better to use an unstable sort than a stable sort."##, }, + Lint { + label: "clippy::std_instead_of_alloc", + description: r##"Finds items imported through `std` when available through `alloc`."##, + }, + Lint { + label: "clippy::std_instead_of_core", + description: r##"Finds items imported through `std` when available through `core`."##, + }, Lint { label: "clippy::str_to_string", description: r##"This lint checks for `.to_string()` method calls on values of type `&str`."##, @@ -6501,6 +6928,10 @@ match."##, description: r##"Checks for the `as_bytes` method called on string literals that contain only ASCII characters."##, }, + Lint { + label: "clippy::string_lit_chars_any", + description: r##"Checks for `.chars().any(|i| i == c)`."##, + }, Lint { label: "clippy::string_slice", description: r##"Checks for slice operations on strings"##, @@ -6532,9 +6963,18 @@ subtracting elements in an Add impl."##, }, Lint { label: "clippy::suspicious_assignment_formatting", - description: r##"Checks for use of the nonexistent `=*`, `=!` and `=-` + description: r##"Checks for usage of the non-existent `=*`, `=!` and `=-` operators."##, }, + Lint { + label: "clippy::suspicious_command_arg_space", + description: r##"Checks for `Command::arg()` invocations that look like they +should be multiple arguments instead, such as `arg(-t ext2)`."##, + }, + Lint { + label: "clippy::suspicious_doc_comments", + description: r##"Detects the use of outer doc comments (`///`, `/**`) followed by a bang (`!`): `///!`"##, + }, Lint { label: "clippy::suspicious_else_formatting", description: r##"Checks for formatting of `else`. It lints if the `else` @@ -6561,12 +7001,24 @@ of binary operators nearby."##, (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and related functions with either zero or one splits."##, }, + Lint { + label: "clippy::suspicious_to_owned", + description: r##"Checks for the usage of `_.to_owned()`, on a `Cow<'_, _>`."##, + }, Lint { label: "clippy::suspicious_unary_op_formatting", description: r##"Checks the formatting of a unary operator on the right hand side of a binary operator. It lints if there is no space between the binary and unary operators, but there is a space between the unary and its operand."##, }, + Lint { + label: "clippy::suspicious_xor_used_as_pow", + description: r##"Warns for a Bitwise XOR (`^`) operator being probably confused as a powering. It will not trigger if any of the numbers are not in decimal."##, + }, + Lint { + label: "clippy::swap_ptr_to_ref", + description: r##"Checks for calls to `core::mem::swap` where either parameter is derived from a pointer"##, + }, Lint { label: "clippy::tabs_in_doc_comments", description: r##"Checks doc comments for usage of tab characters."##, @@ -6577,12 +7029,13 @@ but there is a space between the unary and its operand."##, assign a value in it."##, }, Lint { - label: "clippy::to_digit_is_some", - description: r##"Checks for `.to_digit(..).is_some()` on `char`s."##, + label: "clippy::tests_outside_test_module", + description: r##"Triggers when a testing function (marked with the `#[test]` attribute) isn't inside a testing module +(marked with `#[cfg(test)]`)."##, }, Lint { - label: "clippy::to_string_in_display", - description: r##"Checks for uses of `to_string()` in `Display` traits."##, + label: "clippy::to_digit_is_some", + description: r##"Checks for `.to_digit(..).is_some()` on `char`s."##, }, Lint { label: "clippy::to_string_in_format_args", @@ -6610,7 +7063,7 @@ in a macro that does formatting."##, }, Lint { label: "clippy::trait_duplication_in_bounds", - description: r##"Checks for cases where generics are being used and multiple + description: r##"Checks for cases where generics or trait objects are being used and multiple syntax specifications for trait bounds are used simultaneously."##, }, Lint { @@ -6633,6 +7086,15 @@ syntax specifications for trait bounds are used simultaneously."##, label: "clippy::transmute_int_to_float", description: r##"Checks for transmutes from an integer to a float."##, }, + Lint { + label: "clippy::transmute_int_to_non_zero", + description: r##"Checks for transmutes from integers to `NonZero*` types, and suggests their `new_unchecked` +method instead."##, + }, + Lint { + label: "clippy::transmute_null_to_fn", + description: r##"Checks for null function pointer creation through transmute."##, + }, Lint { label: "clippy::transmute_num_to_bytes", description: r##"Checks for transmutes from a number to an array of `u8`"##, @@ -6646,6 +7108,11 @@ from a reference to a reference."##, label: "clippy::transmute_ptr_to_ref", description: r##"Checks for transmutes from a pointer to a reference."##, }, + Lint { + label: "clippy::transmute_undefined_repr", + description: r##"Checks for transmutes between types which do not have a representation defined relative to +each other."##, + }, Lint { label: "clippy::transmutes_expressible_as_ptr_casts", description: r##"Checks for transmutes that could be a pointer cast."##, @@ -6654,6 +7121,10 @@ from a reference to a reference."##, label: "clippy::transmuting_null", description: r##"Checks for transmute calls which would receive a null pointer."##, }, + Lint { + label: "clippy::trim_split_whitespace", + description: r##"Warns about calling `str::trim` (or variants) before `str::split_whitespace`."##, + }, Lint { label: "clippy::trivial_regex", description: r##"Checks for trivial [regex](https://crates.io/crates/regex) @@ -6665,25 +7136,51 @@ creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`)."##, the argument type is `Copy` and small enough to be more efficient to always pass by value."##, }, - Lint { label: "clippy::try_err", description: r##"Checks for usages of `Err(x)?`."## }, + Lint { label: "clippy::try_err", description: r##"Checks for usage of `Err(x)?`."## }, + Lint { + label: "clippy::tuple_array_conversions", + description: r##"Checks for tuple<=>array conversions that are not done with `.into()`."##, + }, Lint { label: "clippy::type_complexity", description: r##"Checks for types used in structs, parameters and `let` declarations above a certain complexity threshold."##, }, + Lint { + label: "clippy::type_id_on_box", + description: r##"Looks for calls to ` as Any>::type_id`."##, + }, Lint { label: "clippy::type_repetition_in_bounds", description: r##"This lint warns about unnecessary type repetitions in trait bounds"##, }, Lint { - label: "clippy::undocumented_unsafe_blocks", - description: r##"Checks for `unsafe` blocks without a `// Safety: ` comment -explaining why the unsafe operations performed inside -the block are safe."##, + label: "clippy::unchecked_duration_subtraction", + description: r##"Lints subtraction between an [`Instant`] and a [`Duration`]."##, }, Lint { - label: "clippy::undropped_manually_drops", - description: r##"Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`."##, + label: "clippy::undocumented_unsafe_blocks", + description: r##"Checks for `unsafe` blocks and impls without a `// SAFETY: ` comment +explaining why the unsafe operations performed inside +the block are safe. + +Note the comment must appear on the line(s) preceding the unsafe block +with nothing appearing in between. The following is ok: +```rust +foo( + // SAFETY: + // This is a valid safety comment + unsafe { *x } +) +``` +But neither of these are: +```rust +// SAFETY: +// This is not a valid safety comment +foo( + /* SAFETY: Neither is this */ unsafe { *x }, +); +```"##, }, Lint { label: "clippy::unicode_not_nfc", @@ -6704,6 +7201,11 @@ that is not equal to its description: r##"Checks for `set_len()` call that creates `Vec` with uninitialized elements. This is commonly caused by calling `set_len()` right after allocating or reserving a buffer with `new()`, `default()`, `with_capacity()`, or `reserve()`."##, + }, + Lint { + label: "clippy::uninlined_format_args", + description: r##"Detect when a variable is not inlined in a format string, +and suggests to inline it."##, }, Lint { label: "clippy::unit_arg", @@ -6721,24 +7223,41 @@ comparisons (like `==` and `<`) and asserts."##, description: r##"Checks for functions that expect closures of type Fn(...) -> Ord where the implemented closure returns the unit type. The lint also suggests to remove the semi-colon at the end of the statement if present."##, + }, + Lint { + label: "clippy::unnecessary_box_returns", + description: r##"Checks for a return type containing a `Box` where `T` implements `Sized` + +The lint ignores `Box` where `T` is larger than `unnecessary_box_size`, +as returning a large `T` directly may be detrimental to performance."##, }, Lint { label: "clippy::unnecessary_cast", - description: r##"Checks for casts to the same type, casts of int literals to integer types -and casts of float literals to float types."##, + description: r##"Checks for casts to the same type, casts of int literals to integer types, casts of float +literals to float types and casts between raw pointers without changing type or constness."##, }, Lint { label: "clippy::unnecessary_filter_map", - description: r##"Checks for `filter_map` calls which could be replaced by `filter` or `map`. + description: r##"Checks for `filter_map` calls that could be replaced by `filter` or `map`. More specifically it checks if the closure provided is only performing one of the filter or map operations and suggests the appropriate option."##, + }, + Lint { + label: "clippy::unnecessary_find_map", + description: r##"Checks for `find_map` calls that could be replaced by `find` or `map`. More +specifically it checks if the closure provided is only performing one of the +find or map operations and suggests the appropriate option."##, }, Lint { label: "clippy::unnecessary_fold", - description: r##"Checks for using `fold` when a more succinct alternative exists. + description: r##"Checks for usage of `fold` when a more succinct alternative exists. Specifically, this checks for `fold`s which could be replaced by `any`, `all`, `sum` or `product`."##, }, + Lint { + label: "clippy::unnecessary_join", + description: r##"Checks for usage of `.collect::>().join()` on iterators."##, + }, Lint { label: "clippy::unnecessary_lazy_evaluations", description: r##"As the counterpart to `or_fun_call`, this lint looks for unnecessary @@ -6750,7 +7269,16 @@ simpler code: - `and_then` to `and` - `or_else` to `or` - `get_or_insert_with` to `get_or_insert` - - `ok_or_else` to `ok_or`"##, + - `ok_or_else` to `ok_or` + - `then` to `then_some` (for msrv >= 1.62.0)"##, + }, + Lint { + label: "clippy::unnecessary_literal_unwrap", + description: r##"Checks for `.unwrap()` related calls on `Result`s and `Option`s that are constructed."##, + }, + Lint { + label: "clippy::unnecessary_map_on_constructor", + description: r##"Suggest removing the use of a may (or map_err) method when an Option or Result is being construted."##, }, Lint { label: "clippy::unnecessary_mut_passed", @@ -6761,6 +7289,19 @@ requires an immutable reference."##, label: "clippy::unnecessary_operation", description: r##"Checks for expression statements that can be reduced to a sub-expression."##, + }, + Lint { + label: "clippy::unnecessary_owned_empty_strings", + description: r##"Detects cases of owned empty strings being passed as an argument to a function expecting `&str`"##, + }, + Lint { + label: "clippy::unnecessary_safety_comment", + description: r##"Checks for `// SAFETY: ` comments on safe code."##, + }, + Lint { + label: "clippy::unnecessary_safety_doc", + description: r##"Checks for the doc comments of publicly visible +safe functions and traits and warns if there is a `# Safety` section."##, }, Lint { label: "clippy::unnecessary_self_imports", @@ -6768,8 +7309,13 @@ sub-expression."##, }, Lint { label: "clippy::unnecessary_sort_by", - description: r##"Detects uses of `Vec::sort_by` passing in a closure + description: r##"Checks for usage of `Vec::sort_by` passing in a closure which compares the two arguments, either directly or indirectly."##, + }, + Lint { + label: "clippy::unnecessary_struct_initialization", + description: r##"Checks for initialization of a `struct` by copying a base without setting +any field."##, }, Lint { label: "clippy::unnecessary_to_owned", @@ -6854,10 +7400,24 @@ types have different ABI, size or alignment."##, label: "clippy::unused_collect", description: r##"Nothing. This lint has been deprecated."##, }, + Lint { + label: "clippy::unused_format_specs", + description: r##"Detects [formatting parameters] that have no effect on the output of +`format!()`, `println!()` or similar macros."##, + }, Lint { label: "clippy::unused_io_amount", description: r##"Checks for unused written/read amount."##, }, + Lint { + label: "clippy::unused_peekable", + description: r##"Checks for the creation of a `peekable` iterator that is never `.peek()`ed"##, + }, + Lint { + label: "clippy::unused_rounding", + description: r##"Detects cases where a whole-number literal float is being rounded, using +the `floor`, `ceil`, or `round` methods."##, + }, Lint { label: "clippy::unused_self", description: r##"Checks methods that contain a `self` argument but don't use it"##, @@ -6876,13 +7436,17 @@ by nibble or byte."##, description: r##"Checks for functions of type `Result` that contain `expect()` or `unwrap()`"##, }, Lint { - label: "clippy::unwrap_or_else_default", - description: r##"Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and -`Result` values."##, + label: "clippy::unwrap_or_default", + description: r##"Checks for usages of the following functions with an argument that constructs a default value +(e.g., `Default::default` or `String::new`): +- `unwrap_or` +- `unwrap_or_else` +- `or_insert` +- `or_insert_with`"##, }, Lint { label: "clippy::unwrap_used", - description: r##"Checks for `.unwrap()` calls on `Option`s and on `Result`s."##, + description: r##"Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s."##, }, Lint { label: "clippy::upper_case_acronyms", @@ -6890,7 +7454,7 @@ by nibble or byte."##, }, Lint { label: "clippy::use_debug", - description: r##"Checks for use of `Debug` formatting. The purpose of this + description: r##"Checks for usage of `Debug` formatting. The purpose of this lint is to catch debugging remnants."##, }, Lint { @@ -6913,10 +7477,17 @@ types before and after the call are the same."##, description: r##"Checks for `extern crate` and `use` items annotated with lint attributes. -This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]`, -`#[allow(unreachable_pub)]`, `#[allow(clippy::wildcard_imports)]` and -`#[allow(clippy::enum_glob_use)]` on `use` items and `#[allow(unused_imports)]` on -`extern crate` items with a `#[macro_use]` attribute."##, +This lint permits lint attributes for lints emitted on the items themself. +For `use` items these lints are: +* deprecated +* unreachable_pub +* unused_imports +* clippy::enum_glob_use +* clippy::macro_use_imports +* clippy::wildcard_imports + +For `extern crate` items these lints are: +* `unused_imports` on items with `#[macro_use]`"##, }, Lint { label: "clippy::useless_conversion", @@ -6940,17 +7511,24 @@ and transmutes that could be a cast."##, }, Lint { label: "clippy::useless_vec", - description: r##"Checks for usage of `&vec![..]` when using `&[..]` would + description: r##"Checks for usage of `vec![..]` when using `[..]` would be possible."##, }, Lint { label: "clippy::vec_box", - description: r##"Checks for use of `Vec>` where T: Sized anywhere in the code. + description: r##"Checks for usage of `Vec>` where T: Sized anywhere in the code. Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information."##, }, Lint { label: "clippy::vec_init_then_push", - description: r##"Checks for calls to `push` immediately after creating a new `Vec`."##, + description: r##"Checks for calls to `push` immediately after creating a new `Vec`. + +If the `Vec` is created using `with_capacity` this will only lint if the capacity is a +constant and the number of pushes is greater than or equal to the initial capacity. + +If the `Vec` is extended after the initial sequence of pushes and it was default initialized +then this will only lint after there were at least four pushes. This number may change in +the future."##, }, Lint { label: "clippy::vec_resize_to_zero", @@ -6963,7 +7541,7 @@ to `trailing_zeros`"##, }, Lint { label: "clippy::verbose_file_reads", - description: r##"Checks for use of File::read_to_end and File::read_to_string."##, + description: r##"Checks for usage of File::read_to_end and File::read_to_string."##, }, Lint { label: "clippy::vtable_address_comparisons", @@ -7020,18 +7598,19 @@ print a newline."##, }, Lint { label: "clippy::wrong_self_convention", - description: r##"Checks for methods with certain name prefixes and which -doesn't match how self is taken. The actual rules are: + description: r##"Checks for methods with certain name prefixes or suffixes, and which +do not adhere to standard conventions regarding how `self` is taken. +The actual rules are: -|Prefix |Postfix |`self` taken | `self` type | -|-------|------------|-----------------------|--------------| -|`as_` | none |`&self` or `&mut self` | any | -|`from_`| none | none | any | -|`into_`| none |`self` | any | -|`is_` | none |`&self` or none | any | -|`to_` | `_mut` |`&mut self` | any | -|`to_` | not `_mut` |`self` | `Copy` | -|`to_` | not `_mut` |`&self` | not `Copy` | +|Prefix |Postfix |`self` taken | `self` type | +|-------|------------|-------------------------------|--------------| +|`as_` | none |`&self` or `&mut self` | any | +|`from_`| none | none | any | +|`into_`| none |`self` | any | +|`is_` | none |`&mut self` or `&self` or none | any | +|`to_` | `_mut` |`&mut self` | any | +|`to_` | not `_mut` |`self` | `Copy` | +|`to_` | not `_mut` |`&self` | not `Copy` | Note: Clippy doesn't trigger methods with `to_` prefix in: - Traits definition. @@ -7086,15 +7665,18 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::complexity", - description: r##"lint group for: clippy::bind_instead_of_map, clippy::bool_comparison, clippy::borrowed_box, clippy::char_lit_as_u8, clippy::clone_on_copy, clippy::crosspointer_transmute, clippy::deprecated_cfg_attr, clippy::deref_addrof, clippy::derivable_impls, clippy::diverging_sub_expression, clippy::double_comparisons, clippy::double_parens, clippy::duration_subsec, clippy::explicit_counter_loop, clippy::explicit_write, clippy::extra_unused_lifetimes, clippy::filter_map_identity, clippy::filter_next, clippy::flat_map_identity, clippy::get_last_with_len, clippy::identity_op, clippy::inspect_for_each, clippy::int_plus_one, clippy::iter_count, clippy::manual_filter_map, clippy::manual_find_map, clippy::manual_flatten, clippy::manual_split_once, clippy::manual_strip, clippy::manual_swap, clippy::manual_unwrap_or, clippy::map_flatten, clippy::map_identity, clippy::match_as_ref, clippy::match_single_binding, clippy::needless_arbitrary_self_type, clippy::needless_bool, clippy::needless_borrowed_reference, clippy::needless_lifetimes, clippy::needless_option_as_deref, clippy::needless_question_mark, clippy::needless_splitn, clippy::needless_update, clippy::neg_cmp_op_on_partial_ord, clippy::no_effect, clippy::nonminimal_bool, clippy::option_as_ref_deref, clippy::option_filter_map, clippy::option_map_unit_fn, clippy::overflow_check_conditional, clippy::partialeq_ne_impl, clippy::precedence, clippy::ptr_offset_with_cast, clippy::range_zip_with_len, clippy::redundant_closure_call, clippy::redundant_slicing, clippy::ref_in_deref, clippy::repeat_once, clippy::result_map_unit_fn, clippy::search_is_some, clippy::short_circuit_statement, clippy::single_element_loop, clippy::skip_while_next, clippy::string_from_utf8_as_bytes, clippy::strlen_on_c_strings, clippy::temporary_assignment, clippy::too_many_arguments, clippy::transmute_bytes_to_str, clippy::transmute_float_to_int, clippy::transmute_int_to_bool, clippy::transmute_int_to_char, clippy::transmute_int_to_float, clippy::transmute_num_to_bytes, clippy::transmute_ptr_to_ref, clippy::transmutes_expressible_as_ptr_casts, clippy::type_complexity, clippy::unit_arg, clippy::unnecessary_cast, clippy::unnecessary_filter_map, clippy::unnecessary_operation, clippy::unnecessary_sort_by, clippy::unnecessary_unwrap, clippy::unneeded_wildcard_pattern, clippy::useless_asref, clippy::useless_conversion, clippy::useless_format, clippy::vec_box, clippy::while_let_loop, clippy::wildcard_in_or_patterns, clippy::zero_divided_by_zero, clippy::zero_prefixed_literal"##, + description: r##"lint group for: clippy::bind_instead_of_map, clippy::bool_comparison, clippy::borrow_deref_ref, clippy::borrowed_box, clippy::bytes_count_to_len, clippy::char_lit_as_u8, clippy::clone_on_copy, clippy::crosspointer_transmute, clippy::default_constructed_unit_structs, clippy::deprecated_cfg_attr, clippy::deref_addrof, clippy::derivable_impls, clippy::diverging_sub_expression, clippy::double_comparisons, clippy::double_parens, clippy::duration_subsec, clippy::excessive_nesting, clippy::explicit_auto_deref, clippy::explicit_counter_loop, clippy::explicit_write, clippy::extra_unused_lifetimes, clippy::extra_unused_type_parameters, clippy::filter_map_identity, clippy::filter_next, clippy::flat_map_identity, clippy::get_last_with_len, clippy::identity_op, clippy::inspect_for_each, clippy::int_plus_one, clippy::iter_count, clippy::iter_kv_map, clippy::let_with_type_underscore, clippy::manual_filter, clippy::manual_filter_map, clippy::manual_find, clippy::manual_find_map, clippy::manual_flatten, clippy::manual_hash_one, clippy::manual_main_separator_str, clippy::manual_range_patterns, clippy::manual_rem_euclid, clippy::manual_slice_size_calculation, clippy::manual_split_once, clippy::manual_strip, clippy::manual_swap, clippy::manual_unwrap_or, clippy::map_flatten, clippy::map_identity, clippy::match_as_ref, clippy::match_single_binding, clippy::needless_arbitrary_self_type, clippy::needless_bool, clippy::needless_bool_assign, clippy::needless_borrowed_reference, clippy::needless_if, clippy::needless_lifetimes, clippy::needless_match, clippy::needless_option_as_deref, clippy::needless_option_take, clippy::needless_question_mark, clippy::needless_splitn, clippy::needless_update, clippy::neg_cmp_op_on_partial_ord, clippy::no_effect, clippy::nonminimal_bool, clippy::only_used_in_recursion, clippy::option_as_ref_deref, clippy::option_filter_map, clippy::option_map_unit_fn, clippy::or_then_unwrap, clippy::overflow_check_conditional, clippy::partialeq_ne_impl, clippy::precedence, clippy::ptr_offset_with_cast, clippy::range_zip_with_len, clippy::redundant_as_str, clippy::redundant_async_block, clippy::redundant_at_rest_pattern, clippy::redundant_closure_call, clippy::redundant_guards, clippy::redundant_slicing, clippy::repeat_once, clippy::reserve_after_initialization, clippy::result_map_unit_fn, clippy::search_is_some, clippy::seek_from_current, clippy::seek_to_start_instead_of_rewind, clippy::short_circuit_statement, clippy::single_element_loop, clippy::skip_while_next, clippy::string_from_utf8_as_bytes, clippy::strlen_on_c_strings, clippy::temporary_assignment, clippy::too_many_arguments, clippy::transmute_bytes_to_str, clippy::transmute_float_to_int, clippy::transmute_int_to_bool, clippy::transmute_int_to_char, clippy::transmute_int_to_float, clippy::transmute_int_to_non_zero, clippy::transmute_num_to_bytes, clippy::transmute_ptr_to_ref, clippy::transmutes_expressible_as_ptr_casts, clippy::type_complexity, clippy::unit_arg, clippy::unnecessary_cast, clippy::unnecessary_filter_map, clippy::unnecessary_find_map, clippy::unnecessary_literal_unwrap, clippy::unnecessary_map_on_constructor, clippy::unnecessary_operation, clippy::unnecessary_sort_by, clippy::unnecessary_unwrap, clippy::unneeded_wildcard_pattern, clippy::unused_format_specs, clippy::useless_asref, clippy::useless_conversion, clippy::useless_format, clippy::useless_transmute, clippy::vec_box, clippy::while_let_loop, clippy::wildcard_in_or_patterns, clippy::zero_divided_by_zero, clippy::zero_prefixed_literal"##, }, children: &[ "clippy::bind_instead_of_map", "clippy::bool_comparison", + "clippy::borrow_deref_ref", "clippy::borrowed_box", + "clippy::bytes_count_to_len", "clippy::char_lit_as_u8", "clippy::clone_on_copy", "clippy::crosspointer_transmute", + "clippy::default_constructed_unit_structs", "clippy::deprecated_cfg_attr", "clippy::deref_addrof", "clippy::derivable_impls", @@ -7102,9 +7684,12 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::double_comparisons", "clippy::double_parens", "clippy::duration_subsec", + "clippy::excessive_nesting", + "clippy::explicit_auto_deref", "clippy::explicit_counter_loop", "clippy::explicit_write", "clippy::extra_unused_lifetimes", + "clippy::extra_unused_type_parameters", "clippy::filter_map_identity", "clippy::filter_next", "clippy::flat_map_identity", @@ -7113,9 +7698,18 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::inspect_for_each", "clippy::int_plus_one", "clippy::iter_count", + "clippy::iter_kv_map", + "clippy::let_with_type_underscore", + "clippy::manual_filter", "clippy::manual_filter_map", + "clippy::manual_find", "clippy::manual_find_map", "clippy::manual_flatten", + "clippy::manual_hash_one", + "clippy::manual_main_separator_str", + "clippy::manual_range_patterns", + "clippy::manual_rem_euclid", + "clippy::manual_slice_size_calculation", "clippy::manual_split_once", "clippy::manual_strip", "clippy::manual_swap", @@ -7126,29 +7720,41 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::match_single_binding", "clippy::needless_arbitrary_self_type", "clippy::needless_bool", + "clippy::needless_bool_assign", "clippy::needless_borrowed_reference", + "clippy::needless_if", "clippy::needless_lifetimes", + "clippy::needless_match", "clippy::needless_option_as_deref", + "clippy::needless_option_take", "clippy::needless_question_mark", "clippy::needless_splitn", "clippy::needless_update", "clippy::neg_cmp_op_on_partial_ord", "clippy::no_effect", "clippy::nonminimal_bool", + "clippy::only_used_in_recursion", "clippy::option_as_ref_deref", "clippy::option_filter_map", "clippy::option_map_unit_fn", + "clippy::or_then_unwrap", "clippy::overflow_check_conditional", "clippy::partialeq_ne_impl", "clippy::precedence", "clippy::ptr_offset_with_cast", "clippy::range_zip_with_len", + "clippy::redundant_as_str", + "clippy::redundant_async_block", + "clippy::redundant_at_rest_pattern", "clippy::redundant_closure_call", + "clippy::redundant_guards", "clippy::redundant_slicing", - "clippy::ref_in_deref", "clippy::repeat_once", + "clippy::reserve_after_initialization", "clippy::result_map_unit_fn", "clippy::search_is_some", + "clippy::seek_from_current", + "clippy::seek_to_start_instead_of_rewind", "clippy::short_circuit_statement", "clippy::single_element_loop", "clippy::skip_while_next", @@ -7161,6 +7767,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::transmute_int_to_bool", "clippy::transmute_int_to_char", "clippy::transmute_int_to_float", + "clippy::transmute_int_to_non_zero", "clippy::transmute_num_to_bytes", "clippy::transmute_ptr_to_ref", "clippy::transmutes_expressible_as_ptr_casts", @@ -7168,13 +7775,18 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::unit_arg", "clippy::unnecessary_cast", "clippy::unnecessary_filter_map", + "clippy::unnecessary_find_map", + "clippy::unnecessary_literal_unwrap", + "clippy::unnecessary_map_on_constructor", "clippy::unnecessary_operation", "clippy::unnecessary_sort_by", "clippy::unnecessary_unwrap", "clippy::unneeded_wildcard_pattern", + "clippy::unused_format_specs", "clippy::useless_asref", "clippy::useless_conversion", "clippy::useless_format", + "clippy::useless_transmute", "clippy::vec_box", "clippy::while_let_loop", "clippy::wildcard_in_or_patterns", @@ -7185,7 +7797,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::correctness", - description: r##"lint group for: clippy::absurd_extreme_comparisons, clippy::almost_swapped, clippy::approx_constant, clippy::async_yields_async, clippy::bad_bit_mask, clippy::cast_ref_to_mut, clippy::clone_double_ref, clippy::cmp_nan, clippy::deprecated_semver, clippy::derive_hash_xor_eq, clippy::derive_ord_xor_partial_ord, clippy::drop_copy, clippy::drop_ref, clippy::enum_clike_unportable_variant, clippy::eq_op, clippy::erasing_op, clippy::fn_address_comparisons, clippy::forget_copy, clippy::forget_ref, clippy::if_let_mutex, clippy::if_same_then_else, clippy::ifs_same_cond, clippy::ineffective_bit_mask, clippy::infinite_iter, clippy::inherent_to_string_shadow_display, clippy::inline_fn_without_body, clippy::invalid_null_ptr_usage, clippy::invalid_regex, clippy::invisible_characters, clippy::iter_next_loop, clippy::iterator_step_by_zero, clippy::let_underscore_lock, clippy::logic_bug, clippy::match_str_case_mismatch, clippy::mem_replace_with_uninit, clippy::min_max, clippy::mismatched_target_os, clippy::mistyped_literal_suffixes, clippy::modulo_one, clippy::mut_from_ref, clippy::never_loop, clippy::non_octal_unix_permissions, clippy::nonsensical_open_options, clippy::not_unsafe_ptr_arg_deref, clippy::option_env_unwrap, clippy::out_of_bounds_indexing, clippy::panicking_unwrap, clippy::possible_missing_comma, clippy::reversed_empty_ranges, clippy::self_assignment, clippy::serde_api_misuse, clippy::size_of_in_element_count, clippy::suspicious_splitn, clippy::to_string_in_display, clippy::transmuting_null, clippy::undropped_manually_drops, clippy::uninit_assumed_init, clippy::uninit_vec, clippy::unit_cmp, clippy::unit_hash, clippy::unit_return_expecting_ord, clippy::unsound_collection_transmute, clippy::unused_io_amount, clippy::useless_attribute, clippy::vec_resize_to_zero, clippy::vtable_address_comparisons, clippy::while_immutable_condition, clippy::wrong_transmute, clippy::zst_offset"##, + description: r##"lint group for: clippy::absurd_extreme_comparisons, clippy::almost_swapped, clippy::approx_constant, clippy::async_yields_async, clippy::bad_bit_mask, clippy::cast_slice_different_sizes, clippy::deprecated_semver, clippy::derive_ord_xor_partial_ord, clippy::derived_hash_with_manual_eq, clippy::enum_clike_unportable_variant, clippy::eq_op, clippy::erasing_op, clippy::fn_address_comparisons, clippy::if_let_mutex, clippy::if_same_then_else, clippy::ifs_same_cond, clippy::impossible_comparisons, clippy::ineffective_bit_mask, clippy::infinite_iter, clippy::inherent_to_string_shadow_display, clippy::inline_fn_without_body, clippy::invalid_null_ptr_usage, clippy::invalid_regex, clippy::invisible_characters, clippy::iter_next_loop, clippy::iter_skip_zero, clippy::iterator_step_by_zero, clippy::let_underscore_lock, clippy::match_str_case_mismatch, clippy::mem_replace_with_uninit, clippy::min_max, clippy::mismatched_target_os, clippy::mistyped_literal_suffixes, clippy::modulo_one, clippy::mut_from_ref, clippy::never_loop, clippy::non_octal_unix_permissions, clippy::nonsensical_open_options, clippy::not_unsafe_ptr_arg_deref, clippy::option_env_unwrap, clippy::out_of_bounds_indexing, clippy::overly_complex_bool_expr, clippy::panicking_unwrap, clippy::possible_missing_comma, clippy::read_line_without_trim, clippy::read_zero_byte_vec, clippy::recursive_format_impl, clippy::redundant_comparisons, clippy::redundant_locals, clippy::reversed_empty_ranges, clippy::self_assignment, clippy::serde_api_misuse, clippy::size_of_in_element_count, clippy::suspicious_splitn, clippy::transmute_null_to_fn, clippy::transmuting_null, clippy::uninit_assumed_init, clippy::uninit_vec, clippy::unit_cmp, clippy::unit_hash, clippy::unit_return_expecting_ord, clippy::unsound_collection_transmute, clippy::unused_io_amount, clippy::useless_attribute, clippy::vec_resize_to_zero, clippy::vtable_address_comparisons, clippy::while_immutable_condition, clippy::wrong_transmute, clippy::zst_offset"##, }, children: &[ "clippy::absurd_extreme_comparisons", @@ -7193,23 +7805,18 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::approx_constant", "clippy::async_yields_async", "clippy::bad_bit_mask", - "clippy::cast_ref_to_mut", - "clippy::clone_double_ref", - "clippy::cmp_nan", + "clippy::cast_slice_different_sizes", "clippy::deprecated_semver", - "clippy::derive_hash_xor_eq", "clippy::derive_ord_xor_partial_ord", - "clippy::drop_copy", - "clippy::drop_ref", + "clippy::derived_hash_with_manual_eq", "clippy::enum_clike_unportable_variant", "clippy::eq_op", "clippy::erasing_op", "clippy::fn_address_comparisons", - "clippy::forget_copy", - "clippy::forget_ref", "clippy::if_let_mutex", "clippy::if_same_then_else", "clippy::ifs_same_cond", + "clippy::impossible_comparisons", "clippy::ineffective_bit_mask", "clippy::infinite_iter", "clippy::inherent_to_string_shadow_display", @@ -7218,9 +7825,9 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::invalid_regex", "clippy::invisible_characters", "clippy::iter_next_loop", + "clippy::iter_skip_zero", "clippy::iterator_step_by_zero", "clippy::let_underscore_lock", - "clippy::logic_bug", "clippy::match_str_case_mismatch", "clippy::mem_replace_with_uninit", "clippy::min_max", @@ -7234,16 +7841,21 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::not_unsafe_ptr_arg_deref", "clippy::option_env_unwrap", "clippy::out_of_bounds_indexing", + "clippy::overly_complex_bool_expr", "clippy::panicking_unwrap", "clippy::possible_missing_comma", + "clippy::read_line_without_trim", + "clippy::read_zero_byte_vec", + "clippy::recursive_format_impl", + "clippy::redundant_comparisons", + "clippy::redundant_locals", "clippy::reversed_empty_ranges", "clippy::self_assignment", "clippy::serde_api_misuse", "clippy::size_of_in_element_count", "clippy::suspicious_splitn", - "clippy::to_string_in_display", + "clippy::transmute_null_to_fn", "clippy::transmuting_null", - "clippy::undropped_manually_drops", "clippy::uninit_assumed_init", "clippy::uninit_vec", "clippy::unit_cmp", @@ -7286,45 +7898,65 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::nursery", - description: r##"lint group for: clippy::branches_sharing_code, clippy::cognitive_complexity, clippy::debug_assert_with_mut_call, clippy::disallowed_methods, clippy::disallowed_types, clippy::empty_line_after_outer_attr, clippy::equatable_if_let, clippy::fallible_impl_from, clippy::future_not_send, clippy::imprecise_flops, clippy::index_refutable_slice, clippy::missing_const_for_fn, clippy::mutex_integer, clippy::non_send_fields_in_send_ty, clippy::nonstandard_macro_braces, clippy::option_if_let_else, clippy::path_buf_push_overwrite, clippy::redundant_pub_crate, clippy::string_lit_as_bytes, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::trailing_empty_array, clippy::trivial_regex, clippy::use_self, clippy::useless_let_if_seq, clippy::useless_transmute"##, + description: r##"lint group for: clippy::as_ptr_cast_mut, clippy::branches_sharing_code, clippy::clear_with_drain, clippy::cognitive_complexity, clippy::collection_is_never_read, clippy::debug_assert_with_mut_call, clippy::derive_partial_eq_without_eq, clippy::empty_line_after_doc_comments, clippy::empty_line_after_outer_attr, clippy::equatable_if_let, clippy::fallible_impl_from, clippy::future_not_send, clippy::implied_bounds_in_impls, clippy::imprecise_flops, clippy::iter_on_empty_collections, clippy::iter_on_single_items, clippy::iter_with_drain, clippy::large_stack_frames, clippy::manual_clamp, clippy::missing_const_for_fn, clippy::mutex_integer, clippy::needless_collect, clippy::non_send_fields_in_send_ty, clippy::nonstandard_macro_braces, clippy::option_if_let_else, clippy::or_fun_call, clippy::path_buf_push_overwrite, clippy::readonly_write_lock, clippy::redundant_clone, clippy::redundant_pub_crate, clippy::significant_drop_in_scrutinee, clippy::significant_drop_tightening, clippy::string_lit_as_bytes, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::trailing_empty_array, clippy::trait_duplication_in_bounds, clippy::transmute_undefined_repr, clippy::trivial_regex, clippy::tuple_array_conversions, clippy::type_repetition_in_bounds, clippy::unnecessary_struct_initialization, clippy::unused_peekable, clippy::unused_rounding, clippy::use_self, clippy::useless_let_if_seq"##, }, children: &[ + "clippy::as_ptr_cast_mut", "clippy::branches_sharing_code", + "clippy::clear_with_drain", "clippy::cognitive_complexity", + "clippy::collection_is_never_read", "clippy::debug_assert_with_mut_call", - "clippy::disallowed_methods", - "clippy::disallowed_types", + "clippy::derive_partial_eq_without_eq", + "clippy::empty_line_after_doc_comments", "clippy::empty_line_after_outer_attr", "clippy::equatable_if_let", "clippy::fallible_impl_from", "clippy::future_not_send", + "clippy::implied_bounds_in_impls", "clippy::imprecise_flops", - "clippy::index_refutable_slice", + "clippy::iter_on_empty_collections", + "clippy::iter_on_single_items", + "clippy::iter_with_drain", + "clippy::large_stack_frames", + "clippy::manual_clamp", "clippy::missing_const_for_fn", "clippy::mutex_integer", + "clippy::needless_collect", "clippy::non_send_fields_in_send_ty", "clippy::nonstandard_macro_braces", "clippy::option_if_let_else", + "clippy::or_fun_call", "clippy::path_buf_push_overwrite", + "clippy::readonly_write_lock", + "clippy::redundant_clone", "clippy::redundant_pub_crate", + "clippy::significant_drop_in_scrutinee", + "clippy::significant_drop_tightening", "clippy::string_lit_as_bytes", "clippy::suboptimal_flops", "clippy::suspicious_operation_groupings", "clippy::trailing_empty_array", + "clippy::trait_duplication_in_bounds", + "clippy::transmute_undefined_repr", "clippy::trivial_regex", + "clippy::tuple_array_conversions", + "clippy::type_repetition_in_bounds", + "clippy::unnecessary_struct_initialization", + "clippy::unused_peekable", + "clippy::unused_rounding", "clippy::use_self", "clippy::useless_let_if_seq", - "clippy::useless_transmute", ], }, LintGroup { lint: Lint { label: "clippy::pedantic", - description: r##"lint group for: clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::implicit_clone, clippy::implicit_hasher, clippy::implicit_saturating_sub, clippy::inconsistent_struct_constructor, clippy::inefficient_to_string, clippy::inline_always, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_not_returning_iterator, clippy::large_digit_groups, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::let_underscore_drop, clippy::let_unit_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_ok_or, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::no_effect_underscore_binding, clippy::option_option, clippy::ptr_as_ptr, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::similar_names, clippy::single_match_else, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::too_many_lines, clippy::trait_duplication_in_bounds, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::type_repetition_in_bounds, clippy::unicode_not_nfc, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, + description: r##"lint group for: clippy::bool_to_int_with_if, clippy::borrow_as_ptr, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_link_with_quotes, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::ignored_unit_patterns, clippy::implicit_clone, clippy::implicit_hasher, clippy::inconsistent_struct_constructor, clippy::index_refutable_slice, clippy::inefficient_to_string, clippy::inline_always, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_not_returning_iterator, clippy::large_digit_groups, clippy::large_futures, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_instant_elapsed, clippy::manual_let_else, clippy::manual_ok_or, clippy::manual_string_new, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::mismatching_type_param_order, clippy::missing_errors_doc, clippy::missing_fields_in_debug, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::needless_raw_string_hashes, clippy::no_effect_underscore_binding, clippy::no_mangle_with_rust_abi, clippy::option_option, clippy::ptr_as_ptr, clippy::ptr_cast_constness, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::return_self_not_must_use, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::should_panic_without_expect, clippy::similar_names, clippy::single_match_else, clippy::stable_sort_primitive, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::too_many_lines, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::unchecked_duration_subtraction, clippy::unicode_not_nfc, clippy::uninlined_format_args, clippy::unnecessary_box_returns, clippy::unnecessary_join, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, }, children: &[ - "clippy::await_holding_lock", - "clippy::await_holding_refcell_ref", + "clippy::bool_to_int_with_if", + "clippy::borrow_as_ptr", "clippy::case_sensitive_file_extension_comparisons", "clippy::cast_lossless", "clippy::cast_possible_truncation", @@ -7336,6 +7968,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::cloned_instead_of_copied", "clippy::copy_iterator", "clippy::default_trait_access", + "clippy::doc_link_with_quotes", "clippy::doc_markdown", "clippy::empty_enum", "clippy::enum_glob_use", @@ -7349,24 +7982,27 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::fn_params_excessive_bools", "clippy::from_iter_instead_of_collect", "clippy::if_not_else", + "clippy::ignored_unit_patterns", "clippy::implicit_clone", "clippy::implicit_hasher", - "clippy::implicit_saturating_sub", "clippy::inconsistent_struct_constructor", + "clippy::index_refutable_slice", "clippy::inefficient_to_string", "clippy::inline_always", "clippy::invalid_upcast_comparisons", "clippy::items_after_statements", "clippy::iter_not_returning_iterator", "clippy::large_digit_groups", + "clippy::large_futures", "clippy::large_stack_arrays", "clippy::large_types_passed_by_value", - "clippy::let_underscore_drop", - "clippy::let_unit_value", "clippy::linkedlist", "clippy::macro_use_imports", "clippy::manual_assert", + "clippy::manual_instant_elapsed", + "clippy::manual_let_else", "clippy::manual_ok_or", + "clippy::manual_string_new", "clippy::many_single_char_names", "clippy::map_unwrap_or", "clippy::match_bool", @@ -7375,7 +8011,9 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::match_wild_err_arm", "clippy::match_wildcard_for_single_variants", "clippy::maybe_infinite_iter", + "clippy::mismatching_type_param_order", "clippy::missing_errors_doc", + "clippy::missing_fields_in_debug", "clippy::missing_panics_doc", "clippy::module_name_repetitions", "clippy::must_use_candidate", @@ -7385,27 +8023,35 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::needless_continue", "clippy::needless_for_each", "clippy::needless_pass_by_value", + "clippy::needless_raw_string_hashes", "clippy::no_effect_underscore_binding", + "clippy::no_mangle_with_rust_abi", "clippy::option_option", "clippy::ptr_as_ptr", + "clippy::ptr_cast_constness", "clippy::range_minus_one", "clippy::range_plus_one", "clippy::redundant_closure_for_method_calls", "clippy::redundant_else", "clippy::ref_binding_to_reference", "clippy::ref_option_ref", + "clippy::return_self_not_must_use", "clippy::same_functions_in_if_condition", "clippy::semicolon_if_nothing_returned", + "clippy::should_panic_without_expect", "clippy::similar_names", "clippy::single_match_else", + "clippy::stable_sort_primitive", "clippy::string_add_assign", "clippy::struct_excessive_bools", "clippy::too_many_lines", - "clippy::trait_duplication_in_bounds", "clippy::transmute_ptr_to_ptr", "clippy::trivially_copy_pass_by_ref", - "clippy::type_repetition_in_bounds", + "clippy::unchecked_duration_subtraction", "clippy::unicode_not_nfc", + "clippy::uninlined_format_args", + "clippy::unnecessary_box_returns", + "clippy::unnecessary_join", "clippy::unnecessary_wraps", "clippy::unnested_or_patterns", "clippy::unreadable_literal", @@ -7421,29 +8067,33 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::perf", - description: r##"lint group for: clippy::box_collection, clippy::boxed_local, clippy::cmp_owned, clippy::expect_fun_call, clippy::extend_with_drain, clippy::format_in_format_args, clippy::iter_nth, clippy::large_const_arrays, clippy::large_enum_variant, clippy::manual_memcpy, clippy::manual_str_repeat, clippy::map_entry, clippy::mutex_atomic, clippy::needless_collect, clippy::or_fun_call, clippy::redundant_allocation, clippy::redundant_clone, clippy::single_char_pattern, clippy::slow_vector_initialization, clippy::stable_sort_primitive, clippy::to_string_in_format_args, clippy::unnecessary_to_owned, clippy::useless_vec, clippy::vec_init_then_push"##, + description: r##"lint group for: clippy::box_collection, clippy::box_default, clippy::boxed_local, clippy::cmp_owned, clippy::collapsible_str_replace, clippy::drain_collect, clippy::expect_fun_call, clippy::extend_with_drain, clippy::format_collect, clippy::format_in_format_args, clippy::iter_nth, clippy::iter_overeager_cloned, clippy::large_const_arrays, clippy::large_enum_variant, clippy::manual_memcpy, clippy::manual_retain, clippy::manual_str_repeat, clippy::manual_try_fold, clippy::map_entry, clippy::missing_spin_loop, clippy::redundant_allocation, clippy::result_large_err, clippy::single_char_pattern, clippy::slow_vector_initialization, clippy::to_string_in_format_args, clippy::unnecessary_to_owned, clippy::useless_vec, clippy::vec_init_then_push"##, }, children: &[ "clippy::box_collection", + "clippy::box_default", "clippy::boxed_local", "clippy::cmp_owned", + "clippy::collapsible_str_replace", + "clippy::drain_collect", "clippy::expect_fun_call", "clippy::extend_with_drain", + "clippy::format_collect", "clippy::format_in_format_args", "clippy::iter_nth", + "clippy::iter_overeager_cloned", "clippy::large_const_arrays", "clippy::large_enum_variant", "clippy::manual_memcpy", + "clippy::manual_retain", "clippy::manual_str_repeat", + "clippy::manual_try_fold", "clippy::map_entry", - "clippy::mutex_atomic", - "clippy::needless_collect", - "clippy::or_fun_call", + "clippy::missing_spin_loop", "clippy::redundant_allocation", - "clippy::redundant_clone", + "clippy::result_large_err", "clippy::single_char_pattern", "clippy::slow_vector_initialization", - "clippy::stable_sort_primitive", "clippy::to_string_in_format_args", "clippy::unnecessary_to_owned", "clippy::useless_vec", @@ -7453,17 +8103,30 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::restriction", - description: r##"lint group for: clippy::as_conversions, clippy::clone_on_ref_ptr, clippy::create_dir, clippy::dbg_macro, clippy::decimal_literal_representation, clippy::default_numeric_fallback, clippy::disallowed_script_idents, clippy::else_if_without_else, clippy::exhaustive_enums, clippy::exhaustive_structs, clippy::exit, clippy::expect_used, clippy::filetype_is_file, clippy::float_arithmetic, clippy::float_cmp_const, clippy::fn_to_numeric_cast_any, clippy::get_unwrap, clippy::if_then_some_else_none, clippy::implicit_return, clippy::indexing_slicing, clippy::inline_asm_x86_att_syntax, clippy::inline_asm_x86_intel_syntax, clippy::integer_arithmetic, clippy::integer_division, clippy::let_underscore_must_use, clippy::lossy_float_literal, clippy::map_err_ignore, clippy::mem_forget, clippy::missing_docs_in_private_items, clippy::missing_enforced_import_renames, clippy::missing_inline_in_public_items, clippy::mod_module_files, clippy::modulo_arithmetic, clippy::multiple_inherent_impl, clippy::non_ascii_literal, clippy::panic, clippy::panic_in_result_fn, clippy::pattern_type_mismatch, clippy::print_stderr, clippy::print_stdout, clippy::rc_buffer, clippy::rc_mutex, clippy::rest_pat_in_fully_bound_structs, clippy::same_name_method, clippy::self_named_module_files, clippy::separated_literal_suffix, clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated, clippy::str_to_string, clippy::string_add, clippy::string_slice, clippy::string_to_string, clippy::todo, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnecessary_self_imports, clippy::unneeded_field_pattern, clippy::unreachable, clippy::unseparated_literal_suffix, clippy::unwrap_in_result, clippy::unwrap_used, clippy::use_debug, clippy::verbose_file_reads, clippy::wildcard_enum_match_arm"##, + description: r##"lint group for: clippy::absolute_paths, clippy::alloc_instead_of_core, clippy::allow_attributes, clippy::allow_attributes_without_reason, clippy::arithmetic_side_effects, clippy::as_conversions, clippy::as_underscore, clippy::assertions_on_result_states, clippy::big_endian_bytes, clippy::clone_on_ref_ptr, clippy::create_dir, clippy::dbg_macro, clippy::decimal_literal_representation, clippy::default_numeric_fallback, clippy::default_union_representation, clippy::deref_by_slicing, clippy::disallowed_script_idents, clippy::else_if_without_else, clippy::empty_drop, clippy::empty_structs_with_brackets, clippy::error_impl_error, clippy::exhaustive_enums, clippy::exhaustive_structs, clippy::exit, clippy::expect_used, clippy::filetype_is_file, clippy::float_arithmetic, clippy::float_cmp_const, clippy::fn_to_numeric_cast_any, clippy::format_push_string, clippy::get_unwrap, clippy::host_endian_bytes, clippy::if_then_some_else_none, clippy::impl_trait_in_params, clippy::implicit_return, clippy::indexing_slicing, clippy::inline_asm_x86_att_syntax, clippy::inline_asm_x86_intel_syntax, clippy::integer_division, clippy::large_include_file, clippy::let_underscore_must_use, clippy::let_underscore_untyped, clippy::little_endian_bytes, clippy::lossy_float_literal, clippy::map_err_ignore, clippy::mem_forget, clippy::min_ident_chars, clippy::missing_assert_message, clippy::missing_asserts_for_indexing, clippy::missing_docs_in_private_items, clippy::missing_enforced_import_renames, clippy::missing_inline_in_public_items, clippy::missing_trait_methods, clippy::mixed_read_write_in_expression, clippy::mod_module_files, clippy::modulo_arithmetic, clippy::multiple_inherent_impl, clippy::multiple_unsafe_ops_per_block, clippy::mutex_atomic, clippy::needless_raw_strings, clippy::non_ascii_literal, clippy::panic, clippy::panic_in_result_fn, clippy::partial_pub_fields, clippy::pattern_type_mismatch, clippy::print_stderr, clippy::print_stdout, clippy::pub_use, clippy::pub_with_shorthand, clippy::pub_without_shorthand, clippy::question_mark_used, clippy::rc_buffer, clippy::rc_mutex, clippy::redundant_type_annotations, clippy::ref_patterns, clippy::rest_pat_in_fully_bound_structs, clippy::same_name_method, clippy::self_named_module_files, clippy::semicolon_inside_block, clippy::semicolon_outside_block, clippy::separated_literal_suffix, clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated, clippy::single_call_fn, clippy::single_char_lifetime_names, clippy::std_instead_of_alloc, clippy::std_instead_of_core, clippy::str_to_string, clippy::string_add, clippy::string_lit_chars_any, clippy::string_slice, clippy::string_to_string, clippy::suspicious_xor_used_as_pow, clippy::tests_outside_test_module, clippy::todo, clippy::try_err, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnecessary_safety_comment, clippy::unnecessary_safety_doc, clippy::unnecessary_self_imports, clippy::unneeded_field_pattern, clippy::unreachable, clippy::unseparated_literal_suffix, clippy::unwrap_in_result, clippy::unwrap_used, clippy::use_debug, clippy::verbose_file_reads, clippy::wildcard_enum_match_arm"##, }, children: &[ + "clippy::absolute_paths", + "clippy::alloc_instead_of_core", + "clippy::allow_attributes", + "clippy::allow_attributes_without_reason", + "clippy::arithmetic_side_effects", "clippy::as_conversions", + "clippy::as_underscore", + "clippy::assertions_on_result_states", + "clippy::big_endian_bytes", "clippy::clone_on_ref_ptr", "clippy::create_dir", "clippy::dbg_macro", "clippy::decimal_literal_representation", "clippy::default_numeric_fallback", + "clippy::default_union_representation", + "clippy::deref_by_slicing", "clippy::disallowed_script_idents", "clippy::else_if_without_else", + "clippy::empty_drop", + "clippy::empty_structs_with_brackets", + "clippy::error_impl_error", "clippy::exhaustive_enums", "clippy::exhaustive_structs", "clippy::exit", @@ -7472,46 +8135,78 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::float_arithmetic", "clippy::float_cmp_const", "clippy::fn_to_numeric_cast_any", + "clippy::format_push_string", "clippy::get_unwrap", + "clippy::host_endian_bytes", "clippy::if_then_some_else_none", + "clippy::impl_trait_in_params", "clippy::implicit_return", "clippy::indexing_slicing", "clippy::inline_asm_x86_att_syntax", "clippy::inline_asm_x86_intel_syntax", - "clippy::integer_arithmetic", "clippy::integer_division", + "clippy::large_include_file", "clippy::let_underscore_must_use", + "clippy::let_underscore_untyped", + "clippy::little_endian_bytes", "clippy::lossy_float_literal", "clippy::map_err_ignore", "clippy::mem_forget", + "clippy::min_ident_chars", + "clippy::missing_assert_message", + "clippy::missing_asserts_for_indexing", "clippy::missing_docs_in_private_items", "clippy::missing_enforced_import_renames", "clippy::missing_inline_in_public_items", + "clippy::missing_trait_methods", + "clippy::mixed_read_write_in_expression", "clippy::mod_module_files", "clippy::modulo_arithmetic", "clippy::multiple_inherent_impl", + "clippy::multiple_unsafe_ops_per_block", + "clippy::mutex_atomic", + "clippy::needless_raw_strings", "clippy::non_ascii_literal", "clippy::panic", "clippy::panic_in_result_fn", + "clippy::partial_pub_fields", "clippy::pattern_type_mismatch", "clippy::print_stderr", "clippy::print_stdout", + "clippy::pub_use", + "clippy::pub_with_shorthand", + "clippy::pub_without_shorthand", + "clippy::question_mark_used", "clippy::rc_buffer", "clippy::rc_mutex", + "clippy::redundant_type_annotations", + "clippy::ref_patterns", "clippy::rest_pat_in_fully_bound_structs", "clippy::same_name_method", "clippy::self_named_module_files", + "clippy::semicolon_inside_block", + "clippy::semicolon_outside_block", "clippy::separated_literal_suffix", "clippy::shadow_reuse", "clippy::shadow_same", "clippy::shadow_unrelated", + "clippy::single_call_fn", + "clippy::single_char_lifetime_names", + "clippy::std_instead_of_alloc", + "clippy::std_instead_of_core", "clippy::str_to_string", "clippy::string_add", + "clippy::string_lit_chars_any", "clippy::string_slice", "clippy::string_to_string", + "clippy::suspicious_xor_used_as_pow", + "clippy::tests_outside_test_module", "clippy::todo", + "clippy::try_err", "clippy::undocumented_unsafe_blocks", "clippy::unimplemented", + "clippy::unnecessary_safety_comment", + "clippy::unnecessary_safety_doc", "clippy::unnecessary_self_imports", "clippy::unneeded_field_pattern", "clippy::unreachable", @@ -7526,12 +8221,11 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::style", - description: r##"lint group for: clippy::assertions_on_constants, clippy::assign_op_pattern, clippy::blacklisted_name, clippy::blocks_in_if_conditions, clippy::bool_assert_comparison, clippy::borrow_interior_mutable_const, clippy::builtin_type_shadow, clippy::bytes_nth, clippy::chars_last_cmp, clippy::chars_next_cmp, clippy::cmp_null, clippy::collapsible_else_if, clippy::collapsible_if, clippy::collapsible_match, clippy::comparison_chain, clippy::comparison_to_empty, clippy::declare_interior_mutable_const, clippy::double_must_use, clippy::double_neg, clippy::duplicate_underscore_argument, clippy::enum_variant_names, clippy::excessive_precision, clippy::field_reassign_with_default, clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation, clippy::for_kv_map, clippy::from_over_into, clippy::from_str_radix_10, clippy::inconsistent_digit_grouping, clippy::infallible_destructuring_match, clippy::inherent_to_string, clippy::into_iter_on_ref, clippy::iter_cloned_collect, clippy::iter_next_slice, clippy::iter_nth_zero, clippy::iter_skip_next, clippy::just_underscores_and_digits, clippy::len_without_is_empty, clippy::len_zero, clippy::let_and_return, clippy::main_recursion, clippy::manual_async_fn, clippy::manual_map, clippy::manual_non_exhaustive, clippy::manual_range_contains, clippy::manual_saturating_arithmetic, clippy::map_clone, clippy::map_collect_result_unit, clippy::match_like_matches_macro, clippy::match_overlapping_arm, clippy::match_ref_pats, clippy::match_result_ok, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default, clippy::missing_safety_doc, clippy::mixed_case_hex_literals, clippy::module_inception, clippy::must_use_unit, clippy::mut_mutex_lock, clippy::needless_borrow, clippy::needless_doctest_main, clippy::needless_late_init, clippy::needless_range_loop, clippy::needless_return, clippy::neg_multiply, clippy::new_ret_no_self, clippy::new_without_default, clippy::ok_expect, clippy::op_ref, clippy::option_map_or_none, clippy::print_literal, clippy::print_with_newline, clippy::println_empty_string, clippy::ptr_arg, clippy::ptr_eq, clippy::question_mark, clippy::redundant_closure, clippy::redundant_field_names, clippy::redundant_pattern, clippy::redundant_pattern_matching, clippy::redundant_static_lifetimes, clippy::result_map_or_into_option, clippy::result_unit_err, clippy::same_item_push, clippy::self_named_constructors, clippy::should_implement_trait, clippy::single_char_add_str, clippy::single_component_path_imports, clippy::single_match, clippy::string_extend_chars, clippy::tabs_in_doc_comments, clippy::to_digit_is_some, clippy::toplevel_ref_arg, clippy::try_err, clippy::unnecessary_fold, clippy::unnecessary_lazy_evaluations, clippy::unnecessary_mut_passed, clippy::unsafe_removed_from_name, clippy::unused_unit, clippy::unusual_byte_groupings, clippy::unwrap_or_else_default, clippy::upper_case_acronyms, clippy::while_let_on_iterator, clippy::write_literal, clippy::write_with_newline, clippy::writeln_empty_string, clippy::wrong_self_convention, clippy::zero_ptr"##, + description: r##"lint group for: clippy::assertions_on_constants, clippy::assign_op_pattern, clippy::blocks_in_if_conditions, clippy::bool_assert_comparison, clippy::borrow_interior_mutable_const, clippy::builtin_type_shadow, clippy::bytes_nth, clippy::chars_last_cmp, clippy::chars_next_cmp, clippy::cmp_null, clippy::collapsible_else_if, clippy::collapsible_if, clippy::collapsible_match, clippy::comparison_chain, clippy::comparison_to_empty, clippy::declare_interior_mutable_const, clippy::default_instead_of_iter_empty, clippy::disallowed_macros, clippy::disallowed_methods, clippy::disallowed_names, clippy::disallowed_types, clippy::double_must_use, clippy::double_neg, clippy::duplicate_underscore_argument, clippy::enum_variant_names, clippy::err_expect, clippy::excessive_precision, clippy::field_reassign_with_default, clippy::filter_map_bool_then, clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation, clippy::for_kv_map, clippy::from_over_into, clippy::from_str_radix_10, clippy::get_first, clippy::implicit_saturating_add, clippy::implicit_saturating_sub, clippy::inconsistent_digit_grouping, clippy::infallible_destructuring_match, clippy::inherent_to_string, clippy::init_numbered_fields, clippy::into_iter_on_ref, clippy::is_digit_ascii_radix, clippy::items_after_test_module, clippy::iter_cloned_collect, clippy::iter_next_slice, clippy::iter_nth_zero, clippy::iter_skip_next, clippy::just_underscores_and_digits, clippy::len_without_is_empty, clippy::len_zero, clippy::let_and_return, clippy::let_unit_value, clippy::main_recursion, clippy::manual_async_fn, clippy::manual_bits, clippy::manual_is_ascii_check, clippy::manual_is_finite, clippy::manual_is_infinite, clippy::manual_map, clippy::manual_next_back, clippy::manual_non_exhaustive, clippy::manual_range_contains, clippy::manual_saturating_arithmetic, clippy::manual_while_let_some, clippy::map_clone, clippy::map_collect_result_unit, clippy::match_like_matches_macro, clippy::match_overlapping_arm, clippy::match_ref_pats, clippy::match_result_ok, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default, clippy::missing_safety_doc, clippy::mixed_case_hex_literals, clippy::module_inception, clippy::must_use_unit, clippy::mut_mutex_lock, clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::needless_doctest_main, clippy::needless_else, clippy::needless_late_init, clippy::needless_parens_on_range_literals, clippy::needless_pub_self, clippy::needless_range_loop, clippy::needless_return, clippy::needless_return_with_question_mark, clippy::neg_multiply, clippy::new_ret_no_self, clippy::new_without_default, clippy::non_minimal_cfg, clippy::obfuscated_if_else, clippy::ok_expect, clippy::op_ref, clippy::option_map_or_none, clippy::partialeq_to_none, clippy::print_literal, clippy::print_with_newline, clippy::println_empty_string, clippy::ptr_arg, clippy::ptr_eq, clippy::question_mark, clippy::redundant_closure, clippy::redundant_field_names, clippy::redundant_pattern, clippy::redundant_pattern_matching, clippy::redundant_static_lifetimes, clippy::result_map_or_into_option, clippy::result_unit_err, clippy::same_item_push, clippy::self_named_constructors, clippy::should_implement_trait, clippy::single_char_add_str, clippy::single_component_path_imports, clippy::single_match, clippy::string_extend_chars, clippy::tabs_in_doc_comments, clippy::to_digit_is_some, clippy::toplevel_ref_arg, clippy::trim_split_whitespace, clippy::unnecessary_fold, clippy::unnecessary_lazy_evaluations, clippy::unnecessary_mut_passed, clippy::unnecessary_owned_empty_strings, clippy::unsafe_removed_from_name, clippy::unused_unit, clippy::unusual_byte_groupings, clippy::unwrap_or_default, clippy::upper_case_acronyms, clippy::while_let_on_iterator, clippy::write_literal, clippy::write_with_newline, clippy::writeln_empty_string, clippy::wrong_self_convention, clippy::zero_ptr"##, }, children: &[ "clippy::assertions_on_constants", "clippy::assign_op_pattern", - "clippy::blacklisted_name", "clippy::blocks_in_if_conditions", "clippy::bool_assert_comparison", "clippy::borrow_interior_mutable_const", @@ -7546,21 +8240,34 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::comparison_chain", "clippy::comparison_to_empty", "clippy::declare_interior_mutable_const", + "clippy::default_instead_of_iter_empty", + "clippy::disallowed_macros", + "clippy::disallowed_methods", + "clippy::disallowed_names", + "clippy::disallowed_types", "clippy::double_must_use", "clippy::double_neg", "clippy::duplicate_underscore_argument", "clippy::enum_variant_names", + "clippy::err_expect", "clippy::excessive_precision", "clippy::field_reassign_with_default", + "clippy::filter_map_bool_then", "clippy::fn_to_numeric_cast", "clippy::fn_to_numeric_cast_with_truncation", "clippy::for_kv_map", "clippy::from_over_into", "clippy::from_str_radix_10", + "clippy::get_first", + "clippy::implicit_saturating_add", + "clippy::implicit_saturating_sub", "clippy::inconsistent_digit_grouping", "clippy::infallible_destructuring_match", "clippy::inherent_to_string", + "clippy::init_numbered_fields", "clippy::into_iter_on_ref", + "clippy::is_digit_ascii_radix", + "clippy::items_after_test_module", "clippy::iter_cloned_collect", "clippy::iter_next_slice", "clippy::iter_nth_zero", @@ -7569,12 +8276,19 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::len_without_is_empty", "clippy::len_zero", "clippy::let_and_return", + "clippy::let_unit_value", "clippy::main_recursion", "clippy::manual_async_fn", + "clippy::manual_bits", + "clippy::manual_is_ascii_check", + "clippy::manual_is_finite", + "clippy::manual_is_infinite", "clippy::manual_map", + "clippy::manual_next_back", "clippy::manual_non_exhaustive", "clippy::manual_range_contains", "clippy::manual_saturating_arithmetic", + "clippy::manual_while_let_some", "clippy::map_clone", "clippy::map_collect_result_unit", "clippy::match_like_matches_macro", @@ -7589,16 +8303,24 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::must_use_unit", "clippy::mut_mutex_lock", "clippy::needless_borrow", + "clippy::needless_borrows_for_generic_args", "clippy::needless_doctest_main", + "clippy::needless_else", "clippy::needless_late_init", + "clippy::needless_parens_on_range_literals", + "clippy::needless_pub_self", "clippy::needless_range_loop", "clippy::needless_return", + "clippy::needless_return_with_question_mark", "clippy::neg_multiply", "clippy::new_ret_no_self", "clippy::new_without_default", + "clippy::non_minimal_cfg", + "clippy::obfuscated_if_else", "clippy::ok_expect", "clippy::op_ref", "clippy::option_map_or_none", + "clippy::partialeq_to_none", "clippy::print_literal", "clippy::print_with_newline", "clippy::println_empty_string", @@ -7622,14 +8344,15 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::tabs_in_doc_comments", "clippy::to_digit_is_some", "clippy::toplevel_ref_arg", - "clippy::try_err", + "clippy::trim_split_whitespace", "clippy::unnecessary_fold", "clippy::unnecessary_lazy_evaluations", "clippy::unnecessary_mut_passed", + "clippy::unnecessary_owned_empty_strings", "clippy::unsafe_removed_from_name", "clippy::unused_unit", "clippy::unusual_byte_groupings", - "clippy::unwrap_or_else_default", + "clippy::unwrap_or_default", "clippy::upper_case_acronyms", "clippy::while_let_on_iterator", "clippy::write_literal", @@ -7642,25 +8365,59 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::suspicious", - description: r##"lint group for: clippy::blanket_clippy_restriction_lints, clippy::empty_loop, clippy::eval_order_dependence, clippy::float_equality_without_abs, clippy::for_loops_over_fallibles, clippy::misrefactored_assign_op, clippy::mut_range_bound, clippy::mutable_key_type, clippy::octal_escapes, clippy::return_self_not_must_use, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_unary_op_formatting"##, + description: r##"lint group for: clippy::almost_complete_range, clippy::arc_with_non_send_sync, clippy::await_holding_invalid_type, clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::blanket_clippy_restriction_lints, clippy::cast_abs_to_unsigned, clippy::cast_enum_constructor, clippy::cast_enum_truncation, clippy::cast_nan_to_int, clippy::cast_slice_from_raw_parts, clippy::crate_in_macro_def, clippy::drop_non_drop, clippy::duplicate_mod, clippy::empty_loop, clippy::float_equality_without_abs, clippy::forget_non_drop, clippy::four_forward_slashes, clippy::from_raw_with_void_ptr, clippy::iter_out_of_bounds, clippy::let_underscore_future, clippy::lines_filter_map_ok, clippy::maybe_misused_cfg, clippy::misnamed_getters, clippy::misrefactored_assign_op, clippy::multi_assignments, clippy::mut_range_bound, clippy::mutable_key_type, clippy::needless_pass_by_ref_mut, clippy::no_effect_replace, clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, clippy::octal_escapes, clippy::path_ends_with_ext, clippy::permissions_set_readonly_false, clippy::print_in_format_impl, clippy::rc_clone_in_vec_init, clippy::single_range_in_vec_init, clippy::size_of_ref, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_command_arg_space, clippy::suspicious_doc_comments, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_to_owned, clippy::suspicious_unary_op_formatting, clippy::swap_ptr_to_ref, clippy::type_id_on_box"##, }, children: &[ + "clippy::almost_complete_range", + "clippy::arc_with_non_send_sync", + "clippy::await_holding_invalid_type", + "clippy::await_holding_lock", + "clippy::await_holding_refcell_ref", "clippy::blanket_clippy_restriction_lints", + "clippy::cast_abs_to_unsigned", + "clippy::cast_enum_constructor", + "clippy::cast_enum_truncation", + "clippy::cast_nan_to_int", + "clippy::cast_slice_from_raw_parts", + "clippy::crate_in_macro_def", + "clippy::drop_non_drop", + "clippy::duplicate_mod", "clippy::empty_loop", - "clippy::eval_order_dependence", "clippy::float_equality_without_abs", - "clippy::for_loops_over_fallibles", + "clippy::forget_non_drop", + "clippy::four_forward_slashes", + "clippy::from_raw_with_void_ptr", + "clippy::iter_out_of_bounds", + "clippy::let_underscore_future", + "clippy::lines_filter_map_ok", + "clippy::maybe_misused_cfg", + "clippy::misnamed_getters", "clippy::misrefactored_assign_op", + "clippy::multi_assignments", "clippy::mut_range_bound", "clippy::mutable_key_type", + "clippy::needless_pass_by_ref_mut", + "clippy::no_effect_replace", + "clippy::non_canonical_clone_impl", + "clippy::non_canonical_partial_ord_impl", "clippy::octal_escapes", - "clippy::return_self_not_must_use", + "clippy::path_ends_with_ext", + "clippy::permissions_set_readonly_false", + "clippy::print_in_format_impl", + "clippy::rc_clone_in_vec_init", + "clippy::single_range_in_vec_init", + "clippy::size_of_ref", "clippy::suspicious_arithmetic_impl", "clippy::suspicious_assignment_formatting", + "clippy::suspicious_command_arg_space", + "clippy::suspicious_doc_comments", "clippy::suspicious_else_formatting", "clippy::suspicious_map", "clippy::suspicious_op_assign_impl", + "clippy::suspicious_to_owned", "clippy::suspicious_unary_op_formatting", + "clippy::swap_ptr_to_ref", + "clippy::type_id_on_box", ], }, ]; diff --git a/crates/ide-db/src/tests/sourcegen_lints.rs b/crates/ide-db/src/tests/sourcegen_lints.rs index c7d5f3613d4b..457f94d3f9f3 100644 --- a/crates/ide-db/src/tests/sourcegen_lints.rs +++ b/crates/ide-db/src/tests/sourcegen_lints.rs @@ -51,7 +51,7 @@ pub struct LintGroup { let contents = sourcegen::add_preamble("sourcegen_lints", sourcegen::reformat(contents)); - let destination = project_root().join("crates/ide_db/src/generated/lints.rs"); + let destination = project_root().join("crates/ide-db/src/generated/lints.rs"); sourcegen::ensure_file_contents(destination.as_path(), &contents); } @@ -196,7 +196,7 @@ fn generate_descriptor_clippy(buf: &mut String, path: &Path) { let mut clippy_lints: Vec = Vec::new(); let mut clippy_groups: std::collections::BTreeMap> = Default::default(); - for line in file_content.lines().map(|line| line.trim()) { + for line in file_content.lines().map(str::trim) { if let Some(line) = line.strip_prefix(r#""id": ""#) { let clippy_lint = ClippyLint { id: line.strip_suffix(r#"","#).expect("should be suffixed by comma").into(), @@ -211,12 +211,19 @@ fn generate_descriptor_clippy(buf: &mut String, path: &Path) { .push(clippy_lints.last().unwrap().id.clone()); } } else if let Some(line) = line.strip_prefix(r#""docs": ""#) { - let prefix_to_strip = r#" ### What it does"#; - let line = match line.strip_prefix(prefix_to_strip) { - Some(line) => line, + let header = "### What it does"; + let line = match line.find(header) { + Some(idx) => &line[idx + header.len()..], None => { - eprintln!("unexpected clippy prefix for {}", clippy_lints.last().unwrap().id); - continue; + let id = &clippy_lints.last().unwrap().id; + // these just don't have the common header + let allowed = ["allow_attributes", "read_line_without_trim"]; + if allowed.contains(&id.as_str()) { + line + } else { + eprintln!("\nunexpected clippy prefix for {id}, line={line:?}\n",); + continue; + } } }; // Only take the description, any more than this is a lot of additional data we would embed into the exe diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 81d6db564ff5..e54bc48d555b 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -5266,38 +5266,46 @@ pub fn foo() {} #[test] fn hover_feature() { check( - r#"#![feature(box_syntax$0)]"#, - expect![[r##" - *box_syntax* - ``` - box_syntax - ``` - ___ + r#"#![feature(intrinsics$0)]"#, + expect![[r#" + *intrinsics* + ``` + intrinsics + ``` + ___ - # `box_syntax` + # `intrinsics` - The tracking issue for this feature is: [#49733] + The tracking issue for this feature is: None. - [#49733]: https://github.com/rust-lang/rust/issues/49733 + Intrinsics are never intended to be stable directly, but intrinsics are often + exported in some sort of stable manner. Prefer using the stable interfaces to + the intrinsic directly when you can. - See also [`box_patterns`](box-patterns.md) + ------------------------ - ------------------------ - Currently the only stable way to create a `Box` is via the `Box::new` method. - Also it is not possible in stable Rust to destructure a `Box` in a match - pattern. The unstable `box` keyword can be used to create a `Box`. An example - usage would be: + These are imported as if they were FFI functions, with the special + `rust-intrinsic` ABI. For example, if one was in a freestanding + context, but wished to be able to `transmute` between types, and + perform efficient pointer arithmetic, one would import those functions + via a declaration like - ```rust - #![feature(box_syntax)] + ```rust + #![feature(intrinsics)] + #![allow(internal_features)] + # fn main() {} - fn main() { - let b = box 5; - } - ``` + extern "rust-intrinsic" { + fn transmute(x: T) -> U; - "##]], + fn arith_offset(dst: *const T, offset: isize) -> *const T; + } + ``` + + As with any other FFI functions, these are always `unsafe` to call. + + "#]], ) } diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs index 8b5c92c66023..e9b250bebf21 100644 --- a/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs @@ -300,6 +300,8 @@ fn check_test_attrs(path: &Path, text: &str) { // This file. "slow-tests/tidy.rs", "test-utils/src/fixture.rs", + // Generated code from lints contains doc tests in string literals. + "ide-db/src/generated/lints.rs", ]; if text.contains("#[should_panic") && !need_panic.iter().any(|p| path.ends_with(p)) { panic!( From a943b19e0865a7a1bf1ad0562c2e3426ba9bd22d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 29 Sep 2023 15:30:47 +0200 Subject: [PATCH 2274/2442] Make rustc_layout_scalar_valid_range attributes work for non-decimal literals --- crates/hir-ty/src/layout/adt.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index 85ef649b8959..457b227427ed 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -119,7 +119,15 @@ fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound, let attr = attrs.by_key(name).tt_values(); for tree in attr { if let Some(it) = tree.token_trees.first() { - if let Ok(it) = it.to_string().parse() { + let text = it.to_string().replace('_', ""); + let base = match text.as_bytes() { + [b'0', b'x', ..] => 16, + [b'0', b'o', ..] => 8, + [b'0', b'b', ..] => 2, + _ => 10, + }; + + if let Ok(it) = u128::from_str_radix(&text, base) { return Bound::Included(it); } } From dd8ea977b700d9ef6089dea6e5f1353f567c06d1 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Fri, 29 Sep 2023 17:39:26 +0200 Subject: [PATCH 2275/2442] vscode: Fix line and col regexp for problem matcher When building the Rust compiler with `./x check` from within VS Code, the current `rustc` problem matcher thinks that the output from that command that looks like this: Build completed successfully in 0:00:26 is about a problem in a file named `0` on line 00, col 26. This wouldn't be so bad if it wasn't for that VS Code tends to get stuck on this problem because of problems with opening the file '0'. The rust compiler will never output problems with a line or a column that starts with 0, so change the regexp to require lines and cols to begin with [1-9] to fix this problem. --- editors/code/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/code/package.json b/editors/code/package.json index 639588566344..3ceec9edf4b6 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1621,7 +1621,7 @@ "message": 3 }, { - "regexp": "^[\\s->=]*(.*?):(\\d*):(\\d*)\\s*$", + "regexp": "^[\\s->=]*(.*?):([1-9]\\d*):([1-9]\\d*)\\s*$", "file": 1, "line": 2, "column": 3 From ae5d74dffbec2946f198d5dcf0a288a9c06f37de Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 29 Sep 2023 21:06:47 +0200 Subject: [PATCH 2276/2442] typing underscore should not trigger completions in types or patterns --- crates/ide-completion/src/lib.rs | 22 +++++ crates/ide-completion/src/tests/special.rs | 109 +++++++++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs index 2eaa42040a01..2fad293d16d7 100644 --- a/crates/ide-completion/src/lib.rs +++ b/crates/ide-completion/src/lib.rs @@ -169,6 +169,28 @@ pub fn completions( return Some(completions.into()); } + // when the user types a bare `_` (that is it does not belong to an identifier) + // the user might just wanted to type a `_` for type inference or pattern discarding + // so try to suppress completions in those cases + if trigger_character == Some('_') && ctx.original_token.kind() == syntax::SyntaxKind::UNDERSCORE + { + if let CompletionAnalysis::NameRef(NameRefContext { + kind: + NameRefKind::Path( + path_ctx @ PathCompletionCtx { + kind: PathKind::Type { .. } | PathKind::Pat { .. }, + .. + }, + ), + .. + }) = analysis + { + if path_ctx.is_trivial_path() { + return None; + } + } + } + { let acc = &mut completions; diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index 83888e08f1c7..d3dbd7cc2277 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -1372,3 +1372,112 @@ fn main() { expect!("pub const fn baz<'foo>(&'foo mut self, x: &'foo Foo) -> !"), ); } + +#[test] +fn skips_underscore() { + check_with_trigger_character( + r#" +fn foo(_$0) { } +"#, + Some('_'), + expect![[r#""#]], + ); + check_with_trigger_character( + r#" +fn foo(_: _$0) { } +"#, + Some('_'), + expect![[r#""#]], + ); + check_with_trigger_character( + r#" +fn foo() { + foo::<_$0>(); +} +"#, + Some('_'), + expect![[r#""#]], + ); + // underscore expressions are fine, they are invalid so the user definitely meant to type an + // underscored name here + check_with_trigger_character( + r#" +fn foo() { + _$0 +} +"#, + Some('_'), + expect![[r#" + fn foo() fn() + bt u32 + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw let + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); +} + +#[test] +fn no_skip_underscore_ident() { + check_with_trigger_character( + r#" +fn foo(a_$0) { } +"#, + Some('_'), + expect![[r#" + kw mut + kw ref + "#]], + ); + check_with_trigger_character( + r#" +fn foo(_: a_$0) { } +"#, + Some('_'), + expect![[r#" + bt u32 + kw crate:: + kw self:: + "#]], + ); + check_with_trigger_character( + r#" +fn foo() { + foo::(); +} +"#, + Some('_'), + expect![[r#" + tp T + bt u32 + kw crate:: + kw self:: + "#]], + ); +} From af28458643abfc074e479b6e77654f55891e0f39 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sat, 30 Sep 2023 08:37:15 +0330 Subject: [PATCH 2277/2442] Downgrade `unused_variables` to experimental --- crates/ide-diagnostics/src/handlers/unused_variables.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/ide-diagnostics/src/handlers/unused_variables.rs b/crates/ide-diagnostics/src/handlers/unused_variables.rs index 2658f12f8ad3..28ccf474b40b 100644 --- a/crates/ide-diagnostics/src/handlers/unused_variables.rs +++ b/crates/ide-diagnostics/src/handlers/unused_variables.rs @@ -14,6 +14,7 @@ pub(crate) fn unused_variables( "unused variable", ast, ) + .experimental() } #[cfg(test)] From 40f80e29a5f33a5e5209f3075aa771789a3b6002 Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Sat, 30 Sep 2023 08:04:04 -0700 Subject: [PATCH 2278/2442] move `to_camel_case` and `char_has_case` from case_conv to stdx --- .../src/diagnostics/decl_check/case_conv.rs | 54 ++----------------- crates/stdx/src/lib.rs | 51 ++++++++++++++++++ 2 files changed, 55 insertions(+), 50 deletions(-) diff --git a/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs b/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs index 2c1368962092..cbe1af157037 100644 --- a/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs +++ b/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs @@ -11,50 +11,7 @@ pub(crate) fn to_camel_case(ident: &str) -> Option { return None; } - // Taken from rustc. - let ret = ident - .trim_matches('_') - .split('_') - .filter(|component| !component.is_empty()) - .map(|component| { - let mut camel_cased_component = String::with_capacity(component.len()); - - let mut new_word = true; - let mut prev_is_lower_case = true; - - for c in component.chars() { - // Preserve the case if an uppercase letter follows a lowercase letter, so that - // `camelCase` is converted to `CamelCase`. - if prev_is_lower_case && c.is_uppercase() { - new_word = true; - } - - if new_word { - camel_cased_component.extend(c.to_uppercase()); - } else { - camel_cased_component.extend(c.to_lowercase()); - } - - prev_is_lower_case = c.is_lowercase(); - new_word = false; - } - - camel_cased_component - }) - .fold((String::new(), None), |(acc, prev): (_, Option), next| { - // separate two components with an underscore if their boundary cannot - // be distinguished using an uppercase/lowercase case distinction - let join = prev - .and_then(|prev| { - let f = next.chars().next()?; - let l = prev.chars().last()?; - Some(!char_has_case(l) && !char_has_case(f)) - }) - .unwrap_or(false); - (acc + if join { "_" } else { "" } + &next, Some(next)) - }) - .0; - Some(ret) + Some(stdx::to_camel_case(ident)) } /// Converts an identifier to a lower_snake_case form. @@ -97,7 +54,9 @@ fn is_camel_case(name: &str) -> bool { && !name.chars().any(|snd| { let ret = match fst { None => false, - Some(fst) => char_has_case(fst) && snd == '_' || char_has_case(snd) && fst == '_', + Some(fst) => { + stdx::char_has_case(fst) && snd == '_' || stdx::char_has_case(snd) && fst == '_' + } }; fst = Some(snd); @@ -135,11 +94,6 @@ fn is_snake_case bool>(ident: &str, wrong_case: F) -> bool { }) } -// Taken from rustc. -fn char_has_case(c: char) -> bool { - c.is_lowercase() || c.is_uppercase() -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 24990d6a0e71..89c54eee55f1 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs @@ -89,6 +89,57 @@ where words.join("_") } +// Taken from rustc. +pub fn to_camel_case(ident: &str) -> String { + ident + .trim_matches('_') + .split('_') + .filter(|component| !component.is_empty()) + .map(|component| { + let mut camel_cased_component = String::with_capacity(component.len()); + + let mut new_word = true; + let mut prev_is_lower_case = true; + + for c in component.chars() { + // Preserve the case if an uppercase letter follows a lowercase letter, so that + // `camelCase` is converted to `CamelCase`. + if prev_is_lower_case && c.is_uppercase() { + new_word = true; + } + + if new_word { + camel_cased_component.extend(c.to_uppercase()); + } else { + camel_cased_component.extend(c.to_lowercase()); + } + + prev_is_lower_case = c.is_lowercase(); + new_word = false; + } + + camel_cased_component + }) + .fold((String::new(), None), |(acc, prev): (_, Option), next| { + // separate two components with an underscore if their boundary cannot + // be distinguished using an uppercase/lowercase case distinction + let join = prev + .and_then(|prev| { + let f = next.chars().next()?; + let l = prev.chars().last()?; + Some(!char_has_case(l) && !char_has_case(f)) + }) + .unwrap_or(false); + (acc + if join { "_" } else { "" } + &next, Some(next)) + }) + .0 +} + +// Taken from rustc. +pub fn char_has_case(c: char) -> bool { + c.is_lowercase() || c.is_uppercase() +} + pub fn replace(buf: &mut String, from: char, to: &str) { if !buf.contains(from) { return; From 2611fbf62380547555e1ce520a83d6ce24bd72b2 Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Sat, 30 Sep 2023 17:06:00 -0700 Subject: [PATCH 2279/2442] implement basic version of convert_tuple_return_type_to_struct assist --- .../convert_tuple_return_type_to_struct.rs | 891 ++++++++++++++++++ crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 27 + 3 files changed, 920 insertions(+) create mode 100644 crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs diff --git a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs new file mode 100644 index 000000000000..c71a2de7c0f9 --- /dev/null +++ b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs @@ -0,0 +1,891 @@ +use either::Either; +use hir::ModuleDef; +use ide_db::{ + assists::{AssistId, AssistKind}, + defs::Definition, + helpers::mod_path_to_ast, + imports::insert_use::{insert_use, ImportScope}, + search::{FileReference, UsageSearchResult}, + source_change::SourceChangeBuilder, + syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, + FxHashSet, +}; +use syntax::{ + ast::{self, edit::IndentLevel, edit_in_place::Indent, make, HasName}, + match_ast, ted, AstNode, SyntaxNode, +}; + +use crate::assist_context::{AssistContext, Assists}; + +// Assist: convert_tuple_return_type_to_struct +// +// This converts the return type of a function from a tuple type +// into a tuple struct and updates the body accordingly. +// +// ``` +// fn bar() { +// let (a, b, c) = foo(); +// } +// +// fn foo() -> ($0u32, u32, u32) { +// (1, 2, 3) +// } +// ``` +// -> +// ``` +// fn bar() { +// let FooResult(a, b, c) = foo(); +// } +// +// struct FooResult(u32, u32, u32); +// +// fn foo() -> FooResult { +// FooResult(1, 2, 3) +// } +// ``` +pub(crate) fn convert_tuple_return_type_to_struct( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { + let ret_type = ctx.find_node_at_offset::()?; + let type_ref = ret_type.ty()?; + + let ast::Type::TupleType(tuple_ty) = &type_ref else { return None }; + if tuple_ty.fields().any(|field| matches!(field, ast::Type::ImplTraitType(_))) { + return None; + } + + let fn_ = ret_type.syntax().parent().and_then(ast::Fn::cast)?; + let fn_def = ctx.sema.to_def(&fn_)?; + let fn_name = fn_.name()?; + let target_module = ctx.sema.scope(fn_.syntax())?.module().nearest_non_block_module(ctx.db()); + + let target = type_ref.syntax().text_range(); + acc.add( + AssistId("convert_tuple_return_type_to_struct", AssistKind::RefactorRewrite), + "Convert tuple return type to tuple struct", + target, + move |edit| { + let ret_type = edit.make_mut(ret_type); + let fn_ = edit.make_mut(fn_); + + let usages = Definition::Function(fn_def).usages(&ctx.sema).all(); + let struct_name = format!("{}Result", stdx::to_camel_case(&fn_name.to_string())); + let parent = fn_.syntax().ancestors().find_map(>::cast); + add_tuple_struct_def( + edit, + ctx, + &usages, + parent.as_ref().map(|it| it.syntax()).unwrap_or(fn_.syntax()), + tuple_ty, + &struct_name, + &target_module, + ); + + ted::replace( + ret_type.syntax(), + make::ret_type(make::ty(&struct_name)).syntax().clone_for_update(), + ); + + if let Some(fn_body) = fn_.body() { + replace_body_return_values(ast::Expr::BlockExpr(fn_body), &struct_name); + } + + replace_usages(edit, ctx, &usages, &struct_name, &target_module); + }, + ) +} + +/// Replaces tuple usages with the corresponding tuple struct pattern. +fn replace_usages( + edit: &mut SourceChangeBuilder, + ctx: &AssistContext<'_>, + usages: &UsageSearchResult, + struct_name: &str, + target_module: &hir::Module, +) { + for (file_id, references) in usages.iter() { + edit.edit_file(*file_id); + + let refs_with_imports = + augment_references_with_imports(edit, ctx, references, struct_name, target_module); + + refs_with_imports.into_iter().rev().for_each(|(name, import_data)| { + if let Some(fn_) = name.syntax().parent().and_then(ast::Fn::cast) { + cov_mark::hit!(replace_trait_impl_fns); + + if let Some(ret_type) = fn_.ret_type() { + ted::replace( + ret_type.syntax(), + make::ret_type(make::ty(struct_name)).syntax().clone_for_update(), + ); + } + + if let Some(fn_body) = fn_.body() { + replace_body_return_values(ast::Expr::BlockExpr(fn_body), struct_name); + } + } else { + // replace tuple patterns + let pats = name + .syntax() + .ancestors() + .nth(5) + .and_then(node_to_pats) + .or_else(|| { + cov_mark::hit!(replace_method_usage); + + name.syntax() + .parent() + .filter(|node| ast::MethodCallExpr::can_cast(node.kind())) + .and_then(|node| node.parent().and_then(node_to_pats)) + }) + .unwrap_or(Vec::new()); + + let tuple_pats = pats.iter().filter_map(|pat| match pat { + ast::Pat::TuplePat(tuple_pat) => Some(tuple_pat), + _ => None, + }); + for tuple_pat in tuple_pats { + ted::replace( + tuple_pat.syntax(), + make::tuple_struct_pat( + make::path_from_text(struct_name), + tuple_pat.fields(), + ) + .clone_for_update() + .syntax(), + ); + } + } + // add imports across modules where needed + if let Some((import_scope, path)) = import_data { + insert_use(&import_scope, path, &ctx.config.insert_use); + } + }) + } +} + +fn node_to_pats(node: SyntaxNode) -> Option> { + match_ast! { + match node { + ast::LetStmt(it) => it.pat().map(|pat| vec![pat]), + ast::LetExpr(it) => it.pat().map(|pat| vec![pat]), + ast::MatchExpr(it) => it.match_arm_list().map(|arm_list| { + arm_list.arms().filter_map(|arm| arm.pat()).collect() + }), + _ => None, + } + } +} + +fn augment_references_with_imports( + edit: &mut SourceChangeBuilder, + ctx: &AssistContext<'_>, + references: &[FileReference], + struct_name: &str, + target_module: &hir::Module, +) -> Vec<(ast::NameLike, Option<(ImportScope, ast::Path)>)> { + let mut visited_modules = FxHashSet::default(); + + references + .iter() + .filter_map(|FileReference { name, .. }| { + ctx.sema.scope(name.syntax()).map(|scope| (name, scope.module())) + }) + .map(|(name, ref_module)| { + let new_name = edit.make_mut(name.clone()); + + // if the referenced module is not the same as the target one and has not been seen before, add an import + let import_data = if ref_module.nearest_non_block_module(ctx.db()) != *target_module + && !visited_modules.contains(&ref_module) + { + visited_modules.insert(ref_module); + + let import_scope = + ImportScope::find_insert_use_container(new_name.syntax(), &ctx.sema); + let path = ref_module + .find_use_path_prefixed( + ctx.sema.db, + ModuleDef::Module(*target_module), + ctx.config.insert_use.prefix_kind, + ctx.config.prefer_no_std, + ) + .map(|mod_path| { + make::path_concat( + mod_path_to_ast(&mod_path), + make::path_from_text(struct_name), + ) + }); + + import_scope.zip(path) + } else { + None + }; + + (new_name, import_data) + }) + .collect() +} + +// Adds the definition of the tuple struct before the parent function. +fn add_tuple_struct_def( + edit: &mut SourceChangeBuilder, + ctx: &AssistContext<'_>, + usages: &UsageSearchResult, + parent: &SyntaxNode, + tuple_ty: &ast::TupleType, + struct_name: &str, + target_module: &hir::Module, +) { + let make_struct_pub = usages + .iter() + .flat_map(|(_, refs)| refs) + .filter_map(|FileReference { name, .. }| { + ctx.sema.scope(name.syntax()).map(|scope| scope.module()) + }) + .any(|module| module.nearest_non_block_module(ctx.db()) != *target_module); + let visibility = if make_struct_pub { Some(make::visibility_pub()) } else { None }; + + let field_list = ast::FieldList::TupleFieldList(make::tuple_field_list( + tuple_ty.fields().map(|ty| make::tuple_field(visibility.clone(), ty)), + )); + let struct_name = make::name(struct_name); + let struct_def = make::struct_(visibility, struct_name, None, field_list).clone_for_update(); + + let indent = IndentLevel::from_node(parent); + struct_def.reindent_to(indent); + + edit.insert(parent.text_range().start(), format!("{struct_def}\n\n{indent}")); +} + +/// Replaces each returned tuple in `body` with the constructor of the tuple struct named `struct_name`. +fn replace_body_return_values(body: ast::Expr, struct_name: &str) { + let mut exprs_to_wrap = Vec::new(); + + let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e); + walk_expr(&body, &mut |expr| { + if let ast::Expr::ReturnExpr(ret_expr) = expr { + if let Some(ret_expr_arg) = &ret_expr.expr() { + for_each_tail_expr(ret_expr_arg, tail_cb); + } + } + }); + for_each_tail_expr(&body, tail_cb); + + for ret_expr in exprs_to_wrap { + if let ast::Expr::TupleExpr(tuple_expr) = &ret_expr { + let struct_constructor = make::expr_call( + make::expr_path(make::ext::ident_path(struct_name)), + make::arg_list(tuple_expr.fields()), + ) + .clone_for_update(); + ted::replace(ret_expr.syntax(), struct_constructor.syntax()); + } + } +} + +fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { + match e { + ast::Expr::BreakExpr(break_expr) => { + if let Some(break_expr_arg) = break_expr.expr() { + for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e)) + } + } + ast::Expr::ReturnExpr(_) => { + // all return expressions have already been handled by the walk loop + } + e => acc.push(e.clone()), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::tests::{check_assist, check_assist_not_applicable}; + + #[test] + fn function_basic() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +fn bar() -> $0(&'static str, bool) { + ("bar", true) +} +"#, + r#" +struct BarResult(&'static str, bool); + +fn bar() -> BarResult { + BarResult("bar", true) +} +"#, + ) + } + + #[test] + fn struct_and_usages_indented() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +mod foo { + pub(crate) fn foo() { + let (bar, baz) = bar(); + println!("{bar} {baz}"); + } + + pub(crate) fn bar() -> $0(usize, bool) { + (42, true) + } +} +"#, + r#" +mod foo { + pub(crate) fn foo() { + let BarResult(bar, baz) = bar(); + println!("{bar} {baz}"); + } + + struct BarResult(usize, bool); + + pub(crate) fn bar() -> BarResult { + BarResult(42, true) + } +} +"#, + ) + } + + #[test] + fn field_usage() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +fn bar() -> $0(usize, bool) { + (42, true) +} + +fn main() { + let bar_result = bar(); + println!("{} {}", bar_result.1, bar().0); +} +"#, + r#" +struct BarResult(usize, bool); + +fn bar() -> BarResult { + BarResult(42, true) +} + +fn main() { + let bar_result = bar(); + println!("{} {}", bar_result.1, bar().0); +} +"#, + ) + } + + #[test] + fn method_usage() { + cov_mark::check!(replace_method_usage); + check_assist( + convert_tuple_return_type_to_struct, + r#" +struct Foo; + +impl Foo { + fn foo(&self, x: usize) -> $0(usize, usize) { + (x, x) + } +} + +fn main() { + let foo = Foo {}; + let (x, y) = foo.foo(2); +} +"#, + r#" +struct Foo; + +struct FooResult(usize, usize); + +impl Foo { + fn foo(&self, x: usize) -> FooResult { + FooResult(x, x) + } +} + +fn main() { + let foo = Foo {}; + let FooResult(x, y) = foo.foo(2); +} +"#, + ) + } + + #[test] + fn method_usage_within_same_impl() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +struct Foo; + +impl Foo { + fn new() -> $0(usize, usize) { + (0, 0) + } + + fn foo() { + let (mut foo1, mut foo2) = Self::new(); + } +} +"#, + r#" +struct Foo; + +struct NewResult(usize, usize); + +impl Foo { + fn new() -> NewResult { + NewResult(0, 0) + } + + fn foo() { + let NewResult(mut foo1, mut foo2) = Self::new(); + } +} +"#, + ) + } + + #[test] + fn multiple_usages() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +fn bar() -> $0(usize, usize) { + (42, 24) +} + +fn main() { + let bar_result = bar(); + let (foo, b) = bar(); + let (b, baz) = bar(); + + if foo == b && b == baz { + println!("{} {}", bar_result.1, bar().0); + } +} +"#, + r#" +struct BarResult(usize, usize); + +fn bar() -> BarResult { + BarResult(42, 24) +} + +fn main() { + let bar_result = bar(); + let BarResult(foo, b) = bar(); + let BarResult(b, baz) = bar(); + + if foo == b && b == baz { + println!("{} {}", bar_result.1, bar().0); + } +} +"#, + ) + } + + #[test] + fn usage_match_tuple_pat() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +fn bar() -> $0(usize, bool) { + (42, true) +} + +fn main() { + match bar() { + x if x.0 == 0 => println!("0"), + (x, false) => println!("{x}"), + (42, true) => println!("bar"), + _ => println!("foo"), + } +} +"#, + r#" +struct BarResult(usize, bool); + +fn bar() -> BarResult { + BarResult(42, true) +} + +fn main() { + match bar() { + x if x.0 == 0 => println!("0"), + BarResult(x, false) => println!("{x}"), + BarResult(42, true) => println!("bar"), + _ => println!("foo"), + } +} +"#, + ) + } + + #[test] + fn usage_if_let_tuple_pat() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +fn bar() -> $0(usize, bool) { + (42, true) +} + +fn main() { + if let (42, true) = bar() { + println!("bar") + } +} +"#, + r#" +struct BarResult(usize, bool); + +fn bar() -> BarResult { + BarResult(42, true) +} + +fn main() { + if let BarResult(42, true) = bar() { + println!("bar") + } +} +"#, + ) + } + + #[test] + fn function_nested_outer() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +fn bar() -> $0(usize, bool) { + fn foo() -> (usize, bool) { + (42, true) + } + + foo() +} +"#, + r#" +struct BarResult(usize, bool); + +fn bar() -> BarResult { + fn foo() -> (usize, bool) { + (42, true) + } + + foo() +} +"#, + ) + } + + #[test] + fn function_nested_inner() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +fn bar() -> (usize, bool) { + fn foo() -> $0(usize, bool) { + (42, true) + } + + foo() +} +"#, + r#" +fn bar() -> (usize, bool) { + struct FooResult(usize, bool); + + fn foo() -> FooResult { + FooResult(42, true) + } + + foo() +} +"#, + ) + } + + #[test] + fn trait_impl_and_usage() { + cov_mark::check!(replace_trait_impl_fns); + check_assist( + convert_tuple_return_type_to_struct, + r#" +struct Struct; + +trait Foo { + fn foo(&self) -> $0(usize, bool); +} + +impl Foo for Struct { + fn foo(&self) -> (usize, bool) { + (0, true) + } +} + +fn main() { + let s = Struct {}; + let (foo, bar) = s.foo(); + let (foo, bar) = Struct::foo(&s); + println!("{foo} {bar}"); +} +"#, + r#" +struct Struct; + +struct FooResult(usize, bool); + +trait Foo { + fn foo(&self) -> FooResult; +} + +impl Foo for Struct { + fn foo(&self) -> FooResult { + FooResult(0, true) + } +} + +fn main() { + let s = Struct {}; + let FooResult(foo, bar) = s.foo(); + let FooResult(foo, bar) = Struct::foo(&s); + println!("{foo} {bar}"); +} +"#, + ) + } + + #[test] + fn body_wraps_nested() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +fn foo() -> $0(u8, usize, u32) { + if true { + match 3 { + 0 => (1, 2, 3), + _ => return (4, 5, 6), + } + } else { + (2, 1, 3) + } +} +"#, + r#" +struct FooResult(u8, usize, u32); + +fn foo() -> FooResult { + if true { + match 3 { + 0 => FooResult(1, 2, 3), + _ => return FooResult(4, 5, 6), + } + } else { + FooResult(2, 1, 3) + } +} +"#, + ) + } + + #[test] + fn body_wraps_break_and_return() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +fn foo(mut i: isize) -> (usize, $0u32, u8) { + if i < 0 { + return (0, 0, 0); + } + + loop { + if i == 2 { + println!("foo"); + break (1, 2, 3); + } + i += 1; + } +} +"#, + r#" +struct FooResult(usize, u32, u8); + +fn foo(mut i: isize) -> FooResult { + if i < 0 { + return FooResult(0, 0, 0); + } + + loop { + if i == 2 { + println!("foo"); + break FooResult(1, 2, 3); + } + i += 1; + } +} +"#, + ) + } + + #[test] + fn body_doesnt_wrap_identifier() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +fn foo() -> $0(u8, usize, u32) { + let tuple = (1, 2, 3); + tuple +} +"#, + r#" +struct FooResult(u8, usize, u32); + +fn foo() -> FooResult { + let tuple = (1, 2, 3); + tuple +} +"#, + ) + } + + #[test] + fn body_doesnt_wrap_other_exprs() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +fn bar(num: usize) -> (u8, usize, u32) { + (1, num, 3) +} + +fn foo() -> $0(u8, usize, u32) { + bar(2) +} +"#, + r#" +fn bar(num: usize) -> (u8, usize, u32) { + (1, num, 3) +} + +struct FooResult(u8, usize, u32); + +fn foo() -> FooResult { + bar(2) +} +"#, + ) + } + + #[test] + fn cross_file_and_module() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +//- /main.rs +mod foo; + +fn main() { + use foo::bar; + + let (bar, baz) = bar::bar(); + println!("{}", bar == baz); +} + +//- /foo.rs +pub mod bar { + pub fn bar() -> $0(usize, usize) { + (1, 3) + } +} +"#, + r#" +//- /main.rs +use crate::foo::bar::BarResult; + +mod foo; + +fn main() { + use foo::bar; + + let BarResult(bar, baz) = bar::bar(); + println!("{}", bar == baz); +} + +//- /foo.rs +pub mod bar { + pub struct BarResult(pub usize, pub usize); + + pub fn bar() -> BarResult { + BarResult(1, 3) + } +} +"#, + ) + } + + #[test] + fn does_not_replace_nested_usage() { + check_assist( + convert_tuple_return_type_to_struct, + r#" +fn bar() -> $0(usize, bool) { + (42, true) +} + +fn main() { + let ((bar1, bar2), foo) = (bar(), 3); + println!("{bar1} {bar2} {foo}"); +} +"#, + r#" +struct BarResult(usize, bool); + +fn bar() -> BarResult { + BarResult(42, true) +} + +fn main() { + let ((bar1, bar2), foo) = (bar(), 3); + println!("{bar1} {bar2} {foo}"); +} +"#, + ) + } + + #[test] + fn function_with_non_tuple_return_type() { + check_assist_not_applicable( + convert_tuple_return_type_to_struct, + r#" +fn bar() -> $0usize { + 0 +} +"#, + ) + } + + #[test] + fn function_with_impl_type() { + check_assist_not_applicable( + convert_tuple_return_type_to_struct, + r#" +fn bar() -> $0(impl Clone, usize) { + ("bar", 0) +} +"#, + ) + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index a17ce93e928c..3dd1be869df5 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -125,6 +125,7 @@ mod handlers { mod convert_let_else_to_match; mod convert_match_to_let_else; mod convert_nested_function_to_closure; + mod convert_tuple_return_type_to_struct; mod convert_tuple_struct_to_named_struct; mod convert_named_struct_to_tuple_struct; mod convert_to_guarded_return; @@ -239,6 +240,7 @@ mod handlers { convert_iter_for_each_to_for::convert_for_loop_with_for_each, convert_let_else_to_match::convert_let_else_to_match, convert_match_to_let_else::convert_match_to_let_else, + convert_tuple_return_type_to_struct::convert_tuple_return_type_to_struct, convert_named_struct_to_tuple_struct::convert_named_struct_to_tuple_struct, convert_nested_function_to_closure::convert_nested_function_to_closure, convert_to_guarded_return::convert_to_guarded_return, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 63a08a0e5697..cc87ee7b8558 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -586,6 +586,33 @@ fn main() { ) } +#[test] +fn doctest_convert_tuple_return_type_to_struct() { + check_doc_test( + "convert_tuple_return_type_to_struct", + r#####" +fn bar() { + let (a, b, c) = foo(); +} + +fn foo() -> ($0u32, u32, u32) { + (1, 2, 3) +} +"#####, + r#####" +fn bar() { + let FooResult(a, b, c) = foo(); +} + +struct FooResult(u32, u32, u32); + +fn foo() -> FooResult { + FooResult(1, 2, 3) +} +"#####, + ) +} + #[test] fn doctest_convert_tuple_struct_to_named_struct() { check_doc_test( From 146a7cc490b6e45e8b4192e38cab3bae00216712 Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Sun, 1 Oct 2023 11:32:37 -0700 Subject: [PATCH 2280/2442] fix: allow more kinds of if let patterns in guarded return assist --- .../src/handlers/convert_to_guarded_return.rs | 76 ++++++++++++++----- 1 file changed, 57 insertions(+), 19 deletions(-) diff --git a/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/crates/ide-assists/src/handlers/convert_to_guarded_return.rs index 7d0e424769ec..73ba3f5c4cdc 100644 --- a/crates/ide-assists/src/handlers/convert_to_guarded_return.rs +++ b/crates/ide-assists/src/handlers/convert_to_guarded_return.rs @@ -51,22 +51,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext<' // Check if there is an IfLet that we can handle. let (if_let_pat, cond_expr) = if is_pattern_cond(cond.clone()) { let let_ = single_let(cond)?; - match let_.pat() { - Some(ast::Pat::TupleStructPat(pat)) if pat.fields().count() == 1 => { - let path = pat.path()?; - if path.qualifier().is_some() { - return None; - } - - let bound_ident = pat.fields().next()?; - if !ast::IdentPat::can_cast(bound_ident.syntax().kind()) { - return None; - } - - (Some((path, bound_ident)), let_.expr()?) - } - _ => return None, // Unsupported IfLet. - } + (Some(let_.pat()?), let_.expr()?) } else { (None, cond) }; @@ -136,11 +121,10 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext<' }; new_expr.syntax().clone_for_update() } - Some((path, bound_ident)) => { + Some(pat) => { // If-let. - let pat = make::tuple_struct_pat(path, once(bound_ident)); let let_else_stmt = make::let_else_stmt( - pat.into(), + pat, None, cond_expr, ast::make::tail_only_block_expr(early_expression), @@ -442,6 +426,60 @@ fn main() { ); } + #[test] + fn convert_arbitrary_if_let_patterns() { + check_assist( + convert_to_guarded_return, + r#" +fn main() { + $0if let None = Some(92) { + foo(); + } +} +"#, + r#" +fn main() { + let None = Some(92) else { return }; + foo(); +} +"#, + ); + + check_assist( + convert_to_guarded_return, + r#" +fn main() { + $0if let [1, x] = [1, 92] { + foo(x); + } +} +"#, + r#" +fn main() { + let [1, x] = [1, 92] else { return }; + foo(x); +} +"#, + ); + + check_assist( + convert_to_guarded_return, + r#" +fn main() { + $0if let (Some(x), None) = (Some(92), None) { + foo(x); + } +} +"#, + r#" +fn main() { + let (Some(x), None) = (Some(92), None) else { return }; + foo(x); +} +"#, + ); + } + #[test] fn ignore_already_converted_if() { check_assist_not_applicable( From 34d3490198fe6e7f56eb60c9665d25ef9cfd6f4e Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Sun, 1 Oct 2023 21:27:06 -0700 Subject: [PATCH 2281/2442] feat: add assist for applying De Morgan's law to iterators --- .../src/handlers/apply_demorgan.rs | 329 +++++++++++++++++- crates/ide-assists/src/lib.rs | 1 + crates/ide-assists/src/tests/generated.rs | 24 ++ 3 files changed, 352 insertions(+), 2 deletions(-) diff --git a/crates/ide-assists/src/handlers/apply_demorgan.rs b/crates/ide-assists/src/handlers/apply_demorgan.rs index 66bc2f6dadc3..74db300465ae 100644 --- a/crates/ide-assists/src/handlers/apply_demorgan.rs +++ b/crates/ide-assists/src/handlers/apply_demorgan.rs @@ -1,7 +1,13 @@ use std::collections::VecDeque; +use ide_db::{ + assists::GroupLabel, + famous_defs::FamousDefs, + source_change::SourceChangeBuilder, + syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, +}; use syntax::{ - ast::{self, AstNode, Expr::BinExpr}, + ast::{self, make, AstNode, Expr::BinExpr, HasArgList}, ted::{self, Position}, SyntaxKind, }; @@ -89,7 +95,8 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti let dm_lhs = demorganed.lhs()?; - acc.add( + acc.add_group( + &GroupLabel("Apply De Morgan's law".to_string()), AssistId("apply_demorgan", AssistKind::RefactorRewrite), "Apply De Morgan's law", op_range, @@ -143,6 +150,122 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti ) } +// Assist: apply_demorgan_iterator +// +// Apply https://en.wikipedia.org/wiki/De_Morgan%27s_laws[De Morgan's law] to +// `Iterator::all` and `Iterator::any`. +// +// This transforms expressions of the form `!iter.any(|x| predicate(x))` into +// `iter.all(|x| !predicate(x))` and vice versa. This also works the other way for +// `Iterator::all` into `Iterator::any`. +// +// ``` +// # //- minicore: iterator +// fn main() { +// let arr = [1, 2, 3]; +// if !arr.into_iter().$0any(|num| num == 4) { +// println!("foo"); +// } +// } +// ``` +// -> +// ``` +// fn main() { +// let arr = [1, 2, 3]; +// if arr.into_iter().all(|num| num != 4) { +// println!("foo"); +// } +// } +// ``` +pub(crate) fn apply_demorgan_iterator(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?; + let (name, arg_expr) = validate_method_call_expr(ctx, &method_call)?; + + let ast::Expr::ClosureExpr(closure_expr) = arg_expr else { return None }; + let closure_body = closure_expr.body()?; + + let op_range = method_call.syntax().text_range(); + let label = format!("Apply De Morgan's law to `Iterator::{}`", name.text().as_str()); + acc.add_group( + &GroupLabel("Apply De Morgan's law".to_string()), + AssistId("apply_demorgan_iterator", AssistKind::RefactorRewrite), + label, + op_range, + |edit| { + // replace the method name + let new_name = match name.text().as_str() { + "all" => make::name_ref("any"), + "any" => make::name_ref("all"), + _ => unreachable!(), + } + .clone_for_update(); + edit.replace_ast(name, new_name); + + // negate all tail expressions in the closure body + let tail_cb = &mut |e: &_| tail_cb_impl(edit, e); + walk_expr(&closure_body, &mut |expr| { + if let ast::Expr::ReturnExpr(ret_expr) = expr { + if let Some(ret_expr_arg) = &ret_expr.expr() { + for_each_tail_expr(ret_expr_arg, tail_cb); + } + } + }); + for_each_tail_expr(&closure_body, tail_cb); + + // negate the whole method call + if let Some(prefix_expr) = method_call + .syntax() + .parent() + .and_then(ast::PrefixExpr::cast) + .filter(|prefix_expr| matches!(prefix_expr.op_kind(), Some(ast::UnaryOp::Not))) + { + edit.delete(prefix_expr.op_token().unwrap().text_range()); + } else { + edit.insert(method_call.syntax().text_range().start(), "!"); + } + }, + ) +} + +/// Ensures that the method call is to `Iterator::all` or `Iterator::any`. +fn validate_method_call_expr( + ctx: &AssistContext<'_>, + method_call: &ast::MethodCallExpr, +) -> Option<(ast::NameRef, ast::Expr)> { + let name_ref = method_call.name_ref()?; + if name_ref.text() != "all" && name_ref.text() != "any" { + return None; + } + let arg_expr = method_call.arg_list()?.args().next()?; + + let sema = &ctx.sema; + + let receiver = method_call.receiver()?; + let it_type = sema.type_of_expr(&receiver)?.adjusted(); + let module = sema.scope(receiver.syntax())?.module(); + let krate = module.krate(); + + let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?; + it_type.impls_trait(sema.db, iter_trait, &[]).then_some((name_ref, arg_expr)) +} + +fn tail_cb_impl(edit: &mut SourceChangeBuilder, e: &ast::Expr) { + match e { + ast::Expr::BreakExpr(break_expr) => { + if let Some(break_expr_arg) = break_expr.expr() { + for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(edit, e)) + } + } + ast::Expr::ReturnExpr(_) => { + // all return expressions have already been handled by the walk loop + } + e => { + let inverted_body = invert_boolean_expression(e.clone()); + edit.replace(e.syntax().text_range(), inverted_body.syntax().text()); + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -255,4 +378,206 @@ fn f() { !(S <= S || S < S) } "fn() { let x = a && b && c; }", ) } + + #[test] + fn demorgan_iterator_any_all_reverse() { + check_assist( + apply_demorgan_iterator, + r#" +//- minicore: iterator +fn main() { + let arr = [1, 2, 3]; + if arr.into_iter().all(|num| num $0!= 4) { + println!("foo"); + } +} +"#, + r#" +fn main() { + let arr = [1, 2, 3]; + if !arr.into_iter().any(|num| num == 4) { + println!("foo"); + } +} +"#, + ); + } + + #[test] + fn demorgan_iterator_all_any() { + check_assist( + apply_demorgan_iterator, + r#" +//- minicore: iterator +fn main() { + let arr = [1, 2, 3]; + if !arr.into_iter().$0all(|num| num > 3) { + println!("foo"); + } +} +"#, + r#" +fn main() { + let arr = [1, 2, 3]; + if arr.into_iter().any(|num| num <= 3) { + println!("foo"); + } +} +"#, + ); + } + + #[test] + fn demorgan_iterator_multiple_terms() { + check_assist( + apply_demorgan_iterator, + r#" +//- minicore: iterator +fn main() { + let arr = [1, 2, 3]; + if !arr.into_iter().$0any(|num| num > 3 && num == 23 && num <= 30) { + println!("foo"); + } +} +"#, + r#" +fn main() { + let arr = [1, 2, 3]; + if arr.into_iter().all(|num| !(num > 3 && num == 23 && num <= 30)) { + println!("foo"); + } +} +"#, + ); + } + + #[test] + fn demorgan_iterator_double_negation() { + check_assist( + apply_demorgan_iterator, + r#" +//- minicore: iterator +fn main() { + let arr = [1, 2, 3]; + if !arr.into_iter().$0all(|num| !(num > 3)) { + println!("foo"); + } +} +"#, + r#" +fn main() { + let arr = [1, 2, 3]; + if arr.into_iter().any(|num| num > 3) { + println!("foo"); + } +} +"#, + ); + } + + #[test] + fn demorgan_iterator_double_parens() { + check_assist( + apply_demorgan_iterator, + r#" +//- minicore: iterator +fn main() { + let arr = [1, 2, 3]; + if !arr.into_iter().$0any(|num| (num > 3 && (num == 1 || num == 2))) { + println!("foo"); + } +} +"#, + r#" +fn main() { + let arr = [1, 2, 3]; + if arr.into_iter().all(|num| !(num > 3 && (num == 1 || num == 2))) { + println!("foo"); + } +} +"#, + ); + } + + #[test] + fn demorgan_iterator_multiline() { + check_assist( + apply_demorgan_iterator, + r#" +//- minicore: iterator +fn main() { + let arr = [1, 2, 3]; + if arr + .into_iter() + .all$0(|num| !num.is_negative()) + { + println!("foo"); + } +} +"#, + r#" +fn main() { + let arr = [1, 2, 3]; + if !arr + .into_iter() + .any(|num| num.is_negative()) + { + println!("foo"); + } +} +"#, + ); + } + + #[test] + fn demorgan_iterator_block_closure() { + check_assist( + apply_demorgan_iterator, + r#" +//- minicore: iterator +fn main() { + let arr = [-1, 1, 2, 3]; + if arr.into_iter().all(|num: i32| { + $0if num.is_positive() { + num <= 3 + } else { + num >= -1 + } + }) { + println!("foo"); + } +} +"#, + r#" +fn main() { + let arr = [-1, 1, 2, 3]; + if !arr.into_iter().any(|num: i32| { + if num.is_positive() { + num > 3 + } else { + num < -1 + } + }) { + println!("foo"); + } +} +"#, + ); + } + + #[test] + fn demorgan_iterator_wrong_method() { + check_assist_not_applicable( + apply_demorgan_iterator, + r#" +//- minicore: iterator +fn main() { + let arr = [1, 2, 3]; + if !arr.into_iter().$0map(|num| num > 3) { + println!("foo"); + } +} +"#, + ); + } } diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index a17ce93e928c..50476ccf3638 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -226,6 +226,7 @@ mod handlers { add_return_type::add_return_type, add_turbo_fish::add_turbo_fish, apply_demorgan::apply_demorgan, + apply_demorgan::apply_demorgan_iterator, auto_import::auto_import, bind_unused_param::bind_unused_param, bool_to_enum::bool_to_enum, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 5a815d5c6a18..65bd74c018bb 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -244,6 +244,30 @@ fn main() { ) } +#[test] +fn doctest_apply_demorgan_iterator() { + check_doc_test( + "apply_demorgan_iterator", + r#####" +//- minicore: iterator +fn main() { + let arr = [1, 2, 3]; + if !arr.into_iter().$0any(|num| num == 4) { + println!("foo"); + } +} +"#####, + r#####" +fn main() { + let arr = [1, 2, 3]; + if arr.into_iter().all(|num| num != 4) { + println!("foo"); + } +} +"#####, + ) +} + #[test] fn doctest_auto_import() { check_doc_test( From 084ee934b8fe9bcec5a05c724805e48875e09d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 2 Oct 2023 10:47:18 +0300 Subject: [PATCH 2282/2442] Strip base prefix in layout_scalar_valid_range --- crates/hir-ty/src/layout/adt.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index 457b227427ed..c2778b9a8ea0 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -120,14 +120,14 @@ fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound, for tree in attr { if let Some(it) = tree.token_trees.first() { let text = it.to_string().replace('_', ""); - let base = match text.as_bytes() { - [b'0', b'x', ..] => 16, - [b'0', b'o', ..] => 8, - [b'0', b'b', ..] => 2, - _ => 10, + let (text, base) = match text.as_bytes() { + [b'0', b'x', ..] => (&text[2..], 16), + [b'0', b'o', ..] => (&text[2..], 8), + [b'0', b'b', ..] => (&text[2..], 2), + _ => (&*text, 10), }; - if let Ok(it) = u128::from_str_radix(&text, base) { + if let Ok(it) = u128::from_str_radix(text, base) { return Bound::Included(it); } } From 7c113ee77ce1a81d0f177b01ed24c88eae9e17ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 3 Oct 2023 17:32:57 +0300 Subject: [PATCH 2283/2442] Add mock description to rustc-dependencies --- crates/rustc-dependencies/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/rustc-dependencies/Cargo.toml b/crates/rustc-dependencies/Cargo.toml index 901706d3d95f..5c5a3cd8bf32 100644 --- a/crates/rustc-dependencies/Cargo.toml +++ b/crates/rustc-dependencies/Cargo.toml @@ -1,6 +1,8 @@ [package] name = "rustc-dependencies" version = "0.0.0" +description = "TBD" + rust-version.workspace = true edition.workspace = true license.workspace = true From a8ec77dc7e30af115f542e137395e204b0fb5b28 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Tue, 3 Oct 2023 16:44:09 -0400 Subject: [PATCH 2284/2442] address PR feedback. --- crates/rust-analyzer/src/handlers/request.rs | 40 +++----------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index ad6319586cfe..8dc0c97bc58f 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -1997,41 +1997,13 @@ fn run_rustfmt( } RustfmtConfig::CustomCommand { command, args } => { let cmd = PathBuf::from(&command); - let mut components = cmd.components(); - - // to support rustc's suggested, default configuration - let mut cmd = match components.next() { - Some(std::path::Component::CurDir) => { - let rest = components.as_path(); - - let roots = snap - .workspaces - .iter() - .flat_map(|ws| ws.workspace_definition_path()) - .collect::>(); - - let abs: Option = roots.into_iter().find_map(|base| { - let abs = base.join(rest); - std::fs::metadata(&abs).ok().map(|_| abs) - }); - - let command = match abs { - Some(cmd) => cmd, - None => { - tracing::error!( - rustfmt = ?command, - "Unable to make the format command an absolute path" - ); - anyhow::bail!( - "Unable to make the format command an absolute path: {}", - command - ); - } - }; - - process::Command::new(&command.as_os_str()) + let workspace = CargoTargetSpec::for_file(&snap, file_id)?; + let mut cmd = match workspace { + Some(spec) => { + let cmd = spec.workspace_root.join(cmd); + process::Command::new(cmd.as_os_str()) } - _ => process::Command::new(command), + None => process::Command::new(cmd), }; cmd.envs(snap.config.extra_env()); From fe398163b63c11ccc3e4879c77a1157cd65af164 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 4 Oct 2023 12:04:37 +0200 Subject: [PATCH 2285/2442] Recognize custom main function as binary entrypoint for runnables --- crates/hir-def/src/attr.rs | 4 ++ crates/hir/src/lib.rs | 11 +++++ crates/ide/src/runnables.rs | 80 ++++++++++++++++++++++++++----------- 3 files changed, 72 insertions(+), 23 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index c6454eb9ea02..fa3025e0303d 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -215,6 +215,10 @@ impl Attrs { self.doc_exprs().flat_map(|doc_expr| doc_expr.aliases().to_vec()) } + pub fn export_name(&self) -> Option<&SmolStr> { + self.by_key("export_name").string_value() + } + pub fn is_proc_macro(&self) -> bool { self.by_key("proc_macro").exists() } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index a6c6c0dbb8bf..8e48afd6af81 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1971,6 +1971,17 @@ impl Function { db.function_data(self.id).attrs.is_test() } + /// is this a `fn main` or a function with an `export_name` of `main`? + pub fn is_main(self, db: &dyn HirDatabase) -> bool { + if !self.module(db).is_crate_root() { + return false; + } + let data = db.function_data(self.id); + + data.name.to_smol_str() == "main" + || data.attrs.export_name().map(core::ops::Deref::deref) == Some("main") + } + /// Does this function have the ignore attribute? pub fn is_ignore(self, db: &dyn HirDatabase) -> bool { db.function_data(self.id).attrs.is_ignore() diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 2d528c642558..07cdddd15f82 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -308,11 +308,7 @@ pub(crate) fn runnable_fn( sema: &Semantics<'_, RootDatabase>, def: hir::Function, ) -> Option { - let name = def.name(sema.db).to_smol_str(); - - let root = def.module(sema.db).krate().root_module(); - - let kind = if name == "main" && def.module(sema.db) == root { + let kind = if def.is_main(sema.db) { RunnableKind::Bin } else { let test_id = || { @@ -320,7 +316,9 @@ pub(crate) fn runnable_fn( let def: hir::ModuleDef = def.into(); def.canonical_path(sema.db) }; - canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name)) + canonical_path + .map(TestId::Path) + .unwrap_or(TestId::Name(def.name(sema.db).to_smol_str())) }; if def.is_test(sema.db) { @@ -587,6 +585,9 @@ mod tests { $0 fn main() {} +#[export_name = "main"] +fn __cortex_m_rt_main_trampoline() {} + #[test] fn test_foo() {} @@ -604,7 +605,7 @@ mod not_a_root { fn main() {} } "#, - &[TestMod, Bin, Test, Test, Test, Bench], + &[TestMod, Bin, Bin, Test, Test, Test, Bench], expect![[r#" [ Runnable { @@ -613,7 +614,7 @@ mod not_a_root { file_id: FileId( 0, ), - full_range: 0..190, + full_range: 0..253, name: "", kind: Module, }, @@ -642,8 +643,22 @@ mod not_a_root { file_id: FileId( 0, ), - full_range: 15..39, - focus_range: 26..34, + full_range: 15..76, + focus_range: 42..71, + name: "__cortex_m_rt_main_trampoline", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 78..102, + focus_range: 89..97, name: "test_foo", kind: Function, }, @@ -663,8 +678,8 @@ mod not_a_root { file_id: FileId( 0, ), - full_range: 41..92, - focus_range: 73..87, + full_range: 104..155, + focus_range: 136..150, name: "test_full_path", kind: Function, }, @@ -684,8 +699,8 @@ mod not_a_root { file_id: FileId( 0, ), - full_range: 94..128, - focus_range: 115..123, + full_range: 157..191, + focus_range: 178..186, name: "test_foo", kind: Function, }, @@ -705,8 +720,8 @@ mod not_a_root { file_id: FileId( 0, ), - full_range: 130..152, - focus_range: 142..147, + full_range: 193..215, + focus_range: 205..210, name: "bench", kind: Function, }, @@ -1655,12 +1670,18 @@ macro_rules! gen2 { } } } +macro_rules! gen_main { + () => { + fn main() {} + } +} mod tests { gen!(); } gen2!(); +gen_main!(); "#, - &[TestMod, TestMod, Test, Test, TestMod], + &[TestMod, TestMod, Test, Test, TestMod, Bin], expect![[r#" [ Runnable { @@ -1669,7 +1690,7 @@ gen2!(); file_id: FileId( 0, ), - full_range: 0..237, + full_range: 0..315, name: "", kind: Module, }, @@ -1684,8 +1705,8 @@ gen2!(); file_id: FileId( 0, ), - full_range: 202..227, - focus_range: 206..211, + full_range: 267..292, + focus_range: 271..276, name: "tests", kind: Module, description: "mod tests", @@ -1701,7 +1722,7 @@ gen2!(); file_id: FileId( 0, ), - full_range: 218..225, + full_range: 283..290, name: "foo_test", kind: Function, }, @@ -1721,7 +1742,7 @@ gen2!(); file_id: FileId( 0, ), - full_range: 228..236, + full_range: 293..301, name: "foo_test2", kind: Function, }, @@ -1741,7 +1762,7 @@ gen2!(); file_id: FileId( 0, ), - full_range: 228..236, + full_range: 293..301, name: "tests2", kind: Module, description: "mod tests2", @@ -1751,6 +1772,19 @@ gen2!(); }, cfg: None, }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 302..314, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, ] "#]], ); From c266387e130de11c60be2c2d7d0a1d5c3bc3eb62 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 4 Oct 2023 13:06:23 +0200 Subject: [PATCH 2286/2442] Replace unwrap with expect --- crates/ide-assists/src/handlers/apply_demorgan.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/apply_demorgan.rs b/crates/ide-assists/src/handlers/apply_demorgan.rs index 74db300465ae..2d41243c20eb 100644 --- a/crates/ide-assists/src/handlers/apply_demorgan.rs +++ b/crates/ide-assists/src/handlers/apply_demorgan.rs @@ -219,7 +219,12 @@ pub(crate) fn apply_demorgan_iterator(acc: &mut Assists, ctx: &AssistContext<'_> .and_then(ast::PrefixExpr::cast) .filter(|prefix_expr| matches!(prefix_expr.op_kind(), Some(ast::UnaryOp::Not))) { - edit.delete(prefix_expr.op_token().unwrap().text_range()); + edit.delete( + prefix_expr + .op_token() + .expect("prefix expression always has an operator") + .text_range(), + ); } else { edit.insert(method_call.syntax().text_range().start(), "!"); } From 9ba8dbc902321301c084d7512b14589ebe1b024e Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Wed, 4 Oct 2023 08:04:59 -0700 Subject: [PATCH 2287/2442] style: clean up magic number for finding pattern usages --- .../convert_tuple_return_type_to_struct.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs index c71a2de7c0f9..32db5ee8dabf 100644 --- a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs +++ b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs @@ -129,16 +129,12 @@ fn replace_usages( let pats = name .syntax() .ancestors() - .nth(5) - .and_then(node_to_pats) - .or_else(|| { - cov_mark::hit!(replace_method_usage); - - name.syntax() - .parent() - .filter(|node| ast::MethodCallExpr::can_cast(node.kind())) - .and_then(|node| node.parent().and_then(node_to_pats)) + .find(|node| { + ast::CallExpr::can_cast(node.kind()) + || ast::MethodCallExpr::can_cast(node.kind()) }) + .and_then(|node| node.parent()) + .and_then(node_to_pats) .unwrap_or(Vec::new()); let tuple_pats = pats.iter().filter_map(|pat| match pat { @@ -387,7 +383,6 @@ fn main() { #[test] fn method_usage() { - cov_mark::check!(replace_method_usage); check_assist( convert_tuple_return_type_to_struct, r#" From ab091b73d0117d9788549289d3cd1ac709b462dd Mon Sep 17 00:00:00 2001 From: dfireBird Date: Wed, 4 Oct 2023 10:14:03 +0530 Subject: [PATCH 2288/2442] Add config for the default click action of extension status bar --- editors/code/package.json | 13 +++++++++++++ editors/code/src/config.ts | 4 ++++ editors/code/src/ctx.ts | 6 +++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/editors/code/package.json b/editors/code/package.json index 639588566344..349f49465e31 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -371,6 +371,19 @@ ], "markdownDescription": "Problem matchers to use for `rust-analyzer.run` command, eg `[\"$rustc\", \"$rust-panic\"]`." }, + "rust-analyzer.statusBar.clickAction": { + "type": "string", + "enum": [ + "stopServer", + "openLogs" + ], + "enumDescriptions": [ + "Stop Server", + "Open Logs" + ], + "default": "openLogs", + "markdownDescription": "Action to run when clicking the extension status bar item." + }, "rust-analyzer.server.path": { "type": [ "null", diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 9821aee6f92b..987d936943a1 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -329,6 +329,10 @@ export class Config { get showDependenciesExplorer() { return this.get("showDependenciesExplorer"); } + + get statusBarClickAction() { + return this.get("statusBar.clickAction"); + } } // the optional `cb?` parameter is meant to be used to add additional diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 904efa4d5eb0..84d1ad98bd98 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -400,7 +400,11 @@ export class Ctx { statusBar.tooltip.appendText(status.message ?? "Ready"); statusBar.color = undefined; statusBar.backgroundColor = undefined; - statusBar.command = "rust-analyzer.openLogs"; + if (this.config.statusBarClickAction === "stopServer") { + statusBar.command = "rust-analyzer.stopServer"; + } else { + statusBar.command = "rust-analyzer.openLogs"; + } this.dependencies?.refresh(); break; case "warning": From 4af730eb26fc8fc41e0fd8952e8b04759910b580 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Oct 2023 13:21:12 +0200 Subject: [PATCH 2289/2442] Do flyimport completions by prefix search for short paths --- crates/hir-def/src/import_map.rs | 13 +++- .../src/completions/flyimport.rs | 12 +-- crates/ide-completion/src/tests/flyimport.rs | 76 ++++++++++++++++--- crates/ide-db/src/imports/import_assets.rs | 47 +++++++++--- crates/ide-db/src/items_locator.rs | 30 +++++--- crates/ide-db/src/symbol_index.rs | 43 ++++++++--- 6 files changed, 174 insertions(+), 47 deletions(-) diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs index 90763d4c3dfe..6461439bb713 100644 --- a/crates/hir-def/src/import_map.rs +++ b/crates/hir-def/src/import_map.rs @@ -283,6 +283,8 @@ enum SearchMode { /// Import map entry should contain all letters from the query string, /// in the same order, but not necessary adjacent. Fuzzy, + /// Import map entry should match the query string by prefix. + Prefix, } /// Three possible ways to search for the name in associated and/or other items. @@ -324,6 +326,14 @@ impl Query { Self { search_mode: SearchMode::Fuzzy, ..self } } + pub fn prefix(self) -> Self { + Self { search_mode: SearchMode::Prefix, ..self } + } + + pub fn exact(self) -> Self { + Self { search_mode: SearchMode::Exact, ..self } + } + /// Specifies whether we want to include associated items in the result. pub fn assoc_search_mode(self, assoc_mode: AssocSearchMode) -> Self { Self { assoc_mode, ..self } @@ -361,7 +371,8 @@ impl Query { let query_string = if case_insensitive { &self.lowercased } else { &self.query }; match self.search_mode { - SearchMode::Exact => &input == query_string, + SearchMode::Exact => input == *query_string, + SearchMode::Prefix => input.starts_with(query_string), SearchMode::Fuzzy => { let mut input_chars = input.chars(); for query_char in query_string.chars() { diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs index 39c1b7f7b3fb..0961021e48e0 100644 --- a/crates/ide-completion/src/completions/flyimport.rs +++ b/crates/ide-completion/src/completions/flyimport.rs @@ -13,10 +13,9 @@ use crate::{ TypeLocation, }, render::{render_resolution_with_import, render_resolution_with_import_pat, RenderContext}, + Completions, }; -use super::Completions; - // Feature: Completion With Autoimport // // When completing names in the current scope, proposes additional imports from other modules or crates, @@ -377,9 +376,12 @@ fn import_assets_for_path( &ctx.sema, ctx.token.parent()?, )?; - if fuzzy_name_length < 3 { - cov_mark::hit!(flyimport_exact_on_short_path); - assets_for_path.path_fuzzy_name_to_exact(false); + if fuzzy_name_length == 0 { + // nothing matches the empty string exactly, but we still compute assoc items in this case + assets_for_path.path_fuzzy_name_to_exact(); + } else if fuzzy_name_length < 3 { + cov_mark::hit!(flyimport_prefix_on_short_path); + assets_for_path.path_fuzzy_name_to_prefix(); } Some(assets_for_path) } diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs index 4cdfd546f6ad..21f693d79f1d 100644 --- a/crates/ide-completion/src/tests/flyimport.rs +++ b/crates/ide-completion/src/tests/flyimport.rs @@ -116,19 +116,47 @@ fn main() { } #[test] -fn short_paths_are_ignored() { - cov_mark::check!(flyimport_exact_on_short_path); +fn short_paths_are_prefix_matched() { + cov_mark::check!(flyimport_prefix_on_short_path); check( r#" //- /lib.rs crate:dep -pub struct Bar; +pub struct Barc; pub struct Rcar; pub struct Rc; +pub const RC: () = (); pub mod some_module { pub struct Bar; pub struct Rcar; pub struct Rc; + pub const RC: () = (); +} + +//- /main.rs crate:main deps:dep +fn main() { + Rc$0 +} +"#, + expect![[r#" + st Rc (use dep::Rc) + st Rcar (use dep::Rcar) + st Rc (use dep::some_module::Rc) + st Rcar (use dep::some_module::Rcar) + "#]], + ); + check( + r#" +//- /lib.rs crate:dep +pub struct Barc; +pub struct Rcar; +pub struct Rc; +pub const RC: () = (); +pub mod some_module { + pub struct Bar; + pub struct Rcar; + pub struct Rc; + pub const RC: () = (); } //- /main.rs crate:main deps:dep @@ -137,8 +165,36 @@ fn main() { } "#, expect![[r#" + ct RC (use dep::RC) st Rc (use dep::Rc) + st Rcar (use dep::Rcar) + ct RC (use dep::some_module::RC) st Rc (use dep::some_module::Rc) + st Rcar (use dep::some_module::Rcar) + "#]], + ); + check( + r#" +//- /lib.rs crate:dep +pub struct Barc; +pub struct Rcar; +pub struct Rc; +pub const RC: () = (); +pub mod some_module { + pub struct Bar; + pub struct Rcar; + pub struct Rc; + pub const RC: () = (); +} + +//- /main.rs crate:main deps:dep +fn main() { + RC$0 +} +"#, + expect![[r#" + ct RC (use dep::RC) + ct RC (use dep::some_module::RC) "#]], ); } @@ -841,8 +897,8 @@ fn main() { TES$0 }"#, expect![[r#" - ct TEST_CONST (use foo::TEST_CONST) - "#]], + ct TEST_CONST (use foo::TEST_CONST) + "#]], ); check( @@ -858,9 +914,9 @@ fn main() { tes$0 }"#, expect![[r#" - ct TEST_CONST (use foo::TEST_CONST) - fn test_function() (use foo::test_function) fn() -> i32 - "#]], + ct TEST_CONST (use foo::TEST_CONST) + fn test_function() (use foo::test_function) fn() -> i32 + "#]], ); check( @@ -873,9 +929,9 @@ mod foo { } fn main() { - Te$0 + Tes$0 }"#, - expect![[]], + expect![""], ); } diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs index e475c5cd66b6..da5a951f0b7b 100644 --- a/crates/ide-db/src/imports/import_assets.rs +++ b/crates/ide-db/src/imports/import_assets.rs @@ -68,22 +68,29 @@ pub struct FirstSegmentUnresolved { pub enum NameToImport { /// Requires items with names that exactly match the given string, bool indicates case-sensitivity. Exact(String, bool), - /// Requires items with names that case-insensitively contain all letters from the string, + /// Requires items with names that match the given string by prefix, bool indicates case-sensitivity. + Prefix(String, bool), + /// Requires items with names contain all letters from the string, /// in the same order, but not necessary adjacent. - Fuzzy(String), + Fuzzy(String, bool), } impl NameToImport { pub fn exact_case_sensitive(s: String) -> NameToImport { NameToImport::Exact(s, true) } -} -impl NameToImport { + pub fn fuzzy(s: String) -> NameToImport { + // unless all chars are lowercase, we do a case sensitive search + let case_sensitive = s.chars().any(|c| c.is_uppercase()); + NameToImport::Fuzzy(s, case_sensitive) + } + pub fn text(&self) -> &str { match self { - NameToImport::Exact(text, _) => text.as_str(), - NameToImport::Fuzzy(text) => text.as_str(), + NameToImport::Prefix(text, _) + | NameToImport::Exact(text, _) + | NameToImport::Fuzzy(text, _) => text.as_str(), } } } @@ -165,7 +172,7 @@ impl ImportAssets { Some(Self { import_candidate: ImportCandidate::TraitMethod(TraitImportCandidate { receiver_ty, - assoc_item_name: NameToImport::Fuzzy(fuzzy_method_name), + assoc_item_name: NameToImport::fuzzy(fuzzy_method_name), }), module_with_candidate: module_with_method_call, candidate_node, @@ -228,12 +235,30 @@ impl ImportAssets { self.search_for(sema, None, prefer_no_std) } - pub fn path_fuzzy_name_to_exact(&mut self, case_sensitive: bool) { + /// Requires imports to by prefix instead of fuzzily. + pub fn path_fuzzy_name_to_prefix(&mut self) { if let ImportCandidate::Path(PathImportCandidate { name: to_import, .. }) = &mut self.import_candidate { - let name = match to_import { - NameToImport::Fuzzy(name) => std::mem::take(name), + let (name, case_sensitive) = match to_import { + NameToImport::Fuzzy(name, case_sensitive) => { + (std::mem::take(name), *case_sensitive) + } + _ => return, + }; + *to_import = NameToImport::Prefix(name, case_sensitive); + } + } + + /// Requires imports to match exactly instead of fuzzily. + pub fn path_fuzzy_name_to_exact(&mut self) { + if let ImportCandidate::Path(PathImportCandidate { name: to_import, .. }) = + &mut self.import_candidate + { + let (name, case_sensitive) = match to_import { + NameToImport::Fuzzy(name, case_sensitive) => { + (std::mem::take(name), *case_sensitive) + } _ => return, }; *to_import = NameToImport::Exact(name, case_sensitive); @@ -623,7 +648,7 @@ impl ImportCandidate { fuzzy_name: String, sema: &Semantics<'_, RootDatabase>, ) -> Option { - path_import_candidate(sema, qualifier, NameToImport::Fuzzy(fuzzy_name)) + path_import_candidate(sema, qualifier, NameToImport::fuzzy(fuzzy_name)) } } diff --git a/crates/ide-db/src/items_locator.rs b/crates/ide-db/src/items_locator.rs index 3f7a3ec2d0fd..67ed44f08b7f 100644 --- a/crates/ide-db/src/items_locator.rs +++ b/crates/ide-db/src/items_locator.rs @@ -31,26 +31,34 @@ pub fn items_with_name<'a>( ) }); + let prefix = matches!(name, NameToImport::Prefix(..)); let (mut local_query, mut external_query) = match name { - NameToImport::Exact(exact_name, case_sensitive) => { + NameToImport::Prefix(exact_name, case_sensitive) + | NameToImport::Exact(exact_name, case_sensitive) => { let mut local_query = symbol_index::Query::new(exact_name.clone()); - local_query.exact(); - - let external_query = import_map::Query::new(exact_name); - - ( - local_query, - if case_sensitive { external_query.case_sensitive() } else { external_query }, - ) + let mut external_query = import_map::Query::new(exact_name); + if prefix { + local_query.prefix(); + external_query = external_query.prefix(); + } else { + local_query.exact(); + external_query = external_query.exact(); + } + if case_sensitive { + local_query.case_sensitive(); + external_query = external_query.case_sensitive(); + } + (local_query, external_query) } - NameToImport::Fuzzy(fuzzy_search_string) => { + NameToImport::Fuzzy(fuzzy_search_string, case_sensitive) => { let mut local_query = symbol_index::Query::new(fuzzy_search_string.clone()); + local_query.fuzzy(); let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) .fuzzy() .assoc_search_mode(assoc_item_search); - if fuzzy_search_string.to_lowercase() != fuzzy_search_string { + if case_sensitive { local_query.case_sensitive(); external_query = external_query.case_sensitive(); } diff --git a/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs index f699f999baf7..3e89159c2c6e 100644 --- a/crates/ide-db/src/symbol_index.rs +++ b/crates/ide-db/src/symbol_index.rs @@ -43,13 +43,20 @@ use triomphe::Arc; use crate::RootDatabase; +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum SearchMode { + Fuzzy, + Exact, + Prefix, +} + #[derive(Debug)] pub struct Query { query: String, lowercased: String, only_types: bool, libs: bool, - exact: bool, + mode: SearchMode, case_sensitive: bool, limit: usize, } @@ -62,7 +69,7 @@ impl Query { lowercased, only_types: false, libs: false, - exact: false, + mode: SearchMode::Fuzzy, case_sensitive: false, limit: usize::max_value(), } @@ -76,8 +83,16 @@ impl Query { self.libs = true; } + pub fn fuzzy(&mut self) { + self.mode = SearchMode::Fuzzy; + } + pub fn exact(&mut self) { - self.exact = true; + self.mode = SearchMode::Exact; + } + + pub fn prefix(&mut self) { + self.mode = SearchMode::Prefix; } pub fn case_sensitive(&mut self) { @@ -329,13 +344,23 @@ impl Query { { continue; } - if self.exact { - if symbol.name != self.query { - continue; + let skip = match self.mode { + SearchMode::Fuzzy => { + self.case_sensitive + && self.query.chars().any(|c| !symbol.name.contains(c)) } - } else if self.case_sensitive - && self.query.chars().any(|c| !symbol.name.contains(c)) - { + SearchMode::Exact => symbol.name != self.query, + SearchMode::Prefix if self.case_sensitive => { + !symbol.name.starts_with(&self.query) + } + SearchMode::Prefix => symbol + .name + .chars() + .zip(self.lowercased.chars()) + .all(|(n, q)| n.to_lowercase().next() == Some(q)), + }; + + if skip { continue; } From 58239f2990ac8f148d943960a23c625465f7a80e Mon Sep 17 00:00:00 2001 From: cui fliter Date: Thu, 5 Oct 2023 17:41:50 +0800 Subject: [PATCH 2290/2442] Remove repetitive words Signed-off-by: cui fliter --- crates/ide/src/syntax_highlighting.rs | 2 +- crates/mbe/src/expander.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index bb01c81d66fb..dd72484b3807 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -245,7 +245,7 @@ fn traverse( let mut macro_highlighter = MacroHighlighter::default(); // FIXME: these are not perfectly accurate, we determine them by the real file's syntax tree - // an an attribute nested in a macro call will not emit `inside_attribute` + // an attribute nested in a macro call will not emit `inside_attribute` let mut inside_attribute = false; let mut inside_macro_call = false; diff --git a/crates/mbe/src/expander.rs b/crates/mbe/src/expander.rs index f2d89d3efe5a..908048c99042 100644 --- a/crates/mbe/src/expander.rs +++ b/crates/mbe/src/expander.rs @@ -119,7 +119,7 @@ enum Fragment { /// precedence. Note that this impl is different from the one currently in /// `rustc` -- `rustc` doesn't translate fragments into token trees at all. /// - /// At one point in time, we tried to to use "fake" delimiters here a-la + /// At one point in time, we tried to use "fake" delimiters here à la /// proc-macro delimiter=none. As we later discovered, "none" delimiters are /// tricky to handle in the parser, and rustc doesn't handle those either. Expr(tt::TokenTree), From e7295ff40cc507627e763425e78003dc7ac977e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 5 Oct 2023 15:03:44 +0300 Subject: [PATCH 2291/2442] Prepare for rust-bors --- .github/workflows/ci.yaml | 1 + rust-bors.toml | 1 + 2 files changed, 2 insertions(+) create mode 100644 rust-bors.toml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6dc339eddf34..1f2a7796d114 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -8,6 +8,7 @@ on: branches: - auto - try + - automation/bors/try env: CARGO_INCREMENTAL: 0 diff --git a/rust-bors.toml b/rust-bors.toml new file mode 100644 index 000000000000..c31ba66c50f4 --- /dev/null +++ b/rust-bors.toml @@ -0,0 +1 @@ +timeout = 3600 From 114f8a07e99346083e302eed8ea0ab475923b61a Mon Sep 17 00:00:00 2001 From: Tobias Berger Date: Fri, 6 Oct 2023 09:24:28 +0200 Subject: [PATCH 2292/2442] Fix typos exec_intrinsic --- crates/hir-ty/src/mir/eval/shim.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 803ef631f1e0..2de99e41659c 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -1045,7 +1045,7 @@ impl Evaluator<'_> { } "transmute" => { let [arg] = args else { - return Err(MirEvalError::TypeError("trasmute arg is not provided")); + return Err(MirEvalError::TypeError("transmute arg is not provided")); }; destination.write_from_interval(self, arg.interval) } @@ -1065,7 +1065,7 @@ impl Evaluator<'_> { } "ctlz" | "ctlz_nonzero" => { let [arg] = args else { - return Err(MirEvalError::TypeError("cttz arg is not provided")); + return Err(MirEvalError::TypeError("ctlz arg is not provided")); }; let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).leading_zeros() as usize; From 88a00bf49d1d183c65489e6d02b6e4678c824322 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 6 Oct 2023 12:32:37 +0200 Subject: [PATCH 2293/2442] Shrink PatPtr by swapping its AstPtr and Either wrap order --- crates/hir-def/src/body.rs | 6 +- crates/hir-def/src/body/lower.rs | 26 +++-- crates/hir-def/src/body/scope.rs | 5 +- crates/hir-ty/src/diagnostics/decl_check.rs | 72 +++++++------- crates/hir-ty/src/mir/eval.rs | 5 +- crates/hir-ty/src/tests.rs | 14 +-- crates/hir/src/diagnostics.rs | 11 +-- crates/hir/src/lib.rs | 99 ++++++++++--------- .../src/handlers/mismatched_arg_count.rs | 7 +- .../src/handlers/missing_fields.rs | 16 ++- .../src/handlers/no_such_field.rs | 18 ++-- .../src/handlers/private_assoc_item.rs | 10 +- .../src/handlers/type_mismatch.rs | 36 ++++--- .../rust-analyzer/src/cli/analysis_stats.rs | 11 +-- crates/syntax/src/ptr.rs | 18 ++++ 15 files changed, 164 insertions(+), 190 deletions(-) diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index c0baf6011f79..1942c60c075d 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -57,7 +57,7 @@ pub struct Body { pub type ExprPtr = AstPtr; pub type ExprSource = InFile; -pub type PatPtr = Either, AstPtr>; +pub type PatPtr = AstPtr>; pub type PatSource = InFile; pub type LabelPtr = AstPtr; @@ -356,12 +356,12 @@ impl BodySourceMap { } pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option { - let src = node.map(|it| Either::Left(AstPtr::new(it))); + let src = node.map(|it| AstPtr::new(it).wrap_left()); self.pat_map.get(&src).cloned() } pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option { - let src = node.map(|it| Either::Right(AstPtr::new(it))); + let src = node.map(|it| AstPtr::new(it).wrap_right()); self.pat_map.get(&src).cloned() } diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index cc02df80a8ff..e4158d7564bd 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -196,16 +196,12 @@ impl ExprCollector<'_> { if let Some(self_param) = param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false)) { - let ptr = AstPtr::new(&self_param); - let binding_id: la_arena::Idx = self.alloc_binding( - name![self], - BindingAnnotation::new( - self_param.mut_token().is_some() && self_param.amp_token().is_none(), - false, - ), - ); - let param_pat = - self.alloc_pat(Pat::Bind { id: binding_id, subpat: None }, Either::Right(ptr)); + let is_mutable = + self_param.mut_token().is_some() && self_param.amp_token().is_none(); + let ptr = AstPtr::new(&Either::Right(self_param)); + let binding_id: la_arena::Idx = + self.alloc_binding(name![self], BindingAnnotation::new(is_mutable, false)); + let param_pat = self.alloc_pat(Pat::Bind { id: binding_id, subpat: None }, ptr); self.add_definition_to_binding(binding_id, param_pat); self.body.params.push(param_pat); } @@ -1260,8 +1256,8 @@ impl ExprCollector<'_> { (Some(id), Pat::Bind { id, subpat }) }; - let ptr = AstPtr::new(&pat); - let pat = self.alloc_pat(pattern, Either::Left(ptr)); + let ptr = AstPtr::new(&Either::Left(pat)); + let pat = self.alloc_pat(pattern, ptr); if let Some(binding_id) = binding { self.add_definition_to_binding(binding_id, pat); } @@ -1395,7 +1391,7 @@ impl ExprCollector<'_> { ast::Pat::MacroPat(mac) => match mac.macro_call() { Some(call) => { let macro_ptr = AstPtr::new(&call); - let src = self.expander.to_source(Either::Left(AstPtr::new(&pat))); + let src = self.expander.to_source(AstPtr::new(&Either::Left(pat))); let pat = self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| { this.collect_pat_opt(expanded_pat, binding_list) @@ -1430,8 +1426,8 @@ impl ExprCollector<'_> { Pat::Range { start, end } } }; - let ptr = AstPtr::new(&pat); - self.alloc_pat(pattern, Either::Left(ptr)) + let ptr = AstPtr::new(&Either::Left(pat)); + self.alloc_pat(pattern, ptr) } fn collect_pat_opt(&mut self, pat: Option, binding_list: &mut BindingList) -> PatId { diff --git a/crates/hir-def/src/body/scope.rs b/crates/hir-def/src/body/scope.rs index f69466631355..baca293e2904 100644 --- a/crates/hir-def/src/body/scope.rs +++ b/crates/hir-def/src/body/scope.rs @@ -475,10 +475,7 @@ fn foo() { .pat_syntax(*body.bindings[resolved.binding()].definitions.first().unwrap()) .unwrap(); - let local_name = pat_src.value.either( - |it| it.syntax_node_ptr().to_node(file.syntax()), - |it| it.syntax_node_ptr().to_node(file.syntax()), - ); + let local_name = pat_src.value.syntax_node_ptr().to_node(file.syntax()); assert_eq!(local_name.text_range(), expected_name.syntax().text_range()); } diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs index 36d69edf9d5d..60563e02b701 100644 --- a/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/crates/hir-ty/src/diagnostics/decl_check.rs @@ -336,48 +336,44 @@ impl<'a> DeclValidator<'a> { for (id, replacement) in pats_replacements { if let Ok(source_ptr) = source_map.pat_syntax(id) { - if let Some(expr) = source_ptr.value.as_ref().left() { + if let Some(ptr) = source_ptr.value.clone().cast::() { let root = source_ptr.file_syntax(self.db.upcast()); - if let ast::Pat::IdentPat(ident_pat) = expr.to_node(&root) { - let parent = match ident_pat.syntax().parent() { - Some(parent) => parent, - None => continue, - }; - let name_ast = match ident_pat.name() { - Some(name_ast) => name_ast, - None => continue, - }; + let ident_pat = ptr.to_node(&root); + let parent = match ident_pat.syntax().parent() { + Some(parent) => parent, + None => continue, + }; + let name_ast = match ident_pat.name() { + Some(name_ast) => name_ast, + None => continue, + }; - let is_param = ast::Param::can_cast(parent.kind()); + let is_param = ast::Param::can_cast(parent.kind()); - // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement, - // because e.g. match arms are patterns as well. - // In other words, we check that it's a named variable binding. - let is_binding = ast::LetStmt::can_cast(parent.kind()) - || (ast::MatchArm::can_cast(parent.kind()) - && ident_pat.at_token().is_some()); - if !(is_param || is_binding) { - // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm. - continue; - } - - let ident_type = - if is_param { IdentType::Parameter } else { IdentType::Variable }; - - let diagnostic = IncorrectCase { - file: source_ptr.file_id, - ident_type, - ident: AstPtr::new(&name_ast), - expected_case: replacement.expected_case, - ident_text: replacement - .current_name - .display(self.db.upcast()) - .to_string(), - suggested_text: replacement.suggested_text, - }; - - self.sink.push(diagnostic); + // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement, + // because e.g. match arms are patterns as well. + // In other words, we check that it's a named variable binding. + let is_binding = ast::LetStmt::can_cast(parent.kind()) + || (ast::MatchArm::can_cast(parent.kind()) + && ident_pat.at_token().is_some()); + if !(is_param || is_binding) { + // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm. + continue; } + + let ident_type = + if is_param { IdentType::Parameter } else { IdentType::Variable }; + + let diagnostic = IncorrectCase { + file: source_ptr.file_id, + ident_type, + ident: AstPtr::new(&name_ast), + expected_case: replacement.expected_case, + ident_text: replacement.current_name.display(self.db.upcast()).to_string(), + suggested_text: replacement.suggested_text, + }; + + self.sink.push(diagnostic); } } } diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 98c78f7f3051..7823c3203413 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -375,10 +375,7 @@ impl MirEvalError { Err(_) => continue, }, MirSpan::PatId(p) => match source_map.pat_syntax(*p) { - Ok(s) => s.map(|it| match it { - Either::Left(e) => e.into(), - Either::Right(e) => e.into(), - }), + Ok(s) => s.map(|it| it.syntax_node_ptr()), Err(_) => continue, }, MirSpan::Unknown => continue, diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index d22d0d85c8e1..1446e83fa887 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -269,12 +269,7 @@ fn pat_node( Some(match body_source_map.pat_syntax(pat) { Ok(sp) => { let root = db.parse_or_expand(sp.file_id); - sp.map(|ptr| { - ptr.either( - |it| it.to_node(&root).syntax().clone(), - |it| it.to_node(&root).syntax().clone(), - ) - }) + sp.map(|ptr| ptr.to_node(&root).syntax().clone()) } Err(SyntheticSyntax) => return None, }) @@ -303,12 +298,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let syntax_ptr = match body_source_map.pat_syntax(pat) { Ok(sp) => { let root = db.parse_or_expand(sp.file_id); - sp.map(|ptr| { - ptr.either( - |it| it.to_node(&root).syntax().clone(), - |it| it.to_node(&root).syntax().clone(), - ) - }) + sp.map(|ptr| ptr.to_node(&root).syntax().clone()) } Err(SyntheticSyntax) => continue, }; diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 66ad95c5597c..67d3169243c6 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -174,20 +174,19 @@ pub struct MalformedDerive { #[derive(Debug)] pub struct NoSuchField { - pub field: InFile, AstPtr>>, + pub field: InFile>>, pub private: bool, } #[derive(Debug)] pub struct PrivateAssocItem { - pub expr_or_pat: - InFile, Either, AstPtr>>>, + pub expr_or_pat: InFile>>>, pub item: AssocItem, } #[derive(Debug)] pub struct MismatchedTupleStructPatArgCount { - pub expr_or_pat: InFile, AstPtr>>, + pub expr_or_pat: InFile>>, pub expected: usize, pub found: usize, } @@ -228,7 +227,7 @@ pub struct MissingUnsafe { #[derive(Debug)] pub struct MissingFields { pub file: HirFileId, - pub field_list_parent: Either, AstPtr>, + pub field_list_parent: AstPtr>, pub field_list_parent_path: Option>, pub missed_fields: Vec, } @@ -255,7 +254,7 @@ pub struct MissingMatchArms { #[derive(Debug)] pub struct TypeMismatch { - pub expr_or_pat: Either>, InFile>>, + pub expr_or_pat: InFile>>, pub expected: Type, pub actual: Type, } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8e48afd6af81..8246297705ca 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1509,10 +1509,10 @@ impl DefWithBody { &hir_ty::InferenceDiagnostic::NoSuchField { field: expr, private } => { let expr_or_pat = match expr { ExprOrPatId::ExprId(expr) => { - source_map.field_syntax(expr).map(Either::Left) + source_map.field_syntax(expr).map(AstPtr::wrap_left) } ExprOrPatId::PatId(pat) => { - source_map.pat_field_syntax(pat).map(Either::Right) + source_map.pat_field_syntax(pat).map(AstPtr::wrap_right) } }; acc.push(NoSuchField { field: expr_or_pat, private }.into()) @@ -1530,8 +1530,8 @@ impl DefWithBody { } &hir_ty::InferenceDiagnostic::PrivateAssocItem { id, item } => { let expr_or_pat = match id { - ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(Either::Left), - ExprOrPatId::PatId(pat) => pat_syntax(pat).map(Either::Right), + ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left), + ExprOrPatId::PatId(pat) => pat_syntax(pat).map(AstPtr::wrap_right), }; let item = item.into(); acc.push(PrivateAssocItem { expr_or_pat, item }.into()) @@ -1609,12 +1609,17 @@ impl DefWithBody { found, } => { let expr_or_pat = match pat { - ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(Either::Left), - ExprOrPatId::PatId(pat) => source_map - .pat_syntax(pat) - .expect("unexpected synthetic") - .map(|it| it.unwrap_left()) - .map(Either::Right), + ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left), + ExprOrPatId::PatId(pat) => { + let InFile { file_id, value } = + source_map.pat_syntax(pat).expect("unexpected synthetic"); + + // cast from Either -> Either<_, Pat> + let Some(ptr) = AstPtr::try_from_raw(value.syntax_node_ptr()) else { + continue; + }; + InFile { file_id, value: ptr } + } }; acc.push( MismatchedTupleStructPatArgCount { expr_or_pat, expected, found }.into(), @@ -1628,11 +1633,15 @@ impl DefWithBody { ExprOrPatId::PatId(pat) => source_map.pat_syntax(pat).map(Either::Right), }; let expr_or_pat = match expr_or_pat { - Ok(Either::Left(expr)) => Either::Left(expr), - Ok(Either::Right(InFile { file_id, value: Either::Left(pat) })) => { - Either::Right(InFile { file_id, value: pat }) + Ok(Either::Left(expr)) => expr.map(AstPtr::wrap_left), + Ok(Either::Right(InFile { file_id, value: pat })) => { + // cast from Either -> Either<_, Pat> + let Some(ptr) = AstPtr::try_from_raw(pat.syntax_node_ptr()) else { + continue; + }; + InFile { file_id, value: ptr } } - Ok(Either::Right(_)) | Err(SyntheticSyntax) => continue, + Err(SyntheticSyntax) => continue, }; acc.push( @@ -1667,10 +1676,7 @@ impl DefWithBody { Err(_) => continue, }, mir::MirSpan::PatId(p) => match source_map.pat_syntax(p) { - Ok(s) => s.map(|it| match it { - Either::Left(e) => e.into(), - Either::Right(e) => e.into(), - }), + Ok(s) => s.map(|it| it.into()), Err(_) => continue, }, mir::MirSpan::Unknown => continue, @@ -1721,10 +1727,7 @@ impl DefWithBody { Err(_) => continue, }, mir::MirSpan::PatId(p) => match source_map.pat_syntax(*p) { - Ok(s) => s.map(|it| match it { - Either::Left(e) => e.into(), - Either::Right(e) => e.into(), - }), + Ok(s) => s.map(|it| it.into()), Err(_) => continue, }, mir::MirSpan::Unknown => continue, @@ -1763,18 +1766,18 @@ impl DefWithBody { Ok(source_ptr) => { let root = source_ptr.file_syntax(db.upcast()); if let ast::Expr::RecordExpr(record_expr) = - &source_ptr.value.to_node(&root) + source_ptr.value.to_node(&root) { if record_expr.record_expr_field_list().is_some() { + let field_list_parent_path = + record_expr.path().map(|path| AstPtr::new(&path)); acc.push( MissingFields { file: source_ptr.file_id, - field_list_parent: Either::Left(AstPtr::new( + field_list_parent: AstPtr::new(&Either::Left( record_expr, )), - field_list_parent_path: record_expr - .path() - .map(|path| AstPtr::new(&path)), + field_list_parent_path, missed_fields, } .into(), @@ -1786,24 +1789,24 @@ impl DefWithBody { }, Either::Right(record_pat) => match source_map.pat_syntax(record_pat) { Ok(source_ptr) => { - if let Some(expr) = source_ptr.value.as_ref().left() { + if let Some(ptr) = source_ptr.value.clone().cast::() + { let root = source_ptr.file_syntax(db.upcast()); - if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { - if record_pat.record_pat_field_list().is_some() { - acc.push( - MissingFields { - file: source_ptr.file_id, - field_list_parent: Either::Right(AstPtr::new( - &record_pat, - )), - field_list_parent_path: record_pat - .path() - .map(|path| AstPtr::new(&path)), - missed_fields, - } - .into(), - ) - } + let record_pat = ptr.to_node(&root); + if record_pat.record_pat_field_list().is_some() { + let field_list_parent_path = + record_pat.path().map(|path| AstPtr::new(&path)); + acc.push( + MissingFields { + file: source_ptr.file_id, + field_list_parent: AstPtr::new(&Either::Right( + record_pat, + )), + field_list_parent_path, + missed_fields, + } + .into(), + ) } } } @@ -2948,10 +2951,10 @@ impl Local { .map(|&definition| { let src = source_map.pat_syntax(definition).unwrap(); // Hmm... let root = src.file_syntax(db.upcast()); - src.map(|ast| match ast { - // Suspicious unwrap - Either::Left(it) => Either::Left(it.cast().unwrap().to_node(&root)), - Either::Right(it) => Either::Right(it.to_node(&root)), + src.map(|ast| match ast.to_node(&root) { + Either::Left(ast::Pat::IdentPat(it)) => Either::Left(it), + Either::Left(_) => unreachable!("local with non ident-pattern"), + Either::Right(it) => Either::Right(it), }) }) .map(move |source| LocalSource { local: self, source }) diff --git a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs index ede9858c7265..06ba13bcc55c 100644 --- a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs +++ b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs @@ -23,12 +23,7 @@ pub(crate) fn mismatched_tuple_struct_pat_arg_count( Diagnostic::new( DiagnosticCode::RustcHardError("E0023"), message, - invalid_args_range( - ctx, - d.expr_or_pat.clone().map(|it| it.either(Into::into, Into::into)), - d.expected, - d.found, - ), + invalid_args_range(ctx, d.expr_or_pat.clone().map(Into::into), d.expected, d.found), ) } diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index 3178c7fa2bc7..c09be3fee7e1 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -39,7 +39,7 @@ pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingField d.field_list_parent_path .clone() .map(SyntaxNodePtr::from) - .unwrap_or_else(|| d.field_list_parent.clone().either(|it| it.into(), |it| it.into())), + .unwrap_or_else(|| d.field_list_parent.clone().into()), ); Diagnostic::new_with_syntax_node_ptr(ctx, DiagnosticCode::RustcHardError("E0063"), message, ptr) @@ -58,10 +58,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option ctx.sema.scope(ptr.to_node(&root).syntax()).map(|it| it.module()), - Either::Right(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).map(|it| it.module()), - }; + let current_module = + ctx.sema.scope(d.field_list_parent.to_node(&root).syntax()).map(|it| it.module()); let build_text_edit = |parent_syntax, new_syntax: &SyntaxNode, old_syntax| { let edit = { @@ -87,9 +85,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option { - let field_list_parent = record_expr.to_node(&root); + match &d.field_list_parent.to_node(&root) { + Either::Left(field_list_parent) => { let missing_fields = ctx.sema.record_literal_missing_fields(&field_list_parent); let mut locals = FxHashMap::default(); @@ -152,8 +149,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option { - let field_list_parent = record_pat.to_node(&root); + Either::Right(field_list_parent) => { let missing_fields = ctx.sema.record_pattern_missing_fields(&field_list_parent); let old_field_list = field_list_parent.record_pat_field_list()?; diff --git a/crates/ide-diagnostics/src/handlers/no_such_field.rs b/crates/ide-diagnostics/src/handlers/no_such_field.rs index 290c16c9d247..ee8a9c95793c 100644 --- a/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -13,7 +13,7 @@ use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext}; // // This diagnostic is triggered if created structure does not have field provided in record. pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic { - let node = d.field.clone().map(|it| it.either(Into::into, Into::into)); + let node = d.field.clone().map(Into::into); if d.private { // FIXME: quickfix to add required visibility Diagnostic::new_with_syntax_node_ptr( @@ -35,15 +35,13 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option> { // FIXME: quickfix for pattern - match &d.field.value { - Either::Left(ptr) => { - let root = ctx.sema.db.parse_or_expand(d.field.file_id); - missing_record_expr_field_fixes( - &ctx.sema, - d.field.file_id.original_file(ctx.sema.db), - &ptr.to_node(&root), - ) - } + let root = ctx.sema.db.parse_or_expand(d.field.file_id); + match &d.field.value.to_node(&root) { + Either::Left(node) => missing_record_expr_field_fixes( + &ctx.sema, + d.field.file_id.original_file(ctx.sema.db), + node, + ), _ => None, } } diff --git a/crates/ide-diagnostics/src/handlers/private_assoc_item.rs b/crates/ide-diagnostics/src/handlers/private_assoc_item.rs index c44d28e77f6d..a828b8b4fd29 100644 --- a/crates/ide-diagnostics/src/handlers/private_assoc_item.rs +++ b/crates/ide-diagnostics/src/handlers/private_assoc_item.rs @@ -1,5 +1,3 @@ -use either::Either; - use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: private-assoc-item @@ -28,13 +26,7 @@ pub(crate) fn private_assoc_item( }, name, ), - d.expr_or_pat.clone().map(|it| match it { - Either::Left(it) => it.into(), - Either::Right(it) => match it { - Either::Left(it) => it.into(), - Either::Right(it) => it.into(), - }, - }), + d.expr_or_pat.clone().map(Into::into), ) } diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 1f400bb42dde..14454fe8dc40 100644 --- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -1,4 +1,3 @@ -use either::Either; use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, InFile, Type}; use ide_db::{famous_defs::FamousDefs, source_change::SourceChange}; use syntax::{ @@ -14,9 +13,11 @@ use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticCode, Dia // This diagnostic is triggered when the type of an expression or pattern does not match // the expected type. pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic { - let display_range = match &d.expr_or_pat { - Either::Left(expr) => { - adjusted_display_range::(ctx, expr.clone().map(|it| it.into()), &|expr| { + let display_range = match &d.expr_or_pat.value { + expr if ast::Expr::can_cast(expr.kind()) => adjusted_display_range::( + ctx, + InFile { file_id: d.expr_or_pat.file_id, value: expr.syntax_node_ptr() }, + &|expr| { let salient_token_range = match expr { ast::Expr::IfExpr(it) => it.if_token()?.text_range(), ast::Expr::LoopExpr(it) => it.loop_token()?.text_range(), @@ -32,10 +33,15 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) cov_mark::hit!(type_mismatch_range_adjustment); Some(salient_token_range) - }) - } - Either::Right(pat) => { - ctx.sema.diagnostics_display_range(pat.clone().map(|it| it.into())).range + }, + ), + pat => { + ctx.sema + .diagnostics_display_range(InFile { + file_id: d.expr_or_pat.file_id, + value: pat.syntax_node_ptr(), + }) + .range } }; let mut diag = Diagnostic::new( @@ -57,14 +63,12 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option> { let mut fixes = Vec::new(); - match &d.expr_or_pat { - Either::Left(expr_ptr) => { - add_reference(ctx, d, expr_ptr, &mut fixes); - add_missing_ok_or_some(ctx, d, expr_ptr, &mut fixes); - remove_semicolon(ctx, d, expr_ptr, &mut fixes); - str_ref_to_owned(ctx, d, expr_ptr, &mut fixes); - } - Either::Right(_pat_ptr) => {} + if let Some(expr_ptr) = d.expr_or_pat.value.clone().cast::() { + let expr_ptr = &InFile { file_id: d.expr_or_pat.file_id, value: expr_ptr.clone() }; + add_reference(ctx, d, expr_ptr, &mut fixes); + add_missing_ok_or_some(ctx, d, expr_ptr, &mut fixes); + remove_semicolon(ctx, d, expr_ptr, &mut fixes); + str_ref_to_owned(ctx, d, expr_ptr, &mut fixes); } if fixes.is_empty() { diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index dcb3ca6581cb..230ff5f9b86a 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -846,9 +846,7 @@ fn location_csv_pat(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, pat_id: Pa Err(SyntheticSyntax) => return "synthetic,,".to_string(), }; let root = db.parse_or_expand(src.file_id); - let node = src.map(|e| { - e.either(|it| it.to_node(&root).syntax().clone(), |it| it.to_node(&root).syntax().clone()) - }); + let node = src.map(|e| e.to_node(&root).syntax().clone()); let original_range = node.as_ref().original_file_range(db); let path = vfs.file_path(original_range.file_id); let line_index = db.line_index(original_range.file_id); @@ -888,12 +886,7 @@ fn pat_syntax_range( let src = sm.pat_syntax(pat_id); if let Ok(src) = src { let root = db.parse_or_expand(src.file_id); - let node = src.map(|e| { - e.either( - |it| it.to_node(&root).syntax().clone(), - |it| it.to_node(&root).syntax().clone(), - ) - }); + let node = src.map(|e| e.to_node(&root).syntax().clone()); let original_range = node.as_ref().original_file_range(db); let path = vfs.file_path(original_range.file_id); let line_index = db.line_index(original_range.file_id); diff --git a/crates/syntax/src/ptr.rs b/crates/syntax/src/ptr.rs index 1d4a89201ae4..71762996cd7d 100644 --- a/crates/syntax/src/ptr.rs +++ b/crates/syntax/src/ptr.rs @@ -73,6 +73,10 @@ impl AstPtr { Some(AstPtr { raw: self.raw, _ty: PhantomData }) } + pub fn kind(&self) -> parser::SyntaxKind { + self.raw.kind() + } + pub fn upcast(self) -> AstPtr where N: Into, @@ -84,6 +88,20 @@ impl AstPtr { pub fn try_from_raw(raw: SyntaxNodePtr) -> Option> { N::can_cast(raw.kind()).then_some(AstPtr { raw, _ty: PhantomData }) } + + pub fn wrap_left(self) -> AstPtr> + where + either::Either: AstNode, + { + AstPtr { raw: self.raw, _ty: PhantomData } + } + + pub fn wrap_right(self) -> AstPtr> + where + either::Either: AstNode, + { + AstPtr { raw: self.raw, _ty: PhantomData } + } } impl From> for SyntaxNodePtr { From b3ebc9ab6a0793612d75d3587f9de3522f6a71bb Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 6 Oct 2023 13:26:36 +0200 Subject: [PATCH 2294/2442] Check for both path separators on windows --- crates/rust-analyzer/src/handlers/request.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index 8dc0c97bc58f..6c2f1ec3fede 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -2000,8 +2000,18 @@ fn run_rustfmt( let workspace = CargoTargetSpec::for_file(&snap, file_id)?; let mut cmd = match workspace { Some(spec) => { - let cmd = spec.workspace_root.join(cmd); - process::Command::new(cmd.as_os_str()) + // approach: if the command name contains a path seperator, join it with the workspace root. + // however, if the path is absolute, joining will result in the absolute path being preserved. + // as a fallback, rely on $PATH-based discovery. + let cmd_path = + if cfg!(windows) && command.contains(&[std::path::MAIN_SEPARATOR, '/']) { + spec.workspace_root.join(cmd).into() + } else if command.contains(std::path::MAIN_SEPARATOR) { + spec.workspace_root.join(cmd).into() + } else { + cmd + }; + process::Command::new(cmd_path) } None => process::Command::new(cmd), }; From c5d9bfaa52d04cdebc691ec3eb7433e5f27ccddd Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sat, 7 Oct 2023 23:24:55 +0200 Subject: [PATCH 2295/2442] internal: fix automatic rustc/rustdoc lint generation --- crates/ide-db/src/generated/lints.rs | 95 ++++++++-------- crates/ide-db/src/tests/sourcegen_lints.rs | 122 +++++++++++++-------- 2 files changed, 125 insertions(+), 92 deletions(-) diff --git a/crates/ide-db/src/generated/lints.rs b/crates/ide-db/src/generated/lints.rs index 52321d5bf1d7..9ddcae60563e 100644 --- a/crates/ide-db/src/generated/lints.rs +++ b/crates/ide-db/src/generated/lints.rs @@ -30,6 +30,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "asm_sub_register", description: r##"using only a subset of a register for inline asm inputs"##, }, + Lint { + label: "async_fn_in_trait", + description: r##"use of `async fn` in definition of a publicly-reachable trait"##, + }, Lint { label: "bad_asm_style", description: r##"incorrect use of inline assembly"## }, Lint { label: "bare_trait_objects", @@ -80,6 +84,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "const_item_mutation", description: r##"detects attempts to mutate a `const` item"##, }, + Lint { + label: "const_patterns_without_partial_eq", + description: r##"constant in pattern does not implement `PartialEq`"##, + }, Lint { label: "dead_code", description: r##"detect unused, unexported items"## }, Lint { label: "deprecated", description: r##"detects use of deprecated items"## }, Lint { @@ -166,7 +174,7 @@ pub const DEFAULT_LINTS: &[Lint] = &[ }, Lint { label: "future_incompatible", - description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, implied-bounds-entailment, indirect-structural-match, invalid-alignment, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety"##, + description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, const-patterns-without-partial-eq, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, implied-bounds-entailment, indirect-structural-match, invalid-alignment, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety"##, }, Lint { label: "fuzzy_provenance_casts", @@ -731,11 +739,12 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"suggest using `loop { }` instead of `while true { }`"##, }, ]; + pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "future_incompatible", - description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, implied-bounds-entailment, indirect-structural-match, invalid-alignment, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety"##, + description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, coinductive-overlap-in-coherence, conflicting-repr-hints, const-evaluatable-unchecked, const-patterns-without-partial-eq, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, illegal-floating-point-literal-pattern, implied-bounds-entailment, indirect-structural-match, invalid-alignment, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, suspicious-auto-trait-impls, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety"##, }, children: &[ "deref_into_dyn_supertrait", @@ -747,6 +756,7 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ "coinductive_overlap_in_coherence", "conflicting_repr_hints", "const_evaluatable_unchecked", + "const_patterns_without_partial_eq", "deprecated_cfg_attr_crate_type_name", "elided_lifetimes_in_associated_constant", "forbidden_lint_groups", @@ -874,10 +884,6 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ ]; pub const RUSTDOC_LINTS: &[Lint] = &[ - Lint { label: "____", description: r##"-------"## }, - Lint { label: "____", description: r##"lint group for: ---------"## }, - Lint { label: "name", description: r##"meaning"## }, - Lint { label: "name", description: r##"lint group for: sub-lints"## }, Lint { label: "rustdoc::all", description: r##"lint group for: rustdoc::broken-intra-doc-links, rustdoc::private-intra-doc-links, rustdoc::private-doc-tests, rustdoc::invalid-codeblock-attributes, rustdoc::invalid-rust-codeblocks, rustdoc::invalid-html-tags, rustdoc::bare-urls, rustdoc::missing-crate-level-docs, rustdoc::unescaped-backticks, rustdoc::redundant-explicit-links"##, @@ -924,34 +930,25 @@ pub const RUSTDOC_LINTS: &[Lint] = &[ description: r##"detects unescaped backticks in doc comments"##, }, ]; -pub const RUSTDOC_LINT_GROUPS: &[LintGroup] = &[ - LintGroup { - lint: Lint { label: "____", description: r##"lint group for: ---------"## }, - children: &["_________"], + +pub const RUSTDOC_LINT_GROUPS: &[LintGroup] = &[LintGroup { + lint: Lint { + label: "rustdoc::all", + description: r##"lint group for: rustdoc::broken-intra-doc-links, rustdoc::private-intra-doc-links, rustdoc::private-doc-tests, rustdoc::invalid-codeblock-attributes, rustdoc::invalid-rust-codeblocks, rustdoc::invalid-html-tags, rustdoc::bare-urls, rustdoc::missing-crate-level-docs, rustdoc::unescaped-backticks, rustdoc::redundant-explicit-links"##, }, - LintGroup { - lint: Lint { label: "name", description: r##"lint group for: sub-lints"## }, - children: &["sub_lints"], - }, - LintGroup { - lint: Lint { - label: "rustdoc::all", - description: r##"lint group for: rustdoc::broken-intra-doc-links, rustdoc::private-intra-doc-links, rustdoc::private-doc-tests, rustdoc::invalid-codeblock-attributes, rustdoc::invalid-rust-codeblocks, rustdoc::invalid-html-tags, rustdoc::bare-urls, rustdoc::missing-crate-level-docs, rustdoc::unescaped-backticks, rustdoc::redundant-explicit-links"##, - }, - children: &[ - "rustdoc::broken_intra_doc_links", - "rustdoc::private_intra_doc_links", - "rustdoc::private_doc_tests", - "rustdoc::invalid_codeblock_attributes", - "rustdoc::invalid_rust_codeblocks", - "rustdoc::invalid_html_tags", - "rustdoc::bare_urls", - "rustdoc::missing_crate_level_docs", - "rustdoc::unescaped_backticks", - "rustdoc::redundant_explicit_links", - ], - }, -]; + children: &[ + "rustdoc::broken_intra_doc_links", + "rustdoc::private_intra_doc_links", + "rustdoc::private_doc_tests", + "rustdoc::invalid_codeblock_attributes", + "rustdoc::invalid_rust_codeblocks", + "rustdoc::invalid_html_tags", + "rustdoc::bare_urls", + "rustdoc::missing_crate_level_docs", + "rustdoc::unescaped_backticks", + "rustdoc::redundant_explicit_links", + ], +}]; pub const FEATURES: &[Lint] = &[ Lint { @@ -3149,7 +3146,7 @@ of a library. Plugins can extend [Rust's lint infrastructure](../../reference/attributes/diagnostics.md#lint-check-attributes) with additional checks for code style, safety, etc. Now let's write a plugin -[`lint-plugin-test.rs`](https://github.com/rust-lang/rust/blob/master/tests/ui-fulldeps/auxiliary/lint-plugin-test.rs) +[`lint-plugin-test.rs`](https://github.com/rust-lang/rust/blob/master/tests/ui-fulldeps/plugin/auxiliary/lint-plugin-test.rs) that warns about any item named `lintme`. ```rust,ignore (requires-stage-2) @@ -3159,14 +3156,14 @@ extern crate rustc_ast; // Load rustc as a plugin to get macros extern crate rustc_driver; -#[macro_use] extern crate rustc_lint; #[macro_use] extern crate rustc_session; -use rustc_driver::plugin::Registry; -use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; use rustc_ast::ast; +use rustc_driver::plugin::Registry; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; + declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); declare_lint_pass!(Pass => [TEST_LINT]); @@ -3174,9 +3171,7 @@ declare_lint_pass!(Pass => [TEST_LINT]); impl EarlyLintPass for Pass { fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { if it.ident.name.as_str() == "lintme" { - cx.lint(TEST_LINT, |lint| { - lint.build("item is named 'lintme'").set_span(it.span).emit() - }); + cx.lint(TEST_LINT, "item is named 'lintme'", |lint| lint.set_span(it.span)); } } } @@ -5335,6 +5330,12 @@ unless the annotated function is empty or simply panics."##, label: "clippy::into_iter_on_ref", description: r##"Checks for `into_iter` calls on references which should be replaced by `iter` or `iter_mut`."##, + }, + Lint { + label: "clippy::into_iter_without_iter", + description: r##"This is the opposite of the `iter_without_into_iter` lint. +It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method +on the type or on any of the types in its `Deref` chain."##, }, Lint { label: "clippy::invalid_null_ptr_usage", @@ -5431,6 +5432,10 @@ where `x` is greater than the amount of items that an iterator will produce."##, label: "clippy::iter_with_drain", description: r##"Checks for usage of `.drain(..)` on `Vec` and `VecDeque` for iteration."##, }, + Lint { + label: "clippy::iter_without_into_iter", + description: r##"Looks for `iter` and `iter_mut` methods without an associated `IntoIterator for (&|&mut) Type` implementation."##, + }, Lint { label: "clippy::iterator_step_by_zero", description: r##"Checks for calling `.step_by(0)` on iterators which panics."##, @@ -7898,7 +7903,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::nursery", - description: r##"lint group for: clippy::as_ptr_cast_mut, clippy::branches_sharing_code, clippy::clear_with_drain, clippy::cognitive_complexity, clippy::collection_is_never_read, clippy::debug_assert_with_mut_call, clippy::derive_partial_eq_without_eq, clippy::empty_line_after_doc_comments, clippy::empty_line_after_outer_attr, clippy::equatable_if_let, clippy::fallible_impl_from, clippy::future_not_send, clippy::implied_bounds_in_impls, clippy::imprecise_flops, clippy::iter_on_empty_collections, clippy::iter_on_single_items, clippy::iter_with_drain, clippy::large_stack_frames, clippy::manual_clamp, clippy::missing_const_for_fn, clippy::mutex_integer, clippy::needless_collect, clippy::non_send_fields_in_send_ty, clippy::nonstandard_macro_braces, clippy::option_if_let_else, clippy::or_fun_call, clippy::path_buf_push_overwrite, clippy::readonly_write_lock, clippy::redundant_clone, clippy::redundant_pub_crate, clippy::significant_drop_in_scrutinee, clippy::significant_drop_tightening, clippy::string_lit_as_bytes, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::trailing_empty_array, clippy::trait_duplication_in_bounds, clippy::transmute_undefined_repr, clippy::trivial_regex, clippy::tuple_array_conversions, clippy::type_repetition_in_bounds, clippy::unnecessary_struct_initialization, clippy::unused_peekable, clippy::unused_rounding, clippy::use_self, clippy::useless_let_if_seq"##, + description: r##"lint group for: clippy::as_ptr_cast_mut, clippy::branches_sharing_code, clippy::clear_with_drain, clippy::cognitive_complexity, clippy::collection_is_never_read, clippy::debug_assert_with_mut_call, clippy::derive_partial_eq_without_eq, clippy::empty_line_after_doc_comments, clippy::empty_line_after_outer_attr, clippy::equatable_if_let, clippy::fallible_impl_from, clippy::future_not_send, clippy::implied_bounds_in_impls, clippy::imprecise_flops, clippy::iter_on_empty_collections, clippy::iter_on_single_items, clippy::iter_with_drain, clippy::large_stack_frames, clippy::manual_clamp, clippy::missing_const_for_fn, clippy::mutex_integer, clippy::needless_collect, clippy::needless_pass_by_ref_mut, clippy::non_send_fields_in_send_ty, clippy::nonstandard_macro_braces, clippy::option_if_let_else, clippy::or_fun_call, clippy::path_buf_push_overwrite, clippy::readonly_write_lock, clippy::redundant_clone, clippy::redundant_pub_crate, clippy::significant_drop_in_scrutinee, clippy::significant_drop_tightening, clippy::string_lit_as_bytes, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::trailing_empty_array, clippy::trait_duplication_in_bounds, clippy::transmute_undefined_repr, clippy::trivial_regex, clippy::tuple_array_conversions, clippy::type_repetition_in_bounds, clippy::unnecessary_struct_initialization, clippy::unused_peekable, clippy::unused_rounding, clippy::use_self, clippy::useless_let_if_seq"##, }, children: &[ "clippy::as_ptr_cast_mut", @@ -7923,6 +7928,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::missing_const_for_fn", "clippy::mutex_integer", "clippy::needless_collect", + "clippy::needless_pass_by_ref_mut", "clippy::non_send_fields_in_send_ty", "clippy::nonstandard_macro_braces", "clippy::option_if_let_else", @@ -7952,7 +7958,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::pedantic", - description: r##"lint group for: clippy::bool_to_int_with_if, clippy::borrow_as_ptr, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_link_with_quotes, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::ignored_unit_patterns, clippy::implicit_clone, clippy::implicit_hasher, clippy::inconsistent_struct_constructor, clippy::index_refutable_slice, clippy::inefficient_to_string, clippy::inline_always, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_not_returning_iterator, clippy::large_digit_groups, clippy::large_futures, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_instant_elapsed, clippy::manual_let_else, clippy::manual_ok_or, clippy::manual_string_new, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::mismatching_type_param_order, clippy::missing_errors_doc, clippy::missing_fields_in_debug, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::needless_raw_string_hashes, clippy::no_effect_underscore_binding, clippy::no_mangle_with_rust_abi, clippy::option_option, clippy::ptr_as_ptr, clippy::ptr_cast_constness, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::return_self_not_must_use, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::should_panic_without_expect, clippy::similar_names, clippy::single_match_else, clippy::stable_sort_primitive, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::too_many_lines, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::unchecked_duration_subtraction, clippy::unicode_not_nfc, clippy::uninlined_format_args, clippy::unnecessary_box_returns, clippy::unnecessary_join, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, + description: r##"lint group for: clippy::bool_to_int_with_if, clippy::borrow_as_ptr, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_link_with_quotes, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::ignored_unit_patterns, clippy::implicit_clone, clippy::implicit_hasher, clippy::inconsistent_struct_constructor, clippy::index_refutable_slice, clippy::inefficient_to_string, clippy::inline_always, clippy::into_iter_without_iter, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_not_returning_iterator, clippy::iter_without_into_iter, clippy::large_digit_groups, clippy::large_futures, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_instant_elapsed, clippy::manual_let_else, clippy::manual_ok_or, clippy::manual_string_new, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::mismatching_type_param_order, clippy::missing_errors_doc, clippy::missing_fields_in_debug, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::needless_raw_string_hashes, clippy::no_effect_underscore_binding, clippy::no_mangle_with_rust_abi, clippy::option_option, clippy::ptr_as_ptr, clippy::ptr_cast_constness, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::return_self_not_must_use, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::should_panic_without_expect, clippy::similar_names, clippy::single_match_else, clippy::stable_sort_primitive, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::too_many_lines, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::unchecked_duration_subtraction, clippy::unicode_not_nfc, clippy::uninlined_format_args, clippy::unnecessary_box_returns, clippy::unnecessary_join, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, }, children: &[ "clippy::bool_to_int_with_if", @@ -7989,9 +7995,11 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::index_refutable_slice", "clippy::inefficient_to_string", "clippy::inline_always", + "clippy::into_iter_without_iter", "clippy::invalid_upcast_comparisons", "clippy::items_after_statements", "clippy::iter_not_returning_iterator", + "clippy::iter_without_into_iter", "clippy::large_digit_groups", "clippy::large_futures", "clippy::large_stack_arrays", @@ -8365,7 +8373,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::suspicious", - description: r##"lint group for: clippy::almost_complete_range, clippy::arc_with_non_send_sync, clippy::await_holding_invalid_type, clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::blanket_clippy_restriction_lints, clippy::cast_abs_to_unsigned, clippy::cast_enum_constructor, clippy::cast_enum_truncation, clippy::cast_nan_to_int, clippy::cast_slice_from_raw_parts, clippy::crate_in_macro_def, clippy::drop_non_drop, clippy::duplicate_mod, clippy::empty_loop, clippy::float_equality_without_abs, clippy::forget_non_drop, clippy::four_forward_slashes, clippy::from_raw_with_void_ptr, clippy::iter_out_of_bounds, clippy::let_underscore_future, clippy::lines_filter_map_ok, clippy::maybe_misused_cfg, clippy::misnamed_getters, clippy::misrefactored_assign_op, clippy::multi_assignments, clippy::mut_range_bound, clippy::mutable_key_type, clippy::needless_pass_by_ref_mut, clippy::no_effect_replace, clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, clippy::octal_escapes, clippy::path_ends_with_ext, clippy::permissions_set_readonly_false, clippy::print_in_format_impl, clippy::rc_clone_in_vec_init, clippy::single_range_in_vec_init, clippy::size_of_ref, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_command_arg_space, clippy::suspicious_doc_comments, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_to_owned, clippy::suspicious_unary_op_formatting, clippy::swap_ptr_to_ref, clippy::type_id_on_box"##, + description: r##"lint group for: clippy::almost_complete_range, clippy::arc_with_non_send_sync, clippy::await_holding_invalid_type, clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::blanket_clippy_restriction_lints, clippy::cast_abs_to_unsigned, clippy::cast_enum_constructor, clippy::cast_enum_truncation, clippy::cast_nan_to_int, clippy::cast_slice_from_raw_parts, clippy::crate_in_macro_def, clippy::drop_non_drop, clippy::duplicate_mod, clippy::empty_loop, clippy::float_equality_without_abs, clippy::forget_non_drop, clippy::four_forward_slashes, clippy::from_raw_with_void_ptr, clippy::iter_out_of_bounds, clippy::let_underscore_future, clippy::lines_filter_map_ok, clippy::maybe_misused_cfg, clippy::misnamed_getters, clippy::misrefactored_assign_op, clippy::multi_assignments, clippy::mut_range_bound, clippy::mutable_key_type, clippy::no_effect_replace, clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, clippy::octal_escapes, clippy::path_ends_with_ext, clippy::permissions_set_readonly_false, clippy::print_in_format_impl, clippy::rc_clone_in_vec_init, clippy::single_range_in_vec_init, clippy::size_of_ref, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_command_arg_space, clippy::suspicious_doc_comments, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_to_owned, clippy::suspicious_unary_op_formatting, clippy::swap_ptr_to_ref, clippy::type_id_on_box"##, }, children: &[ "clippy::almost_complete_range", @@ -8396,7 +8404,6 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::multi_assignments", "clippy::mut_range_bound", "clippy::mutable_key_type", - "clippy::needless_pass_by_ref_mut", "clippy::no_effect_replace", "clippy::non_canonical_clone_impl", "clippy::non_canonical_partial_ord_impl", diff --git a/crates/ide-db/src/tests/sourcegen_lints.rs b/crates/ide-db/src/tests/sourcegen_lints.rs index 457f94d3f9f3..8d7117b0c902 100644 --- a/crates/ide-db/src/tests/sourcegen_lints.rs +++ b/crates/ide-db/src/tests/sourcegen_lints.rs @@ -55,37 +55,56 @@ pub struct LintGroup { sourcegen::ensure_file_contents(destination.as_path(), &contents); } +/// Parses the output of `rustdoc -Whelp` and prints `Lint` and `LintGroup` constants into `buf`. +/// +/// As of writing, the output of `rustc -Whelp` (not rustdoc) has the following format: +/// +/// ```text +/// Lint checks provided by rustc: +/// +/// name default meaning +/// ---- ------- ------- +/// +/// ... +/// +/// Lint groups provided by rustc: +/// +/// name sub-lints +/// ---- --------- +/// +/// ... +/// ``` +/// +/// `rustdoc -Whelp` (and any other custom `rustc` driver) adds another two +/// tables after the `rustc` ones, with a different title but the same format. fn generate_lint_descriptor(sh: &Shell, buf: &mut String) { - // FIXME: rustdoc currently requires an input file for -Whelp cc https://github.com/rust-lang/rust/pull/88831 - let file = project_root().join(file!()); - let stdout = cmd!(sh, "rustdoc -W help {file}").read().unwrap(); - let start_lints = stdout.find("---- ------- -------").unwrap(); - let start_lint_groups = stdout.find("---- ---------").unwrap(); - let start_lints_rustdoc = - stdout.find("Lint checks provided by plugins loaded by this crate:").unwrap(); - let start_lint_groups_rustdoc = - stdout.find("Lint groups provided by plugins loaded by this crate:").unwrap(); + let stdout = cmd!(sh, "rustdoc -Whelp").read().unwrap(); + let lints_pat = "---- ------- -------\n"; + let lint_groups_pat = "---- ---------\n"; + let lints = find_and_slice(&stdout, lints_pat); + let lint_groups = find_and_slice(lints, lint_groups_pat); + let lints_rustdoc = find_and_slice(lint_groups, lints_pat); + let lint_groups_rustdoc = find_and_slice(lints_rustdoc, lint_groups_pat); buf.push_str(r#"pub const DEFAULT_LINTS: &[Lint] = &["#); buf.push('\n'); - let lints = stdout[start_lints..].lines().skip(1).take_while(|l| !l.is_empty()).map(|line| { + let lints = lints.lines().take_while(|l| !l.is_empty()).map(|line| { let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap(); let (_default_level, description) = rest.trim().split_once(char::is_whitespace).unwrap(); (name.trim(), Cow::Borrowed(description.trim()), vec![]) }); - let lint_groups = - stdout[start_lint_groups..].lines().skip(1).take_while(|l| !l.is_empty()).map(|line| { - let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap(); - ( - name.trim(), - format!("lint group for: {}", lints.trim()).into(), - lints - .split_ascii_whitespace() - .map(|s| s.trim().trim_matches(',').replace('-', "_")) - .collect(), - ) - }); + let lint_groups = lint_groups.lines().take_while(|l| !l.is_empty()).map(|line| { + let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap(); + ( + name.trim(), + format!("lint group for: {}", lints.trim()).into(), + lints + .split_ascii_whitespace() + .map(|s| s.trim().trim_matches(',').replace('-', "_")) + .collect(), + ) + }); let lints = lints .chain(lint_groups) @@ -94,7 +113,8 @@ fn generate_lint_descriptor(sh: &Shell, buf: &mut String) { for (name, description, ..) in &lints { push_lint_completion(buf, &name.replace('-', "_"), description); } - buf.push_str("];\n"); + buf.push_str("];\n\n"); + buf.push_str(r#"pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &["#); for (name, description, children) in &lints { if !children.is_empty() { @@ -115,27 +135,23 @@ fn generate_lint_descriptor(sh: &Shell, buf: &mut String) { buf.push_str(r#"pub const RUSTDOC_LINTS: &[Lint] = &["#); buf.push('\n'); - let lints_rustdoc = - stdout[start_lints_rustdoc..].lines().skip(2).take_while(|l| !l.is_empty()).map(|line| { - let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap(); - let (_default_level, description) = - rest.trim().split_once(char::is_whitespace).unwrap(); - (name.trim(), Cow::Borrowed(description.trim()), vec![]) - }); + let lints_rustdoc = lints_rustdoc.lines().take_while(|l| !l.is_empty()).map(|line| { + let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap(); + let (_default_level, description) = rest.trim().split_once(char::is_whitespace).unwrap(); + (name.trim(), Cow::Borrowed(description.trim()), vec![]) + }); let lint_groups_rustdoc = - stdout[start_lint_groups_rustdoc..].lines().skip(2).take_while(|l| !l.is_empty()).map( - |line| { - let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap(); - ( - name.trim(), - format!("lint group for: {}", lints.trim()).into(), - lints - .split_ascii_whitespace() - .map(|s| s.trim().trim_matches(',').replace('-', "_")) - .collect(), - ) - }, - ); + lint_groups_rustdoc.lines().take_while(|l| !l.is_empty()).map(|line| { + let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap(); + ( + name.trim(), + format!("lint group for: {}", lints.trim()).into(), + lints + .split_ascii_whitespace() + .map(|s| s.trim().trim_matches(',').replace('-', "_")) + .collect(), + ) + }); let lints_rustdoc = lints_rustdoc .chain(lint_groups_rustdoc) @@ -145,7 +161,7 @@ fn generate_lint_descriptor(sh: &Shell, buf: &mut String) { for (name, description, ..) in &lints_rustdoc { push_lint_completion(buf, &name.replace('-', "_"), description) } - buf.push_str("];\n"); + buf.push_str("];\n\n"); buf.push_str(r#"pub const RUSTDOC_LINT_GROUPS: &[LintGroup] = &["#); for (name, description, children) in &lints_rustdoc { @@ -157,14 +173,24 @@ fn generate_lint_descriptor(sh: &Shell, buf: &mut String) { buf.push_str("];\n"); } +#[track_caller] +fn find_and_slice<'a>(i: &'a str, p: &str) -> &'a str { + let idx = i.find(p).unwrap(); + &i[idx + p.len()..] +} + +/// Parses the unstable book root directory at `src_dir` and prints a constant +/// with the list of unstable features into `buf`. +/// +/// It does this by looking for all `.md` files in the `language-features` and +/// `library-features` directories, and using the file name as the feature +/// name, and the file contents as the feature description. fn generate_feature_descriptor(buf: &mut String, src_dir: &Path) { let mut features = ["language-features", "library-features"] .into_iter() .flat_map(|it| sourcegen::list_files(&src_dir.join(it))) - .filter(|path| { - // Get all `.md ` files - path.extension().unwrap_or_default().to_str().unwrap_or_default() == "md" - }) + // Get all `.md` files + .filter(|path| path.extension() == Some("md".as_ref())) .map(|path| { let feature_ident = path.file_stem().unwrap().to_str().unwrap().replace('-', "_"); let doc = fs::read_to_string(path).unwrap(); From 3dfc1bfc67c9779ec3c936c1987349ac77cd8af4 Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Sun, 8 Oct 2023 03:31:23 +0200 Subject: [PATCH 2296/2442] Use vscode.env.openExternal instead of the vscode.open command for docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the VS Code documentation, the vscode.open command opens the URL _in the editor_ (https://code.visualstudio.com/api/references/commands). However, in reality, it seems to do so only for file:// URLs, falling back to other applications for other URL schemes (at least for HTTP/HTTPS). Until now, the URL to the documentation was always HTTP based, so using the vscode.open command was perfectly fine. However, displaying local documentation will be supported from now on (see next commit). Local documentation is not HTTP-based, but instead addressed via a file:// URL. The file URL would therefore be opened in VS Code instead of in the browser — this is definitely not what the user wants. Therefore, the vscode.env.openExternal function is used instead, this function never opens the URL in VS Code. --- editors/code/src/commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 245557b1e88a..5e602510601a 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -950,7 +950,7 @@ export function openDocs(ctx: CtxInit): Cmd { const doclink = await client.sendRequest(ra.openDocs, { position, textDocument }); if (doclink != null) { - await vscode.commands.executeCommand("vscode.open", vscode.Uri.parse(doclink)); + await vscode.env.openExternal(vscode.Uri.parse(doclink)); } }; } From aeef7b644b135c80c2fc7a28954d97194df7fabc Mon Sep 17 00:00:00 2001 From: Victor Song Date: Fri, 29 Sep 2023 03:49:37 -0500 Subject: [PATCH 2297/2442] Add config option to use `rust-analyzer` specific target dir Adds a Rust Analyzer configuration option to set a custom target directory for builds. This is a workaround for Rust Analyzer blocking debug builds while running `cargo check`. This change should close #6007 --- crates/rust-analyzer/src/config.rs | 200 ++++++++++++++++++++++++----- docs/user/generated_config.adoc | 9 ++ editors/code/package.json | 15 +++ 3 files changed, 190 insertions(+), 34 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 8e780baa36dd..3cd6fa49b204 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -480,6 +480,13 @@ config_data! { /// tests or binaries. For example, it may be `--release`. runnables_extraArgs: Vec = "[]", + /// Optional path to a rust-analyzer specific target directory. + /// This is useful to prevent rust-analyzer's `cargo check` from blocking builds. + /// + /// Set to `true` to use a subdirectory of the existing target directory or + /// set to a path to use that path. + rust_analyzerTargetDir: Option = "null", + /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private /// projects, or "discover" to try to automatically find it if the `rustc-dev` component /// is installed. @@ -1192,6 +1199,7 @@ impl Config { } pub fn cargo(&self) -> CargoConfig { + let target_directory = self.target_dir_from_config(); let rustc_source = self.data.rustc_source.as_ref().map(|rustc_src| { if rustc_src == "discover" { RustLibSource::Discover @@ -1209,6 +1217,10 @@ impl Config { let sysroot_src = self.data.cargo_sysrootSrc.as_ref().map(|sysroot| self.root_path.join(sysroot)); + let mut extra_args = self.data.cargo_extraArgs.clone(); + + add_target_dir_to_args(&mut extra_args, target_directory); + CargoConfig { features: match &self.data.cargo_features { CargoFeaturesDef::All => CargoFeatures::All, @@ -1261,7 +1273,7 @@ impl Config { InvocationLocation::Workspace => project_model::InvocationLocation::Workspace, }, run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(), - extra_args: self.data.cargo_extraArgs.clone(), + extra_args, extra_env: self.data.cargo_extraEnv.clone(), } } @@ -1281,10 +1293,14 @@ impl Config { } pub fn flycheck(&self) -> FlycheckConfig { + let target_directory = self.target_dir_from_config(); + match &self.data.check_overrideCommand { Some(args) if !args.is_empty() => { let mut args = args.clone(); let command = args.remove(0); + add_target_dir_to_args(&mut args, target_directory); + FlycheckConfig::CustomCommand { command, args, @@ -1303,42 +1319,61 @@ impl Config { }, } } - Some(_) | None => FlycheckConfig::CargoCommand { - command: self.data.check_command.clone(), - target_triples: self - .data - .check_targets - .clone() - .and_then(|targets| match &targets.0[..] { - [] => None, - targets => Some(targets.into()), - }) - .unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()), - all_targets: self.data.check_allTargets, - no_default_features: self - .data - .check_noDefaultFeatures - .unwrap_or(self.data.cargo_noDefaultFeatures), - all_features: matches!( - self.data.check_features.as_ref().unwrap_or(&self.data.cargo_features), - CargoFeaturesDef::All - ), - features: match self - .data - .check_features - .clone() - .unwrap_or_else(|| self.data.cargo_features.clone()) - { - CargoFeaturesDef::All => vec![], - CargoFeaturesDef::Selected(it) => it, - }, - extra_args: self.check_extra_args(), - extra_env: self.check_extra_env(), - ansi_color_output: self.color_diagnostic_output(), - }, + Some(_) | None => { + let mut extra_args = self.check_extra_args(); + add_target_dir_to_args(&mut extra_args, target_directory); + + FlycheckConfig::CargoCommand { + command: self.data.check_command.clone(), + target_triples: self + .data + .check_targets + .clone() + .and_then(|targets| match &targets.0[..] { + [] => None, + targets => Some(targets.into()), + }) + .unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()), + all_targets: self.data.check_allTargets, + no_default_features: self + .data + .check_noDefaultFeatures + .unwrap_or(self.data.cargo_noDefaultFeatures), + all_features: matches!( + self.data.check_features.as_ref().unwrap_or(&self.data.cargo_features), + CargoFeaturesDef::All + ), + features: match self + .data + .check_features + .clone() + .unwrap_or_else(|| self.data.cargo_features.clone()) + { + CargoFeaturesDef::All => vec![], + CargoFeaturesDef::Selected(it) => it, + }, + extra_args, + extra_env: self.check_extra_env(), + ansi_color_output: self.color_diagnostic_output(), + } + } } } + fn target_dir_from_config(&self) -> Option { + self.data + .rust_analyzerTargetDir + .as_ref() + .map(|target_dir| match target_dir { + TargetDirectory::UseSubdirectory(yes) if *yes => { + Some(String::from("target/rust-analyzer")) + } + TargetDirectory::UseSubdirectory(_) => None, + TargetDirectory::Directory(dir) => Some(dir.clone()), + }) + .flatten() + } + pub fn check_on_save(&self) -> bool { self.data.checkOnSave } @@ -1690,6 +1725,13 @@ impl Config { self.is_visual_studio_code } } + +fn add_target_dir_to_args(args: &mut Vec, target_dir: Option) { + if let Some(target_dir) = target_dir { + args.push(format!("--target-dir={}", target_dir)); + } +} + // Deserialization definitions macro_rules! create_bool_or_string_de { @@ -2037,6 +2079,14 @@ pub enum MemoryLayoutHoverRenderKindDef { Both, } +#[derive(Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +#[serde(untagged)] +pub enum TargetDirectory { + UseSubdirectory(bool), + Directory(String), +} + macro_rules! _config_data { (struct $name:ident { $( @@ -2465,6 +2515,19 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json }, ], }, + "Option" => set! { + "anyOf": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "string" + }, + ], + }, _ => panic!("missing entry for {ty}: {default}"), } @@ -2625,4 +2688,73 @@ mod tests { Some(AbsPathBuf::try_from(project_root().join("./server")).unwrap()) ); } + + #[test] + fn cargo_target_dir_unset() { + let mut config = Config::new( + AbsPathBuf::try_from(project_root()).unwrap(), + Default::default(), + vec![], + false, + ); + config + .update(serde_json::json!({ + "rust": { "analyzerTargetDir": null } + })) + .unwrap(); + assert_eq!(config.data.rust_analyzerTargetDir, None); + assert_eq!(config.cargo().extra_args.len(), 0); + assert!( + matches!(config.flycheck(), FlycheckConfig::CargoCommand { extra_args, .. } if extra_args.is_empty()) + ); + } + + #[test] + fn cargo_target_dir_subdir() { + let mut config = Config::new( + AbsPathBuf::try_from(project_root()).unwrap(), + Default::default(), + vec![], + false, + ); + config + .update(serde_json::json!({ + "rust": { "analyzerTargetDir": true } + })) + .unwrap(); + assert_eq!( + config.data.rust_analyzerTargetDir, + Some(TargetDirectory::UseSubdirectory(true)) + ); + assert_eq!( + config.cargo().extra_args, + vec!["--target-dir=target/rust-analyzer".to_string()] + ); + assert!( + matches!(config.flycheck(), FlycheckConfig::CargoCommand { extra_args, .. } if extra_args == vec!["--target-dir=target/rust-analyzer".to_string()]) + ); + } + + #[test] + fn cargo_target_dir_relative_dir() { + let mut config = Config::new( + AbsPathBuf::try_from(project_root()).unwrap(), + Default::default(), + vec![], + false, + ); + config + .update(serde_json::json!({ + "rust": { "analyzerTargetDir": "other_folder" } + })) + .unwrap(); + assert_eq!( + config.data.rust_analyzerTargetDir, + Some(TargetDirectory::Directory("other_folder".to_string())) + ); + assert_eq!(config.cargo().extra_args, vec!["--target-dir=other_folder".to_string()]); + assert!( + matches!(config.flycheck(), FlycheckConfig::CargoCommand { extra_args, .. } if extra_args == vec!["--target-dir=other_folder".to_string()]) + ); + } } diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index dec7a5075748..f7ae6afe3860 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -757,6 +757,15 @@ Command to be executed instead of 'cargo' for runnables. Additional arguments to be passed to cargo for runnables such as tests or binaries. For example, it may be `--release`. -- +[[rust-analyzer.rust.analyzerTargetDir]]rust-analyzer.rust.analyzerTargetDir (default: `null`):: ++ +-- +Optional path to a rust-analyzer specific target directory. +This is useful to prevent rust-analyzer's `cargo check` from blocking builds. + +Set to `true` to use a subdirectory of the existing target directory or +set to a path to use that path. +-- [[rust-analyzer.rustc.source]]rust-analyzer.rustc.source (default: `null`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index 554b05c46c70..e1402cb0f5c4 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1488,6 +1488,21 @@ "type": "string" } }, + "rust-analyzer.rust.analyzerTargetDir": { + "markdownDescription": "Optional path to a rust-analyzer specific target directory.\nThis is useful to prevent rust-analyzer's `cargo check` from blocking builds.\n\nSet to `true` to use a subdirectory of the existing target directory or\nset to a path to use that path.", + "default": null, + "anyOf": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "string" + } + ] + }, "rust-analyzer.rustc.source": { "markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.", "default": null, From 53b670059456ba15e4374e5ab7ba4e2468066d0c Mon Sep 17 00:00:00 2001 From: Victor Song Date: Sat, 30 Sep 2023 21:02:12 -0500 Subject: [PATCH 2298/2442] Add dedicated `target_dir` field to `CargoConfig` and `FlycheckConfig` Add dedicated field for `target_dir` in the configurations for Cargo and Flycheck. Also change the directory to be a `PathBuf` as opposed to a `String` to be more appropriate to the operating system. --- crates/flycheck/src/lib.rs | 5 + crates/project-model/src/build_scripts.rs | 4 + crates/project-model/src/cargo_workspace.rs | 2 + crates/rust-analyzer/src/config.rs | 111 ++++++++------------ 4 files changed, 54 insertions(+), 68 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 2de719af92ce..0749d91eb32a 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -50,6 +50,7 @@ pub enum FlycheckConfig { extra_args: Vec, extra_env: FxHashMap, ansi_color_output: bool, + target_dir: Option, }, CustomCommand { command: String, @@ -308,6 +309,7 @@ impl FlycheckActor { features, extra_env, ansi_color_output, + target_dir, } => { let mut cmd = Command::new(toolchain::cargo()); cmd.arg(command); @@ -340,6 +342,9 @@ impl FlycheckActor { cmd.arg(features.join(" ")); } } + if let Some(target_dir) = target_dir { + cmd.arg("--target-dir").arg(target_dir); + } cmd.envs(extra_env); (cmd, extra_args) } diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index fb0f3ab7d174..68cd40c040b3 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -73,6 +73,10 @@ impl WorkspaceBuildScripts { cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]); cmd.args(&config.extra_args); + if let Some(target_dir) = &config.target_dir { + cmd.arg("--target-dir").arg(target_dir); + } + // --all-targets includes tests, benches and examples in addition to the // default lib and bins. This is an independent concept from the --target // flag below. diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index e47808a2cc9f..ca3d6e0596ca 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -96,6 +96,8 @@ pub struct CargoConfig { pub extra_env: FxHashMap, pub invocation_strategy: InvocationStrategy, pub invocation_location: InvocationLocation, + /// Optional path to use instead of `target` when building + pub target_dir: Option, } pub type Package = Idx; diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 3cd6fa49b204..8f1543de0045 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -1199,7 +1199,6 @@ impl Config { } pub fn cargo(&self) -> CargoConfig { - let target_directory = self.target_dir_from_config(); let rustc_source = self.data.rustc_source.as_ref().map(|rustc_src| { if rustc_src == "discover" { RustLibSource::Discover @@ -1217,10 +1216,6 @@ impl Config { let sysroot_src = self.data.cargo_sysrootSrc.as_ref().map(|sysroot| self.root_path.join(sysroot)); - let mut extra_args = self.data.cargo_extraArgs.clone(); - - add_target_dir_to_args(&mut extra_args, target_directory); - CargoConfig { features: match &self.data.cargo_features { CargoFeaturesDef::All => CargoFeatures::All, @@ -1273,8 +1268,9 @@ impl Config { InvocationLocation::Workspace => project_model::InvocationLocation::Workspace, }, run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(), - extra_args, + extra_args: self.data.cargo_extraArgs.clone(), extra_env: self.data.cargo_extraEnv.clone(), + target_dir: self.target_dir_from_config(), } } @@ -1293,14 +1289,10 @@ impl Config { } pub fn flycheck(&self) -> FlycheckConfig { - let target_directory = self.target_dir_from_config(); - match &self.data.check_overrideCommand { Some(args) if !args.is_empty() => { let mut args = args.clone(); let command = args.remove(0); - add_target_dir_to_args(&mut args, target_directory); - FlycheckConfig::CustomCommand { command, args, @@ -1319,54 +1311,50 @@ impl Config { }, } } - Some(_) | None => { - let mut extra_args = self.check_extra_args(); - add_target_dir_to_args(&mut extra_args, target_directory); - - FlycheckConfig::CargoCommand { - command: self.data.check_command.clone(), - target_triples: self - .data - .check_targets - .clone() - .and_then(|targets| match &targets.0[..] { - [] => None, - targets => Some(targets.into()), - }) - .unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()), - all_targets: self.data.check_allTargets, - no_default_features: self - .data - .check_noDefaultFeatures - .unwrap_or(self.data.cargo_noDefaultFeatures), - all_features: matches!( - self.data.check_features.as_ref().unwrap_or(&self.data.cargo_features), - CargoFeaturesDef::All - ), - features: match self - .data - .check_features - .clone() - .unwrap_or_else(|| self.data.cargo_features.clone()) - { - CargoFeaturesDef::All => vec![], - CargoFeaturesDef::Selected(it) => it, - }, - extra_args, - extra_env: self.check_extra_env(), - ansi_color_output: self.color_diagnostic_output(), - } - } + Some(_) | None => FlycheckConfig::CargoCommand { + command: self.data.check_command.clone(), + target_triples: self + .data + .check_targets + .clone() + .and_then(|targets| match &targets.0[..] { + [] => None, + targets => Some(targets.into()), + }) + .unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()), + all_targets: self.data.check_allTargets, + no_default_features: self + .data + .check_noDefaultFeatures + .unwrap_or(self.data.cargo_noDefaultFeatures), + all_features: matches!( + self.data.check_features.as_ref().unwrap_or(&self.data.cargo_features), + CargoFeaturesDef::All + ), + features: match self + .data + .check_features + .clone() + .unwrap_or_else(|| self.data.cargo_features.clone()) + { + CargoFeaturesDef::All => vec![], + CargoFeaturesDef::Selected(it) => it, + }, + extra_args: self.check_extra_args(), + extra_env: self.check_extra_env(), + ansi_color_output: self.color_diagnostic_output(), + target_dir: self.target_dir_from_config(), + }, } } - fn target_dir_from_config(&self) -> Option { + fn target_dir_from_config(&self) -> Option { self.data .rust_analyzerTargetDir .as_ref() .map(|target_dir| match target_dir { TargetDirectory::UseSubdirectory(yes) if *yes => { - Some(String::from("target/rust-analyzer")) + Some(PathBuf::from("target/rust-analyzer")) } TargetDirectory::UseSubdirectory(_) => None, TargetDirectory::Directory(dir) => Some(dir.clone()), @@ -1725,13 +1713,6 @@ impl Config { self.is_visual_studio_code } } - -fn add_target_dir_to_args(args: &mut Vec, target_dir: Option) { - if let Some(target_dir) = target_dir { - args.push(format!("--target-dir={}", target_dir)); - } -} - // Deserialization definitions macro_rules! create_bool_or_string_de { @@ -2084,7 +2065,7 @@ pub enum MemoryLayoutHoverRenderKindDef { #[serde(untagged)] pub enum TargetDirectory { UseSubdirectory(bool), - Directory(String), + Directory(PathBuf), } macro_rules! _config_data { @@ -2703,9 +2684,8 @@ mod tests { })) .unwrap(); assert_eq!(config.data.rust_analyzerTargetDir, None); - assert_eq!(config.cargo().extra_args.len(), 0); assert!( - matches!(config.flycheck(), FlycheckConfig::CargoCommand { extra_args, .. } if extra_args.is_empty()) + matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == None) ); } @@ -2726,12 +2706,8 @@ mod tests { config.data.rust_analyzerTargetDir, Some(TargetDirectory::UseSubdirectory(true)) ); - assert_eq!( - config.cargo().extra_args, - vec!["--target-dir=target/rust-analyzer".to_string()] - ); assert!( - matches!(config.flycheck(), FlycheckConfig::CargoCommand { extra_args, .. } if extra_args == vec!["--target-dir=target/rust-analyzer".to_string()]) + matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(PathBuf::from("target/rust-analyzer"))) ); } @@ -2750,11 +2726,10 @@ mod tests { .unwrap(); assert_eq!( config.data.rust_analyzerTargetDir, - Some(TargetDirectory::Directory("other_folder".to_string())) + Some(TargetDirectory::Directory(PathBuf::from("other_folder"))) ); - assert_eq!(config.cargo().extra_args, vec!["--target-dir=other_folder".to_string()]); assert!( - matches!(config.flycheck(), FlycheckConfig::CargoCommand { extra_args, .. } if extra_args == vec!["--target-dir=other_folder".to_string()]) + matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(PathBuf::from("other_folder"))) ); } } From ef0b3bbef1a1b4cd88619f9a5f43d526f96af184 Mon Sep 17 00:00:00 2001 From: Victor Song Date: Sat, 30 Sep 2023 21:21:00 -0500 Subject: [PATCH 2299/2442] Clarify documentation on new parameter --- crates/rust-analyzer/src/config.rs | 2 +- docs/user/generated_config.adoc | 2 +- editors/code/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 8f1543de0045..39a98bcd29a8 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -484,7 +484,7 @@ config_data! { /// This is useful to prevent rust-analyzer's `cargo check` from blocking builds. /// /// Set to `true` to use a subdirectory of the existing target directory or - /// set to a path to use that path. + /// set to a path relative to the workspace to use that path. rust_analyzerTargetDir: Option = "null", /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index f7ae6afe3860..4440caaed89c 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -764,7 +764,7 @@ Optional path to a rust-analyzer specific target directory. This is useful to prevent rust-analyzer's `cargo check` from blocking builds. Set to `true` to use a subdirectory of the existing target directory or -set to a path to use that path. +set to a path relative to the workspace to use that path. -- [[rust-analyzer.rustc.source]]rust-analyzer.rustc.source (default: `null`):: + diff --git a/editors/code/package.json b/editors/code/package.json index e1402cb0f5c4..a18acb98301d 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1489,7 +1489,7 @@ } }, "rust-analyzer.rust.analyzerTargetDir": { - "markdownDescription": "Optional path to a rust-analyzer specific target directory.\nThis is useful to prevent rust-analyzer's `cargo check` from blocking builds.\n\nSet to `true` to use a subdirectory of the existing target directory or\nset to a path to use that path.", + "markdownDescription": "Optional path to a rust-analyzer specific target directory.\nThis is useful to prevent rust-analyzer's `cargo check` from blocking builds.\n\nSet to `true` to use a subdirectory of the existing target directory or\nset to a path relative to the workspace to use that path.", "default": null, "anyOf": [ { From 3682c3791bff7a98179d256c1b972ee75e91b5d4 Mon Sep 17 00:00:00 2001 From: Victor Song Date: Sat, 30 Sep 2023 21:23:16 -0500 Subject: [PATCH 2300/2442] Set `CARGO_TARGET_DIR` when using Flycheck custom command --- crates/flycheck/src/lib.rs | 6 ++++++ crates/rust-analyzer/src/config.rs | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 0749d91eb32a..f0d2f79f6332 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -58,6 +58,7 @@ pub enum FlycheckConfig { extra_env: FxHashMap, invocation_strategy: InvocationStrategy, invocation_location: InvocationLocation, + target_dir: Option, }, } @@ -354,10 +355,15 @@ impl FlycheckActor { extra_env, invocation_strategy, invocation_location, + target_dir, } => { let mut cmd = Command::new(command); cmd.envs(extra_env); + if let Some(target_dir) = target_dir { + cmd.env("CARGO_TARGET_DIR", target_dir); + } + match invocation_location { InvocationLocation::Workspace => { match invocation_strategy { diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 39a98bcd29a8..23cf71cff4fa 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -1289,6 +1289,7 @@ impl Config { } pub fn flycheck(&self) -> FlycheckConfig { + let target_dir = self.target_dir_from_config(); match &self.data.check_overrideCommand { Some(args) if !args.is_empty() => { let mut args = args.clone(); @@ -1309,6 +1310,7 @@ impl Config { } InvocationLocation::Workspace => flycheck::InvocationLocation::Workspace, }, + target_dir, } } Some(_) | None => FlycheckConfig::CargoCommand { @@ -1343,7 +1345,7 @@ impl Config { extra_args: self.check_extra_args(), extra_env: self.check_extra_env(), ansi_color_output: self.color_diagnostic_output(), - target_dir: self.target_dir_from_config(), + target_dir, }, } } From 2290cc3cf393079d30c026249af27838cc2d4595 Mon Sep 17 00:00:00 2001 From: Victor Song Date: Wed, 4 Oct 2023 08:13:01 -0500 Subject: [PATCH 2301/2442] Pass target directory as flag instead of env variable --- crates/flycheck/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index f0d2f79f6332..c2ad2661eb46 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -360,10 +360,6 @@ impl FlycheckActor { let mut cmd = Command::new(command); cmd.envs(extra_env); - if let Some(target_dir) = target_dir { - cmd.env("CARGO_TARGET_DIR", target_dir); - } - match invocation_location { InvocationLocation::Workspace => { match invocation_strategy { @@ -381,6 +377,10 @@ impl FlycheckActor { } } + if let Some(target_dir) = target_dir { + cmd.arg("--target-dir").arg(target_dir); + } + (cmd, args) } }; From 9771e1e18fafef7571ad46374c5e55d4acd8aa09 Mon Sep 17 00:00:00 2001 From: Victor Song Date: Mon, 9 Oct 2023 02:03:45 -0500 Subject: [PATCH 2302/2442] Don't pass any target directory options to custom flycheck --- crates/flycheck/src/lib.rs | 6 ------ crates/rust-analyzer/src/config.rs | 4 +--- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index c2ad2661eb46..0749d91eb32a 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -58,7 +58,6 @@ pub enum FlycheckConfig { extra_env: FxHashMap, invocation_strategy: InvocationStrategy, invocation_location: InvocationLocation, - target_dir: Option, }, } @@ -355,7 +354,6 @@ impl FlycheckActor { extra_env, invocation_strategy, invocation_location, - target_dir, } => { let mut cmd = Command::new(command); cmd.envs(extra_env); @@ -377,10 +375,6 @@ impl FlycheckActor { } } - if let Some(target_dir) = target_dir { - cmd.arg("--target-dir").arg(target_dir); - } - (cmd, args) } }; diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 23cf71cff4fa..39a98bcd29a8 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -1289,7 +1289,6 @@ impl Config { } pub fn flycheck(&self) -> FlycheckConfig { - let target_dir = self.target_dir_from_config(); match &self.data.check_overrideCommand { Some(args) if !args.is_empty() => { let mut args = args.clone(); @@ -1310,7 +1309,6 @@ impl Config { } InvocationLocation::Workspace => flycheck::InvocationLocation::Workspace, }, - target_dir, } } Some(_) | None => FlycheckConfig::CargoCommand { @@ -1345,7 +1343,7 @@ impl Config { extra_args: self.check_extra_args(), extra_env: self.check_extra_env(), ansi_color_output: self.color_diagnostic_output(), - target_dir, + target_dir: self.target_dir_from_config(), }, } } From a39d2076db1f39e49a7c7c5365eac8a11abcdc9e Mon Sep 17 00:00:00 2001 From: Victor Song Date: Mon, 9 Oct 2023 02:14:46 -0500 Subject: [PATCH 2303/2442] Addressed PR style comments --- crates/rust-analyzer/src/config.rs | 21 +++++++++------------ docs/user/generated_config.adoc | 3 ++- editors/code/package.json | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 39a98bcd29a8..c8df4255d96b 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -481,7 +481,8 @@ config_data! { runnables_extraArgs: Vec = "[]", /// Optional path to a rust-analyzer specific target directory. - /// This is useful to prevent rust-analyzer's `cargo check` from blocking builds. + /// This prevents rust-analyzer's `cargo check` from locking the `Cargo.lock` + /// at the expense of duplicating build artifacts. /// /// Set to `true` to use a subdirectory of the existing target directory or /// set to a path relative to the workspace to use that path. @@ -1349,17 +1350,13 @@ impl Config { } fn target_dir_from_config(&self) -> Option { - self.data - .rust_analyzerTargetDir - .as_ref() - .map(|target_dir| match target_dir { - TargetDirectory::UseSubdirectory(yes) if *yes => { - Some(PathBuf::from("target/rust-analyzer")) - } - TargetDirectory::UseSubdirectory(_) => None, - TargetDirectory::Directory(dir) => Some(dir.clone()), - }) - .flatten() + self.data.rust_analyzerTargetDir.as_ref().and_then(|target_dir| match target_dir { + TargetDirectory::UseSubdirectory(yes) if *yes => { + Some(PathBuf::from("target/rust-analyzer")) + } + TargetDirectory::UseSubdirectory(_) => None, + TargetDirectory::Directory(dir) => Some(dir.clone()), + }) } pub fn check_on_save(&self) -> bool { diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 4440caaed89c..7c76ae81bea0 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -761,7 +761,8 @@ tests or binaries. For example, it may be `--release`. + -- Optional path to a rust-analyzer specific target directory. -This is useful to prevent rust-analyzer's `cargo check` from blocking builds. +This prevents rust-analyzer's `cargo check` from locking the `Cargo.lock` +at the expense of duplicating build artifacts. Set to `true` to use a subdirectory of the existing target directory or set to a path relative to the workspace to use that path. diff --git a/editors/code/package.json b/editors/code/package.json index a18acb98301d..fc6597a0d402 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1489,7 +1489,7 @@ } }, "rust-analyzer.rust.analyzerTargetDir": { - "markdownDescription": "Optional path to a rust-analyzer specific target directory.\nThis is useful to prevent rust-analyzer's `cargo check` from blocking builds.\n\nSet to `true` to use a subdirectory of the existing target directory or\nset to a path relative to the workspace to use that path.", + "markdownDescription": "Optional path to a rust-analyzer specific target directory.\nThis prevents rust-analyzer's `cargo check` from locking the `Cargo.lock`\nat the expense of duplicating build artifacts.\n\nSet to `true` to use a subdirectory of the existing target directory or\nset to a path relative to the workspace to use that path.", "default": null, "anyOf": [ { From 0c4be03456846af044c97c691824e50fe55c227a Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sun, 8 Oct 2023 01:04:14 +0200 Subject: [PATCH 2304/2442] feat: generate descriptors for all unstable features --- crates/ide-db/src/generated/lints.rs | 5581 ++++++++++++++++++++ crates/ide-db/src/tests/sourcegen_lints.rs | 36 +- 2 files changed, 5611 insertions(+), 6 deletions(-) diff --git a/crates/ide-db/src/generated/lints.rs b/crates/ide-db/src/generated/lints.rs index 9ddcae60563e..1cb6ff8627a2 100644 --- a/crates/ide-db/src/generated/lints.rs +++ b/crates/ide-db/src/generated/lints.rs @@ -9,6 +9,7 @@ pub struct LintGroup { pub lint: Lint, pub children: &'static [&'static str], } + pub const DEFAULT_LINTS: &[Lint] = &[ Lint { label: "absolute_paths_not_starting_with_crate", @@ -951,6 +952,39 @@ pub const RUSTDOC_LINT_GROUPS: &[LintGroup] = &[LintGroup { }]; pub const FEATURES: &[Lint] = &[ + Lint { + label: "aarch64_ver_target_feature", + description: r##"# `aarch64_ver_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "abi_amdgpu_kernel", + description: r##"# `abi_amdgpu_kernel` + +The tracking issue for this feature is: [#51575] + +[#51575]: https://github.com/rust-lang/rust/issues/51575 + +------------------------ +"##, + }, + Lint { + label: "abi_avr_interrupt", + description: r##"# `abi_avr_interrupt` + +The tracking issue for this feature is: [#69664] + +[#69664]: https://github.com/rust-lang/rust/issues/69664 + +------------------------ +"##, + }, Lint { label: "abi_c_cmse_nonsecure_call", description: r##"# `abi_c_cmse_nonsecure_call` @@ -1151,6 +1185,121 @@ $ cat $(find -name '*.s') ret; } ``` +"##, + }, + Lint { + label: "abi_riscv_interrupt", + description: r##"# `abi_riscv_interrupt` + +The tracking issue for this feature is: [#111889] + +[#111889]: https://github.com/rust-lang/rust/issues/111889 + +------------------------ +"##, + }, + Lint { + label: "abi_unadjusted", + description: r##"# `abi_unadjusted` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "abi_vectorcall", + description: r##"# `abi_vectorcall` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "abi_x86_interrupt", + description: r##"# `abi_x86_interrupt` + +The tracking issue for this feature is: [#40180] + +[#40180]: https://github.com/rust-lang/rust/issues/40180 + +------------------------ +"##, + }, + Lint { + label: "absolute_path", + description: r##"# `absolute_path` + +The tracking issue for this feature is: [#92750] + +[#92750]: https://github.com/rust-lang/rust/issues/92750 + +------------------------ +"##, + }, + Lint { + label: "addr_parse_ascii", + description: r##"# `addr_parse_ascii` + +The tracking issue for this feature is: [#101035] + +[#101035]: https://github.com/rust-lang/rust/issues/101035 + +------------------------ +"##, + }, + Lint { + label: "adt_const_params", + description: r##"# `adt_const_params` + +The tracking issue for this feature is: [#95174] + +[#95174]: https://github.com/rust-lang/rust/issues/95174 + +------------------------ +"##, + }, + Lint { + label: "alloc_error_handler", + description: r##"# `alloc_error_handler` + +The tracking issue for this feature is: [#51540] + +[#51540]: https://github.com/rust-lang/rust/issues/51540 + +------------------------ +"##, + }, + Lint { + label: "alloc_error_hook", + description: r##"# `alloc_error_hook` + +The tracking issue for this feature is: [#51245] + +[#51245]: https://github.com/rust-lang/rust/issues/51245 + +------------------------ +"##, + }, + Lint { + label: "alloc_internals", + description: r##"# `alloc_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "alloc_layout_extra", + description: r##"# `alloc_layout_extra` + +The tracking issue for this feature is: [#55724] + +[#55724]: https://github.com/rust-lang/rust/issues/55724 + +------------------------ "##, }, Lint { @@ -1180,6 +1329,165 @@ This feature does not have a tracking issue, it is an unstable implementation detail of the `global_allocator` feature not intended for use outside the compiler. +------------------------ +"##, + }, + Lint { + label: "allow_internal_unsafe", + description: r##"# `allow_internal_unsafe` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "allow_internal_unstable", + description: r##"# `allow_internal_unstable` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "anonymous_lifetime_in_impl_trait", + description: r##"# `anonymous_lifetime_in_impl_trait` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "arbitrary_self_types", + description: r##"# `arbitrary_self_types` + +The tracking issue for this feature is: [#44874] + +[#44874]: https://github.com/rust-lang/rust/issues/44874 + +------------------------ +"##, + }, + Lint { + label: "arc_unwrap_or_clone", + description: r##"# `arc_unwrap_or_clone` + +The tracking issue for this feature is: [#93610] + +[#93610]: https://github.com/rust-lang/rust/issues/93610 + +------------------------ +"##, + }, + Lint { + label: "arm_target_feature", + description: r##"# `arm_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "array_chunks", + description: r##"# `array_chunks` + +The tracking issue for this feature is: [#74985] + +[#74985]: https://github.com/rust-lang/rust/issues/74985 + +------------------------ +"##, + }, + Lint { + label: "array_into_iter_constructors", + description: r##"# `array_into_iter_constructors` + +The tracking issue for this feature is: [#91583] + +[#91583]: https://github.com/rust-lang/rust/issues/91583 + +------------------------ +"##, + }, + Lint { + label: "array_methods", + description: r##"# `array_methods` + +The tracking issue for this feature is: [#76118] + +[#76118]: https://github.com/rust-lang/rust/issues/76118 + +------------------------ +"##, + }, + Lint { + label: "array_try_from_fn", + description: r##"# `array_try_from_fn` + +The tracking issue for this feature is: [#89379] + +[#89379]: https://github.com/rust-lang/rust/issues/89379 + +------------------------ +"##, + }, + Lint { + label: "array_try_map", + description: r##"# `array_try_map` + +The tracking issue for this feature is: [#79711] + +[#79711]: https://github.com/rust-lang/rust/issues/79711 + +------------------------ +"##, + }, + Lint { + label: "array_windows", + description: r##"# `array_windows` + +The tracking issue for this feature is: [#75027] + +[#75027]: https://github.com/rust-lang/rust/issues/75027 + +------------------------ +"##, + }, + Lint { + label: "as_array_of_cells", + description: r##"# `as_array_of_cells` + +The tracking issue for this feature is: [#88248] + +[#88248]: https://github.com/rust-lang/rust/issues/88248 + +------------------------ +"##, + }, + Lint { + label: "ascii_char", + description: r##"# `ascii_char` + +The tracking issue for this feature is: [#110998] + +[#110998]: https://github.com/rust-lang/rust/issues/110998 + +------------------------ +"##, + }, + Lint { + label: "ascii_char_variants", + description: r##"# `ascii_char_variants` + +The tracking issue for this feature is: [#110998] + +[#110998]: https://github.com/rust-lang/rust/issues/110998 + ------------------------ "##, }, @@ -1391,6 +1699,138 @@ The tracking issue for this feature is: [#93334] ------------------------ This feature adds a `may_unwind` option to `asm!` which allows an `asm` block to unwind stack and be part of the stack unwinding process. This option is only supported by the LLVM backend right now. +"##, + }, + Lint { + label: "assert_matches", + description: r##"# `assert_matches` + +The tracking issue for this feature is: [#82775] + +[#82775]: https://github.com/rust-lang/rust/issues/82775 + +------------------------ +"##, + }, + Lint { + label: "associated_const_equality", + description: r##"# `associated_const_equality` + +The tracking issue for this feature is: [#92827] + +[#92827]: https://github.com/rust-lang/rust/issues/92827 + +------------------------ +"##, + }, + Lint { + label: "associated_type_bounds", + description: r##"# `associated_type_bounds` + +The tracking issue for this feature is: [#52662] + +[#52662]: https://github.com/rust-lang/rust/issues/52662 + +------------------------ +"##, + }, + Lint { + label: "associated_type_defaults", + description: r##"# `associated_type_defaults` + +The tracking issue for this feature is: [#29661] + +[#29661]: https://github.com/rust-lang/rust/issues/29661 + +------------------------ +"##, + }, + Lint { + label: "async_closure", + description: r##"# `async_closure` + +The tracking issue for this feature is: [#62290] + +[#62290]: https://github.com/rust-lang/rust/issues/62290 + +------------------------ +"##, + }, + Lint { + label: "async_fn_in_trait", + description: r##"# `async_fn_in_trait` + +The tracking issue for this feature is: [#91611] + +[#91611]: https://github.com/rust-lang/rust/issues/91611 + +------------------------ +"##, + }, + Lint { + label: "async_fn_track_caller", + description: r##"# `async_fn_track_caller` + +The tracking issue for this feature is: [#110011] + +[#110011]: https://github.com/rust-lang/rust/issues/110011 + +------------------------ +"##, + }, + Lint { + label: "async_iter_from_iter", + description: r##"# `async_iter_from_iter` + +The tracking issue for this feature is: [#81798] + +[#81798]: https://github.com/rust-lang/rust/issues/81798 + +------------------------ +"##, + }, + Lint { + label: "async_iterator", + description: r##"# `async_iterator` + +The tracking issue for this feature is: [#79024] + +[#79024]: https://github.com/rust-lang/rust/issues/79024 + +------------------------ +"##, + }, + Lint { + label: "atomic_bool_fetch_not", + description: r##"# `atomic_bool_fetch_not` + +The tracking issue for this feature is: [#98485] + +[#98485]: https://github.com/rust-lang/rust/issues/98485 + +------------------------ +"##, + }, + Lint { + label: "atomic_from_mut", + description: r##"# `atomic_from_mut` + +The tracking issue for this feature is: [#76314] + +[#76314]: https://github.com/rust-lang/rust/issues/76314 + +------------------------ +"##, + }, + Lint { + label: "atomic_from_ptr", + description: r##"# `atomic_from_ptr` + +The tracking issue for this feature is: [#108652] + +[#108652]: https://github.com/rust-lang/rust/issues/108652 + +------------------------ "##, }, Lint { @@ -1501,6 +1941,116 @@ Auto traits cannot have any trait items, such as methods or associated types. Th ## Supertraits Auto traits cannot have supertraits. This is for soundness reasons, as the interaction of coinduction with implied bounds is difficult to reconcile. +"##, + }, + Lint { + label: "avx512_target_feature", + description: r##"# `avx512_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "backtrace_frames", + description: r##"# `backtrace_frames` + +The tracking issue for this feature is: [#79676] + +[#79676]: https://github.com/rust-lang/rust/issues/79676 + +------------------------ +"##, + }, + Lint { + label: "bigint_helper_methods", + description: r##"# `bigint_helper_methods` + +The tracking issue for this feature is: [#85532] + +[#85532]: https://github.com/rust-lang/rust/issues/85532 + +------------------------ +"##, + }, + Lint { + label: "binary_heap_as_slice", + description: r##"# `binary_heap_as_slice` + +The tracking issue for this feature is: [#83659] + +[#83659]: https://github.com/rust-lang/rust/issues/83659 + +------------------------ +"##, + }, + Lint { + label: "binary_heap_drain_sorted", + description: r##"# `binary_heap_drain_sorted` + +The tracking issue for this feature is: [#59278] + +[#59278]: https://github.com/rust-lang/rust/issues/59278 + +------------------------ +"##, + }, + Lint { + label: "binary_heap_into_iter_sorted", + description: r##"# `binary_heap_into_iter_sorted` + +The tracking issue for this feature is: [#59278] + +[#59278]: https://github.com/rust-lang/rust/issues/59278 + +------------------------ +"##, + }, + Lint { + label: "bound_as_ref", + description: r##"# `bound_as_ref` + +The tracking issue for this feature is: [#80996] + +[#80996]: https://github.com/rust-lang/rust/issues/80996 + +------------------------ +"##, + }, + Lint { + label: "bound_map", + description: r##"# `bound_map` + +The tracking issue for this feature is: [#86026] + +[#86026]: https://github.com/rust-lang/rust/issues/86026 + +------------------------ +"##, + }, + Lint { + label: "box_into_boxed_slice", + description: r##"# `box_into_boxed_slice` + +The tracking issue for this feature is: [#71582] + +[#71582]: https://github.com/rust-lang/rust/issues/71582 + +------------------------ +"##, + }, + Lint { + label: "box_into_inner", + description: r##"# `box_into_inner` + +The tracking issue for this feature is: [#80437] + +[#80437]: https://github.com/rust-lang/rust/issues/80437 + +------------------------ "##, }, Lint { @@ -1535,6 +2085,105 @@ fn main() { } } ``` +"##, + }, + Lint { + label: "bpf_target_feature", + description: r##"# `bpf_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "btree_cursors", + description: r##"# `btree_cursors` + +The tracking issue for this feature is: [#107540] + +[#107540]: https://github.com/rust-lang/rust/issues/107540 + +------------------------ +"##, + }, + Lint { + label: "btree_extract_if", + description: r##"# `btree_extract_if` + +The tracking issue for this feature is: [#70530] + +[#70530]: https://github.com/rust-lang/rust/issues/70530 + +------------------------ +"##, + }, + Lint { + label: "btreemap_alloc", + description: r##"# `btreemap_alloc` + +The tracking issue for this feature is: [#32838] + +[#32838]: https://github.com/rust-lang/rust/issues/32838 + +------------------------ +"##, + }, + Lint { + label: "buf_read_has_data_left", + description: r##"# `buf_read_has_data_left` + +The tracking issue for this feature is: [#86423] + +[#86423]: https://github.com/rust-lang/rust/issues/86423 + +------------------------ +"##, + }, + Lint { + label: "builtin_syntax", + description: r##"# `builtin_syntax` + +The tracking issue for this feature is: [#110680] + +[#110680]: https://github.com/rust-lang/rust/issues/110680 + +------------------------ +"##, + }, + Lint { + label: "byte_slice_trim_ascii", + description: r##"# `byte_slice_trim_ascii` + +The tracking issue for this feature is: [#94035] + +[#94035]: https://github.com/rust-lang/rust/issues/94035 + +------------------------ +"##, + }, + Lint { + label: "c_size_t", + description: r##"# `c_size_t` + +The tracking issue for this feature is: [#88345] + +[#88345]: https://github.com/rust-lang/rust/issues/88345 + +------------------------ +"##, + }, + Lint { + label: "c_str_literals", + description: r##"# `c_str_literals` + +The tracking issue for this feature is: [#105723] + +[#105723]: https://github.com/rust-lang/rust/issues/105723 + +------------------------ "##, }, Lint { @@ -1631,6 +2280,94 @@ pub unsafe extern "C" fn vadd(n: usize, mut args: VaList) -> usize { This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "can_vector", + description: r##"# `can_vector` + +The tracking issue for this feature is: [#69941] + +[#69941]: https://github.com/rust-lang/rust/issues/69941 + +------------------------ +"##, + }, + Lint { + label: "cell_leak", + description: r##"# `cell_leak` + +The tracking issue for this feature is: [#69099] + +[#69099]: https://github.com/rust-lang/rust/issues/69099 + +------------------------ +"##, + }, + Lint { + label: "cell_update", + description: r##"# `cell_update` + +The tracking issue for this feature is: [#50186] + +[#50186]: https://github.com/rust-lang/rust/issues/50186 + +------------------------ +"##, + }, + Lint { + label: "cfg_accessible", + description: r##"# `cfg_accessible` + +The tracking issue for this feature is: [#64797] + +[#64797]: https://github.com/rust-lang/rust/issues/64797 + +------------------------ +"##, + }, + Lint { + label: "cfg_eval", + description: r##"# `cfg_eval` + +The tracking issue for this feature is: [#82679] + +[#82679]: https://github.com/rust-lang/rust/issues/82679 + +------------------------ +"##, + }, + Lint { + label: "cfg_match", + description: r##"# `cfg_match` + +The tracking issue for this feature is: [#115585] + +[#115585]: https://github.com/rust-lang/rust/issues/115585 + +------------------------ +"##, + }, + Lint { + label: "cfg_overflow_checks", + description: r##"# `cfg_overflow_checks` + +The tracking issue for this feature is: [#111466] + +[#111466]: https://github.com/rust-lang/rust/issues/111466 + +------------------------ +"##, + }, + Lint { + label: "cfg_relocation_model", + description: r##"# `cfg_relocation_model` + +The tracking issue for this feature is: [#114929] + +[#114929]: https://github.com/rust-lang/rust/issues/114929 + ------------------------ "##, }, @@ -1670,6 +2407,61 @@ fn b() { } } ``` +"##, + }, + Lint { + label: "cfg_target_abi", + description: r##"# `cfg_target_abi` + +The tracking issue for this feature is: [#80970] + +[#80970]: https://github.com/rust-lang/rust/issues/80970 + +------------------------ +"##, + }, + Lint { + label: "cfg_target_compact", + description: r##"# `cfg_target_compact` + +The tracking issue for this feature is: [#96901] + +[#96901]: https://github.com/rust-lang/rust/issues/96901 + +------------------------ +"##, + }, + Lint { + label: "cfg_target_has_atomic", + description: r##"# `cfg_target_has_atomic` + +The tracking issue for this feature is: [#94039] + +[#94039]: https://github.com/rust-lang/rust/issues/94039 + +------------------------ +"##, + }, + Lint { + label: "cfg_target_has_atomic_equal_alignment", + description: r##"# `cfg_target_has_atomic_equal_alignment` + +The tracking issue for this feature is: [#93822] + +[#93822]: https://github.com/rust-lang/rust/issues/93822 + +------------------------ +"##, + }, + Lint { + label: "cfg_target_thread_local", + description: r##"# `cfg_target_thread_local` + +The tracking issue for this feature is: [#29594] + +[#29594]: https://github.com/rust-lang/rust/issues/29594 + +------------------------ "##, }, Lint { @@ -1738,6 +2530,48 @@ extern { type Type2; } ``` +"##, + }, + Lint { + label: "char_indices_offset", + description: r##"# `char_indices_offset` + +The tracking issue for this feature is: [#83871] + +[#83871]: https://github.com/rust-lang/rust/issues/83871 + +------------------------ +"##, + }, + Lint { + label: "char_internals", + description: r##"# `char_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "char_min", + description: r##"# `char_min` + +The tracking issue for this feature is: [#114298] + +[#114298]: https://github.com/rust-lang/rust/issues/114298 + +------------------------ +"##, + }, + Lint { + label: "closure_lifetime_binder", + description: r##"# `closure_lifetime_binder` + +The tracking issue for this feature is: [#97362] + +[#97362]: https://github.com/rust-lang/rust/issues/97362 + +------------------------ "##, }, Lint { @@ -1754,6 +2588,17 @@ Allows using the `#[track_caller]` attribute on closures and generators. Calls made to the closure or generator will have caller information available through `std::panic::Location::caller()`, just like using `#[track_caller]` on a function. +"##, + }, + Lint { + label: "cmp_minmax", + description: r##"# `cmp_minmax` + +The tracking issue for this feature is: [#115939] + +[#115939]: https://github.com/rust-lang/rust/issues/115939 + +------------------------ "##, }, Lint { @@ -1839,6 +2684,28 @@ $ arm-none-eabi-objdump -D function.o 3c: f7ff fffe bl 0 <_ZN4core9panicking5panic17h5c028258ca2fb3f5E> 40: defe udf #254 ; 0xfe ``` +"##, + }, + Lint { + label: "coerce_unsized", + description: r##"# `coerce_unsized` + +The tracking issue for this feature is: [#18598] + +[#18598]: https://github.com/rust-lang/rust/issues/18598 + +------------------------ +"##, + }, + Lint { + label: "collapse_debuginfo", + description: r##"# `collapse_debuginfo` + +The tracking issue for this feature is: [#100758] + +[#100758]: https://github.com/rust-lang/rust/issues/100758 + +------------------------ "##, }, Lint { @@ -1847,6 +2714,17 @@ $ arm-none-eabi-objdump -D function.o This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "concat_bytes", + description: r##"# `concat_bytes` + +The tracking issue for this feature is: [#87555] + +[#87555]: https://github.com/rust-lang/rust/issues/87555 + ------------------------ "##, }, @@ -1874,6 +2752,1030 @@ fn main() { assert_eq!(f(), 23); } ``` +"##, + }, + Lint { + label: "const_align_of_val", + description: r##"# `const_align_of_val` + +The tracking issue for this feature is: [#46571] + +[#46571]: https://github.com/rust-lang/rust/issues/46571 + +------------------------ +"##, + }, + Lint { + label: "const_align_of_val_raw", + description: r##"# `const_align_of_val_raw` + +The tracking issue for this feature is: [#46571] + +[#46571]: https://github.com/rust-lang/rust/issues/46571 + +------------------------ +"##, + }, + Lint { + label: "const_align_offset", + description: r##"# `const_align_offset` + +The tracking issue for this feature is: [#90962] + +[#90962]: https://github.com/rust-lang/rust/issues/90962 + +------------------------ +"##, + }, + Lint { + label: "const_alloc_error", + description: r##"# `const_alloc_error` + +The tracking issue for this feature is: [#92523] + +[#92523]: https://github.com/rust-lang/rust/issues/92523 + +------------------------ +"##, + }, + Lint { + label: "const_alloc_layout", + description: r##"# `const_alloc_layout` + +The tracking issue for this feature is: [#67521] + +[#67521]: https://github.com/rust-lang/rust/issues/67521 + +------------------------ +"##, + }, + Lint { + label: "const_arguments_as_str", + description: r##"# `const_arguments_as_str` + +The tracking issue for this feature is: [#103900] + +[#103900]: https://github.com/rust-lang/rust/issues/103900 + +------------------------ +"##, + }, + Lint { + label: "const_array_from_ref", + description: r##"# `const_array_from_ref` + +The tracking issue for this feature is: [#90206] + +[#90206]: https://github.com/rust-lang/rust/issues/90206 + +------------------------ +"##, + }, + Lint { + label: "const_array_into_iter_constructors", + description: r##"# `const_array_into_iter_constructors` + +The tracking issue for this feature is: [#91583] + +[#91583]: https://github.com/rust-lang/rust/issues/91583 + +------------------------ +"##, + }, + Lint { + label: "const_assert_type2", + description: r##"# `const_assert_type2` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_assume", + description: r##"# `const_assume` + +The tracking issue for this feature is: [#76972] + +[#76972]: https://github.com/rust-lang/rust/issues/76972 + +------------------------ +"##, + }, + Lint { + label: "const_async_blocks", + description: r##"# `const_async_blocks` + +The tracking issue for this feature is: [#85368] + +[#85368]: https://github.com/rust-lang/rust/issues/85368 + +------------------------ +"##, + }, + Lint { + label: "const_bigint_helper_methods", + description: r##"# `const_bigint_helper_methods` + +The tracking issue for this feature is: [#85532] + +[#85532]: https://github.com/rust-lang/rust/issues/85532 + +------------------------ +"##, + }, + Lint { + label: "const_black_box", + description: r##"# `const_black_box` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_box", + description: r##"# `const_box` + +The tracking issue for this feature is: [#92521] + +[#92521]: https://github.com/rust-lang/rust/issues/92521 + +------------------------ +"##, + }, + Lint { + label: "const_btree_len", + description: r##"# `const_btree_len` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_caller_location", + description: r##"# `const_caller_location` + +The tracking issue for this feature is: [#76156] + +[#76156]: https://github.com/rust-lang/rust/issues/76156 + +------------------------ +"##, + }, + Lint { + label: "const_cell_into_inner", + description: r##"# `const_cell_into_inner` + +The tracking issue for this feature is: [#78729] + +[#78729]: https://github.com/rust-lang/rust/issues/78729 + +------------------------ +"##, + }, + Lint { + label: "const_char_from_u32_unchecked", + description: r##"# `const_char_from_u32_unchecked` + +The tracking issue for this feature is: [#89259] + +[#89259]: https://github.com/rust-lang/rust/issues/89259 + +------------------------ +"##, + }, + Lint { + label: "const_closures", + description: r##"# `const_closures` + +The tracking issue for this feature is: [#106003] + +[#106003]: https://github.com/rust-lang/rust/issues/106003 + +------------------------ +"##, + }, + Lint { + label: "const_collections_with_hasher", + description: r##"# `const_collections_with_hasher` + +The tracking issue for this feature is: [#102575] + +[#102575]: https://github.com/rust-lang/rust/issues/102575 + +------------------------ +"##, + }, + Lint { + label: "const_cow_is_borrowed", + description: r##"# `const_cow_is_borrowed` + +The tracking issue for this feature is: [#65143] + +[#65143]: https://github.com/rust-lang/rust/issues/65143 + +------------------------ +"##, + }, + Lint { + label: "const_cstr_from_ptr", + description: r##"# `const_cstr_from_ptr` + +The tracking issue for this feature is: [#113219] + +[#113219]: https://github.com/rust-lang/rust/issues/113219 + +------------------------ +"##, + }, + Lint { + label: "const_discriminant", + description: r##"# `const_discriminant` + +The tracking issue for this feature is: [#69821] + +[#69821]: https://github.com/rust-lang/rust/issues/69821 + +------------------------ +"##, + }, + Lint { + label: "const_eval_select", + description: r##"# `const_eval_select` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_exact_div", + description: r##"# `const_exact_div` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_extern_fn", + description: r##"# `const_extern_fn` + +The tracking issue for this feature is: [#64926] + +[#64926]: https://github.com/rust-lang/rust/issues/64926 + +------------------------ +"##, + }, + Lint { + label: "const_float_bits_conv", + description: r##"# `const_float_bits_conv` + +The tracking issue for this feature is: [#72447] + +[#72447]: https://github.com/rust-lang/rust/issues/72447 + +------------------------ +"##, + }, + Lint { + label: "const_float_classify", + description: r##"# `const_float_classify` + +The tracking issue for this feature is: [#72505] + +[#72505]: https://github.com/rust-lang/rust/issues/72505 + +------------------------ +"##, + }, + Lint { + label: "const_fmt_arguments_new", + description: r##"# `const_fmt_arguments_new` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_fn_floating_point_arithmetic", + description: r##"# `const_fn_floating_point_arithmetic` + +The tracking issue for this feature is: [#57241] + +[#57241]: https://github.com/rust-lang/rust/issues/57241 + +------------------------ +"##, + }, + Lint { + label: "const_for", + description: r##"# `const_for` + +The tracking issue for this feature is: [#87575] + +[#87575]: https://github.com/rust-lang/rust/issues/87575 + +------------------------ +"##, + }, + Lint { + label: "const_format_args", + description: r##"# `const_format_args` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_hash", + description: r##"# `const_hash` + +The tracking issue for this feature is: [#104061] + +[#104061]: https://github.com/rust-lang/rust/issues/104061 + +------------------------ +"##, + }, + Lint { + label: "const_heap", + description: r##"# `const_heap` + +The tracking issue for this feature is: [#79597] + +[#79597]: https://github.com/rust-lang/rust/issues/79597 + +------------------------ +"##, + }, + Lint { + label: "const_index_range_slice_index", + description: r##"# `const_index_range_slice_index` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_inherent_unchecked_arith", + description: r##"# `const_inherent_unchecked_arith` + +The tracking issue for this feature is: [#85122] + +[#85122]: https://github.com/rust-lang/rust/issues/85122 + +------------------------ +"##, + }, + Lint { + label: "const_int_unchecked_arith", + description: r##"# `const_int_unchecked_arith` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_intoiterator_identity", + description: r##"# `const_intoiterator_identity` + +The tracking issue for this feature is: [#90603] + +[#90603]: https://github.com/rust-lang/rust/issues/90603 + +------------------------ +"##, + }, + Lint { + label: "const_intrinsic_compare_bytes", + description: r##"# `const_intrinsic_compare_bytes` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_intrinsic_forget", + description: r##"# `const_intrinsic_forget` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_intrinsic_raw_eq", + description: r##"# `const_intrinsic_raw_eq` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_io_structs", + description: r##"# `const_io_structs` + +The tracking issue for this feature is: [#78812] + +[#78812]: https://github.com/rust-lang/rust/issues/78812 + +------------------------ +"##, + }, + Lint { + label: "const_ip", + description: r##"# `const_ip` + +The tracking issue for this feature is: [#76205] + +[#76205]: https://github.com/rust-lang/rust/issues/76205 + +------------------------ +"##, + }, + Lint { + label: "const_ipv4", + description: r##"# `const_ipv4` + +The tracking issue for this feature is: [#76205] + +[#76205]: https://github.com/rust-lang/rust/issues/76205 + +------------------------ +"##, + }, + Lint { + label: "const_ipv6", + description: r##"# `const_ipv6` + +The tracking issue for this feature is: [#76205] + +[#76205]: https://github.com/rust-lang/rust/issues/76205 + +------------------------ +"##, + }, + Lint { + label: "const_likely", + description: r##"# `const_likely` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_location_fields", + description: r##"# `const_location_fields` + +The tracking issue for this feature is: [#102911] + +[#102911]: https://github.com/rust-lang/rust/issues/102911 + +------------------------ +"##, + }, + Lint { + label: "const_maybe_uninit_array_assume_init", + description: r##"# `const_maybe_uninit_array_assume_init` + +The tracking issue for this feature is: [#96097] + +[#96097]: https://github.com/rust-lang/rust/issues/96097 + +------------------------ +"##, + }, + Lint { + label: "const_maybe_uninit_as_mut_ptr", + description: r##"# `const_maybe_uninit_as_mut_ptr` + +The tracking issue for this feature is: [#75251] + +[#75251]: https://github.com/rust-lang/rust/issues/75251 + +------------------------ +"##, + }, + Lint { + label: "const_maybe_uninit_assume_init", + description: r##"# `const_maybe_uninit_assume_init` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_maybe_uninit_assume_init_read", + description: r##"# `const_maybe_uninit_assume_init_read` + +The tracking issue for this feature is: [#63567] + +[#63567]: https://github.com/rust-lang/rust/issues/63567 + +------------------------ +"##, + }, + Lint { + label: "const_maybe_uninit_uninit_array", + description: r##"# `const_maybe_uninit_uninit_array` + +The tracking issue for this feature is: [#96097] + +[#96097]: https://github.com/rust-lang/rust/issues/96097 + +------------------------ +"##, + }, + Lint { + label: "const_maybe_uninit_write", + description: r##"# `const_maybe_uninit_write` + +The tracking issue for this feature is: [#63567] + +[#63567]: https://github.com/rust-lang/rust/issues/63567 + +------------------------ +"##, + }, + Lint { + label: "const_maybe_uninit_zeroed", + description: r##"# `const_maybe_uninit_zeroed` + +The tracking issue for this feature is: [#91850] + +[#91850]: https://github.com/rust-lang/rust/issues/91850 + +------------------------ +"##, + }, + Lint { + label: "const_mut_refs", + description: r##"# `const_mut_refs` + +The tracking issue for this feature is: [#57349] + +[#57349]: https://github.com/rust-lang/rust/issues/57349 + +------------------------ +"##, + }, + Lint { + label: "const_nonnull_new", + description: r##"# `const_nonnull_new` + +The tracking issue for this feature is: [#93235] + +[#93235]: https://github.com/rust-lang/rust/issues/93235 + +------------------------ +"##, + }, + Lint { + label: "const_num_midpoint", + description: r##"# `const_num_midpoint` + +The tracking issue for this feature is: [#110840] + +[#110840]: https://github.com/rust-lang/rust/issues/110840 + +------------------------ +"##, + }, + Lint { + label: "const_option", + description: r##"# `const_option` + +The tracking issue for this feature is: [#67441] + +[#67441]: https://github.com/rust-lang/rust/issues/67441 + +------------------------ +"##, + }, + Lint { + label: "const_option_ext", + description: r##"# `const_option_ext` + +The tracking issue for this feature is: [#91930] + +[#91930]: https://github.com/rust-lang/rust/issues/91930 + +------------------------ +"##, + }, + Lint { + label: "const_pin", + description: r##"# `const_pin` + +The tracking issue for this feature is: [#76654] + +[#76654]: https://github.com/rust-lang/rust/issues/76654 + +------------------------ +"##, + }, + Lint { + label: "const_pointer_byte_offsets", + description: r##"# `const_pointer_byte_offsets` + +The tracking issue for this feature is: [#96283] + +[#96283]: https://github.com/rust-lang/rust/issues/96283 + +------------------------ +"##, + }, + Lint { + label: "const_pointer_is_aligned", + description: r##"# `const_pointer_is_aligned` + +The tracking issue for this feature is: [#104203] + +[#104203]: https://github.com/rust-lang/rust/issues/104203 + +------------------------ +"##, + }, + Lint { + label: "const_precise_live_drops", + description: r##"# `const_precise_live_drops` + +The tracking issue for this feature is: [#73255] + +[#73255]: https://github.com/rust-lang/rust/issues/73255 + +------------------------ +"##, + }, + Lint { + label: "const_pref_align_of", + description: r##"# `const_pref_align_of` + +The tracking issue for this feature is: [#91971] + +[#91971]: https://github.com/rust-lang/rust/issues/91971 + +------------------------ +"##, + }, + Lint { + label: "const_ptr_as_ref", + description: r##"# `const_ptr_as_ref` + +The tracking issue for this feature is: [#91822] + +[#91822]: https://github.com/rust-lang/rust/issues/91822 + +------------------------ +"##, + }, + Lint { + label: "const_ptr_is_null", + description: r##"# `const_ptr_is_null` + +The tracking issue for this feature is: [#74939] + +[#74939]: https://github.com/rust-lang/rust/issues/74939 + +------------------------ +"##, + }, + Lint { + label: "const_ptr_sub_ptr", + description: r##"# `const_ptr_sub_ptr` + +The tracking issue for this feature is: [#95892] + +[#95892]: https://github.com/rust-lang/rust/issues/95892 + +------------------------ +"##, + }, + Lint { + label: "const_ptr_write", + description: r##"# `const_ptr_write` + +The tracking issue for this feature is: [#86302] + +[#86302]: https://github.com/rust-lang/rust/issues/86302 + +------------------------ +"##, + }, + Lint { + label: "const_range_bounds", + description: r##"# `const_range_bounds` + +The tracking issue for this feature is: [#108082] + +[#108082]: https://github.com/rust-lang/rust/issues/108082 + +------------------------ +"##, + }, + Lint { + label: "const_raw_ptr_comparison", + description: r##"# `const_raw_ptr_comparison` + +The tracking issue for this feature is: [#53020] + +[#53020]: https://github.com/rust-lang/rust/issues/53020 + +------------------------ +"##, + }, + Lint { + label: "const_refs_to_cell", + description: r##"# `const_refs_to_cell` + +The tracking issue for this feature is: [#80384] + +[#80384]: https://github.com/rust-lang/rust/issues/80384 + +------------------------ +"##, + }, + Lint { + label: "const_replace", + description: r##"# `const_replace` + +The tracking issue for this feature is: [#83164] + +[#83164]: https://github.com/rust-lang/rust/issues/83164 + +------------------------ +"##, + }, + Lint { + label: "const_result", + description: r##"# `const_result` + +The tracking issue for this feature is: [#82814] + +[#82814]: https://github.com/rust-lang/rust/issues/82814 + +------------------------ +"##, + }, + Lint { + label: "const_size_of_val", + description: r##"# `const_size_of_val` + +The tracking issue for this feature is: [#46571] + +[#46571]: https://github.com/rust-lang/rust/issues/46571 + +------------------------ +"##, + }, + Lint { + label: "const_size_of_val_raw", + description: r##"# `const_size_of_val_raw` + +The tracking issue for this feature is: [#46571] + +[#46571]: https://github.com/rust-lang/rust/issues/46571 + +------------------------ +"##, + }, + Lint { + label: "const_slice_first_last", + description: r##"# `const_slice_first_last` + +The tracking issue for this feature is: [#83570] + +[#83570]: https://github.com/rust-lang/rust/issues/83570 + +------------------------ +"##, + }, + Lint { + label: "const_slice_from_mut_ptr_range", + description: r##"# `const_slice_from_mut_ptr_range` + +The tracking issue for this feature is: [#89792] + +[#89792]: https://github.com/rust-lang/rust/issues/89792 + +------------------------ +"##, + }, + Lint { + label: "const_slice_from_ptr_range", + description: r##"# `const_slice_from_ptr_range` + +The tracking issue for this feature is: [#89792] + +[#89792]: https://github.com/rust-lang/rust/issues/89792 + +------------------------ +"##, + }, + Lint { + label: "const_slice_from_raw_parts_mut", + description: r##"# `const_slice_from_raw_parts_mut` + +The tracking issue for this feature is: [#67456] + +[#67456]: https://github.com/rust-lang/rust/issues/67456 + +------------------------ +"##, + }, + Lint { + label: "const_slice_from_ref", + description: r##"# `const_slice_from_ref` + +The tracking issue for this feature is: [#90206] + +[#90206]: https://github.com/rust-lang/rust/issues/90206 + +------------------------ +"##, + }, + Lint { + label: "const_slice_index", + description: r##"# `const_slice_index` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_slice_ptr_len", + description: r##"# `const_slice_ptr_len` + +The tracking issue for this feature is: [#71146] + +[#71146]: https://github.com/rust-lang/rust/issues/71146 + +------------------------ +"##, + }, + Lint { + label: "const_slice_split_at_mut", + description: r##"# `const_slice_split_at_mut` + +The tracking issue for this feature is: [#101804] + +[#101804]: https://github.com/rust-lang/rust/issues/101804 + +------------------------ +"##, + }, + Lint { + label: "const_str_from_utf8", + description: r##"# `const_str_from_utf8` + +The tracking issue for this feature is: [#91006] + +[#91006]: https://github.com/rust-lang/rust/issues/91006 + +------------------------ +"##, + }, + Lint { + label: "const_str_from_utf8_unchecked_mut", + description: r##"# `const_str_from_utf8_unchecked_mut` + +The tracking issue for this feature is: [#91005] + +[#91005]: https://github.com/rust-lang/rust/issues/91005 + +------------------------ +"##, + }, + Lint { + label: "const_swap", + description: r##"# `const_swap` + +The tracking issue for this feature is: [#83163] + +[#83163]: https://github.com/rust-lang/rust/issues/83163 + +------------------------ +"##, + }, + Lint { + label: "const_trait_impl", + description: r##"# `const_trait_impl` + +The tracking issue for this feature is: [#67792] + +[#67792]: https://github.com/rust-lang/rust/issues/67792 + +------------------------ +"##, + }, + Lint { + label: "const_try", + description: r##"# `const_try` + +The tracking issue for this feature is: [#74935] + +[#74935]: https://github.com/rust-lang/rust/issues/74935 + +------------------------ +"##, + }, + Lint { + label: "const_type_id", + description: r##"# `const_type_id` + +The tracking issue for this feature is: [#77125] + +[#77125]: https://github.com/rust-lang/rust/issues/77125 + +------------------------ +"##, + }, + Lint { + label: "const_type_name", + description: r##"# `const_type_name` + +The tracking issue for this feature is: [#63084] + +[#63084]: https://github.com/rust-lang/rust/issues/63084 + +------------------------ +"##, + }, + Lint { + label: "const_unicode_case_lookup", + description: r##"# `const_unicode_case_lookup` + +The tracking issue for this feature is: [#101400] + +[#101400]: https://github.com/rust-lang/rust/issues/101400 + +------------------------ +"##, + }, + Lint { + label: "const_unsafecell_get_mut", + description: r##"# `const_unsafecell_get_mut` + +The tracking issue for this feature is: [#88836] + +[#88836]: https://github.com/rust-lang/rust/issues/88836 + +------------------------ +"##, + }, + Lint { + label: "const_waker", + description: r##"# `const_waker` + +The tracking issue for this feature is: [#102012] + +[#102012]: https://github.com/rust-lang/rust/issues/102012 + +------------------------ +"##, + }, + Lint { + label: "container_error_extra", + description: r##"# `container_error_extra` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "control_flow_enum", + description: r##"# `control_flow_enum` + +The tracking issue for this feature is: [#75744] + +[#75744]: https://github.com/rust-lang/rust/issues/75744 + +------------------------ +"##, + }, + Lint { + label: "convert_float_to_int", + description: r##"# `convert_float_to_int` + +The tracking issue for this feature is: [#67057] + +[#67057]: https://github.com/rust-lang/rust/issues/67057 + +------------------------ "##, }, Lint { @@ -1944,6 +3846,81 @@ fn bar() { // ... } ``` +"##, + }, + Lint { + label: "cow_is_borrowed", + description: r##"# `cow_is_borrowed` + +The tracking issue for this feature is: [#65143] + +[#65143]: https://github.com/rust-lang/rust/issues/65143 + +------------------------ +"##, + }, + Lint { + label: "csky_target_feature", + description: r##"# `csky_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "cstr_count_bytes", + description: r##"# `cstr_count_bytes` + +The tracking issue for this feature is: [#114441] + +[#114441]: https://github.com/rust-lang/rust/issues/114441 + +------------------------ +"##, + }, + Lint { + label: "cursor_remaining", + description: r##"# `cursor_remaining` + +The tracking issue for this feature is: [#86369] + +[#86369]: https://github.com/rust-lang/rust/issues/86369 + +------------------------ +"##, + }, + Lint { + label: "custom_code_classes_in_docs", + description: r##"# `custom_code_classes_in_docs` + +The tracking issue for this feature is: [#79483] + +[#79483]: https://github.com/rust-lang/rust/issues/79483 + +------------------------ +"##, + }, + Lint { + label: "custom_inner_attributes", + description: r##"# `custom_inner_attributes` + +The tracking issue for this feature is: [#54726] + +[#54726]: https://github.com/rust-lang/rust/issues/54726 + +------------------------ +"##, + }, + Lint { + label: "custom_mir", + description: r##"# `custom_mir` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ "##, }, Lint { @@ -1980,6 +3957,17 @@ const WILL_PASS: i32 = 0; #[test_case] const WILL_FAIL: i32 = 4; ``` +"##, + }, + Lint { + label: "deadline_api", + description: r##"# `deadline_api` + +The tracking issue for this feature is: [#46316] + +[#46316]: https://github.com/rust-lang/rust/issues/46316 + +------------------------ "##, }, Lint { @@ -1988,6 +3976,50 @@ const WILL_FAIL: i32 = 4; This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "decl_macro", + description: r##"# `decl_macro` + +The tracking issue for this feature is: [#39412] + +[#39412]: https://github.com/rust-lang/rust/issues/39412 + +------------------------ +"##, + }, + Lint { + label: "default_type_parameter_fallback", + description: r##"# `default_type_parameter_fallback` + +The tracking issue for this feature is: [#27336] + +[#27336]: https://github.com/rust-lang/rust/issues/27336 + +------------------------ +"##, + }, + Lint { + label: "deprecated_safe", + description: r##"# `deprecated_safe` + +The tracking issue for this feature is: [#94978] + +[#94978]: https://github.com/rust-lang/rust/issues/94978 + +------------------------ +"##, + }, + Lint { + label: "deprecated_suggestion", + description: r##"# `deprecated_suggestion` + +The tracking issue for this feature is: [#94785] + +[#94785]: https://github.com/rust-lang/rust/issues/94785 + ------------------------ "##, }, @@ -1997,6 +4029,15 @@ This feature is internal to the Rust compiler and is not intended for general us This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "derive_const", + description: r##"# `derive_const` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + ------------------------ "##, }, @@ -2006,6 +4047,79 @@ This feature is internal to the Rust compiler and is not intended for general us This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "diagnostic_namespace", + description: r##"# `diagnostic_namespace` + +The tracking issue for this feature is: [#111996] + +[#111996]: https://github.com/rust-lang/rust/issues/111996 + +------------------------ +"##, + }, + Lint { + label: "dir_entry_ext2", + description: r##"# `dir_entry_ext2` + +The tracking issue for this feature is: [#85573] + +[#85573]: https://github.com/rust-lang/rust/issues/85573 + +------------------------ +"##, + }, + Lint { + label: "discriminant_kind", + description: r##"# `discriminant_kind` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "dispatch_from_dyn", + description: r##"# `dispatch_from_dyn` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "div_duration", + description: r##"# `div_duration` + +The tracking issue for this feature is: [#63139] + +[#63139]: https://github.com/rust-lang/rust/issues/63139 + +------------------------ +"##, + }, + Lint { + label: "do_not_recommend", + description: r##"# `do_not_recommend` + +The tracking issue for this feature is: [#51992] + +[#51992]: https://github.com/rust-lang/rust/issues/51992 + +------------------------ +"##, + }, + Lint { + label: "doc_auto_cfg", + description: r##"# `doc_auto_cfg` + +The tracking issue for this feature is: [#43781] + +[#43781]: https://github.com/rust-lang/rust/issues/43781 + ------------------------ "##, }, @@ -2057,6 +4171,17 @@ pub struct Icon { [#43781]: https://github.com/rust-lang/rust/issues/43781 [#43348]: https://github.com/rust-lang/rust/issues/43348 +"##, + }, + Lint { + label: "doc_cfg_hide", + description: r##"# `doc_cfg_hide` + +The tracking issue for this feature is: [#43781] + +[#43781]: https://github.com/rust-lang/rust/issues/43781 + +------------------------ "##, }, Lint { @@ -2122,6 +4247,180 @@ See also its documentation in [the rustdoc book][rustdoc-book-notable_trait]. [#45040]: https://github.com/rust-lang/rust/issues/45040 [#45039]: https://github.com/rust-lang/rust/pull/45039 [rustdoc-book-notable_trait]: ../../rustdoc/unstable-features.html#adding-your-trait-to-the-notable-traits-dialog +"##, + }, + Lint { + label: "downcast_unchecked", + description: r##"# `downcast_unchecked` + +The tracking issue for this feature is: [#90850] + +[#90850]: https://github.com/rust-lang/rust/issues/90850 + +------------------------ +"##, + }, + Lint { + label: "drain_keep_rest", + description: r##"# `drain_keep_rest` + +The tracking issue for this feature is: [#101122] + +[#101122]: https://github.com/rust-lang/rust/issues/101122 + +------------------------ +"##, + }, + Lint { + label: "dropck_eyepatch", + description: r##"# `dropck_eyepatch` + +The tracking issue for this feature is: [#34761] + +[#34761]: https://github.com/rust-lang/rust/issues/34761 + +------------------------ +"##, + }, + Lint { + label: "duration_constants", + description: r##"# `duration_constants` + +The tracking issue for this feature is: [#57391] + +[#57391]: https://github.com/rust-lang/rust/issues/57391 + +------------------------ +"##, + }, + Lint { + label: "duration_consts_float", + description: r##"# `duration_consts_float` + +The tracking issue for this feature is: [#72440] + +[#72440]: https://github.com/rust-lang/rust/issues/72440 + +------------------------ +"##, + }, + Lint { + label: "dyn_star", + description: r##"# `dyn_star` + +The tracking issue for this feature is: [#102425] + +[#102425]: https://github.com/rust-lang/rust/issues/102425 + +------------------------ +"##, + }, + Lint { + label: "edition_panic", + description: r##"# `edition_panic` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "effects", + description: r##"# `effects` + +The tracking issue for this feature is: [#102090] + +[#102090]: https://github.com/rust-lang/rust/issues/102090 + +------------------------ +"##, + }, + Lint { + label: "entry_insert", + description: r##"# `entry_insert` + +The tracking issue for this feature is: [#65225] + +[#65225]: https://github.com/rust-lang/rust/issues/65225 + +------------------------ +"##, + }, + Lint { + label: "ermsb_target_feature", + description: r##"# `ermsb_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "error_generic_member_access", + description: r##"# `error_generic_member_access` + +The tracking issue for this feature is: [#99301] + +[#99301]: https://github.com/rust-lang/rust/issues/99301 + +------------------------ +"##, + }, + Lint { + label: "error_in_core", + description: r##"# `error_in_core` + +The tracking issue for this feature is: [#103765] + +[#103765]: https://github.com/rust-lang/rust/issues/103765 + +------------------------ +"##, + }, + Lint { + label: "error_iter", + description: r##"# `error_iter` + +The tracking issue for this feature is: [#58520] + +[#58520]: https://github.com/rust-lang/rust/issues/58520 + +------------------------ +"##, + }, + Lint { + label: "error_reporter", + description: r##"# `error_reporter` + +The tracking issue for this feature is: [#90172] + +[#90172]: https://github.com/rust-lang/rust/issues/90172 + +------------------------ +"##, + }, + Lint { + label: "error_type_id", + description: r##"# `error_type_id` + +The tracking issue for this feature is: [#60784] + +[#60784]: https://github.com/rust-lang/rust/issues/60784 + +------------------------ +"##, + }, + Lint { + label: "exact_size_is_empty", + description: r##"# `exact_size_is_empty` + +The tracking issue for this feature is: [#35428] + +[#35428]: https://github.com/rust-lang/rust/issues/35428 + +------------------------ "##, }, Lint { @@ -2152,6 +4451,72 @@ stabilized. _ => println!("nor is everything else.") } ``` +"##, + }, + Lint { + label: "exclusive_wrapper", + description: r##"# `exclusive_wrapper` + +The tracking issue for this feature is: [#98407] + +[#98407]: https://github.com/rust-lang/rust/issues/98407 + +------------------------ +"##, + }, + Lint { + label: "exhaustive_patterns", + description: r##"# `exhaustive_patterns` + +The tracking issue for this feature is: [#51085] + +[#51085]: https://github.com/rust-lang/rust/issues/51085 + +------------------------ +"##, + }, + Lint { + label: "exit_status_error", + description: r##"# `exit_status_error` + +The tracking issue for this feature is: [#84908] + +[#84908]: https://github.com/rust-lang/rust/issues/84908 + +------------------------ +"##, + }, + Lint { + label: "exitcode_exit_method", + description: r##"# `exitcode_exit_method` + +The tracking issue for this feature is: [#97100] + +[#97100]: https://github.com/rust-lang/rust/issues/97100 + +------------------------ +"##, + }, + Lint { + label: "explicit_tail_calls", + description: r##"# `explicit_tail_calls` + +The tracking issue for this feature is: [#112788] + +[#112788]: https://github.com/rust-lang/rust/issues/112788 + +------------------------ +"##, + }, + Lint { + label: "extend_one", + description: r##"# `extend_one` + +The tracking issue for this feature is: [#72631] + +[#72631]: https://github.com/rust-lang/rust/issues/72631 + +------------------------ "##, }, Lint { @@ -2166,6 +4531,28 @@ The tracking issue for this feature is: [#100189] This feature adds the possibility of using `sysv64`, `win64` or `efiapi` calling conventions on functions with varargs. +"##, + }, + Lint { + label: "extern_types", + description: r##"# `extern_types` + +The tracking issue for this feature is: [#43467] + +[#43467]: https://github.com/rust-lang/rust/issues/43467 + +------------------------ +"##, + }, + Lint { + label: "extract_if", + description: r##"# `extract_if` + +The tracking issue for this feature is: [#43244] + +[#43244]: https://github.com/rust-lang/rust/issues/43244 + +------------------------ "##, }, Lint { @@ -2300,6 +4687,72 @@ against are compatible with those of the `#[ffi_pure]`. [ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacigdac.html [GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute [IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_pure.htm +"##, + }, + Lint { + label: "ffi_returns_twice", + description: r##"# `ffi_returns_twice` + +The tracking issue for this feature is: [#58314] + +[#58314]: https://github.com/rust-lang/rust/issues/58314 + +------------------------ +"##, + }, + Lint { + label: "file_create_new", + description: r##"# `file_create_new` + +The tracking issue for this feature is: [#105135] + +[#105135]: https://github.com/rust-lang/rust/issues/105135 + +------------------------ +"##, + }, + Lint { + label: "file_set_times", + description: r##"# `file_set_times` + +The tracking issue for this feature is: [#98245] + +[#98245]: https://github.com/rust-lang/rust/issues/98245 + +------------------------ +"##, + }, + Lint { + label: "float_gamma", + description: r##"# `float_gamma` + +The tracking issue for this feature is: [#99842] + +[#99842]: https://github.com/rust-lang/rust/issues/99842 + +------------------------ +"##, + }, + Lint { + label: "float_minimum_maximum", + description: r##"# `float_minimum_maximum` + +The tracking issue for this feature is: [#91079] + +[#91079]: https://github.com/rust-lang/rust/issues/91079 + +------------------------ +"##, + }, + Lint { + label: "float_next_up_down", + description: r##"# `float_next_up_down` + +The tracking issue for this feature is: [#91399] + +[#91399]: https://github.com/rust-lang/rust/issues/91399 + +------------------------ "##, }, Lint { @@ -2308,6 +4761,15 @@ against are compatible with those of the `#[ffi_pure]`. This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "fmt_helpers_for_derive", + description: r##"# `fmt_helpers_for_derive` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + ------------------------ "##, }, @@ -2317,6 +4779,26 @@ This feature is internal to the Rust compiler and is not intended for general us This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "fn_align", + description: r##"# `fn_align` + +The tracking issue for this feature is: [#82232] + +[#82232]: https://github.com/rust-lang/rust/issues/82232 + +------------------------ +"##, + }, + Lint { + label: "fn_ptr_trait", + description: r##"# `fn_ptr_trait` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + ------------------------ "##, }, @@ -2357,6 +4839,90 @@ fn main() { assert_eq!(adder(2), 5); } ``` +"##, + }, + Lint { + label: "forget_unsized", + description: r##"# `forget_unsized` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "format_args_nl", + description: r##"# `format_args_nl` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "fs_try_exists", + description: r##"# `fs_try_exists` + +The tracking issue for this feature is: [#83186] + +[#83186]: https://github.com/rust-lang/rust/issues/83186 + +------------------------ +"##, + }, + Lint { + label: "fundamental", + description: r##"# `fundamental` + +The tracking issue for this feature is: [#29635] + +[#29635]: https://github.com/rust-lang/rust/issues/29635 + +------------------------ +"##, + }, + Lint { + label: "future_join", + description: r##"# `future_join` + +The tracking issue for this feature is: [#91642] + +[#91642]: https://github.com/rust-lang/rust/issues/91642 + +------------------------ +"##, + }, + Lint { + label: "gen_future", + description: r##"# `gen_future` + +The tracking issue for this feature is: [#50547] + +[#50547]: https://github.com/rust-lang/rust/issues/50547 + +------------------------ +"##, + }, + Lint { + label: "generator_clone", + description: r##"# `generator_clone` + +The tracking issue for this feature is: [#95360] + +[#95360]: https://github.com/rust-lang/rust/issues/95360 + +------------------------ +"##, + }, + Lint { + label: "generator_trait", + description: r##"# `generator_trait` + +The tracking issue for this feature is: [#43122] + +[#43122]: https://github.com/rust-lang/rust/issues/43122 + +------------------------ "##, }, Lint { @@ -2607,6 +5173,92 @@ Here we can also note that the `Done` state, if resumed, panics immediately as it's invalid to resume a completed generator. It's also worth noting that this is just a rough desugaring, not a normative specification for what the compiler does. +"##, + }, + Lint { + label: "generic_arg_infer", + description: r##"# `generic_arg_infer` + +The tracking issue for this feature is: [#85077] + +[#85077]: https://github.com/rust-lang/rust/issues/85077 + +------------------------ +"##, + }, + Lint { + label: "generic_assert", + description: r##"# `generic_assert` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "generic_assert_internals", + description: r##"# `generic_assert_internals` + +The tracking issue for this feature is: [#44838] + +[#44838]: https://github.com/rust-lang/rust/issues/44838 + +------------------------ +"##, + }, + Lint { + label: "generic_associated_types_extended", + description: r##"# `generic_associated_types_extended` + +The tracking issue for this feature is: [#95451] + +[#95451]: https://github.com/rust-lang/rust/issues/95451 + +------------------------ +"##, + }, + Lint { + label: "generic_const_exprs", + description: r##"# `generic_const_exprs` + +The tracking issue for this feature is: [#76560] + +[#76560]: https://github.com/rust-lang/rust/issues/76560 + +------------------------ +"##, + }, + Lint { + label: "generic_const_items", + description: r##"# `generic_const_items` + +The tracking issue for this feature is: [#113521] + +[#113521]: https://github.com/rust-lang/rust/issues/113521 + +------------------------ +"##, + }, + Lint { + label: "get_many_mut", + description: r##"# `get_many_mut` + +The tracking issue for this feature is: [#104642] + +[#104642]: https://github.com/rust-lang/rust/issues/104642 + +------------------------ +"##, + }, + Lint { + label: "get_mut_unchecked", + description: r##"# `get_mut_unchecked` + +The tracking issue for this feature is: [#63292] + +[#63292]: https://github.com/rust-lang/rust/issues/63292 + +------------------------ "##, }, Lint { @@ -2641,6 +5293,136 @@ fn main() { let [(a @ 3..), c] = xs else { return; }; } ``` +"##, + }, + Lint { + label: "hash_extract_if", + description: r##"# `hash_extract_if` + +The tracking issue for this feature is: [#59618] + +[#59618]: https://github.com/rust-lang/rust/issues/59618 + +------------------------ +"##, + }, + Lint { + label: "hash_raw_entry", + description: r##"# `hash_raw_entry` + +The tracking issue for this feature is: [#56167] + +[#56167]: https://github.com/rust-lang/rust/issues/56167 + +------------------------ +"##, + }, + Lint { + label: "hash_set_entry", + description: r##"# `hash_set_entry` + +The tracking issue for this feature is: [#60896] + +[#60896]: https://github.com/rust-lang/rust/issues/60896 + +------------------------ +"##, + }, + Lint { + label: "hasher_prefixfree_extras", + description: r##"# `hasher_prefixfree_extras` + +The tracking issue for this feature is: [#96762] + +[#96762]: https://github.com/rust-lang/rust/issues/96762 + +------------------------ +"##, + }, + Lint { + label: "hashmap_internals", + description: r##"# `hashmap_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "hexagon_target_feature", + description: r##"# `hexagon_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "hint_must_use", + description: r##"# `hint_must_use` + +The tracking issue for this feature is: [#94745] + +[#94745]: https://github.com/rust-lang/rust/issues/94745 + +------------------------ +"##, + }, + Lint { + label: "if_let_guard", + description: r##"# `if_let_guard` + +The tracking issue for this feature is: [#51114] + +[#51114]: https://github.com/rust-lang/rust/issues/51114 + +------------------------ +"##, + }, + Lint { + label: "impl_trait_in_assoc_type", + description: r##"# `impl_trait_in_assoc_type` + +The tracking issue for this feature is: [#63063] + +[#63063]: https://github.com/rust-lang/rust/issues/63063 + +------------------------ +"##, + }, + Lint { + label: "impl_trait_in_fn_trait_return", + description: r##"# `impl_trait_in_fn_trait_return` + +The tracking issue for this feature is: [#99697] + +[#99697]: https://github.com/rust-lang/rust/issues/99697 + +------------------------ +"##, + }, + Lint { + label: "imported_main", + description: r##"# `imported_main` + +The tracking issue for this feature is: [#28937] + +[#28937]: https://github.com/rust-lang/rust/issues/28937 + +------------------------ +"##, + }, + Lint { + label: "inherent_associated_types", + description: r##"# `inherent_associated_types` + +The tracking issue for this feature is: [#8995] + +[#8995]: https://github.com/rust-lang/rust/issues/8995 + +------------------------ "##, }, Lint { @@ -2705,6 +5487,46 @@ match some_int { ``` [#76001]: https://github.com/rust-lang/rust/issues/76001 +"##, + }, + Lint { + label: "inplace_iteration", + description: r##"# `inplace_iteration` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "int_roundings", + description: r##"# `int_roundings` + +The tracking issue for this feature is: [#88581] + +[#88581]: https://github.com/rust-lang/rust/issues/88581 + +------------------------ +"##, + }, + Lint { + label: "integer_atomics", + description: r##"# `integer_atomics` + +The tracking issue for this feature is: [#99069] + +[#99069]: https://github.com/rust-lang/rust/issues/99069 + +------------------------ +"##, + }, + Lint { + label: "internal_impls_macro", + description: r##"# `internal_impls_macro` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ "##, }, Lint { @@ -2767,6 +5589,92 @@ extern "rust-intrinsic" { ``` As with any other FFI functions, these are always `unsafe` to call. +"##, + }, + Lint { + label: "io_error_downcast", + description: r##"# `io_error_downcast` + +The tracking issue for this feature is: [#99262] + +[#99262]: https://github.com/rust-lang/rust/issues/99262 + +------------------------ +"##, + }, + Lint { + label: "io_error_more", + description: r##"# `io_error_more` + +The tracking issue for this feature is: [#86442] + +[#86442]: https://github.com/rust-lang/rust/issues/86442 + +------------------------ +"##, + }, + Lint { + label: "io_error_uncategorized", + description: r##"# `io_error_uncategorized` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "io_slice_advance", + description: r##"# `io_slice_advance` + +The tracking issue for this feature is: [#62726] + +[#62726]: https://github.com/rust-lang/rust/issues/62726 + +------------------------ +"##, + }, + Lint { + label: "ip", + description: r##"# `ip` + +The tracking issue for this feature is: [#27709] + +[#27709]: https://github.com/rust-lang/rust/issues/27709 + +------------------------ +"##, + }, + Lint { + label: "ip_bits", + description: r##"# `ip_bits` + +The tracking issue for this feature is: [#113744] + +[#113744]: https://github.com/rust-lang/rust/issues/113744 + +------------------------ +"##, + }, + Lint { + label: "ip_in_core", + description: r##"# `ip_in_core` + +The tracking issue for this feature is: [#108443] + +[#108443]: https://github.com/rust-lang/rust/issues/108443 + +------------------------ +"##, + }, + Lint { + label: "is_ascii_octdigit", + description: r##"# `is_ascii_octdigit` + +The tracking issue for this feature is: [#101288] + +[#101288]: https://github.com/rust-lang/rust/issues/101288 + +------------------------ "##, }, Lint { @@ -2782,6 +5690,160 @@ The tracking issue for this feature is: [#53485] Add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `[T]`; add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `Iterator`. +"##, + }, + Lint { + label: "isqrt", + description: r##"# `isqrt` + +The tracking issue for this feature is: [#116226] + +[#116226]: https://github.com/rust-lang/rust/issues/116226 + +------------------------ +"##, + }, + Lint { + label: "iter_advance_by", + description: r##"# `iter_advance_by` + +The tracking issue for this feature is: [#77404] + +[#77404]: https://github.com/rust-lang/rust/issues/77404 + +------------------------ +"##, + }, + Lint { + label: "iter_array_chunks", + description: r##"# `iter_array_chunks` + +The tracking issue for this feature is: [#100450] + +[#100450]: https://github.com/rust-lang/rust/issues/100450 + +------------------------ +"##, + }, + Lint { + label: "iter_collect_into", + description: r##"# `iter_collect_into` + +The tracking issue for this feature is: [#94780] + +[#94780]: https://github.com/rust-lang/rust/issues/94780 + +------------------------ +"##, + }, + Lint { + label: "iter_from_generator", + description: r##"# `iter_from_generator` + +The tracking issue for this feature is: [#43122] + +[#43122]: https://github.com/rust-lang/rust/issues/43122 + +------------------------ +"##, + }, + Lint { + label: "iter_intersperse", + description: r##"# `iter_intersperse` + +The tracking issue for this feature is: [#79524] + +[#79524]: https://github.com/rust-lang/rust/issues/79524 + +------------------------ +"##, + }, + Lint { + label: "iter_is_partitioned", + description: r##"# `iter_is_partitioned` + +The tracking issue for this feature is: [#62544] + +[#62544]: https://github.com/rust-lang/rust/issues/62544 + +------------------------ +"##, + }, + Lint { + label: "iter_map_windows", + description: r##"# `iter_map_windows` + +The tracking issue for this feature is: [#87155] + +[#87155]: https://github.com/rust-lang/rust/issues/87155 + +------------------------ +"##, + }, + Lint { + label: "iter_next_chunk", + description: r##"# `iter_next_chunk` + +The tracking issue for this feature is: [#98326] + +[#98326]: https://github.com/rust-lang/rust/issues/98326 + +------------------------ +"##, + }, + Lint { + label: "iter_order_by", + description: r##"# `iter_order_by` + +The tracking issue for this feature is: [#64295] + +[#64295]: https://github.com/rust-lang/rust/issues/64295 + +------------------------ +"##, + }, + Lint { + label: "iter_partition_in_place", + description: r##"# `iter_partition_in_place` + +The tracking issue for this feature is: [#62543] + +[#62543]: https://github.com/rust-lang/rust/issues/62543 + +------------------------ +"##, + }, + Lint { + label: "iter_repeat_n", + description: r##"# `iter_repeat_n` + +The tracking issue for this feature is: [#104434] + +[#104434]: https://github.com/rust-lang/rust/issues/104434 + +------------------------ +"##, + }, + Lint { + label: "iterator_try_collect", + description: r##"# `iterator_try_collect` + +The tracking issue for this feature is: [#94047] + +[#94047]: https://github.com/rust-lang/rust/issues/94047 + +------------------------ +"##, + }, + Lint { + label: "iterator_try_reduce", + description: r##"# `iterator_try_reduce` + +The tracking issue for this feature is: [#87053] + +[#87053]: https://github.com/rust-lang/rust/issues/87053 + +------------------------ "##, }, Lint { @@ -2901,6 +5963,81 @@ return a valid pointer, and so needs to do the check internally. An up-to-date list of all language items can be found [here] in the compiler code. [here]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_hir/src/lang_items.rs +"##, + }, + Lint { + label: "large_assignments", + description: r##"# `large_assignments` + +The tracking issue for this feature is: [#83518] + +[#83518]: https://github.com/rust-lang/rust/issues/83518 + +------------------------ +"##, + }, + Lint { + label: "layout_for_ptr", + description: r##"# `layout_for_ptr` + +The tracking issue for this feature is: [#69835] + +[#69835]: https://github.com/rust-lang/rust/issues/69835 + +------------------------ +"##, + }, + Lint { + label: "lazy_cell", + description: r##"# `lazy_cell` + +The tracking issue for this feature is: [#109736] + +[#109736]: https://github.com/rust-lang/rust/issues/109736 + +------------------------ +"##, + }, + Lint { + label: "lazy_cell_consume", + description: r##"# `lazy_cell_consume` + +The tracking issue for this feature is: [#109736] + +[#109736]: https://github.com/rust-lang/rust/issues/109736 + +------------------------ +"##, + }, + Lint { + label: "lazy_type_alias", + description: r##"# `lazy_type_alias` + +The tracking issue for this feature is: [#112792] + +[#112792]: https://github.com/rust-lang/rust/issues/112792 + +------------------------ +"##, + }, + Lint { + label: "let_chains", + description: r##"# `let_chains` + +The tracking issue for this feature is: [#53667] + +[#53667]: https://github.com/rust-lang/rust/issues/53667 + +------------------------ +"##, + }, + Lint { + label: "liballoc_internals", + description: r##"# `liballoc_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ "##, }, Lint { @@ -2918,6 +6055,127 @@ This feature is internal to the Rust compiler and is not intended for general us This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "link_llvm_intrinsics", + description: r##"# `link_llvm_intrinsics` + +The tracking issue for this feature is: [#29602] + +[#29602]: https://github.com/rust-lang/rust/issues/29602 + +------------------------ +"##, + }, + Lint { + label: "linkage", + description: r##"# `linkage` + +The tracking issue for this feature is: [#29603] + +[#29603]: https://github.com/rust-lang/rust/issues/29603 + +------------------------ +"##, + }, + Lint { + label: "linked_list_cursors", + description: r##"# `linked_list_cursors` + +The tracking issue for this feature is: [#58533] + +[#58533]: https://github.com/rust-lang/rust/issues/58533 + +------------------------ +"##, + }, + Lint { + label: "linked_list_remove", + description: r##"# `linked_list_remove` + +The tracking issue for this feature is: [#69210] + +[#69210]: https://github.com/rust-lang/rust/issues/69210 + +------------------------ +"##, + }, + Lint { + label: "lint_reasons", + description: r##"# `lint_reasons` + +The tracking issue for this feature is: [#54503] + +[#54503]: https://github.com/rust-lang/rust/issues/54503 + +------------------------ +"##, + }, + Lint { + label: "linux_pidfd", + description: r##"# `linux_pidfd` + +The tracking issue for this feature is: [#82971] + +[#82971]: https://github.com/rust-lang/rust/issues/82971 + +------------------------ +"##, + }, + Lint { + label: "log_syntax", + description: r##"# `log_syntax` + +The tracking issue for this feature is: [#29598] + +[#29598]: https://github.com/rust-lang/rust/issues/29598 + +------------------------ +"##, + }, + Lint { + label: "macro_metavar_expr", + description: r##"# `macro_metavar_expr` + +The tracking issue for this feature is: [#83527] + +[#83527]: https://github.com/rust-lang/rust/issues/83527 + +------------------------ +"##, + }, + Lint { + label: "map_entry_replace", + description: r##"# `map_entry_replace` + +The tracking issue for this feature is: [#44286] + +[#44286]: https://github.com/rust-lang/rust/issues/44286 + +------------------------ +"##, + }, + Lint { + label: "map_many_mut", + description: r##"# `map_many_mut` + +The tracking issue for this feature is: [#97601] + +[#97601]: https://github.com/rust-lang/rust/issues/97601 + +------------------------ +"##, + }, + Lint { + label: "map_try_insert", + description: r##"# `map_try_insert` + +The tracking issue for this feature is: [#82766] + +[#82766]: https://github.com/rust-lang/rust/issues/82766 + ------------------------ "##, }, @@ -2958,6 +6216,116 @@ fn cheap_clone(t: T) -> T { This is expected to replace the unstable `overlapping_marker_traits` feature, which applied to all empty traits (without needing an opt-in). +"##, + }, + Lint { + label: "maybe_uninit_array_assume_init", + description: r##"# `maybe_uninit_array_assume_init` + +The tracking issue for this feature is: [#96097] + +[#96097]: https://github.com/rust-lang/rust/issues/96097 + +------------------------ +"##, + }, + Lint { + label: "maybe_uninit_as_bytes", + description: r##"# `maybe_uninit_as_bytes` + +The tracking issue for this feature is: [#93092] + +[#93092]: https://github.com/rust-lang/rust/issues/93092 + +------------------------ +"##, + }, + Lint { + label: "maybe_uninit_slice", + description: r##"# `maybe_uninit_slice` + +The tracking issue for this feature is: [#63569] + +[#63569]: https://github.com/rust-lang/rust/issues/63569 + +------------------------ +"##, + }, + Lint { + label: "maybe_uninit_uninit_array", + description: r##"# `maybe_uninit_uninit_array` + +The tracking issue for this feature is: [#96097] + +[#96097]: https://github.com/rust-lang/rust/issues/96097 + +------------------------ +"##, + }, + Lint { + label: "maybe_uninit_uninit_array_transpose", + description: r##"# `maybe_uninit_uninit_array_transpose` + +The tracking issue for this feature is: [#96097] + +[#96097]: https://github.com/rust-lang/rust/issues/96097 + +------------------------ +"##, + }, + Lint { + label: "maybe_uninit_write_slice", + description: r##"# `maybe_uninit_write_slice` + +The tracking issue for this feature is: [#79995] + +[#79995]: https://github.com/rust-lang/rust/issues/79995 + +------------------------ +"##, + }, + Lint { + label: "mem_copy_fn", + description: r##"# `mem_copy_fn` + +The tracking issue for this feature is: [#98262] + +[#98262]: https://github.com/rust-lang/rust/issues/98262 + +------------------------ +"##, + }, + Lint { + label: "min_specialization", + description: r##"# `min_specialization` + +The tracking issue for this feature is: [#31844] + +[#31844]: https://github.com/rust-lang/rust/issues/31844 + +------------------------ +"##, + }, + Lint { + label: "mips_target_feature", + description: r##"# `mips_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "more_float_constants", + description: r##"# `more_float_constants` + +The tracking issue for this feature is: [#103883] + +[#103883]: https://github.com/rust-lang/rust/issues/103883 + +------------------------ "##, }, Lint { @@ -2991,6 +6359,59 @@ impl A for Foo { type Assoc = StructStruct; } ``` +"##, + }, + Lint { + label: "multiple_supertrait_upcastable", + description: r##"# `multiple_supertrait_upcastable` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "must_not_suspend", + description: r##"# `must_not_suspend` + +The tracking issue for this feature is: [#83310] + +[#83310]: https://github.com/rust-lang/rust/issues/83310 + +------------------------ +"##, + }, + Lint { + label: "mutex_unlock", + description: r##"# `mutex_unlock` + +The tracking issue for this feature is: [#81872] + +[#81872]: https://github.com/rust-lang/rust/issues/81872 + +------------------------ +"##, + }, + Lint { + label: "mutex_unpoison", + description: r##"# `mutex_unpoison` + +The tracking issue for this feature is: [#96469] + +[#96469]: https://github.com/rust-lang/rust/issues/96469 + +------------------------ +"##, + }, + Lint { + label: "naked_functions", + description: r##"# `naked_functions` + +The tracking issue for this feature is: [#32408] + +[#32408]: https://github.com/rust-lang/rust/issues/32408 + +------------------------ "##, }, Lint { @@ -3013,6 +6434,26 @@ This modifier translates to `--as-needed` for ld-like linkers, and to `-dead_str The modifier does nothing for linkers that don't support it (e.g. `link.exe`). The default for this modifier is unclear, some targets currently specify it as `+as-needed`, some do not. We may want to try making `+as-needed` a default for all targets. +"##, + }, + Lint { + label: "needs_panic_runtime", + description: r##"# `needs_panic_runtime` + +The tracking issue for this feature is: [#32837] + +[#32837]: https://github.com/rust-lang/rust/issues/32837 + +------------------------ +"##, + }, + Lint { + label: "negative_bounds", + description: r##"# `negative_bounds` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ "##, }, Lint { @@ -3074,6 +6515,50 @@ This serves two purposes: * For proving the correctness of unsafe code, we can use that impl as evidence that no `DerefMut` or `Clone` impl exists. * It prevents downstream crates from creating such impls. +"##, + }, + Lint { + label: "never_type", + description: r##"# `never_type` + +The tracking issue for this feature is: [#35121] + +[#35121]: https://github.com/rust-lang/rust/issues/35121 + +------------------------ +"##, + }, + Lint { + label: "never_type_fallback", + description: r##"# `never_type_fallback` + +The tracking issue for this feature is: [#65992] + +[#65992]: https://github.com/rust-lang/rust/issues/65992 + +------------------------ +"##, + }, + Lint { + label: "new_uninit", + description: r##"# `new_uninit` + +The tracking issue for this feature is: [#63291] + +[#63291]: https://github.com/rust-lang/rust/issues/63291 + +------------------------ +"##, + }, + Lint { + label: "no_core", + description: r##"# `no_core` + +The tracking issue for this feature is: [#29639] + +[#29639]: https://github.com/rust-lang/rust/issues/29639 + +------------------------ "##, }, Lint { @@ -3107,6 +6592,319 @@ fn foo() { // ... } ``` +"##, + }, + Lint { + label: "non_exhaustive_omitted_patterns_lint", + description: r##"# `non_exhaustive_omitted_patterns_lint` + +The tracking issue for this feature is: [#89554] + +[#89554]: https://github.com/rust-lang/rust/issues/89554 + +------------------------ +"##, + }, + Lint { + label: "non_lifetime_binders", + description: r##"# `non_lifetime_binders` + +The tracking issue for this feature is: [#108185] + +[#108185]: https://github.com/rust-lang/rust/issues/108185 + +------------------------ +"##, + }, + Lint { + label: "nonzero_ops", + description: r##"# `nonzero_ops` + +The tracking issue for this feature is: [#84186] + +[#84186]: https://github.com/rust-lang/rust/issues/84186 + +------------------------ +"##, + }, + Lint { + label: "noop_waker", + description: r##"# `noop_waker` + +The tracking issue for this feature is: [#98286] + +[#98286]: https://github.com/rust-lang/rust/issues/98286 + +------------------------ +"##, + }, + Lint { + label: "num_midpoint", + description: r##"# `num_midpoint` + +The tracking issue for this feature is: [#110840] + +[#110840]: https://github.com/rust-lang/rust/issues/110840 + +------------------------ +"##, + }, + Lint { + label: "numfmt", + description: r##"# `numfmt` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "object_safe_for_dispatch", + description: r##"# `object_safe_for_dispatch` + +The tracking issue for this feature is: [#43561] + +[#43561]: https://github.com/rust-lang/rust/issues/43561 + +------------------------ +"##, + }, + Lint { + label: "offset_of", + description: r##"# `offset_of` + +The tracking issue for this feature is: [#106655] + +[#106655]: https://github.com/rust-lang/rust/issues/106655 + +------------------------ +"##, + }, + Lint { + label: "omit_gdb_pretty_printer_section", + description: r##"# `omit_gdb_pretty_printer_section` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "once_cell_try", + description: r##"# `once_cell_try` + +The tracking issue for this feature is: [#109737] + +[#109737]: https://github.com/rust-lang/rust/issues/109737 + +------------------------ +"##, + }, + Lint { + label: "one_sided_range", + description: r##"# `one_sided_range` + +The tracking issue for this feature is: [#69780] + +[#69780]: https://github.com/rust-lang/rust/issues/69780 + +------------------------ +"##, + }, + Lint { + label: "optimize_attribute", + description: r##"# `optimize_attribute` + +The tracking issue for this feature is: [#54882] + +[#54882]: https://github.com/rust-lang/rust/issues/54882 + +------------------------ +"##, + }, + Lint { + label: "option_get_or_insert_default", + description: r##"# `option_get_or_insert_default` + +The tracking issue for this feature is: [#82901] + +[#82901]: https://github.com/rust-lang/rust/issues/82901 + +------------------------ +"##, + }, + Lint { + label: "option_take_if", + description: r##"# `option_take_if` + +The tracking issue for this feature is: [#98934] + +[#98934]: https://github.com/rust-lang/rust/issues/98934 + +------------------------ +"##, + }, + Lint { + label: "option_zip", + description: r##"# `option_zip` + +The tracking issue for this feature is: [#70086] + +[#70086]: https://github.com/rust-lang/rust/issues/70086 + +------------------------ +"##, + }, + Lint { + label: "panic_abort", + description: r##"# `panic_abort` + +The tracking issue for this feature is: [#32837] + +[#32837]: https://github.com/rust-lang/rust/issues/32837 + +------------------------ +"##, + }, + Lint { + label: "panic_always_abort", + description: r##"# `panic_always_abort` + +The tracking issue for this feature is: [#84438] + +[#84438]: https://github.com/rust-lang/rust/issues/84438 + +------------------------ +"##, + }, + Lint { + label: "panic_backtrace_config", + description: r##"# `panic_backtrace_config` + +The tracking issue for this feature is: [#93346] + +[#93346]: https://github.com/rust-lang/rust/issues/93346 + +------------------------ +"##, + }, + Lint { + label: "panic_can_unwind", + description: r##"# `panic_can_unwind` + +The tracking issue for this feature is: [#92988] + +[#92988]: https://github.com/rust-lang/rust/issues/92988 + +------------------------ +"##, + }, + Lint { + label: "panic_info_message", + description: r##"# `panic_info_message` + +The tracking issue for this feature is: [#66745] + +[#66745]: https://github.com/rust-lang/rust/issues/66745 + +------------------------ +"##, + }, + Lint { + label: "panic_internals", + description: r##"# `panic_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "panic_runtime", + description: r##"# `panic_runtime` + +The tracking issue for this feature is: [#32837] + +[#32837]: https://github.com/rust-lang/rust/issues/32837 + +------------------------ +"##, + }, + Lint { + label: "panic_unwind", + description: r##"# `panic_unwind` + +The tracking issue for this feature is: [#32837] + +[#32837]: https://github.com/rust-lang/rust/issues/32837 + +------------------------ +"##, + }, + Lint { + label: "panic_update_hook", + description: r##"# `panic_update_hook` + +The tracking issue for this feature is: [#92649] + +[#92649]: https://github.com/rust-lang/rust/issues/92649 + +------------------------ +"##, + }, + Lint { + label: "path_file_prefix", + description: r##"# `path_file_prefix` + +The tracking issue for this feature is: [#86319] + +[#86319]: https://github.com/rust-lang/rust/issues/86319 + +------------------------ +"##, + }, + Lint { + label: "pattern", + description: r##"# `pattern` + +The tracking issue for this feature is: [#27721] + +[#27721]: https://github.com/rust-lang/rust/issues/27721 + +------------------------ +"##, + }, + Lint { + label: "peer_credentials_unix_socket", + description: r##"# `peer_credentials_unix_socket` + +The tracking issue for this feature is: [#42839] + +[#42839]: https://github.com/rust-lang/rust/issues/42839 + +------------------------ +"##, + }, + Lint { + label: "pin_deref_mut", + description: r##"# `pin_deref_mut` + +The tracking issue for this feature is: [#86918] + +[#86918]: https://github.com/rust-lang/rust/issues/86918 + +------------------------ +"##, + }, + Lint { + label: "platform_intrinsics", + description: r##"# `platform_intrinsics` + +The tracking issue for this feature is: [#27731] + +[#27731]: https://github.com/rust-lang/rust/issues/27731 + +------------------------ "##, }, Lint { @@ -3225,6 +7023,88 @@ conversion. You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`, including those provided by plugins loaded by `foo.rs`. +"##, + }, + Lint { + label: "pointer_byte_offsets", + description: r##"# `pointer_byte_offsets` + +The tracking issue for this feature is: [#96283] + +[#96283]: https://github.com/rust-lang/rust/issues/96283 + +------------------------ +"##, + }, + Lint { + label: "pointer_is_aligned", + description: r##"# `pointer_is_aligned` + +The tracking issue for this feature is: [#96284] + +[#96284]: https://github.com/rust-lang/rust/issues/96284 + +------------------------ +"##, + }, + Lint { + label: "pointer_like_trait", + description: r##"# `pointer_like_trait` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "portable_simd", + description: r##"# `portable_simd` + +The tracking issue for this feature is: [#86656] + +[#86656]: https://github.com/rust-lang/rust/issues/86656 + +------------------------ +"##, + }, + Lint { + label: "powerpc_target_feature", + description: r##"# `powerpc_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "precise_pointer_size_matching", + description: r##"# `precise_pointer_size_matching` + +The tracking issue for this feature is: [#56354] + +[#56354]: https://github.com/rust-lang/rust/issues/56354 + +------------------------ +"##, + }, + Lint { + label: "prelude_2024", + description: r##"# `prelude_2024` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "prelude_import", + description: r##"# `prelude_import` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ "##, }, Lint { @@ -3233,6 +7113,123 @@ including those provided by plugins loaded by `foo.rs`. This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "proc_macro_byte_character", + description: r##"# `proc_macro_byte_character` + +The tracking issue for this feature is: [#115268] + +[#115268]: https://github.com/rust-lang/rust/issues/115268 + +------------------------ +"##, + }, + Lint { + label: "proc_macro_def_site", + description: r##"# `proc_macro_def_site` + +The tracking issue for this feature is: [#54724] + +[#54724]: https://github.com/rust-lang/rust/issues/54724 + +------------------------ +"##, + }, + Lint { + label: "proc_macro_diagnostic", + description: r##"# `proc_macro_diagnostic` + +The tracking issue for this feature is: [#54140] + +[#54140]: https://github.com/rust-lang/rust/issues/54140 + +------------------------ +"##, + }, + Lint { + label: "proc_macro_expand", + description: r##"# `proc_macro_expand` + +The tracking issue for this feature is: [#90765] + +[#90765]: https://github.com/rust-lang/rust/issues/90765 + +------------------------ +"##, + }, + Lint { + label: "proc_macro_hygiene", + description: r##"# `proc_macro_hygiene` + +The tracking issue for this feature is: [#54727] + +[#54727]: https://github.com/rust-lang/rust/issues/54727 + +------------------------ +"##, + }, + Lint { + label: "proc_macro_internals", + description: r##"# `proc_macro_internals` + +The tracking issue for this feature is: [#27812] + +[#27812]: https://github.com/rust-lang/rust/issues/27812 + +------------------------ +"##, + }, + Lint { + label: "proc_macro_quote", + description: r##"# `proc_macro_quote` + +The tracking issue for this feature is: [#54722] + +[#54722]: https://github.com/rust-lang/rust/issues/54722 + +------------------------ +"##, + }, + Lint { + label: "proc_macro_span", + description: r##"# `proc_macro_span` + +The tracking issue for this feature is: [#54725] + +[#54725]: https://github.com/rust-lang/rust/issues/54725 + +------------------------ +"##, + }, + Lint { + label: "proc_macro_tracked_env", + description: r##"# `proc_macro_tracked_env` + +The tracking issue for this feature is: [#99515] + +[#99515]: https://github.com/rust-lang/rust/issues/99515 + +------------------------ +"##, + }, + Lint { + label: "process_exitcode_internals", + description: r##"# `process_exitcode_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "process_internals", + description: r##"# `process_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + ------------------------ "##, }, @@ -3251,6 +7248,207 @@ The tracking issue for this feature is: [#42524](https://github.com/rust-lang/ru This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "ptr_addr_eq", + description: r##"# `ptr_addr_eq` + +The tracking issue for this feature is: [#116324] + +[#116324]: https://github.com/rust-lang/rust/issues/116324 + +------------------------ +"##, + }, + Lint { + label: "ptr_alignment_type", + description: r##"# `ptr_alignment_type` + +The tracking issue for this feature is: [#102070] + +[#102070]: https://github.com/rust-lang/rust/issues/102070 + +------------------------ +"##, + }, + Lint { + label: "ptr_as_uninit", + description: r##"# `ptr_as_uninit` + +The tracking issue for this feature is: [#75402] + +[#75402]: https://github.com/rust-lang/rust/issues/75402 + +------------------------ +"##, + }, + Lint { + label: "ptr_from_ref", + description: r##"# `ptr_from_ref` + +The tracking issue for this feature is: [#106116] + +[#106116]: https://github.com/rust-lang/rust/issues/106116 + +------------------------ +"##, + }, + Lint { + label: "ptr_internals", + description: r##"# `ptr_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "ptr_mask", + description: r##"# `ptr_mask` + +The tracking issue for this feature is: [#98290] + +[#98290]: https://github.com/rust-lang/rust/issues/98290 + +------------------------ +"##, + }, + Lint { + label: "ptr_metadata", + description: r##"# `ptr_metadata` + +The tracking issue for this feature is: [#81513] + +[#81513]: https://github.com/rust-lang/rust/issues/81513 + +------------------------ +"##, + }, + Lint { + label: "ptr_sub_ptr", + description: r##"# `ptr_sub_ptr` + +The tracking issue for this feature is: [#95892] + +[#95892]: https://github.com/rust-lang/rust/issues/95892 + +------------------------ +"##, + }, + Lint { + label: "ptr_to_from_bits", + description: r##"# `ptr_to_from_bits` + +The tracking issue for this feature is: [#91126] + +[#91126]: https://github.com/rust-lang/rust/issues/91126 + +------------------------ +"##, + }, + Lint { + label: "pub_crate_should_not_need_unstable_attr", + description: r##"# `pub_crate_should_not_need_unstable_attr` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "raw_os_error_ty", + description: r##"# `raw_os_error_ty` + +The tracking issue for this feature is: [#107792] + +[#107792]: https://github.com/rust-lang/rust/issues/107792 + +------------------------ +"##, + }, + Lint { + label: "raw_os_nonzero", + description: r##"# `raw_os_nonzero` + +The tracking issue for this feature is: [#82363] + +[#82363]: https://github.com/rust-lang/rust/issues/82363 + +------------------------ +"##, + }, + Lint { + label: "raw_ref_op", + description: r##"# `raw_ref_op` + +The tracking issue for this feature is: [#64490] + +[#64490]: https://github.com/rust-lang/rust/issues/64490 + +------------------------ +"##, + }, + Lint { + label: "raw_slice_split", + description: r##"# `raw_slice_split` + +The tracking issue for this feature is: [#95595] + +[#95595]: https://github.com/rust-lang/rust/issues/95595 + +------------------------ +"##, + }, + Lint { + label: "raw_vec_internals", + description: r##"# `raw_vec_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "read_buf", + description: r##"# `read_buf` + +The tracking issue for this feature is: [#78485] + +[#78485]: https://github.com/rust-lang/rust/issues/78485 + +------------------------ +"##, + }, + Lint { + label: "ready_into_inner", + description: r##"# `ready_into_inner` + +The tracking issue for this feature is: [#101196] + +[#101196]: https://github.com/rust-lang/rust/issues/101196 + +------------------------ +"##, + }, + Lint { + label: "receiver_trait", + description: r##"# `receiver_trait` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "register_tool", + description: r##"# `register_tool` + +The tracking issue for this feature is: [#66079] + +[#66079]: https://github.com/rust-lang/rust/issues/66079 + ------------------------ "##, }, @@ -3274,6 +7472,103 @@ enum Foo { Bar(u64), } ``` +"##, + }, + Lint { + label: "repr_simd", + description: r##"# `repr_simd` + +The tracking issue for this feature is: [#27731] + +[#27731]: https://github.com/rust-lang/rust/issues/27731 + +------------------------ +"##, + }, + Lint { + label: "restricted_std", + description: r##"# `restricted_std` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "result_flattening", + description: r##"# `result_flattening` + +The tracking issue for this feature is: [#70142] + +[#70142]: https://github.com/rust-lang/rust/issues/70142 + +------------------------ +"##, + }, + Lint { + label: "result_option_inspect", + description: r##"# `result_option_inspect` + +The tracking issue for this feature is: [#91345] + +[#91345]: https://github.com/rust-lang/rust/issues/91345 + +------------------------ +"##, + }, + Lint { + label: "return_position_impl_trait_in_trait", + description: r##"# `return_position_impl_trait_in_trait` + +The tracking issue for this feature is: [#91611] + +[#91611]: https://github.com/rust-lang/rust/issues/91611 + +------------------------ +"##, + }, + Lint { + label: "return_type_notation", + description: r##"# `return_type_notation` + +The tracking issue for this feature is: [#109417] + +[#109417]: https://github.com/rust-lang/rust/issues/109417 + +------------------------ +"##, + }, + Lint { + label: "riscv_target_feature", + description: r##"# `riscv_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "round_char_boundary", + description: r##"# `round_char_boundary` + +The tracking issue for this feature is: [#93743] + +[#93743]: https://github.com/rust-lang/rust/issues/93743 + +------------------------ +"##, + }, + Lint { + label: "round_ties_even", + description: r##"# `round_ties_even` + +The tracking issue for this feature is: [#96710] + +[#96710]: https://github.com/rust-lang/rust/issues/96710 + +------------------------ "##, }, Lint { @@ -3282,6 +7577,39 @@ enum Foo { This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "rtm_target_feature", + description: r##"# `rtm_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "rust_cold_cc", + description: r##"# `rust_cold_cc` + +The tracking issue for this feature is: [#97544] + +[#97544]: https://github.com/rust-lang/rust/issues/97544 + +------------------------ +"##, + }, + Lint { + label: "rustc_allow_const_fn_unstable", + description: r##"# `rustc_allow_const_fn_unstable` + +The tracking issue for this feature is: [#69399] + +[#69399]: https://github.com/rust-lang/rust/issues/69399 + ------------------------ "##, }, @@ -3340,6 +7668,326 @@ error: size: Size { raw: 16 } error: aborting due to 2 previous errors ``` +"##, + }, + Lint { + label: "rustc_private", + description: r##"# `rustc_private` + +The tracking issue for this feature is: [#27812] + +[#27812]: https://github.com/rust-lang/rust/issues/27812 + +------------------------ +"##, + }, + Lint { + label: "rustdoc_internals", + description: r##"# `rustdoc_internals` + +The tracking issue for this feature is: [#90418] + +[#90418]: https://github.com/rust-lang/rust/issues/90418 + +------------------------ +"##, + }, + Lint { + label: "rustdoc_missing_doc_code_examples", + description: r##"# `rustdoc_missing_doc_code_examples` + +The tracking issue for this feature is: [#101730] + +[#101730]: https://github.com/rust-lang/rust/issues/101730 + +------------------------ +"##, + }, + Lint { + label: "sealed", + description: r##"# `sealed` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "seek_stream_len", + description: r##"# `seek_stream_len` + +The tracking issue for this feature is: [#59359] + +[#59359]: https://github.com/rust-lang/rust/issues/59359 + +------------------------ +"##, + }, + Lint { + label: "set_ptr_value", + description: r##"# `set_ptr_value` + +The tracking issue for this feature is: [#75091] + +[#75091]: https://github.com/rust-lang/rust/issues/75091 + +------------------------ +"##, + }, + Lint { + label: "setgroups", + description: r##"# `setgroups` + +The tracking issue for this feature is: [#90747] + +[#90747]: https://github.com/rust-lang/rust/issues/90747 + +------------------------ +"##, + }, + Lint { + label: "sgx_platform", + description: r##"# `sgx_platform` + +The tracking issue for this feature is: [#56975] + +[#56975]: https://github.com/rust-lang/rust/issues/56975 + +------------------------ +"##, + }, + Lint { + label: "simd_ffi", + description: r##"# `simd_ffi` + +The tracking issue for this feature is: [#27731] + +[#27731]: https://github.com/rust-lang/rust/issues/27731 + +------------------------ +"##, + }, + Lint { + label: "sized_type_properties", + description: r##"# `sized_type_properties` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "slice_as_chunks", + description: r##"# `slice_as_chunks` + +The tracking issue for this feature is: [#74985] + +[#74985]: https://github.com/rust-lang/rust/issues/74985 + +------------------------ +"##, + }, + Lint { + label: "slice_concat_ext", + description: r##"# `slice_concat_ext` + +The tracking issue for this feature is: [#27747] + +[#27747]: https://github.com/rust-lang/rust/issues/27747 + +------------------------ +"##, + }, + Lint { + label: "slice_concat_trait", + description: r##"# `slice_concat_trait` + +The tracking issue for this feature is: [#27747] + +[#27747]: https://github.com/rust-lang/rust/issues/27747 + +------------------------ +"##, + }, + Lint { + label: "slice_first_last_chunk", + description: r##"# `slice_first_last_chunk` + +The tracking issue for this feature is: [#111774] + +[#111774]: https://github.com/rust-lang/rust/issues/111774 + +------------------------ +"##, + }, + Lint { + label: "slice_flatten", + description: r##"# `slice_flatten` + +The tracking issue for this feature is: [#95629] + +[#95629]: https://github.com/rust-lang/rust/issues/95629 + +------------------------ +"##, + }, + Lint { + label: "slice_from_ptr_range", + description: r##"# `slice_from_ptr_range` + +The tracking issue for this feature is: [#89792] + +[#89792]: https://github.com/rust-lang/rust/issues/89792 + +------------------------ +"##, + }, + Lint { + label: "slice_group_by", + description: r##"# `slice_group_by` + +The tracking issue for this feature is: [#80552] + +[#80552]: https://github.com/rust-lang/rust/issues/80552 + +------------------------ +"##, + }, + Lint { + label: "slice_index_methods", + description: r##"# `slice_index_methods` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "slice_internals", + description: r##"# `slice_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "slice_iter_mut_as_mut_slice", + description: r##"# `slice_iter_mut_as_mut_slice` + +The tracking issue for this feature is: [#93079] + +[#93079]: https://github.com/rust-lang/rust/issues/93079 + +------------------------ +"##, + }, + Lint { + label: "slice_partition_dedup", + description: r##"# `slice_partition_dedup` + +The tracking issue for this feature is: [#54279] + +[#54279]: https://github.com/rust-lang/rust/issues/54279 + +------------------------ +"##, + }, + Lint { + label: "slice_pattern", + description: r##"# `slice_pattern` + +The tracking issue for this feature is: [#56345] + +[#56345]: https://github.com/rust-lang/rust/issues/56345 + +------------------------ +"##, + }, + Lint { + label: "slice_ptr_get", + description: r##"# `slice_ptr_get` + +The tracking issue for this feature is: [#74265] + +[#74265]: https://github.com/rust-lang/rust/issues/74265 + +------------------------ +"##, + }, + Lint { + label: "slice_ptr_len", + description: r##"# `slice_ptr_len` + +The tracking issue for this feature is: [#71146] + +[#71146]: https://github.com/rust-lang/rust/issues/71146 + +------------------------ +"##, + }, + Lint { + label: "slice_range", + description: r##"# `slice_range` + +The tracking issue for this feature is: [#76393] + +[#76393]: https://github.com/rust-lang/rust/issues/76393 + +------------------------ +"##, + }, + Lint { + label: "slice_split_at_unchecked", + description: r##"# `slice_split_at_unchecked` + +The tracking issue for this feature is: [#76014] + +[#76014]: https://github.com/rust-lang/rust/issues/76014 + +------------------------ +"##, + }, + Lint { + label: "slice_swap_unchecked", + description: r##"# `slice_swap_unchecked` + +The tracking issue for this feature is: [#88539] + +[#88539]: https://github.com/rust-lang/rust/issues/88539 + +------------------------ +"##, + }, + Lint { + label: "slice_take", + description: r##"# `slice_take` + +The tracking issue for this feature is: [#62280] + +[#62280]: https://github.com/rust-lang/rust/issues/62280 + +------------------------ +"##, + }, + Lint { + label: "solid_ext", + description: r##"# `solid_ext` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "sort_floats", + description: r##"# `sort_floats` + +The tracking issue for this feature is: [#93396] + +[#93396]: https://github.com/rust-lang/rust/issues/93396 + +------------------------ "##, }, Lint { @@ -3348,6 +7996,68 @@ error: aborting due to 2 previous errors This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "spec_option_partial_eq", + description: r##"# `spec_option_partial_eq` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "specialization", + description: r##"# `specialization` + +The tracking issue for this feature is: [#31844] + +[#31844]: https://github.com/rust-lang/rust/issues/31844 + +------------------------ +"##, + }, + Lint { + label: "split_array", + description: r##"# `split_array` + +The tracking issue for this feature is: [#90091] + +[#90091]: https://github.com/rust-lang/rust/issues/90091 + +------------------------ +"##, + }, + Lint { + label: "split_as_slice", + description: r##"# `split_as_slice` + +The tracking issue for this feature is: [#96137] + +[#96137]: https://github.com/rust-lang/rust/issues/96137 + +------------------------ +"##, + }, + Lint { + label: "sse4a_target_feature", + description: r##"# `sse4a_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "staged_api", + description: r##"# `staged_api` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + ------------------------ "##, }, @@ -3412,6 +8122,59 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 } ``` +"##, + }, + Lint { + label: "std_internals", + description: r##"# `std_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "stdio_makes_pipe", + description: r##"# `stdio_makes_pipe` + +The tracking issue for this feature is: [#98288] + +[#98288]: https://github.com/rust-lang/rust/issues/98288 + +------------------------ +"##, + }, + Lint { + label: "stdsimd", + description: r##"# `stdsimd` + +The tracking issue for this feature is: [#48556] + +[#48556]: https://github.com/rust-lang/rust/issues/48556 + +------------------------ +"##, + }, + Lint { + label: "step_trait", + description: r##"# `step_trait` + +The tracking issue for this feature is: [#42168] + +[#42168]: https://github.com/rust-lang/rust/issues/42168 + +------------------------ +"##, + }, + Lint { + label: "stmt_expr_attributes", + description: r##"# `stmt_expr_attributes` + +The tracking issue for this feature is: [#15701] + +[#15701]: https://github.com/rust-lang/rust/issues/15701 + +------------------------ "##, }, Lint { @@ -3420,6 +8183,39 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "str_split_inclusive_remainder", + description: r##"# `str_split_inclusive_remainder` + +The tracking issue for this feature is: [#77998] + +[#77998]: https://github.com/rust-lang/rust/issues/77998 + +------------------------ +"##, + }, + Lint { + label: "str_split_remainder", + description: r##"# `str_split_remainder` + +The tracking issue for this feature is: [#77998] + +[#77998]: https://github.com/rust-lang/rust/issues/77998 + +------------------------ +"##, + }, + Lint { + label: "str_split_whitespace_remainder", + description: r##"# `str_split_whitespace_remainder` + +The tracking issue for this feature is: [#77998] + +[#77998]: https://github.com/rust-lang/rust/issues/77998 + ------------------------ "##, }, @@ -3447,6 +8243,127 @@ fn main() { //~^ WARNING: strict provenance disallows casting integer `usize` to pointer `*const u8` } ``` +"##, + }, + Lint { + label: "strict_provenance_atomic_ptr", + description: r##"# `strict_provenance_atomic_ptr` + +The tracking issue for this feature is: [#99108] + +[#99108]: https://github.com/rust-lang/rust/issues/99108 + +------------------------ +"##, + }, + Lint { + label: "string_deref_patterns", + description: r##"# `string_deref_patterns` + +The tracking issue for this feature is: [#87121] + +[#87121]: https://github.com/rust-lang/rust/issues/87121 + +------------------------ +"##, + }, + Lint { + label: "string_extend_from_within", + description: r##"# `string_extend_from_within` + +The tracking issue for this feature is: [#103806] + +[#103806]: https://github.com/rust-lang/rust/issues/103806 + +------------------------ +"##, + }, + Lint { + label: "string_remove_matches", + description: r##"# `string_remove_matches` + +The tracking issue for this feature is: [#72826] + +[#72826]: https://github.com/rust-lang/rust/issues/72826 + +------------------------ +"##, + }, + Lint { + label: "structural_match", + description: r##"# `structural_match` + +The tracking issue for this feature is: [#31434] + +[#31434]: https://github.com/rust-lang/rust/issues/31434 + +------------------------ +"##, + }, + Lint { + label: "sync_unsafe_cell", + description: r##"# `sync_unsafe_cell` + +The tracking issue for this feature is: [#95439] + +[#95439]: https://github.com/rust-lang/rust/issues/95439 + +------------------------ +"##, + }, + Lint { + label: "target_feature_11", + description: r##"# `target_feature_11` + +The tracking issue for this feature is: [#69098] + +[#69098]: https://github.com/rust-lang/rust/issues/69098 + +------------------------ +"##, + }, + Lint { + label: "tbm_target_feature", + description: r##"# `tbm_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "tcp_linger", + description: r##"# `tcp_linger` + +The tracking issue for this feature is: [#88494] + +[#88494]: https://github.com/rust-lang/rust/issues/88494 + +------------------------ +"##, + }, + Lint { + label: "tcp_quickack", + description: r##"# `tcp_quickack` + +The tracking issue for this feature is: [#96256] + +[#96256]: https://github.com/rust-lang/rust/issues/96256 + +------------------------ +"##, + }, + Lint { + label: "tcplistener_into_incoming", + description: r##"# `tcplistener_into_incoming` + +The tracking issue for this feature is: [#88339] + +[#88339]: https://github.com/rust-lang/rust/issues/88339 + +------------------------ "##, }, Lint { @@ -3609,6 +8526,57 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured However, the optimizer can still modify a testcase in an undesirable manner even when using either of the above. +"##, + }, + Lint { + label: "test_2018_feature", + description: r##"# `test_2018_feature` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "test_unstable_lint", + description: r##"# `test_unstable_lint` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "thin_box", + description: r##"# `thin_box` + +The tracking issue for this feature is: [#92791] + +[#92791]: https://github.com/rust-lang/rust/issues/92791 + +------------------------ +"##, + }, + Lint { + label: "thread_id_value", + description: r##"# `thread_id_value` + +The tracking issue for this feature is: [#67939] + +[#67939]: https://github.com/rust-lang/rust/issues/67939 + +------------------------ +"##, + }, + Lint { + label: "thread_local", + description: r##"# `thread_local` + +The tracking issue for this feature is: [#29594] + +[#29594]: https://github.com/rust-lang/rust/issues/29594 + +------------------------ "##, }, Lint { @@ -3617,6 +8585,28 @@ even when using either of the above. This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "thread_sleep_until", + description: r##"# `thread_sleep_until` + +The tracking issue for this feature is: [#113752] + +[#113752]: https://github.com/rust-lang/rust/issues/113752 + +------------------------ +"##, + }, + Lint { + label: "thread_spawn_unchecked", + description: r##"# `thread_spawn_unchecked` + +The tracking issue for this feature is: [#55132] + +[#55132]: https://github.com/rust-lang/rust/issues/55132 + ------------------------ "##, }, @@ -3661,6 +8651,17 @@ note: trace_macro Finished dev [unoptimized + debuginfo] target(s) in 0.60 secs ``` +"##, + }, + Lint { + label: "track_path", + description: r##"# `track_path` + +The tracking issue for this feature is: [#99515] + +[#99515]: https://github.com/rust-lang/rust/issues/99515 + +------------------------ "##, }, Lint { @@ -3730,6 +8731,28 @@ impl Bar for T {} let bar: &dyn Bar = &123; let foo: &dyn Foo = bar; ``` +"##, + }, + Lint { + label: "transmutability", + description: r##"# `transmutability` + +The tracking issue for this feature is: [#99571] + +[#99571]: https://github.com/rust-lang/rust/issues/99571 + +------------------------ +"##, + }, + Lint { + label: "transmute_generic_consts", + description: r##"# `transmute_generic_consts` + +The tracking issue for this feature is: [#109929] + +[#109929]: https://github.com/rust-lang/rust/issues/109929 + +------------------------ "##, }, Lint { @@ -3817,6 +8840,59 @@ example, it is unspecified whether `size_of::()` is equal to it is transparent). The Rust compiler is free to perform this optimization if possible, but is not required to, and different compiler versions may differ in their application of these optimizations. +"##, + }, + Lint { + label: "trivial_bounds", + description: r##"# `trivial_bounds` + +The tracking issue for this feature is: [#48214] + +[#48214]: https://github.com/rust-lang/rust/issues/48214 + +------------------------ +"##, + }, + Lint { + label: "trusted_len", + description: r##"# `trusted_len` + +The tracking issue for this feature is: [#37572] + +[#37572]: https://github.com/rust-lang/rust/issues/37572 + +------------------------ +"##, + }, + Lint { + label: "trusted_len_next_unchecked", + description: r##"# `trusted_len_next_unchecked` + +The tracking issue for this feature is: [#37572] + +[#37572]: https://github.com/rust-lang/rust/issues/37572 + +------------------------ +"##, + }, + Lint { + label: "trusted_random_access", + description: r##"# `trusted_random_access` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "trusted_step", + description: r##"# `trusted_step` + +The tracking issue for this feature is: [#85731] + +[#85731]: https://github.com/rust-lang/rust/issues/85731 + +------------------------ "##, }, Lint { @@ -3851,6 +8927,92 @@ let result: Result = try { }; assert!(result.is_err()); ``` +"##, + }, + Lint { + label: "try_find", + description: r##"# `try_find` + +The tracking issue for this feature is: [#63178] + +[#63178]: https://github.com/rust-lang/rust/issues/63178 + +------------------------ +"##, + }, + Lint { + label: "try_reserve_kind", + description: r##"# `try_reserve_kind` + +The tracking issue for this feature is: [#48043] + +[#48043]: https://github.com/rust-lang/rust/issues/48043 + +------------------------ +"##, + }, + Lint { + label: "try_trait_v2", + description: r##"# `try_trait_v2` + +The tracking issue for this feature is: [#84277] + +[#84277]: https://github.com/rust-lang/rust/issues/84277 + +------------------------ +"##, + }, + Lint { + label: "try_trait_v2_residual", + description: r##"# `try_trait_v2_residual` + +The tracking issue for this feature is: [#91285] + +[#91285]: https://github.com/rust-lang/rust/issues/91285 + +------------------------ +"##, + }, + Lint { + label: "try_trait_v2_yeet", + description: r##"# `try_trait_v2_yeet` + +The tracking issue for this feature is: [#96374] + +[#96374]: https://github.com/rust-lang/rust/issues/96374 + +------------------------ +"##, + }, + Lint { + label: "tuple_trait", + description: r##"# `tuple_trait` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "type_alias_impl_trait", + description: r##"# `type_alias_impl_trait` + +The tracking issue for this feature is: [#63063] + +[#63063]: https://github.com/rust-lang/rust/issues/63063 + +------------------------ +"##, + }, + Lint { + label: "type_ascription", + description: r##"# `type_ascription` + +The tracking issue for this feature is: [#23416] + +[#23416]: https://github.com/rust-lang/rust/issues/23416 + +------------------------ "##, }, Lint { @@ -3888,6 +9050,39 @@ fn main () { }; } ``` +"##, + }, + Lint { + label: "type_name_of_val", + description: r##"# `type_name_of_val` + +The tracking issue for this feature is: [#66359] + +[#66359]: https://github.com/rust-lang/rust/issues/66359 + +------------------------ +"##, + }, + Lint { + label: "type_privacy_lints", + description: r##"# `type_privacy_lints` + +The tracking issue for this feature is: [#48054] + +[#48054]: https://github.com/rust-lang/rust/issues/48054 + +------------------------ +"##, + }, + Lint { + label: "uefi_std", + description: r##"# `uefi_std` + +The tracking issue for this feature is: [#100499] + +[#100499]: https://github.com/rust-lang/rust/issues/100499 + +------------------------ "##, }, Lint { @@ -3917,6 +9112,59 @@ extern "rust-call" fn add_args(args: (u32, u32)) -> u32 { fn main() {} ``` +"##, + }, + Lint { + label: "unchecked_math", + description: r##"# `unchecked_math` + +The tracking issue for this feature is: [#85122] + +[#85122]: https://github.com/rust-lang/rust/issues/85122 + +------------------------ +"##, + }, + Lint { + label: "unicode_internals", + description: r##"# `unicode_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "unique_rc_arc", + description: r##"# `unique_rc_arc` + +The tracking issue for this feature is: [#112566] + +[#112566]: https://github.com/rust-lang/rust/issues/112566 + +------------------------ +"##, + }, + Lint { + label: "unix_file_vectored_at", + description: r##"# `unix_file_vectored_at` + +The tracking issue for this feature is: [#89517] + +[#89517]: https://github.com/rust-lang/rust/issues/89517 + +------------------------ +"##, + }, + Lint { + label: "unix_set_mark", + description: r##"# `unix_set_mark` + +The tracking issue for this feature is: [#96467] + +[#96467]: https://github.com/rust-lang/rust/issues/96467 + +------------------------ "##, }, Lint { @@ -3983,6 +9231,81 @@ reset `SIGPIPE` to `SIG_DFL`. If `#[unix_sigpipe = "..."]` is specified, no matter what its value is, the signal disposition of `SIGPIPE` is no longer reset. This means that the child inherits the parent's `SIGPIPE` behavior. +"##, + }, + Lint { + label: "unix_socket_ancillary_data", + description: r##"# `unix_socket_ancillary_data` + +The tracking issue for this feature is: [#76915] + +[#76915]: https://github.com/rust-lang/rust/issues/76915 + +------------------------ +"##, + }, + Lint { + label: "unix_socket_peek", + description: r##"# `unix_socket_peek` + +The tracking issue for this feature is: [#76923] + +[#76923]: https://github.com/rust-lang/rust/issues/76923 + +------------------------ +"##, + }, + Lint { + label: "unnamed_fields", + description: r##"# `unnamed_fields` + +The tracking issue for this feature is: [#49804] + +[#49804]: https://github.com/rust-lang/rust/issues/49804 + +------------------------ +"##, + }, + Lint { + label: "unsafe_cell_from_mut", + description: r##"# `unsafe_cell_from_mut` + +The tracking issue for this feature is: [#111645] + +[#111645]: https://github.com/rust-lang/rust/issues/111645 + +------------------------ +"##, + }, + Lint { + label: "unsafe_pin_internals", + description: r##"# `unsafe_pin_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "unsize", + description: r##"# `unsize` + +The tracking issue for this feature is: [#18598] + +[#18598]: https://github.com/rust-lang/rust/issues/18598 + +------------------------ +"##, + }, + Lint { + label: "unsized_fn_params", + description: r##"# `unsized_fn_params` + +The tracking issue for this feature is: [#48055] + +[#48055]: https://github.com/rust-lang/rust/issues/48055 + +------------------------ "##, }, Lint { @@ -4193,6 +9516,17 @@ fn main() { ``` [RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md +"##, + }, + Lint { + label: "unwrap_infallible", + description: r##"# `unwrap_infallible` + +The tracking issue for this feature is: [#61695] + +[#61695]: https://github.com/rust-lang/rust/issues/61695 + +------------------------ "##, }, Lint { @@ -4201,6 +9535,149 @@ fn main() { This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "used_with_arg", + description: r##"# `used_with_arg` + +The tracking issue for this feature is: [#93798] + +[#93798]: https://github.com/rust-lang/rust/issues/93798 + +------------------------ +"##, + }, + Lint { + label: "utf16_extra", + description: r##"# `utf16_extra` + +The tracking issue for this feature is: [#94919] + +[#94919]: https://github.com/rust-lang/rust/issues/94919 + +------------------------ +"##, + }, + Lint { + label: "utf16_extra_const", + description: r##"# `utf16_extra_const` + +The tracking issue for this feature is: [#94919] + +[#94919]: https://github.com/rust-lang/rust/issues/94919 + +------------------------ +"##, + }, + Lint { + label: "utf8_chunks", + description: r##"# `utf8_chunks` + +The tracking issue for this feature is: [#99543] + +[#99543]: https://github.com/rust-lang/rust/issues/99543 + +------------------------ +"##, + }, + Lint { + label: "variant_count", + description: r##"# `variant_count` + +The tracking issue for this feature is: [#73662] + +[#73662]: https://github.com/rust-lang/rust/issues/73662 + +------------------------ +"##, + }, + Lint { + label: "vec_into_raw_parts", + description: r##"# `vec_into_raw_parts` + +The tracking issue for this feature is: [#65816] + +[#65816]: https://github.com/rust-lang/rust/issues/65816 + +------------------------ +"##, + }, + Lint { + label: "vec_push_within_capacity", + description: r##"# `vec_push_within_capacity` + +The tracking issue for this feature is: [#100486] + +[#100486]: https://github.com/rust-lang/rust/issues/100486 + +------------------------ +"##, + }, + Lint { + label: "vec_split_at_spare", + description: r##"# `vec_split_at_spare` + +The tracking issue for this feature is: [#81944] + +[#81944]: https://github.com/rust-lang/rust/issues/81944 + +------------------------ +"##, + }, + Lint { + label: "waker_getters", + description: r##"# `waker_getters` + +The tracking issue for this feature is: [#87021] + +[#87021]: https://github.com/rust-lang/rust/issues/87021 + +------------------------ +"##, + }, + Lint { + label: "wasi_ext", + description: r##"# `wasi_ext` + +The tracking issue for this feature is: [#71213] + +[#71213]: https://github.com/rust-lang/rust/issues/71213 + +------------------------ +"##, + }, + Lint { + label: "wasm_abi", + description: r##"# `wasm_abi` + +The tracking issue for this feature is: [#83788] + +[#83788]: https://github.com/rust-lang/rust/issues/83788 + +------------------------ +"##, + }, + Lint { + label: "wasm_target_feature", + description: r##"# `wasm_target_feature` + +The tracking issue for this feature is: [#44839] + +[#44839]: https://github.com/rust-lang/rust/issues/44839 + +------------------------ +"##, + }, + Lint { + label: "windows_by_handle", + description: r##"# `windows_by_handle` + +The tracking issue for this feature is: [#63010] + +[#63010]: https://github.com/rust-lang/rust/issues/63010 + ------------------------ "##, }, @@ -4228,6 +9705,59 @@ This feature is internal to the Rust compiler and is not intended for general us This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "windows_process_exit_code_from", + description: r##"# `windows_process_exit_code_from` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "windows_process_extensions_async_pipes", + description: r##"# `windows_process_extensions_async_pipes` + +The tracking issue for this feature is: [#98289] + +[#98289]: https://github.com/rust-lang/rust/issues/98289 + +------------------------ +"##, + }, + Lint { + label: "windows_process_extensions_force_quotes", + description: r##"# `windows_process_extensions_force_quotes` + +The tracking issue for this feature is: [#82227] + +[#82227]: https://github.com/rust-lang/rust/issues/82227 + +------------------------ +"##, + }, + Lint { + label: "windows_process_extensions_main_thread_handle", + description: r##"# `windows_process_extensions_main_thread_handle` + +The tracking issue for this feature is: [#96723] + +[#96723]: https://github.com/rust-lang/rust/issues/96723 + +------------------------ +"##, + }, + Lint { + label: "windows_process_extensions_raw_attribute", + description: r##"# `windows_process_extensions_raw_attribute` + +The tracking issue for this feature is: [#114854] + +[#114854]: https://github.com/rust-lang/rust/issues/114854 + ------------------------ "##, }, @@ -4237,6 +9767,57 @@ This feature is internal to the Rust compiler and is not intended for general us This feature is internal to the Rust compiler and is not intended for general use. +------------------------ +"##, + }, + Lint { + label: "with_negative_coherence", + description: r##"# `with_negative_coherence` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "wrapping_int_impl", + description: r##"# `wrapping_int_impl` + +The tracking issue for this feature is: [#32463] + +[#32463]: https://github.com/rust-lang/rust/issues/32463 + +------------------------ +"##, + }, + Lint { + label: "wrapping_next_power_of_two", + description: r##"# `wrapping_next_power_of_two` + +The tracking issue for this feature is: [#32463] + +[#32463]: https://github.com/rust-lang/rust/issues/32463 + +------------------------ +"##, + }, + Lint { + label: "write_all_vectored", + description: r##"# `write_all_vectored` + +The tracking issue for this feature is: [#70436] + +[#70436]: https://github.com/rust-lang/rust/issues/70436 + +------------------------ +"##, + }, + Lint { + label: "yeet_desugar_details", + description: r##"# `yeet_desugar_details` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + ------------------------ "##, }, diff --git a/crates/ide-db/src/tests/sourcegen_lints.rs b/crates/ide-db/src/tests/sourcegen_lints.rs index 8d7117b0c902..c8cf87d3c205 100644 --- a/crates/ide-db/src/tests/sourcegen_lints.rs +++ b/crates/ide-db/src/tests/sourcegen_lints.rs @@ -1,4 +1,5 @@ -//! Generates descriptors structure for unstable feature from Unstable Book +//! Generates descriptor structures for unstable features from the unstable book +//! and lints from rustc, rustdoc, and clippy. use std::{borrow::Cow, fs, path::Path}; use itertools::Itertools; @@ -6,6 +7,8 @@ use stdx::format_to; use test_utils::project_root; use xshell::{cmd, Shell}; +const DESTINATION: &str = "crates/ide-db/src/generated/lints.rs"; + /// This clones rustc repo, and so is not worth to keep up-to-date. We update /// manually by un-ignoring the test from time to time. #[test] @@ -14,11 +17,21 @@ fn sourcegen_lint_completions() { let sh = &Shell::new().unwrap(); let rust_repo = project_root().join("./target/rust"); - if !rust_repo.exists() { + if rust_repo.exists() { + cmd!(sh, "git -C {rust_repo} pull --rebase").run().unwrap(); + } else { cmd!(sh, "git clone --depth=1 https://github.com/rust-lang/rust {rust_repo}") .run() .unwrap(); } + // need submodules for Cargo to parse the workspace correctly + cmd!( + sh, + "git -C {rust_repo} submodule update --init --recursive --depth=1 -- + compiler library src/tools" + ) + .run() + .unwrap(); let mut contents = String::from( r" @@ -27,17 +40,28 @@ pub struct Lint { pub label: &'static str, pub description: &'static str, } + pub struct LintGroup { pub lint: Lint, pub children: &'static [&'static str], } + ", ); generate_lint_descriptor(sh, &mut contents); contents.push('\n'); - generate_feature_descriptor(&mut contents, &rust_repo.join("src/doc/unstable-book/src")); + let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()); + let unstable_book = project_root().join("./target/unstable-book-gen"); + cmd!( + sh, + "{cargo} run --manifest-path {rust_repo}/src/tools/unstable-book-gen/Cargo.toml -- + {rust_repo}/library {rust_repo}/compiler {rust_repo}/src {unstable_book}" + ) + .run() + .unwrap(); + generate_feature_descriptor(&mut contents, &unstable_book.join("src")); contents.push('\n'); let lints_json = project_root().join("./target/clippy_lints.json"); @@ -51,7 +75,7 @@ pub struct LintGroup { let contents = sourcegen::add_preamble("sourcegen_lints", sourcegen::reformat(contents)); - let destination = project_root().join("crates/ide-db/src/generated/lints.rs"); + let destination = project_root().join(DESTINATION); sourcegen::ensure_file_contents(destination.as_path(), &contents); } @@ -179,8 +203,8 @@ fn find_and_slice<'a>(i: &'a str, p: &str) -> &'a str { &i[idx + p.len()..] } -/// Parses the unstable book root directory at `src_dir` and prints a constant -/// with the list of unstable features into `buf`. +/// Parses the unstable book `src_dir` and prints a constant with the list of +/// unstable features into `buf`. /// /// It does this by looking for all `.md` files in the `language-features` and /// `library-features` directories, and using the file name as the feature From e8372e04840a113c7aedb9cc5c7f387014d09e0b Mon Sep 17 00:00:00 2001 From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com> Date: Sun, 8 Oct 2023 03:52:15 +0200 Subject: [PATCH 2305/2442] vscode: Support opening local documentation if available Displaying local instead of web docs can have many benefits: - the web version may have different features enabled than locally selected - the standard library may be a different version than is available online - the user may not be online and therefore cannot access the web documentation - the documentation may not be available online at all, for example because it is for a new feature in a library the user is currently developing If the documentation is not available locally, the extension still falls back to the web version. --- editors/code/src/client.ts | 1 + editors/code/src/commands.ts | 20 +++++++++++++++++++- editors/code/src/lsp_ext.ts | 6 +++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index ba8546763ec8..96e888402baf 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -389,6 +389,7 @@ class ExperimentalFeatures implements lc.StaticFeature { serverStatusNotification: true, colorDiagnosticOutput: true, openServerLogs: true, + localDocs: true, commands: { commands: [ "rust-analyzer.runSingle", diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 5e602510601a..4d5c3cf45764 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -21,6 +21,7 @@ import type { LanguageClient } from "vscode-languageclient/node"; import { LINKED_COMMANDS } from "./client"; import type { DependencyId } from "./dependencies_provider"; import { unwrapUndefinable } from "./undefinable"; +import { log } from "./util"; export * from "./ast_inspector"; export * from "./run"; @@ -947,7 +948,24 @@ export function openDocs(ctx: CtxInit): Cmd { const position = editor.selection.active; const textDocument = { uri: editor.document.uri.toString() }; - const doclink = await client.sendRequest(ra.openDocs, { position, textDocument }); + const doclinks = await client.sendRequest(ra.openDocs, { position, textDocument }); + + let fileType = vscode.FileType.Unknown; + if (typeof doclinks.local === "string") { + try { + fileType = (await vscode.workspace.fs.stat(vscode.Uri.parse(doclinks.local))).type; + } catch (e) { + log.debug("stat() threw error. Falling back to web version", e); + } + } + + let doclink; + if (fileType & vscode.FileType.File) { + // file does exist locally + doclink = doclinks.local; + } else { + doclink = doclinks.web; + } if (doclink != null) { await vscode.env.openExternal(vscode.Uri.parse(doclink)); diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index bb7896973f17..a1cd88b89c94 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -135,7 +135,11 @@ export const onEnter = new lc.RequestType( "experimental/openCargoToml", ); -export const openDocs = new lc.RequestType( +export interface DocsUrls { + local: string | void; + web: string | void; +} +export const openDocs = new lc.RequestType( "experimental/externalDocs", ); export const parentModule = new lc.RequestType< From 36eac9abee9d7beaa7e129c04ef9dd0cad3c6641 Mon Sep 17 00:00:00 2001 From: Ryan Mehri Date: Tue, 3 Oct 2023 22:19:09 -0700 Subject: [PATCH 2306/2442] fix: add incorrect case diagnostics for module names --- crates/hir-def/src/lib.rs | 13 +++++ crates/hir-ty/src/diagnostics/decl_check.rs | 55 ++++++++++++++++++- crates/hir/src/lib.rs | 11 +--- .../src/handlers/incorrect_case.rs | 54 ++++++++++++++++++ 4 files changed, 123 insertions(+), 10 deletions(-) diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 9c6f652f1ec7..495e2d476970 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -73,6 +73,7 @@ use hir_expand::{ db::ExpandDatabase, eager::expand_eager_macro_input, hygiene::Hygiene, + name::Name, proc_macro::ProcMacroExpander, AstId, ExpandError, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, UnresolvedMacro, @@ -174,6 +175,18 @@ impl ModuleId { self.krate } + pub fn name(self, db: &dyn db::DefDatabase) -> Option { + let def_map = self.def_map(db); + let parent = def_map[self.local_id].parent?; + def_map[parent].children.iter().find_map(|(name, module_id)| { + if *module_id == self.local_id { + Some(name.clone()) + } else { + None + } + }) + } + pub fn containing_module(self, db: &dyn db::DefDatabase) -> Option { self.def_map(db).containing_module(self.local_id) } diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs index 36d69edf9d5d..4c7039f078fa 100644 --- a/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/crates/hir-ty/src/diagnostics/decl_check.rs @@ -9,6 +9,7 @@ //! - constants (e.g. `const FOO: u8 = 10;`) //! - static items (e.g. `static FOO: u8 = 10;`) //! - match arm bindings (e.g. `foo @ Some(_)`) +//! - modules (e.g. `mod foo { ... }` or `mod foo;`) mod case_conv; @@ -19,7 +20,7 @@ use hir_def::{ hir::{Pat, PatId}, src::HasSource, AdtId, AttrDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, ItemContainerId, - Lookup, ModuleDefId, StaticId, StructId, + Lookup, ModuleDefId, ModuleId, StaticId, StructId, }; use hir_expand::{ name::{AsName, Name}, @@ -83,6 +84,7 @@ pub enum IdentType { Structure, Variable, Variant, + Module, } impl fmt::Display for IdentType { @@ -97,6 +99,7 @@ impl fmt::Display for IdentType { IdentType::Structure => "Structure", IdentType::Variable => "Variable", IdentType::Variant => "Variant", + IdentType::Module => "Module", }; repr.fmt(f) @@ -132,6 +135,7 @@ impl<'a> DeclValidator<'a> { pub(super) fn validate_item(&mut self, item: ModuleDefId) { match item { + ModuleDefId::ModuleId(module_id) => self.validate_module(module_id), ModuleDefId::FunctionId(func) => self.validate_func(func), ModuleDefId::AdtId(adt) => self.validate_adt(adt), ModuleDefId::ConstId(const_id) => self.validate_const(const_id), @@ -230,6 +234,55 @@ impl<'a> DeclValidator<'a> { || parent() } + fn validate_module(&mut self, module_id: ModuleId) { + // Check whether non-snake case identifiers are allowed for this module. + if self.allowed(module_id.into(), allow::NON_SNAKE_CASE, false) { + return; + } + + // Check the module name. + let Some(module_name) = module_id.name(self.db.upcast()) else { return }; + let module_name_replacement = + module_name.as_str().and_then(to_lower_snake_case).map(|new_name| Replacement { + current_name: module_name, + suggested_text: new_name, + expected_case: CaseType::LowerSnakeCase, + }); + + if let Some(module_name_replacement) = module_name_replacement { + let module_data = &module_id.def_map(self.db.upcast())[module_id.local_id]; + let module_src = module_data.declaration_source(self.db.upcast()); + + if let Some(module_src) = module_src { + let ast_ptr = match module_src.value.name() { + Some(name) => name, + None => { + never!( + "Replacement ({:?}) was generated for a module without a name: {:?}", + module_name_replacement, + module_src + ); + return; + } + }; + + let diagnostic = IncorrectCase { + file: module_src.file_id, + ident_type: IdentType::Module, + ident: AstPtr::new(&ast_ptr), + expected_case: module_name_replacement.expected_case, + ident_text: module_name_replacement + .current_name + .display(self.db.upcast()) + .to_string(), + suggested_text: module_name_replacement.suggested_text, + }; + + self.sink.push(diagnostic); + } + } + } + fn validate_func(&mut self, func: FunctionId) { let data = self.db.function_data(func); if matches!(func.lookup(self.db.upcast()).container, ItemContainerId::ExternBlockId(_)) { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index a6c6c0dbb8bf..c34e7ad91ff1 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -452,15 +452,7 @@ impl HasVisibility for ModuleDef { impl Module { /// Name of this module. pub fn name(self, db: &dyn HirDatabase) -> Option { - let def_map = self.id.def_map(db.upcast()); - let parent = def_map[self.id.local_id].parent?; - def_map[parent].children.iter().find_map(|(name, module_id)| { - if *module_id == self.id.local_id { - Some(name.clone()) - } else { - None - } - }) + self.id.name(db.upcast()) } /// Returns the crate this module is part of. @@ -571,6 +563,7 @@ impl Module { if def_map[m.id.local_id].origin.is_inline() { m.diagnostics(db, acc) } + acc.extend(def.diagnostics(db)) } ModuleDef::Trait(t) => { for diag in db.trait_data_with_diagnostics(t.id).1.iter() { diff --git a/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/crates/ide-diagnostics/src/handlers/incorrect_case.rs index 7824011db67a..85dbb7e6f263 100644 --- a/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -111,6 +111,31 @@ fn some_fn() { let what_aweird_formatting = 10; another_func(what_aweird_formatting); } +"#, + ); + + check_fix( + r#" +static S: i32 = M::A; + +mod $0M { + pub const A: i32 = 10; +} + +mod other { + use crate::M::A; +} +"#, + r#" +static S: i32 = m::A; + +mod m { + pub const A: i32 = 10; +} + +mod other { + use crate::m::A; +} "#, ); } @@ -518,17 +543,20 @@ fn NonSnakeCaseName(some_var: u8) -> u8 { #[deny(nonstandard_style)] mod CheckNonstandardStyle { + //^^^^^^^^^^^^^^^^^^^^^ 💡 error: Module `CheckNonstandardStyle` should have snake_case name, e.g. `check_nonstandard_style` fn HiImABadFnName() {} //^^^^^^^^^^^^^^ 💡 error: Function `HiImABadFnName` should have snake_case name, e.g. `hi_im_abad_fn_name` } #[deny(warnings)] mod CheckBadStyle { + //^^^^^^^^^^^^^ 💡 error: Module `CheckBadStyle` should have snake_case name, e.g. `check_bad_style` struct fooo; //^^^^ 💡 error: Structure `fooo` should have CamelCase name, e.g. `Fooo` } mod F { + //^ 💡 warn: Module `F` should have snake_case name, e.g. `f` #![deny(non_snake_case)] fn CheckItWorksWithModAttr() {} //^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: Function `CheckItWorksWithModAttr` should have snake_case name, e.g. `check_it_works_with_mod_attr` @@ -649,4 +677,30 @@ enum E { "#, ); } + + #[test] + fn module_name_inline() { + check_diagnostics( + r#" +mod M { + //^ 💡 warn: Module `M` should have snake_case name, e.g. `m` + mod IncorrectCase {} + //^^^^^^^^^^^^^ 💡 warn: Module `IncorrectCase` should have snake_case name, e.g. `incorrect_case` +} +"#, + ); + } + + #[test] + fn module_name_decl() { + check_diagnostics( + r#" +//- /Foo.rs + +//- /main.rs +mod Foo; + //^^^ 💡 warn: Module `Foo` should have snake_case name, e.g. `foo` +"#, + ) + } } From a7fada46500dd15609d5846183b89f5a11399f19 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Wed, 11 Oct 2023 17:44:27 +0800 Subject: [PATCH 2307/2442] add replace_is_some_with_if_let_some assist --- .../replace_is_some_with_if_let_some.rs | 90 +++++++++++++++++++ crates/ide-assists/src/lib.rs | 2 + 2 files changed, 92 insertions(+) create mode 100644 crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs diff --git a/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs b/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs new file mode 100644 index 000000000000..dfc2a8715003 --- /dev/null +++ b/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs @@ -0,0 +1,90 @@ +use syntax::ast::{self, AstNode}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: replace_is_some_with_if_let +// +// Replace `if x.is_some()` with `if let Some(_tmp) = x`. +// +// ``` +// fn main() { +// let x = Some(1); +// if x.is_som$0e() {} +// } +// ``` +// -> +// ``` +// fn main() { +// let x = Some(1); +// if let Some(_tmp) = x {} +// } +// ``` +pub(crate) fn replace_is_some_with_if_let_some( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { + let if_expr = ctx.find_node_at_offset::()?; + + let cond = if_expr.condition()?; + let call_expr = match cond { + ast::Expr::MethodCallExpr(call) => call, + _ => return None, + }; + + let name_ref = call_expr.name_ref()?; + if name_ref.text() != "is_some" { + return None; + } + + let receiver = call_expr.receiver()?; + let target = call_expr.syntax().text_range(); + + acc.add( + AssistId("replace_is_some_with_if_let_some", AssistKind::RefactorRewrite), + "Replace `is_some` with `if let Some`", + target, + |edit| { + let replacement = format!("let Some(_tmp) = {}", receiver); + edit.replace(target, replacement); + }, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::replace_is_some_with_if_let_some; + + #[test] + fn replace_is_some_with_if_let_works() { + check_assist( + replace_is_some_with_if_let_some, + r#" +fn main() { + let x = Some(1); + if x.is_som$0e() {} +} +"#, + r#" +fn main() { + let x = Some(1); + if let Some(_tmp) = x {} +} +"#, + ); + } + + #[test] + fn replace_is_some_with_if_let_not_applicable() { + check_assist_not_applicable( + replace_is_some_with_if_let_some, + r#" +fn main() { + let x = Some(1); + if x.is_non$0e() {} +} +"#, + ); + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 7b1961ae5493..d6accbb097ee 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -213,6 +213,7 @@ mod handlers { mod unwrap_block; mod unwrap_result_return_type; mod unqualify_method_call; + mod replace_is_some_with_if_let_some; mod wrap_return_type_in_result; mod into_to_qualified_from; @@ -332,6 +333,7 @@ mod handlers { unwrap_result_return_type::unwrap_result_return_type, unwrap_tuple::unwrap_tuple, unqualify_method_call::unqualify_method_call, + replace_is_some_with_if_let_some::replace_is_some_with_if_let_some, wrap_return_type_in_result::wrap_return_type_in_result, // These are manually sorted for better priorities. By default, // priority is determined by the size of the target range (smaller From 1fe6ac87e91f97ac28111863970aff6f5d2deb31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20Valletb=C3=B3?= Date: Wed, 11 Oct 2023 12:19:00 +0200 Subject: [PATCH 2308/2442] add diagnosis messages for chars and byte literal errors --- crates/parser/src/lexed_str.rs | 55 +++++++++++ .../lexer/err/byte_char_literals.rast | 92 +++++++++++++++++++ .../test_data/lexer/err/byte_char_literals.rs | 47 ++++++++++ .../test_data/lexer/err/char_literals.rast | 92 +++++++++++++++++++ .../test_data/lexer/err/char_literals.rs | 47 ++++++++++ .../test_data/lexer/ok/byte_strings.rast | 6 -- .../parser/test_data/lexer/ok/byte_strings.rs | 6 +- crates/parser/test_data/lexer/ok/chars.rast | 2 - crates/parser/test_data/lexer/ok/chars.rs | 2 +- 9 files changed, 337 insertions(+), 12 deletions(-) create mode 100644 crates/parser/test_data/lexer/err/byte_char_literals.rast create mode 100644 crates/parser/test_data/lexer/err/byte_char_literals.rs create mode 100644 crates/parser/test_data/lexer/err/char_literals.rast create mode 100644 crates/parser/test_data/lexer/err/char_literals.rs diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs index 30c1c4f8c75b..031ac27724e4 100644 --- a/crates/parser/src/lexed_str.rs +++ b/crates/parser/src/lexed_str.rs @@ -9,8 +9,11 @@ //! include info about comments and whitespace. use rustc_dependencies::lexer as rustc_lexer; + use std::ops; +use rustc_lexer::unescape::{Mode, EscapeError}; + use crate::{ SyntaxKind::{self, *}, T, @@ -254,13 +257,28 @@ impl<'a> Converter<'a> { rustc_lexer::LiteralKind::Char { terminated } => { if !terminated { err = "Missing trailing `'` symbol to terminate the character literal"; + } else { + let text = &self.res.text[self.offset + 1..][..len - 1]; + let i = text.rfind('\'').unwrap(); + let text = &text[..i]; + if let Err(e) = rustc_lexer::unescape::unescape_char(text) { + err = error_to_diagnostic_message(e, Mode::Char); + } } CHAR } rustc_lexer::LiteralKind::Byte { terminated } => { if !terminated { err = "Missing trailing `'` symbol to terminate the byte literal"; + } else { + let text = &self.res.text[self.offset + 2..][..len - 2]; + let i = text.rfind('\'').unwrap(); + let text = &text[..i]; + if let Err(e) = rustc_lexer::unescape::unescape_char(text) { + err = error_to_diagnostic_message(e, Mode::Byte); + } } + BYTE } rustc_lexer::LiteralKind::Str { terminated } => { @@ -305,3 +323,40 @@ impl<'a> Converter<'a> { self.push(syntax_kind, len, err); } } + +fn error_to_diagnostic_message(error: EscapeError, mode: Mode) -> &'static str { + match error { + EscapeError::ZeroChars => "empty character literal", + EscapeError::MoreThanOneChar => "character literal may only contain one codepoint", + EscapeError::LoneSlash => "", + EscapeError::InvalidEscape if mode == Mode::Byte || mode == Mode::ByteStr => { + "unknown byte escape" + } + EscapeError::InvalidEscape => "unknown character escape", + EscapeError::BareCarriageReturn => "", + EscapeError::BareCarriageReturnInRawString => "", + EscapeError::EscapeOnlyChar if mode == Mode::Byte => "byte constant must be escaped", + EscapeError::EscapeOnlyChar => "character constant must be escaped", + EscapeError::TooShortHexEscape => "numeric character escape is too short", + EscapeError::InvalidCharInHexEscape => "invalid character in numeric character escape", + EscapeError::OutOfRangeHexEscape => "out of range hex escape", + EscapeError::NoBraceInUnicodeEscape => "incorrect unicode escape sequence", + EscapeError::InvalidCharInUnicodeEscape => "invalid character in unicode escape", + EscapeError::EmptyUnicodeEscape => "empty unicode escape", + EscapeError::UnclosedUnicodeEscape => "unterminated unicode escape", + EscapeError::LeadingUnderscoreUnicodeEscape => "invalid start of unicode escape", + EscapeError::OverlongUnicodeEscape => "overlong unicode escape", + EscapeError::LoneSurrogateUnicodeEscape => "invalid unicode character escape", + EscapeError::OutOfRangeUnicodeEscape => "invalid unicode character escape", + EscapeError::UnicodeEscapeInByte => "unicode escape in byte string", + EscapeError::NonAsciiCharInByte if mode == Mode::Byte => { + "non-ASCII character in byte literal" + } + EscapeError::NonAsciiCharInByte if mode == Mode::ByteStr => { + "non-ASCII character in byte string literal" + } + EscapeError::NonAsciiCharInByte => "non-ASCII character in raw byte string literal", + EscapeError::UnskippedWhitespaceWarning => "", + EscapeError::MultipleSkippedLinesWarning => "", + } +} diff --git a/crates/parser/test_data/lexer/err/byte_char_literals.rast b/crates/parser/test_data/lexer/err/byte_char_literals.rast new file mode 100644 index 000000000000..24892bc23948 --- /dev/null +++ b/crates/parser/test_data/lexer/err/byte_char_literals.rast @@ -0,0 +1,92 @@ +BYTE "b''" error: empty character literal +WHITESPACE "\n" +BYTE "b'\\'" error: Missing trailing `'` symbol to terminate the byte literal +WHITESPACE "\n" +BYTE "b'\n'" error: byte constant must be escaped +WHITESPACE "\n" +BYTE "b'spam'" error: character literal may only contain one codepoint +WHITESPACE "\n" +BYTE "b'\\x0ff'" error: character literal may only contain one codepoint +WHITESPACE "\n" +BYTE "b'\\\"a'" error: character literal may only contain one codepoint +WHITESPACE "\n" +BYTE "b'\\na'" error: character literal may only contain one codepoint +WHITESPACE "\n" +BYTE "b'\\ra'" error: character literal may only contain one codepoint +WHITESPACE "\n" +BYTE "b'\\ta'" error: character literal may only contain one codepoint +WHITESPACE "\n" +BYTE "b'\\\\a'" error: character literal may only contain one codepoint +WHITESPACE "\n" +BYTE "b'\\'a'" error: character literal may only contain one codepoint +WHITESPACE "\n" +BYTE "b'\\0a'" error: character literal may only contain one codepoint +WHITESPACE "\n" +BYTE "b'\\u{0}x'" error: character literal may only contain one codepoint +WHITESPACE "\n" +BYTE "b'\\u{1F63b}}'" error: character literal may only contain one codepoint +WHITESPACE "\n" +BYTE "b'\\v'" error: unknown byte escape +WHITESPACE "\n" +BYTE "b'\\💩'" error: unknown byte escape +WHITESPACE "\n" +BYTE "b'\\●'" error: unknown byte escape +WHITESPACE "\n" +BYTE "b'\\\\\\r'" error: character literal may only contain one codepoint +WHITESPACE "\n" +BYTE "b'\\x'" error: numeric character escape is too short +WHITESPACE "\n" +BYTE "b'\\x0'" error: numeric character escape is too short +WHITESPACE "\n" +BYTE "b'\\xf'" error: numeric character escape is too short +WHITESPACE "\n" +BYTE "b'\\xa'" error: numeric character escape is too short +WHITESPACE "\n" +BYTE "b'\\xx'" error: invalid character in numeric character escape +WHITESPACE "\n" +BYTE "b'\\xы'" error: invalid character in numeric character escape +WHITESPACE "\n" +BYTE "b'\\x🦀'" error: invalid character in numeric character escape +WHITESPACE "\n" +BYTE "b'\\xtt'" error: invalid character in numeric character escape +WHITESPACE "\n" +BYTE "b'\\xff'" error: out of range hex escape +WHITESPACE "\n" +BYTE "b'\\xFF'" error: out of range hex escape +WHITESPACE "\n" +BYTE "b'\\x80'" error: out of range hex escape +WHITESPACE "\n" +BYTE "b'\\u'" error: incorrect unicode escape sequence +WHITESPACE "\n" +BYTE "b'\\u[0123]'" error: incorrect unicode escape sequence +WHITESPACE "\n" +BYTE "b'\\u{0x}'" error: invalid character in unicode escape +WHITESPACE "\n" +BYTE "b'\\u{'" error: unterminated unicode escape +WHITESPACE "\n" +BYTE "b'\\u{0000'" error: unterminated unicode escape +WHITESPACE "\n" +BYTE "b'\\u{}'" error: empty unicode escape +WHITESPACE "\n" +BYTE "b'\\u{_0000}'" error: invalid start of unicode escape +WHITESPACE "\n" +BYTE "b'\\u{0000000}'" error: overlong unicode escape +WHITESPACE "\n" +BYTE "b'\\u{FFFFFF}'" error: invalid unicode character escape +WHITESPACE "\n" +BYTE "b'\\u{ffffff}'" error: invalid unicode character escape +WHITESPACE "\n" +BYTE "b'\\u{ffffff}'" error: invalid unicode character escape +WHITESPACE "\n" +BYTE "b'\\u{DC00}'" error: invalid unicode character escape +WHITESPACE "\n" +BYTE "b'\\u{DDDD}'" error: invalid unicode character escape +WHITESPACE "\n" +BYTE "b'\\u{DFFF}'" error: invalid unicode character escape +WHITESPACE "\n" +BYTE "b'\\u{D800}'" error: invalid unicode character escape +WHITESPACE "\n" +BYTE "b'\\u{DAAA}'" error: invalid unicode character escape +WHITESPACE "\n" +BYTE "b'\\u{DBFF}'" error: invalid unicode character escape +WHITESPACE "\n" diff --git a/crates/parser/test_data/lexer/err/byte_char_literals.rs b/crates/parser/test_data/lexer/err/byte_char_literals.rs new file mode 100644 index 000000000000..9f2f4309e769 --- /dev/null +++ b/crates/parser/test_data/lexer/err/byte_char_literals.rs @@ -0,0 +1,47 @@ +b'' +b'\' +b' +' +b'spam' +b'\x0ff' +b'\"a' +b'\na' +b'\ra' +b'\ta' +b'\\a' +b'\'a' +b'\0a' +b'\u{0}x' +b'\u{1F63b}}' +b'\v' +b'\💩' +b'\●' +b'\\\r' +b'\x' +b'\x0' +b'\xf' +b'\xa' +b'\xx' +b'\xы' +b'\x🦀' +b'\xtt' +b'\xff' +b'\xFF' +b'\x80' +b'\u' +b'\u[0123]' +b'\u{0x}' +b'\u{' +b'\u{0000' +b'\u{}' +b'\u{_0000}' +b'\u{0000000}' +b'\u{FFFFFF}' +b'\u{ffffff}' +b'\u{ffffff}' +b'\u{DC00}' +b'\u{DDDD}' +b'\u{DFFF}' +b'\u{D800}' +b'\u{DAAA}' +b'\u{DBFF}' diff --git a/crates/parser/test_data/lexer/err/char_literals.rast b/crates/parser/test_data/lexer/err/char_literals.rast new file mode 100644 index 000000000000..b1e1364d4c2c --- /dev/null +++ b/crates/parser/test_data/lexer/err/char_literals.rast @@ -0,0 +1,92 @@ +CHAR "'hello'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "''" error: empty character literal +WHITESPACE "\n" +CHAR "'\n'" error: character constant must be escaped +WHITESPACE "\n" +CHAR "'spam'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "'\\x0ff'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "'\\\"a'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "'\\na'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "'\\ra'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "'\\ta'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "'\\\\a'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "'\\'a'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "'\\0a'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "'\\u{0}x'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "'\\u{1F63b}}'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "'\\v'" error: unknown character escape +WHITESPACE "\n" +CHAR "'\\💩'" error: unknown character escape +WHITESPACE "\n" +CHAR "'\\●'" error: unknown character escape +WHITESPACE "\n" +CHAR "'\\\\\\r'" error: character literal may only contain one codepoint +WHITESPACE "\n" +CHAR "'\\x'" error: numeric character escape is too short +WHITESPACE "\n" +CHAR "'\\x0'" error: numeric character escape is too short +WHITESPACE "\n" +CHAR "'\\xf'" error: numeric character escape is too short +WHITESPACE "\n" +CHAR "'\\xa'" error: numeric character escape is too short +WHITESPACE "\n" +CHAR "'\\xx'" error: invalid character in numeric character escape +WHITESPACE "\n" +CHAR "'\\xы'" error: invalid character in numeric character escape +WHITESPACE "\n" +CHAR "'\\x🦀'" error: invalid character in numeric character escape +WHITESPACE "\n" +CHAR "'\\xtt'" error: invalid character in numeric character escape +WHITESPACE "\n" +CHAR "'\\xff'" error: out of range hex escape +WHITESPACE "\n" +CHAR "'\\xFF'" error: out of range hex escape +WHITESPACE "\n" +CHAR "'\\x80'" error: out of range hex escape +WHITESPACE "\n" +CHAR "'\\u'" error: incorrect unicode escape sequence +WHITESPACE "\n" +CHAR "'\\u[0123]'" error: incorrect unicode escape sequence +WHITESPACE "\n" +CHAR "'\\u{0x}'" error: invalid character in unicode escape +WHITESPACE "\n" +CHAR "'\\u{'" error: unterminated unicode escape +WHITESPACE "\n" +CHAR "'\\u{0000'" error: unterminated unicode escape +WHITESPACE "\n" +CHAR "'\\u{}'" error: empty unicode escape +WHITESPACE "\n" +CHAR "'\\u{_0000}'" error: invalid start of unicode escape +WHITESPACE "\n" +CHAR "'\\u{0000000}'" error: overlong unicode escape +WHITESPACE "\n" +CHAR "'\\u{FFFFFF}'" error: invalid unicode character escape +WHITESPACE "\n" +CHAR "'\\u{ffffff}'" error: invalid unicode character escape +WHITESPACE "\n" +CHAR "'\\u{ffffff}'" error: invalid unicode character escape +WHITESPACE "\n" +CHAR "'\\u{DC00}'" error: invalid unicode character escape +WHITESPACE "\n" +CHAR "'\\u{DDDD}'" error: invalid unicode character escape +WHITESPACE "\n" +CHAR "'\\u{DFFF}'" error: invalid unicode character escape +WHITESPACE "\n" +CHAR "'\\u{D800}'" error: invalid unicode character escape +WHITESPACE "\n" +CHAR "'\\u{DAAA}'" error: invalid unicode character escape +WHITESPACE "\n" +CHAR "'\\u{DBFF}'" error: invalid unicode character escape +WHITESPACE "\n" diff --git a/crates/parser/test_data/lexer/err/char_literals.rs b/crates/parser/test_data/lexer/err/char_literals.rs new file mode 100644 index 000000000000..291f99d8020c --- /dev/null +++ b/crates/parser/test_data/lexer/err/char_literals.rs @@ -0,0 +1,47 @@ +'hello' +'' +' +' +'spam' +'\x0ff' +'\"a' +'\na' +'\ra' +'\ta' +'\\a' +'\'a' +'\0a' +'\u{0}x' +'\u{1F63b}}' +'\v' +'\💩' +'\●' +'\\\r' +'\x' +'\x0' +'\xf' +'\xa' +'\xx' +'\xы' +'\x🦀' +'\xtt' +'\xff' +'\xFF' +'\x80' +'\u' +'\u[0123]' +'\u{0x}' +'\u{' +'\u{0000' +'\u{}' +'\u{_0000}' +'\u{0000000}' +'\u{FFFFFF}' +'\u{ffffff}' +'\u{ffffff}' +'\u{DC00}' +'\u{DDDD}' +'\u{DFFF}' +'\u{D800}' +'\u{DAAA}' +'\u{DBFF}' diff --git a/crates/parser/test_data/lexer/ok/byte_strings.rast b/crates/parser/test_data/lexer/ok/byte_strings.rast index c848ac368e4f..fd20ca57ac6c 100644 --- a/crates/parser/test_data/lexer/ok/byte_strings.rast +++ b/crates/parser/test_data/lexer/ok/byte_strings.rast @@ -1,13 +1,9 @@ -BYTE "b''" -WHITESPACE " " BYTE "b'x'" WHITESPACE " " BYTE_STRING "b\"foo\"" WHITESPACE " " BYTE_STRING "br\"\"" WHITESPACE "\n" -BYTE "b''suf" -WHITESPACE " " BYTE_STRING "b\"\"ix" WHITESPACE " " BYTE_STRING "br\"\"br" @@ -17,6 +13,4 @@ WHITESPACE " " BYTE "b'\\\\'" WHITESPACE " " BYTE "b'\\''" -WHITESPACE " " -BYTE "b'hello'" WHITESPACE "\n" diff --git a/crates/parser/test_data/lexer/ok/byte_strings.rs b/crates/parser/test_data/lexer/ok/byte_strings.rs index b54930f5e699..65460d02cb27 100644 --- a/crates/parser/test_data/lexer/ok/byte_strings.rs +++ b/crates/parser/test_data/lexer/ok/byte_strings.rs @@ -1,3 +1,3 @@ -b'' b'x' b"foo" br"" -b''suf b""ix br""br -b'\n' b'\\' b'\'' b'hello' +b'x' b"foo" br"" +b""ix br""br +b'\n' b'\\' b'\'' diff --git a/crates/parser/test_data/lexer/ok/chars.rast b/crates/parser/test_data/lexer/ok/chars.rast index 66e58cc298f4..07172a4ecc0a 100644 --- a/crates/parser/test_data/lexer/ok/chars.rast +++ b/crates/parser/test_data/lexer/ok/chars.rast @@ -4,8 +4,6 @@ CHAR "' '" WHITESPACE " " CHAR "'0'" WHITESPACE " " -CHAR "'hello'" -WHITESPACE " " CHAR "'\\x7f'" WHITESPACE " " CHAR "'\\n'" diff --git a/crates/parser/test_data/lexer/ok/chars.rs b/crates/parser/test_data/lexer/ok/chars.rs index 454ee0a5f617..15f52c113c11 100644 --- a/crates/parser/test_data/lexer/ok/chars.rs +++ b/crates/parser/test_data/lexer/ok/chars.rs @@ -1 +1 @@ -'x' ' ' '0' 'hello' '\x7f' '\n' '\\' '\'' +'x' ' ' '0' '\x7f' '\n' '\\' '\'' From f58a8250dc3104e336ec8611702d015bd47f508a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20Valletb=C3=B3?= Date: Wed, 11 Oct 2023 12:36:53 +0200 Subject: [PATCH 2309/2442] fix: cargo fmt --- crates/parser/src/lexed_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs index 031ac27724e4..8e8bdce1eef2 100644 --- a/crates/parser/src/lexed_str.rs +++ b/crates/parser/src/lexed_str.rs @@ -12,7 +12,7 @@ use rustc_dependencies::lexer as rustc_lexer; use std::ops; -use rustc_lexer::unescape::{Mode, EscapeError}; +use rustc_lexer::unescape::{EscapeError, Mode}; use crate::{ SyntaxKind::{self, *}, From 677e6f3439b91769a9b54c18afe5c136c14d9e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20Valletb=C3=B3?= Date: Wed, 11 Oct 2023 13:09:12 +0200 Subject: [PATCH 2310/2442] fix: use unescape_byte function for Byte literals --- crates/parser/src/lexed_str.rs | 2 +- .../lexer/err/byte_char_literals.rast | 28 ++++++++----------- .../test_data/lexer/err/byte_char_literals.rs | 3 -- 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs index 8e8bdce1eef2..84cedc1fa3f0 100644 --- a/crates/parser/src/lexed_str.rs +++ b/crates/parser/src/lexed_str.rs @@ -274,7 +274,7 @@ impl<'a> Converter<'a> { let text = &self.res.text[self.offset + 2..][..len - 2]; let i = text.rfind('\'').unwrap(); let text = &text[..i]; - if let Err(e) = rustc_lexer::unescape::unescape_char(text) { + if let Err(e) = rustc_lexer::unescape::unescape_byte(text) { err = error_to_diagnostic_message(e, Mode::Byte); } } diff --git a/crates/parser/test_data/lexer/err/byte_char_literals.rast b/crates/parser/test_data/lexer/err/byte_char_literals.rast index 24892bc23948..7603c9099daa 100644 --- a/crates/parser/test_data/lexer/err/byte_char_literals.rast +++ b/crates/parser/test_data/lexer/err/byte_char_literals.rast @@ -22,9 +22,9 @@ BYTE "b'\\'a'" error: character literal may only contain one codepoint WHITESPACE "\n" BYTE "b'\\0a'" error: character literal may only contain one codepoint WHITESPACE "\n" -BYTE "b'\\u{0}x'" error: character literal may only contain one codepoint +BYTE "b'\\u{0}x'" error: unicode escape in byte string WHITESPACE "\n" -BYTE "b'\\u{1F63b}}'" error: character literal may only contain one codepoint +BYTE "b'\\u{1F63b}}'" error: unicode escape in byte string WHITESPACE "\n" BYTE "b'\\v'" error: unknown byte escape WHITESPACE "\n" @@ -50,12 +50,6 @@ BYTE "b'\\x🦀'" error: invalid character in numeric character escape WHITESPACE "\n" BYTE "b'\\xtt'" error: invalid character in numeric character escape WHITESPACE "\n" -BYTE "b'\\xff'" error: out of range hex escape -WHITESPACE "\n" -BYTE "b'\\xFF'" error: out of range hex escape -WHITESPACE "\n" -BYTE "b'\\x80'" error: out of range hex escape -WHITESPACE "\n" BYTE "b'\\u'" error: incorrect unicode escape sequence WHITESPACE "\n" BYTE "b'\\u[0123]'" error: incorrect unicode escape sequence @@ -72,21 +66,21 @@ BYTE "b'\\u{_0000}'" error: invalid start of unicode escape WHITESPACE "\n" BYTE "b'\\u{0000000}'" error: overlong unicode escape WHITESPACE "\n" -BYTE "b'\\u{FFFFFF}'" error: invalid unicode character escape +BYTE "b'\\u{FFFFFF}'" error: unicode escape in byte string WHITESPACE "\n" -BYTE "b'\\u{ffffff}'" error: invalid unicode character escape +BYTE "b'\\u{ffffff}'" error: unicode escape in byte string WHITESPACE "\n" -BYTE "b'\\u{ffffff}'" error: invalid unicode character escape +BYTE "b'\\u{ffffff}'" error: unicode escape in byte string WHITESPACE "\n" -BYTE "b'\\u{DC00}'" error: invalid unicode character escape +BYTE "b'\\u{DC00}'" error: unicode escape in byte string WHITESPACE "\n" -BYTE "b'\\u{DDDD}'" error: invalid unicode character escape +BYTE "b'\\u{DDDD}'" error: unicode escape in byte string WHITESPACE "\n" -BYTE "b'\\u{DFFF}'" error: invalid unicode character escape +BYTE "b'\\u{DFFF}'" error: unicode escape in byte string WHITESPACE "\n" -BYTE "b'\\u{D800}'" error: invalid unicode character escape +BYTE "b'\\u{D800}'" error: unicode escape in byte string WHITESPACE "\n" -BYTE "b'\\u{DAAA}'" error: invalid unicode character escape +BYTE "b'\\u{DAAA}'" error: unicode escape in byte string WHITESPACE "\n" -BYTE "b'\\u{DBFF}'" error: invalid unicode character escape +BYTE "b'\\u{DBFF}'" error: unicode escape in byte string WHITESPACE "\n" diff --git a/crates/parser/test_data/lexer/err/byte_char_literals.rs b/crates/parser/test_data/lexer/err/byte_char_literals.rs index 9f2f4309e769..b2d06e490bd6 100644 --- a/crates/parser/test_data/lexer/err/byte_char_literals.rs +++ b/crates/parser/test_data/lexer/err/byte_char_literals.rs @@ -25,9 +25,6 @@ b'\xx' b'\xы' b'\x🦀' b'\xtt' -b'\xff' -b'\xFF' -b'\x80' b'\u' b'\u[0123]' b'\u{0x}' From e1aeb7fa794e228ca9099ac7679e8a1d0b22238a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20Valletb=C3=B3?= Date: Wed, 11 Oct 2023 15:25:52 +0200 Subject: [PATCH 2311/2442] fix: handle errors for string byte string and c_string --- crates/parser/src/lexed_str.rs | 42 ++++++++++++++++++- .../test_data/lexer/err/byte_strings.rast | 28 +++++++++++++ .../test_data/lexer/err/byte_strings.rs | 14 +++++++ .../parser/test_data/lexer/err/c_strings.rast | 28 +++++++++++++ .../parser/test_data/lexer/err/c_strings.rs | 14 +++++++ .../parser/test_data/lexer/err/strings.rast | 28 +++++++++++++ crates/parser/test_data/lexer/err/strings.rs | 14 +++++++ 7 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 crates/parser/test_data/lexer/err/byte_strings.rast create mode 100644 crates/parser/test_data/lexer/err/byte_strings.rs create mode 100644 crates/parser/test_data/lexer/err/c_strings.rast create mode 100644 crates/parser/test_data/lexer/err/c_strings.rs create mode 100644 crates/parser/test_data/lexer/err/strings.rast create mode 100644 crates/parser/test_data/lexer/err/strings.rs diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs index 84cedc1fa3f0..c2e25daf37f6 100644 --- a/crates/parser/src/lexed_str.rs +++ b/crates/parser/src/lexed_str.rs @@ -8,7 +8,10 @@ //! Note that these tokens, unlike the tokens we feed into the parser, do //! include info about comments and whitespace. -use rustc_dependencies::lexer as rustc_lexer; +use rustc_dependencies::lexer::{ + self as rustc_lexer, + unescape::{unescape_c_string, unescape_literal}, +}; use std::ops; @@ -284,18 +287,45 @@ impl<'a> Converter<'a> { rustc_lexer::LiteralKind::Str { terminated } => { if !terminated { err = "Missing trailing `\"` symbol to terminate the string literal"; + } else { + let text = &self.res.text[self.offset + 1..][..len - 1]; + let i = text.rfind('"').unwrap(); + let text = &text[..i]; + rustc_lexer::unescape::unescape_literal(text, Mode::Str, &mut |_, res| { + if let Err(e) = res { + err = error_to_diagnostic_message(e, Mode::Str); + } + }); } STRING } rustc_lexer::LiteralKind::ByteStr { terminated } => { if !terminated { err = "Missing trailing `\"` symbol to terminate the byte string literal"; + } else { + let text = &self.res.text[self.offset + 2..][..len - 2]; + let i = text.rfind('"').unwrap(); + let text = &text[..i]; + rustc_lexer::unescape::unescape_literal(text, Mode::ByteStr, &mut |_, res| { + if let Err(e) = res { + err = error_to_diagnostic_message(e, Mode::ByteStr); + } + }) } BYTE_STRING } rustc_lexer::LiteralKind::CStr { terminated } => { if !terminated { err = "Missing trailing `\"` symbol to terminate the string literal"; + } else { + let text = &self.res.text[self.offset + 2..][..len - 2]; + let i = text.rfind('"').unwrap(); + let text = &text[..i]; + rustc_lexer::unescape::unescape_c_string(text, Mode::CStr, &mut |_, res| { + if let Err(e) = res { + err = error_to_diagnostic_message(e, Mode::CStr); + } + }) } C_STRING } @@ -360,3 +390,13 @@ fn error_to_diagnostic_message(error: EscapeError, mode: Mode) -> &'static str { EscapeError::MultipleSkippedLinesWarning => "", } } + +fn fill_unescape_string_error(text: &str, mode: Mode, mut error_message: &str) { + + rustc_lexer::unescape::unescape_c_string(text, mode, &mut |_, res| { + if let Err(e) = res { + error_message = error_to_diagnostic_message(e, mode); + } + }); +} + diff --git a/crates/parser/test_data/lexer/err/byte_strings.rast b/crates/parser/test_data/lexer/err/byte_strings.rast new file mode 100644 index 000000000000..e8d8ff8cefb4 --- /dev/null +++ b/crates/parser/test_data/lexer/err/byte_strings.rast @@ -0,0 +1,28 @@ +BYTE_STRING "b\"\\💩\"" error: unknown byte escape +WHITESPACE "\n" +BYTE_STRING "b\"\\●\"" error: unknown byte escape +WHITESPACE "\n" +BYTE_STRING "b\"\\u{_0000}\"" error: invalid start of unicode escape +WHITESPACE "\n" +BYTE_STRING "b\"\\u{0000000}\"" error: overlong unicode escape +WHITESPACE "\n" +BYTE_STRING "b\"\\u{FFFFFF}\"" error: unicode escape in byte string +WHITESPACE "\n" +BYTE_STRING "b\"\\u{ffffff}\"" error: unicode escape in byte string +WHITESPACE "\n" +BYTE_STRING "b\"\\u{ffffff}\"" error: unicode escape in byte string +WHITESPACE "\n" +BYTE_STRING "b\"\\u{DC00}\"" error: unicode escape in byte string +WHITESPACE "\n" +BYTE_STRING "b\"\\u{DDDD}\"" error: unicode escape in byte string +WHITESPACE "\n" +BYTE_STRING "b\"\\u{DFFF}\"" error: unicode escape in byte string +WHITESPACE "\n" +BYTE_STRING "b\"\\u{D800}\"" error: unicode escape in byte string +WHITESPACE "\n" +BYTE_STRING "b\"\\u{DAAA}\"" error: unicode escape in byte string +WHITESPACE "\n" +BYTE_STRING "b\"\\u{DBFF}\"" error: unicode escape in byte string +WHITESPACE "\n" +BYTE_STRING "b\"\\xы\"" error: invalid character in numeric character escape +WHITESPACE "\n" diff --git a/crates/parser/test_data/lexer/err/byte_strings.rs b/crates/parser/test_data/lexer/err/byte_strings.rs new file mode 100644 index 000000000000..e74847137b1e --- /dev/null +++ b/crates/parser/test_data/lexer/err/byte_strings.rs @@ -0,0 +1,14 @@ +b"\💩" +b"\●" +b"\u{_0000}" +b"\u{0000000}" +b"\u{FFFFFF}" +b"\u{ffffff}" +b"\u{ffffff}" +b"\u{DC00}" +b"\u{DDDD}" +b"\u{DFFF}" +b"\u{D800}" +b"\u{DAAA}" +b"\u{DBFF}" +b"\xы" diff --git a/crates/parser/test_data/lexer/err/c_strings.rast b/crates/parser/test_data/lexer/err/c_strings.rast new file mode 100644 index 000000000000..1b4424ba5c78 --- /dev/null +++ b/crates/parser/test_data/lexer/err/c_strings.rast @@ -0,0 +1,28 @@ +C_STRING "c\"\\💩\"" error: unknown character escape +WHITESPACE "\n" +C_STRING "c\"\\●\"" error: unknown character escape +WHITESPACE "\n" +C_STRING "c\"\\u{_0000}\"" error: invalid start of unicode escape +WHITESPACE "\n" +C_STRING "c\"\\u{0000000}\"" error: overlong unicode escape +WHITESPACE "\n" +C_STRING "c\"\\u{FFFFFF}\"" error: invalid unicode character escape +WHITESPACE "\n" +C_STRING "c\"\\u{ffffff}\"" error: invalid unicode character escape +WHITESPACE "\n" +C_STRING "c\"\\u{ffffff}\"" error: invalid unicode character escape +WHITESPACE "\n" +C_STRING "c\"\\u{DC00}\"" error: invalid unicode character escape +WHITESPACE "\n" +C_STRING "c\"\\u{DDDD}\"" error: invalid unicode character escape +WHITESPACE "\n" +C_STRING "c\"\\u{DFFF}\"" error: invalid unicode character escape +WHITESPACE "\n" +C_STRING "c\"\\u{D800}\"" error: invalid unicode character escape +WHITESPACE "\n" +C_STRING "c\"\\u{DAAA}\"" error: invalid unicode character escape +WHITESPACE "\n" +C_STRING "c\"\\u{DBFF}\"" error: invalid unicode character escape +WHITESPACE "\n" +C_STRING "c\"\\xы\"" error: invalid character in numeric character escape +WHITESPACE "\n" diff --git a/crates/parser/test_data/lexer/err/c_strings.rs b/crates/parser/test_data/lexer/err/c_strings.rs new file mode 100644 index 000000000000..1b78ffc28a00 --- /dev/null +++ b/crates/parser/test_data/lexer/err/c_strings.rs @@ -0,0 +1,14 @@ +c"\💩" +c"\●" +c"\u{_0000}" +c"\u{0000000}" +c"\u{FFFFFF}" +c"\u{ffffff}" +c"\u{ffffff}" +c"\u{DC00}" +c"\u{DDDD}" +c"\u{DFFF}" +c"\u{D800}" +c"\u{DAAA}" +c"\u{DBFF}" +c"\xы" diff --git a/crates/parser/test_data/lexer/err/strings.rast b/crates/parser/test_data/lexer/err/strings.rast new file mode 100644 index 000000000000..0cd1747208e4 --- /dev/null +++ b/crates/parser/test_data/lexer/err/strings.rast @@ -0,0 +1,28 @@ +STRING "\"\\💩\"" error: unknown character escape +WHITESPACE "\n" +STRING "\"\\●\"" error: unknown character escape +WHITESPACE "\n" +STRING "\"\\u{_0000}\"" error: invalid start of unicode escape +WHITESPACE "\n" +STRING "\"\\u{0000000}\"" error: overlong unicode escape +WHITESPACE "\n" +STRING "\"\\u{FFFFFF}\"" error: invalid unicode character escape +WHITESPACE "\n" +STRING "\"\\u{ffffff}\"" error: invalid unicode character escape +WHITESPACE "\n" +STRING "\"\\u{ffffff}\"" error: invalid unicode character escape +WHITESPACE "\n" +STRING "\"\\u{DC00}\"" error: invalid unicode character escape +WHITESPACE "\n" +STRING "\"\\u{DDDD}\"" error: invalid unicode character escape +WHITESPACE "\n" +STRING "\"\\u{DFFF}\"" error: invalid unicode character escape +WHITESPACE "\n" +STRING "\"\\u{D800}\"" error: invalid unicode character escape +WHITESPACE "\n" +STRING "\"\\u{DAAA}\"" error: invalid unicode character escape +WHITESPACE "\n" +STRING "\"\\u{DBFF}\"" error: invalid unicode character escape +WHITESPACE "\n" +STRING "\"\\xы\"" error: invalid character in numeric character escape +WHITESPACE "\n" diff --git a/crates/parser/test_data/lexer/err/strings.rs b/crates/parser/test_data/lexer/err/strings.rs new file mode 100644 index 000000000000..2499516d3fa9 --- /dev/null +++ b/crates/parser/test_data/lexer/err/strings.rs @@ -0,0 +1,14 @@ +"\💩" +"\●" +"\u{_0000}" +"\u{0000000}" +"\u{FFFFFF}" +"\u{ffffff}" +"\u{ffffff}" +"\u{DC00}" +"\u{DDDD}" +"\u{DFFF}" +"\u{D800}" +"\u{DAAA}" +"\u{DBFF}" +"\xы" From 2e713a7a2f33a1ded183036f71c6242ae814f783 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:45:16 +0200 Subject: [PATCH 2312/2442] docs: Add Zed to IDE list. --- docs/user/manual.adoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 5dafd1a4c8c9..f5a1cec814c6 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -555,6 +555,11 @@ There is a package named `ra_ap_rust_analyzer` available on https://crates.io/cr For more details, see https://github.com/rust-lang/rust-analyzer/blob/master/.github/workflows/publish.yml[the publish workflow]. +=== Zed + +https://zed.dev[Zed] has native `rust-analyzer` support. +If the LSP binary is not available, Zed can install it when opening a Rust file. + == Troubleshooting Start with looking at the rust-analyzer version. From b769f34f6371b13f7ce81cefe65579911331eb16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20Valletb=C3=B3?= Date: Wed, 11 Oct 2023 15:45:45 +0200 Subject: [PATCH 2313/2442] chore: move common code to function --- crates/parser/src/lexed_str.rs | 46 ++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs index c2e25daf37f6..4d322f21ae70 100644 --- a/crates/parser/src/lexed_str.rs +++ b/crates/parser/src/lexed_str.rs @@ -291,11 +291,7 @@ impl<'a> Converter<'a> { let text = &self.res.text[self.offset + 1..][..len - 1]; let i = text.rfind('"').unwrap(); let text = &text[..i]; - rustc_lexer::unescape::unescape_literal(text, Mode::Str, &mut |_, res| { - if let Err(e) = res { - err = error_to_diagnostic_message(e, Mode::Str); - } - }); + err = unescape_string_error_message(text, Mode::Str); } STRING } @@ -306,11 +302,7 @@ impl<'a> Converter<'a> { let text = &self.res.text[self.offset + 2..][..len - 2]; let i = text.rfind('"').unwrap(); let text = &text[..i]; - rustc_lexer::unescape::unescape_literal(text, Mode::ByteStr, &mut |_, res| { - if let Err(e) = res { - err = error_to_diagnostic_message(e, Mode::ByteStr); - } - }) + err = unescape_string_error_message(text, Mode::ByteStr); } BYTE_STRING } @@ -321,11 +313,7 @@ impl<'a> Converter<'a> { let text = &self.res.text[self.offset + 2..][..len - 2]; let i = text.rfind('"').unwrap(); let text = &text[..i]; - rustc_lexer::unescape::unescape_c_string(text, Mode::CStr, &mut |_, res| { - if let Err(e) = res { - err = error_to_diagnostic_message(e, Mode::CStr); - } - }) + err = unescape_string_error_message(text, Mode::CStr); } C_STRING } @@ -391,12 +379,26 @@ fn error_to_diagnostic_message(error: EscapeError, mode: Mode) -> &'static str { } } -fn fill_unescape_string_error(text: &str, mode: Mode, mut error_message: &str) { - - rustc_lexer::unescape::unescape_c_string(text, mode, &mut |_, res| { - if let Err(e) = res { - error_message = error_to_diagnostic_message(e, mode); +fn unescape_string_error_message(text: &str, mode: Mode) -> &'static str { + let mut error_message = ""; + match mode { + Mode::CStr => { + rustc_lexer::unescape::unescape_c_string(text, mode, &mut |_, res| { + if let Err(e) = res { + error_message = error_to_diagnostic_message(e, mode); + } + }); } - }); + Mode::ByteStr | Mode::Str => { + rustc_lexer::unescape::unescape_literal(text, mode, &mut |_, res| { + if let Err(e) = res { + error_message = error_to_diagnostic_message(e, mode); + } + }); + } + _ => { + // Other Modes are not supported yet or do not apply + } + } + error_message } - From 4b281ffdf2c0315722729ec090f74c0d49feca1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20Valletb=C3=B3?= Date: Wed, 11 Oct 2023 15:52:05 +0200 Subject: [PATCH 2314/2442] chore: format imports --- crates/parser/src/lexed_str.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs index 4d322f21ae70..13189b8bd003 100644 --- a/crates/parser/src/lexed_str.rs +++ b/crates/parser/src/lexed_str.rs @@ -7,11 +7,9 @@ //! //! Note that these tokens, unlike the tokens we feed into the parser, do //! include info about comments and whitespace. +// -use rustc_dependencies::lexer::{ - self as rustc_lexer, - unescape::{unescape_c_string, unescape_literal}, -}; +use rustc_dependencies::lexer as rustc_lexer; use std::ops; From 6845c80a2fd52e2d8c58bda0e55c39c4bb836ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20Valletb=C3=B3?= Date: Wed, 11 Oct 2023 15:52:22 +0200 Subject: [PATCH 2315/2442] fix: format --- crates/parser/src/lexed_str.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs index 13189b8bd003..b9e7566fdf9b 100644 --- a/crates/parser/src/lexed_str.rs +++ b/crates/parser/src/lexed_str.rs @@ -7,7 +7,6 @@ //! //! Note that these tokens, unlike the tokens we feed into the parser, do //! include info about comments and whitespace. -// use rustc_dependencies::lexer as rustc_lexer; From 3605bb38ff7ecb1b0c9cde25a1c1d9938ac3bb51 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Thu, 12 Oct 2023 11:50:44 +0800 Subject: [PATCH 2316/2442] fix CI: generate doctest --- .../replace_is_some_with_if_let_some.rs | 6 +++--- crates/ide-assists/src/tests/generated.rs | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs b/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs index dfc2a8715003..70892fe27025 100644 --- a/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs +++ b/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs @@ -2,7 +2,7 @@ use syntax::ast::{self, AstNode}; use crate::{AssistContext, AssistId, AssistKind, Assists}; -// Assist: replace_is_some_with_if_let +// Assist: replace_is_some_with_if_let_some // // Replace `if x.is_some()` with `if let Some(_tmp) = x`. // @@ -57,7 +57,7 @@ mod tests { use super::replace_is_some_with_if_let_some; #[test] - fn replace_is_some_with_if_let_works() { + fn replace_is_some_with_if_let_some_works() { check_assist( replace_is_some_with_if_let_some, r#" @@ -76,7 +76,7 @@ fn main() { } #[test] - fn replace_is_some_with_if_let_not_applicable() { + fn replace_is_some_with_if_let_some_not_applicable() { check_assist_not_applicable( replace_is_some_with_if_let_some, r#" diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 18f7591cf082..d2b801336a55 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -2558,6 +2558,25 @@ fn handle(action: Action) { ) } +#[test] +fn doctest_replace_is_some_with_if_let_some() { + check_doc_test( + "replace_is_some_with_if_let_some", + r#####" +fn main() { + let x = Some(1); + if x.is_som$0e() {} +} +"#####, + r#####" +fn main() { + let x = Some(1); + if let Some(_tmp) = x {} +} +"#####, + ) +} + #[test] fn doctest_replace_let_with_if_let() { check_doc_test( From 506b1e515b7c9f834d9fd2523f57f9a3221af42f Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Thu, 12 Oct 2023 23:26:42 +0800 Subject: [PATCH 2317/2442] feat: add replace_is_ok_with_if_let_ok assist --- .../replace_is_method_with_if_let_method.rs | 124 ++++++++++++++++++ .../replace_is_some_with_if_let_some.rs | 90 ------------- crates/ide-assists/src/lib.rs | 4 +- 3 files changed, 126 insertions(+), 92 deletions(-) create mode 100644 crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs delete mode 100644 crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs diff --git a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs new file mode 100644 index 000000000000..b897ddc24578 --- /dev/null +++ b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs @@ -0,0 +1,124 @@ +use syntax::ast::{self, AstNode}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: replace_is_some_with_if_let_some +// +// Replace `if x.is_some()` with `if let Some(_tmp) = x` or `if x.is_ok()` with `if let Ok(_tmp) = x`. +// +// ``` +// fn main() { +// let x = Some(1); +// if x.is_som$0e() {} +// } +// ``` +// -> +// ``` +// fn main() { +// let x = Some(1); +// if let Some(_tmp) = x {} +// } +// ``` +pub(crate) fn replace_is_method_with_if_let_method( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { + let if_expr = ctx.find_node_at_offset::()?; + + let cond = if_expr.condition()?; + let call_expr = match cond { + ast::Expr::MethodCallExpr(call) => call, + _ => return None, + }; + + let name_ref = call_expr.name_ref()?; + match name_ref.text().as_str() { + "is_some" | "is_ok" => { + let receiver = call_expr.receiver()?; + let target = call_expr.syntax().text_range(); + + let (assist_id, message, text) = if name_ref.text() == "is_some" { + ("replace_is_some_with_if_let_some", "Replace `is_some` with `if let Some`", "Some") + } else { + ("replace_is_ok_with_if_let_ok", "Replace `is_ok` with `if let Ok`", "Ok") + }; + + acc.add(AssistId(assist_id, AssistKind::RefactorRewrite), message, target, |edit| { + let replacement = format!("let {}(_tmp) = {}", text, receiver); + edit.replace(target, replacement); + }) + } + _ => return None, + } +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::replace_is_method_with_if_let_method; + + #[test] + fn replace_is_some_with_if_let_some_works() { + check_assist( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Some(1); + if x.is_som$0e() {} +} +"#, + r#" +fn main() { + let x = Some(1); + if let Some(_tmp) = x {} +} +"#, + ); + } + + #[test] + fn replace_is_some_with_if_let_some_not_applicable() { + check_assist_not_applicable( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Some(1); + if x.is_non$0e() {} +} +"#, + ); + } + + #[test] + fn replace_is_ok_with_if_let_ok_works() { + check_assist( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Ok(1); + if x.is_o$0k() {} +} +"#, + r#" +fn main() { + let x = Ok(1); + if let Ok(_tmp) = x {} +} +"#, + ); + } + + #[test] + fn replace_is_ok_with_if_let_ok_not_applicable() { + check_assist_not_applicable( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Ok(1); + if x.is_e$0rr() {} +} +"#, + ); + } +} diff --git a/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs b/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs deleted file mode 100644 index 70892fe27025..000000000000 --- a/crates/ide-assists/src/handlers/replace_is_some_with_if_let_some.rs +++ /dev/null @@ -1,90 +0,0 @@ -use syntax::ast::{self, AstNode}; - -use crate::{AssistContext, AssistId, AssistKind, Assists}; - -// Assist: replace_is_some_with_if_let_some -// -// Replace `if x.is_some()` with `if let Some(_tmp) = x`. -// -// ``` -// fn main() { -// let x = Some(1); -// if x.is_som$0e() {} -// } -// ``` -// -> -// ``` -// fn main() { -// let x = Some(1); -// if let Some(_tmp) = x {} -// } -// ``` -pub(crate) fn replace_is_some_with_if_let_some( - acc: &mut Assists, - ctx: &AssistContext<'_>, -) -> Option<()> { - let if_expr = ctx.find_node_at_offset::()?; - - let cond = if_expr.condition()?; - let call_expr = match cond { - ast::Expr::MethodCallExpr(call) => call, - _ => return None, - }; - - let name_ref = call_expr.name_ref()?; - if name_ref.text() != "is_some" { - return None; - } - - let receiver = call_expr.receiver()?; - let target = call_expr.syntax().text_range(); - - acc.add( - AssistId("replace_is_some_with_if_let_some", AssistKind::RefactorRewrite), - "Replace `is_some` with `if let Some`", - target, - |edit| { - let replacement = format!("let Some(_tmp) = {}", receiver); - edit.replace(target, replacement); - }, - ) -} - -#[cfg(test)] -mod tests { - use crate::tests::{check_assist, check_assist_not_applicable}; - - use super::replace_is_some_with_if_let_some; - - #[test] - fn replace_is_some_with_if_let_some_works() { - check_assist( - replace_is_some_with_if_let_some, - r#" -fn main() { - let x = Some(1); - if x.is_som$0e() {} -} -"#, - r#" -fn main() { - let x = Some(1); - if let Some(_tmp) = x {} -} -"#, - ); - } - - #[test] - fn replace_is_some_with_if_let_some_not_applicable() { - check_assist_not_applicable( - replace_is_some_with_if_let_some, - r#" -fn main() { - let x = Some(1); - if x.is_non$0e() {} -} -"#, - ); - } -} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index d6accbb097ee..a8adedc1273b 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -213,7 +213,7 @@ mod handlers { mod unwrap_block; mod unwrap_result_return_type; mod unqualify_method_call; - mod replace_is_some_with_if_let_some; + mod replace_is_method_with_if_let_method; mod wrap_return_type_in_result; mod into_to_qualified_from; @@ -333,7 +333,7 @@ mod handlers { unwrap_result_return_type::unwrap_result_return_type, unwrap_tuple::unwrap_tuple, unqualify_method_call::unqualify_method_call, - replace_is_some_with_if_let_some::replace_is_some_with_if_let_some, + replace_is_method_with_if_let_method::replace_is_method_with_if_let_method, wrap_return_type_in_result::wrap_return_type_in_result, // These are manually sorted for better priorities. By default, // priority is determined by the size of the target range (smaller From 5bbca22720508798d4eda888d8c91f58d29e1f34 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Fri, 13 Oct 2023 00:09:13 +0800 Subject: [PATCH 2318/2442] update mod order to adapt alphabetically sorted --- crates/ide-assists/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index a8adedc1273b..d2b291631c8a 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -195,6 +195,7 @@ mod handlers { mod replace_try_expr_with_match; mod replace_derive_with_manual_impl; mod replace_if_let_with_match; + mod replace_is_method_with_if_let_method; mod replace_method_eager_lazy; mod replace_arith_op; mod introduce_named_generic; @@ -213,7 +214,6 @@ mod handlers { mod unwrap_block; mod unwrap_result_return_type; mod unqualify_method_call; - mod replace_is_method_with_if_let_method; mod wrap_return_type_in_result; mod into_to_qualified_from; @@ -314,6 +314,7 @@ mod handlers { replace_derive_with_manual_impl::replace_derive_with_manual_impl, replace_if_let_with_match::replace_if_let_with_match, replace_if_let_with_match::replace_match_with_if_let, + replace_is_method_with_if_let_method::replace_is_method_with_if_let_method, replace_let_with_if_let::replace_let_with_if_let, replace_method_eager_lazy::replace_with_eager_method, replace_method_eager_lazy::replace_with_lazy_method, @@ -333,7 +334,6 @@ mod handlers { unwrap_result_return_type::unwrap_result_return_type, unwrap_tuple::unwrap_tuple, unqualify_method_call::unqualify_method_call, - replace_is_method_with_if_let_method::replace_is_method_with_if_let_method, wrap_return_type_in_result::wrap_return_type_in_result, // These are manually sorted for better priorities. By default, // priority is determined by the size of the target range (smaller From bc34e8f1ad252aeda6064708abe3af944b6faf5d Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Sat, 14 Oct 2023 11:05:38 +0800 Subject: [PATCH 2319/2442] feat: make cursor select at _tmp --- .../src/handlers/replace_is_method_with_if_let_method.rs | 8 ++++---- crates/ide-assists/src/tests/generated.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs index b897ddc24578..e5b4c33eb34f 100644 --- a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs +++ b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs @@ -16,7 +16,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` // fn main() { // let x = Some(1); -// if let Some(_tmp) = x {} +// if let Some(${0:_tmp}) = x {} // } // ``` pub(crate) fn replace_is_method_with_if_let_method( @@ -44,7 +44,7 @@ pub(crate) fn replace_is_method_with_if_let_method( }; acc.add(AssistId(assist_id, AssistKind::RefactorRewrite), message, target, |edit| { - let replacement = format!("let {}(_tmp) = {}", text, receiver); + let replacement = format!("let {}({}) = {}", text, "${0:_tmp}", receiver); edit.replace(target, replacement); }) } @@ -71,7 +71,7 @@ fn main() { r#" fn main() { let x = Some(1); - if let Some(_tmp) = x {} + if let Some(${0:_tmp}) = x {} } "#, ); @@ -103,7 +103,7 @@ fn main() { r#" fn main() { let x = Ok(1); - if let Ok(_tmp) = x {} + if let Ok(${0:_tmp}) = x {} } "#, ); diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index d2b801336a55..6b4a97440877 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -2571,7 +2571,7 @@ fn main() { r#####" fn main() { let x = Some(1); - if let Some(_tmp) = x {} + if let Some(${0:_tmp}) = x {} } "#####, ) From 3f4368a090157d631cd3715baa60e823d679f07d Mon Sep 17 00:00:00 2001 From: harpsword Date: Sat, 14 Oct 2023 11:28:23 +0800 Subject: [PATCH 2320/2442] fix: fix typo in mbe/lib.rs comment --- crates/mbe/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 9d886a1c979a..a439c9c50d6c 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs @@ -3,7 +3,7 @@ //! interface, although it contains some code to bridge `SyntaxNode`s and //! `TokenTree`s as well! //! -//! The tes for this functionality live in another crate: +//! The tests for this functionality live in another crate: //! `hir_def::macro_expansion_tests::mbe`. #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] From 8217ff9c1651201645316877694a7a58d2fd469d Mon Sep 17 00:00:00 2001 From: Christian Schott <56631269+ChristianSchott@users.noreply.github.com> Date: Sat, 14 Oct 2023 19:20:11 +0200 Subject: [PATCH 2321/2442] make ProjectionStore-impls pub-accessible --- crates/hir-ty/src/mir.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs index 797f4c1248d6..747ca54858c8 100644 --- a/crates/hir-ty/src/mir.rs +++ b/crates/hir-ty/src/mir.rs @@ -243,16 +243,16 @@ impl Default for ProjectionStore { } impl ProjectionStore { - fn shrink_to_fit(&mut self) { + pub fn shrink_to_fit(&mut self) { self.id_to_proj.shrink_to_fit(); self.proj_to_id.shrink_to_fit(); } - fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option { + pub fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option { self.proj_to_id.get(projection).copied() } - fn intern(&mut self, projection: Box<[PlaceElem]>) -> ProjectionId { + pub fn intern(&mut self, projection: Box<[PlaceElem]>) -> ProjectionId { let new_id = ProjectionId(self.proj_to_id.len() as u32); match self.proj_to_id.entry(projection) { Entry::Occupied(id) => *id.get(), @@ -267,13 +267,13 @@ impl ProjectionStore { } impl ProjectionId { - const EMPTY: ProjectionId = ProjectionId(0); + pub const EMPTY: ProjectionId = ProjectionId(0); - fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] { + pub fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] { store.id_to_proj.get(&self).unwrap() } - fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId { + pub fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId { let mut current = self.lookup(store).to_vec(); current.push(projection); store.intern(current.into()) From d33fd15ecfe385b8fdd787c813074f9aa451ef37 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 15 Oct 2023 17:58:50 +0200 Subject: [PATCH 2322/2442] Fix metrics workflow to use deploy key --- .github/workflows/metrics.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/metrics.yaml b/.github/workflows/metrics.yaml index bbeccd1621df..91615f1b79fb 100644 --- a/.github/workflows/metrics.yaml +++ b/.github/workflows/metrics.yaml @@ -140,11 +140,12 @@ jobs: - name: Combine json run: | - git clone --depth 1 https://$METRICS_TOKEN@github.com/rust-analyzer/metrics.git + echo "${{ secrets.METRICS_DEPLOY_KEY }}" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + + git clone --depth 1 git@github.com/rust-analyzer/metrics.git jq -s ".[0] * .[1] * .[2] * .[3] * .[4] * .[5]" build.json self.json ripgrep-13.0.0.json webrender-2022.json diesel-1.4.8.json hyper-0.14.18.json -c >> metrics/metrics.json cd metrics git add . git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈 git push origin master - env: - METRICS_TOKEN: ${{ secrets.METRICS_TOKEN }} From 40acc5250f2d3cb146b8abe12933402b107895cb Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 29 Sep 2023 20:42:26 +0200 Subject: [PATCH 2323/2442] Update rustc_abi dependency --- Cargo.lock | 50 +++++++----------- crates/hir-def/src/data/adt.rs | 2 +- crates/hir-ty/src/layout.rs | 78 ++++++++++++++++++---------- crates/hir-ty/src/layout/adt.rs | 9 ++-- crates/hir/src/lib.rs | 24 +++++++-- crates/ide/src/hover/render.rs | 3 +- crates/ide/src/view_memory_layout.rs | 18 +++---- crates/rustc-dependencies/Cargo.toml | 10 ++-- crates/rustc-dependencies/src/lib.rs | 39 ++++++++------ 9 files changed, 135 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 476c0475ce43..2a56bddb76ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -608,27 +608,6 @@ dependencies = [ "typed-arena", ] -[[package]] -name = "hkalbasi-rustc-ap-rustc_abi" -version = "0.0.20221221" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adabaadad9aa7576f97af02241cdf5554d62fb3d51a84cb05d77ba28edd3013f" -dependencies = [ - "bitflags 1.3.2", - "hkalbasi-rustc-ap-rustc_index", - "tracing", -] - -[[package]] -name = "hkalbasi-rustc-ap-rustc_index" -version = "0.0.20221221" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4d3c48474e09afb0f5efbd6f758e05411699301a113c47d454d28ec7059d00e" -dependencies = [ - "arrayvec", - "smallvec", -] - [[package]] name = "home" version = "0.5.5" @@ -1474,10 +1453,21 @@ dependencies = [ ] [[package]] -name = "ra-ap-rustc_index" -version = "0.10.0" +name = "ra-ap-rustc_abi" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b5fa61d34da18e148dc3a81f654488ea07f40938d8aefb17f8b64bb78c6120" +checksum = "a51b7a02377b3246ec5c095b852b5cf1678bd9ed6b572b2a79efbf7ad711c292" +dependencies = [ + "bitflags 1.3.2", + "ra-ap-rustc_index", + "tracing", +] + +[[package]] +name = "ra-ap-rustc_index" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643ca3609870b1778d9cd1f2a8e4ccb4af0f48f3637cc257a09494d087bd93dc" dependencies = [ "arrayvec", "smallvec", @@ -1485,9 +1475,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.10.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2e2f6b48422e4eed5218277ab7cc9733e60dd8f3167f4f36a49a0cafe4dc195" +checksum = "30ffd24f9ba4f1d25ff27ca1469b8d22a3bdfb12cf644fc8bfcb63121fa5da6b" dependencies = [ "unicode-properties", "unicode-xid", @@ -1495,9 +1485,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.10.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7369ad01cc79f9e3513c9f6a6326f6b980100e4862a7ac71b9991c88108bb" +checksum = "207b5ac1a21d4926695e03b605ffb9f63d4968e0488e9197c04c512c37303aa7" dependencies = [ "ra-ap-rustc_index", "ra-ap-rustc_lexer", @@ -1623,8 +1613,8 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" name = "rustc-dependencies" version = "0.0.0" dependencies = [ - "hkalbasi-rustc-ap-rustc_abi", - "hkalbasi-rustc-ap-rustc_index", + "ra-ap-rustc_abi", + "ra-ap-rustc_index", "ra-ap-rustc_lexer", "ra-ap-rustc_parse_format", ] diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index b163112db918..76c8d9a0c367 100644 --- a/crates/hir-def/src/data/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -178,7 +178,7 @@ fn parse_repr_tt(tt: &Subtree) -> Option { } } - Some(ReprOptions { int, align: max_align, pack: min_pack, flags, field_shuffle_seed: 0 }) + Some(ReprOptions { int, align: max_align, pack: min_pack, flags }) } impl StructData { diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index ee558956a761..603e58f9d462 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -9,6 +9,10 @@ use hir_def::{ LocalEnumVariantId, LocalFieldId, StructId, }; use la_arena::{Idx, RawIdx}; +use rustc_dependencies::{ + abi::AddressSpace, + index::{IndexSlice, IndexVec}, +}; use stdx::never; use triomphe::Arc; @@ -34,7 +38,7 @@ mod target; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct RustcEnumVariantIdx(pub LocalEnumVariantId); -impl rustc_dependencies::index::vec::Idx for RustcEnumVariantIdx { +impl rustc_dependencies::index::Idx for RustcEnumVariantIdx { fn new(idx: usize) -> Self { RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32))) } @@ -44,9 +48,28 @@ impl rustc_dependencies::index::vec::Idx for RustcEnumVariantIdx { } } -pub type Layout = LayoutS; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct RustcFieldIdx(pub LocalFieldId); + +impl RustcFieldIdx { + pub fn new(idx: usize) -> Self { + RustcFieldIdx(Idx::from_raw(RawIdx::from(idx as u32))) + } +} + +impl rustc_dependencies::index::Idx for RustcFieldIdx { + fn new(idx: usize) -> Self { + RustcFieldIdx(Idx::from_raw(RawIdx::from(idx as u32))) + } + + fn index(self) -> usize { + u32::from(self.0.into_raw()) as usize + } +} + +pub type Layout = LayoutS; pub type TagEncoding = hir_def::layout::TagEncoding; -pub type Variants = hir_def::layout::Variants; +pub type Variants = hir_def::layout::Variants; #[derive(Debug, PartialEq, Eq, Clone)] pub enum LayoutError { @@ -66,7 +89,7 @@ struct LayoutCx<'a> { impl<'a> LayoutCalculator for LayoutCx<'a> { type TargetDataLayoutRef = &'a TargetDataLayout; - fn delay_bug(&self, txt: &str) { + fn delay_bug(&self, txt: String) { never!("{}", txt); } @@ -145,6 +168,8 @@ fn layout_of_simd_ty( largest_niche: e_ly.largest_niche, size, align, + max_repr_align: None, + unadjusted_abi_align: align.abi, })) } @@ -230,7 +255,7 @@ pub fn layout_of_ty_query( .map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), trait_env.clone())) .collect::, _>>()?; let fields = fields.iter().map(|it| &**it).collect::>(); - let fields = fields.iter().collect::>(); + let fields = fields.iter().collect::>(); cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)? } TyKind::Array(element, count) => { @@ -255,6 +280,8 @@ pub fn layout_of_ty_query( largest_niche, align: element.align, size, + max_repr_align: None, + unadjusted_abi_align: element.align.abi, } } TyKind::Slice(element) => { @@ -266,11 +293,23 @@ pub fn layout_of_ty_query( largest_niche: None, align: element.align, size: Size::ZERO, + max_repr_align: None, + unadjusted_abi_align: element.align.abi, } } + TyKind::Str => Layout { + variants: Variants::Single { index: struct_variant_idx() }, + fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, + abi: Abi::Aggregate { sized: false }, + largest_niche: None, + align: dl.i8_align, + size: Size::ZERO, + max_repr_align: None, + unadjusted_abi_align: dl.i8_align.abi, + }, // Potentially-wide pointers. TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => { - let mut data_ptr = scalar_unit(dl, Primitive::Pointer); + let mut data_ptr = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA)); if matches!(ty.kind(Interner), TyKind::Ref(..)) { data_ptr.valid_range_mut().start = 1; } @@ -294,7 +333,7 @@ pub fn layout_of_ty_query( scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false)) } TyKind::Dyn(..) => { - let mut vtable = scalar_unit(dl, Primitive::Pointer); + let mut vtable = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA)); vtable.valid_range_mut().start = 1; vtable } @@ -308,22 +347,7 @@ pub fn layout_of_ty_query( cx.scalar_pair(data_ptr, metadata) } TyKind::FnDef(_, _) => layout_of_unit(&cx, dl)?, - TyKind::Str => Layout { - variants: Variants::Single { index: struct_variant_idx() }, - fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, - abi: Abi::Aggregate { sized: false }, - largest_niche: None, - align: dl.i8_align, - size: Size::ZERO, - }, - TyKind::Never => Layout { - variants: Variants::Single { index: struct_variant_idx() }, - fields: FieldsShape::Primitive, - abi: Abi::Uninhabited, - largest_niche: None, - align: dl.i8_align, - size: Size::ZERO, - }, + TyKind::Never => cx.layout_of_never_type(), TyKind::Dyn(_) | TyKind::Foreign(_) => { let mut unit = layout_of_unit(&cx, dl)?; match unit.abi { @@ -333,7 +357,7 @@ pub fn layout_of_ty_query( unit } TyKind::Function(_) => { - let mut ptr = scalar_unit(dl, Primitive::Pointer); + let mut ptr = scalar_unit(dl, Primitive::Pointer(dl.instruction_address_space)); ptr.valid_range_mut().start = 1; Layout::scalar(dl, ptr) } @@ -363,7 +387,7 @@ pub fn layout_of_ty_query( }) .collect::, _>>()?; let fields = fields.iter().map(|it| &**it).collect::>(); - let fields = fields.iter().collect::>(); + let fields = fields.iter().collect::>(); cx.univariant(dl, &fields, &ReprOptions::default(), StructKind::AlwaysSized) .ok_or(LayoutError::Unknown)? } @@ -398,9 +422,9 @@ pub fn layout_of_ty_recover( } fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result { - cx.univariant::( + cx.univariant::( dl, - &[], + IndexSlice::empty(), &ReprOptions::default(), StructKind::AlwaysSized, ) diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index c2778b9a8ea0..5e713c17cf81 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -8,6 +8,7 @@ use hir_def::{ AdtId, EnumVariantId, LocalEnumVariantId, VariantId, }; use la_arena::RawIdx; +use rustc_dependencies::index::IndexVec; use smallvec::SmallVec; use triomphe::Arc; @@ -20,8 +21,8 @@ use crate::{ use super::LayoutCx; -pub(crate) fn struct_variant_idx() -> RustcEnumVariantIdx { - RustcEnumVariantIdx(LocalEnumVariantId::from_raw(RawIdx::from(0))) +pub(crate) const fn struct_variant_idx() -> RustcEnumVariantIdx { + RustcEnumVariantIdx(LocalEnumVariantId::from_raw(RawIdx::from_u32(0))) } pub fn layout_of_adt_query( @@ -74,7 +75,7 @@ pub fn layout_of_adt_query( .iter() .map(|it| it.iter().map(|it| &**it).collect::>()) .collect::>(); - let variants = variants.iter().map(|it| it.iter().collect()).collect(); + let variants = variants.iter().map(|it| it.iter().collect()).collect::>(); let result = if matches!(def, AdtId::UnionId(..)) { cx.layout_of_union(&repr, &variants).ok_or(LayoutError::Unknown)? } else { @@ -105,7 +106,7 @@ pub fn layout_of_adt_query( && variants .iter() .next() - .and_then(|it| it.last().map(|it| !it.is_unsized())) + .and_then(|it| it.iter().last().map(|it| !it.is_unsized())) .unwrap_or(true), ) .ok_or(LayoutError::SizeOverflow)? diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8246297705ca..2883229d11e2 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -64,7 +64,7 @@ use hir_ty::{ consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt}, diagnostics::BodyValidationDiagnostic, known_const_to_ast, - layout::{Layout as TyLayout, RustcEnumVariantIdx, TagEncoding}, + layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, method_resolution::{self, TyFingerprint}, mir::{self, interpret_mir}, primitive::UintTy, @@ -4540,15 +4540,31 @@ impl Layout { Some(self.0.largest_niche?.available(&*self.1)) } - pub fn field_offset(&self, idx: usize) -> Option { + pub fn field_offset(&self, field: Field) -> Option { match self.0.fields { layout::FieldsShape::Primitive => None, layout::FieldsShape::Union(_) => Some(0), layout::FieldsShape::Array { stride, count } => { - let i = u64::try_from(idx).ok()?; + let i = u64::try_from(field.index()).ok()?; (i < count).then_some((stride * i).bytes()) } - layout::FieldsShape::Arbitrary { ref offsets, .. } => Some(offsets.get(idx)?.bytes()), + layout::FieldsShape::Arbitrary { ref offsets, .. } => { + Some(offsets.get(RustcFieldIdx(field.id))?.bytes()) + } + } + } + + pub fn tuple_field_offset(&self, field: usize) -> Option { + match self.0.fields { + layout::FieldsShape::Primitive => None, + layout::FieldsShape::Union(_) => Some(0), + layout::FieldsShape::Array { stride, count } => { + let i = u64::try_from(field).ok()?; + (i < count).then_some((stride * i).bytes()) + } + layout::FieldsShape::Arbitrary { ref offsets, .. } => { + Some(offsets.get(RustcFieldIdx::new(field))?.bytes()) + } } } diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index f72ce37d1d94..d0a02fd0dba2 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -402,10 +402,9 @@ pub(super) fn definition( |&it| it.layout(db), |_| { let var_def = it.parent_def(db); - let id = it.index(); match var_def { hir::VariantDef::Struct(s) => { - Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(id)) + Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(it)) } _ => None, } diff --git a/crates/ide/src/view_memory_layout.rs b/crates/ide/src/view_memory_layout.rs index 2f6332abd259..3802978f4941 100644 --- a/crates/ide/src/view_memory_layout.rs +++ b/crates/ide/src/view_memory_layout.rs @@ -55,6 +55,7 @@ impl fmt::Display for RecursiveMemoryLayout { } } +#[derive(Copy, Clone)] enum FieldOrTupleIdx { Field(Field), TupleIdx(usize), @@ -71,13 +72,6 @@ impl FieldOrTupleIdx { FieldOrTupleIdx::TupleIdx(i) => format!(".{i}").to_owned(), } } - - fn index(&self) -> usize { - match *self { - FieldOrTupleIdx::Field(f) => f.index(), - FieldOrTupleIdx::TupleIdx(i) => i, - } - } } // Feature: View Memory Layout @@ -138,7 +132,10 @@ pub(crate) fn view_memory_layout( return; } - fields.sort_by_key(|(f, _)| layout.field_offset(f.index()).unwrap()); + fields.sort_by_key(|&(f, _)| match f { + FieldOrTupleIdx::Field(f) => layout.field_offset(f).unwrap_or(0), + FieldOrTupleIdx::TupleIdx(f) => layout.tuple_field_offset(f).unwrap_or(0), + }); let children_start = nodes.len(); nodes[parent_idx].children_start = children_start as i64; @@ -151,7 +148,10 @@ pub(crate) fn view_memory_layout( typename: child_ty.display(db).to_string(), size: child_layout.size(), alignment: child_layout.align(), - offset: layout.field_offset(field.index()).unwrap_or(0), + offset: match *field { + FieldOrTupleIdx::Field(f) => layout.field_offset(f).unwrap_or(0), + FieldOrTupleIdx::TupleIdx(f) => layout.tuple_field_offset(f).unwrap_or(0), + }, parent_idx: parent_idx as i64, children_start: -1, children_len: 0, diff --git a/crates/rustc-dependencies/Cargo.toml b/crates/rustc-dependencies/Cargo.toml index 5c5a3cd8bf32..7ead3d84cd3c 100644 --- a/crates/rustc-dependencies/Cargo.toml +++ b/crates/rustc-dependencies/Cargo.toml @@ -11,12 +11,10 @@ authors.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ra-ap-rustc_lexer = { version = "0.10.0" } -ra-ap-rustc_parse_format = { version = "0.10.0", default-features = false } - -# Upstream broke this for us so we can't update it -hkalbasi-rustc-ap-rustc_abi = { version = "0.0.20221221", default-features = false } -hkalbasi-rustc-ap-rustc_index = { version = "0.0.20221221", default-features = false } +ra-ap-rustc_lexer = { version = "0.14.0" } +ra-ap-rustc_parse_format = { version = "0.14.0", default-features = false } +ra-ap-rustc_index = { version = "0.14.0", default-features = false } +ra-ap-rustc_abi = { version = "0.14.0", default-features = false } [features] in-rust-tree = [] diff --git a/crates/rustc-dependencies/src/lib.rs b/crates/rustc-dependencies/src/lib.rs index c1d3f05f34e7..13fcbc491937 100644 --- a/crates/rustc-dependencies/src/lib.rs +++ b/crates/rustc-dependencies/src/lib.rs @@ -6,34 +6,43 @@ #[cfg(feature = "in-rust-tree")] extern crate rustc_lexer; -#[cfg(feature = "in-rust-tree")] -pub mod lexer { - pub use ::rustc_lexer::*; -} - -#[cfg(not(feature = "in-rust-tree"))] pub mod lexer { + #[cfg(not(feature = "in-rust-tree"))] pub use ::ra_ap_rustc_lexer::*; + + #[cfg(feature = "in-rust-tree")] + pub use ::rustc_lexer::*; } #[cfg(feature = "in-rust-tree")] extern crate rustc_parse_format; -#[cfg(feature = "in-rust-tree")] pub mod parse_format { + #[cfg(not(feature = "in-rust-tree"))] + pub use ::ra_ap_rustc_parse_format::*; + + #[cfg(feature = "in-rust-tree")] pub use ::rustc_parse_format::*; } -#[cfg(not(feature = "in-rust-tree"))] -pub mod parse_format { - pub use ::ra_ap_rustc_parse_format::*; +#[cfg(feature = "in-rust-tree")] +extern crate rustc_abi; + +pub mod abi { + #[cfg(not(feature = "in-rust-tree"))] + pub use ::ra_ap_rustc_abi::*; + + #[cfg(feature = "in-rust-tree")] + pub use ::rustc_abi::*; } -// Upstream broke this for us so we can't update it -pub mod abi { - pub use ::hkalbasi_rustc_ap_rustc_abi::*; -} +#[cfg(feature = "in-rust-tree")] +extern crate rustc_index; pub mod index { - pub use ::hkalbasi_rustc_ap_rustc_index::*; + #[cfg(not(feature = "in-rust-tree"))] + pub use ::ra_ap_rustc_index::*; + + #[cfg(feature = "in-rust-tree")] + pub use ::rustc_index::*; } From 03bec1112ad5594b31fe7489f448b4f69117df5b Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Sun, 15 Oct 2023 16:34:23 -0700 Subject: [PATCH 2324/2442] Expand Emacs documentation Emacs 29 is now released, and include an example of enabling clippy. --- docs/user/manual.adoc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index f5a1cec814c6..b605de4c7b82 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -237,7 +237,7 @@ To use `rust-analyzer`, you need to install and enable one of the two popular LS ==== Eglot -Eglot is the more minimalistic and lightweight LSP client for Emacs, integrates well with existing Emacs functionality and will be built into Emacs starting from release 29. +Eglot is the more minimalistic and lightweight LSP client for Emacs, integrates well with existing Emacs functionality and is built into Emacs starting from release 29. After installing Eglot, e.g. via `M-x package-install` (not needed from Emacs 29), you can enable it via the `M-x eglot` command or load it automatically in `rust-mode` via @@ -246,6 +246,15 @@ After installing Eglot, e.g. via `M-x package-install` (not needed from Emacs 29 (add-hook 'rust-mode-hook 'eglot-ensure) ---- +To enable clippy, you will need to configure the initialization options to pass the `check.command` setting. + +[source,emacs-lisp] +---- +(add-to-list 'eglot-server-programs + '((rust-ts-mode rust-mode) . + ("rust-analyzer" :initializationOptions (:check (:command "clippy"))))) +---- + For more detailed instructions and options see the https://joaotavora.github.io/eglot[Eglot manual] (also available from Emacs via `M-x info`) and the https://github.com/joaotavora/eglot/blob/master/README.md[Eglot readme]. From 222be4885877ed8a7e1f78139f97547e8a44682b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 16 Oct 2023 15:13:48 +0300 Subject: [PATCH 2325/2442] Create .ssh before writing deploy key --- .github/workflows/metrics.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/metrics.yaml b/.github/workflows/metrics.yaml index 91615f1b79fb..e43149916ebc 100644 --- a/.github/workflows/metrics.yaml +++ b/.github/workflows/metrics.yaml @@ -140,8 +140,10 @@ jobs: - name: Combine json run: | + mkdir ~/.ssh echo "${{ secrets.METRICS_DEPLOY_KEY }}" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 + chmod 700 ~/.ssh git clone --depth 1 git@github.com/rust-analyzer/metrics.git jq -s ".[0] * .[1] * .[2] * .[3] * .[4] * .[5]" build.json self.json ripgrep-13.0.0.json webrender-2022.json diesel-1.4.8.json hyper-0.14.18.json -c >> metrics/metrics.json From 490cdfecb59f3d60db97318b2fa90414685702ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 16 Oct 2023 16:34:03 +0300 Subject: [PATCH 2326/2442] Fix metrics repo url --- .github/workflows/metrics.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/metrics.yaml b/.github/workflows/metrics.yaml index e43149916ebc..741e559953fc 100644 --- a/.github/workflows/metrics.yaml +++ b/.github/workflows/metrics.yaml @@ -145,7 +145,7 @@ jobs: chmod 600 ~/.ssh/id_ed25519 chmod 700 ~/.ssh - git clone --depth 1 git@github.com/rust-analyzer/metrics.git + git clone --depth 1 git@github.com:rust-analyzer/metrics.git jq -s ".[0] * .[1] * .[2] * .[3] * .[4] * .[5]" build.json self.json ripgrep-13.0.0.json webrender-2022.json diesel-1.4.8.json hyper-0.14.18.json -c >> metrics/metrics.json cd metrics git add . From 1a0fe58d81b5703082c06711bfb08c7563dc1701 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Tue, 17 Oct 2023 17:34:11 +0800 Subject: [PATCH 2327/2442] refactor: change generated variable name --- .../replace_is_method_with_if_let_method.rs | 58 +++++++++++++++++-- crates/ide-assists/src/tests/generated.rs | 2 +- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs index e5b4c33eb34f..b1daaea1ed1b 100644 --- a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs +++ b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs @@ -1,6 +1,6 @@ use syntax::ast::{self, AstNode}; -use crate::{AssistContext, AssistId, AssistKind, Assists}; +use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; // Assist: replace_is_some_with_if_let_some // @@ -16,7 +16,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` // fn main() { // let x = Some(1); -// if let Some(${0:_tmp}) = x {} +// if let Some(${0:x}) = x {} // } // ``` pub(crate) fn replace_is_method_with_if_let_method( @@ -35,6 +35,13 @@ pub(crate) fn replace_is_method_with_if_let_method( match name_ref.text().as_str() { "is_some" | "is_ok" => { let receiver = call_expr.receiver()?; + + let var_name = if let ast::Expr::PathExpr(path_expr) = receiver.clone() { + path_expr.path()?.to_string() + } else { + suggest_name::for_variable(&receiver, &ctx.sema) + }; + let target = call_expr.syntax().text_range(); let (assist_id, message, text) = if name_ref.text() == "is_some" { @@ -44,7 +51,8 @@ pub(crate) fn replace_is_method_with_if_let_method( }; acc.add(AssistId(assist_id, AssistKind::RefactorRewrite), message, target, |edit| { - let replacement = format!("let {}({}) = {}", text, "${0:_tmp}", receiver); + let var_name = format!("${{0:{}}}", var_name); + let replacement = format!("let {}({}) = {}", text, var_name, receiver); edit.replace(target, replacement); }) } @@ -71,7 +79,27 @@ fn main() { r#" fn main() { let x = Some(1); - if let Some(${0:_tmp}) = x {} + if let Some(${0:x}) = x {} +} +"#, + ); + + check_assist( + replace_is_method_with_if_let_method, + r#" +fn test() -> Option { + Some(1) +} +fn main() { + if test().is_som$0e() {} +} +"#, + r#" +fn test() -> Option { + Some(1) +} +fn main() { + if let Some(${0:test}) = test() {} } "#, ); @@ -103,7 +131,27 @@ fn main() { r#" fn main() { let x = Ok(1); - if let Ok(${0:_tmp}) = x {} + if let Ok(${0:x}) = x {} +} +"#, + ); + + check_assist( + replace_is_method_with_if_let_method, + r#" +fn test() -> Result { + Ok(1) +} +fn main() { + if test().is_o$0k() {} +} +"#, + r#" +fn test() -> Result { + Ok(1) +} +fn main() { + if let Ok(${0:test}) = test() {} } "#, ); diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 6b4a97440877..e9d0d373ee7c 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -2571,7 +2571,7 @@ fn main() { r#####" fn main() { let x = Some(1); - if let Some(${0:_tmp}) = x {} + if let Some(${0:x}) = x {} } "#####, ) From 4296fe52baba36de060691db9ef482b68845aeb4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 18 Oct 2023 14:02:56 +0200 Subject: [PATCH 2328/2442] Add command for only opening external docs and attempt to fix vscode-remote issue --- editors/code/package.json | 9 +++++-- editors/code/src/commands.ts | 46 +++++++++++++++++++++++++++--------- editors/code/src/lsp_ext.ts | 8 +++---- editors/code/src/main.ts | 1 + 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/editors/code/package.json b/editors/code/package.json index fc6597a0d402..2dde66c97006 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -248,6 +248,11 @@ "title": "Open Docs", "category": "rust-analyzer" }, + { + "command": "rust-analyzer.openExternalDocs", + "title": "Open External Docs", + "category": "rust-analyzer" + }, { "command": "rust-analyzer.openCargoToml", "title": "Open Cargo.toml", @@ -260,12 +265,12 @@ }, { "command": "rust-analyzer.moveItemUp", - "title": "Move item up", + "title": "Move Item Up", "category": "rust-analyzer" }, { "command": "rust-analyzer.moveItemDown", - "title": "Move item down", + "title": "Move Item Down", "category": "rust-analyzer" }, { diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 4d5c3cf45764..7e24de664e9e 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -948,27 +948,51 @@ export function openDocs(ctx: CtxInit): Cmd { const position = editor.selection.active; const textDocument = { uri: editor.document.uri.toString() }; - const doclinks = await client.sendRequest(ra.openDocs, { position, textDocument }); + const docLinks = await client.sendRequest(ra.openDocs, { position, textDocument }); + log.debug(docLinks); let fileType = vscode.FileType.Unknown; - if (typeof doclinks.local === "string") { + if (docLinks.local !== undefined) { try { - fileType = (await vscode.workspace.fs.stat(vscode.Uri.parse(doclinks.local))).type; + fileType = (await vscode.workspace.fs.stat(vscode.Uri.parse(docLinks.local))).type; } catch (e) { log.debug("stat() threw error. Falling back to web version", e); } } - let doclink; - if (fileType & vscode.FileType.File) { - // file does exist locally - doclink = doclinks.local; - } else { - doclink = doclinks.web; + let docLink = fileType & vscode.FileType.File ? docLinks.local : docLinks.web; + if (docLink) { + // instruct vscode to handle the vscode-remote link directly + if (docLink.startsWith("vscode-remote://")) { + docLink = docLink.replace("vscode-remote://", "vscode://vscode-remote/"); + } + const docUri = vscode.Uri.parse(docLink); + await vscode.env.openExternal(docUri); } + }; +} - if (doclink != null) { - await vscode.env.openExternal(vscode.Uri.parse(doclink)); +export function openExternalDocs(ctx: CtxInit): Cmd { + return async () => { + const editor = vscode.window.activeTextEditor; + if (!editor) { + return; + } + const client = ctx.client; + + const position = editor.selection.active; + const textDocument = { uri: editor.document.uri.toString() }; + + const docLinks = await client.sendRequest(ra.openDocs, { position, textDocument }); + + let docLink = docLinks.web; + if (docLink) { + // instruct vscode to handle the vscode-remote link directly + if (docLink.startsWith("vscode-remote://")) { + docLink = docLink.replace("vscode-remote://", "vscode://vscode-remote/"); + } + const docUri = vscode.Uri.parse(docLink); + await vscode.env.openExternal(docUri); } }; } diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index a1cd88b89c94..f959a76639e0 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -74,8 +74,8 @@ export interface FetchDependencyListParams {} export interface FetchDependencyListResult { crates: { - name: string | undefined; - version: string | undefined; + name?: string; + version?: string; path: string; }[]; } @@ -136,8 +136,8 @@ export const openCargoToml = new lc.RequestType( "experimental/externalDocs", diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index ee5e5b1b80c8..5de5aabc39f7 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -170,6 +170,7 @@ function createCommands(): Record { debug: { enabled: commands.debug }, newDebugConfig: { enabled: commands.newDebugConfig }, openDocs: { enabled: commands.openDocs }, + openExternalDocs: { enabled: commands.openExternalDocs }, openCargoToml: { enabled: commands.openCargoToml }, peekTests: { enabled: commands.peekTests }, moveItemUp: { enabled: commands.moveItemUp }, From a7f77d89a952a0e93276afb91c470e9da1dd5f77 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Wed, 18 Oct 2023 22:40:07 +0800 Subject: [PATCH 2329/2442] fix: auto import trait if needed --- .../src/handlers/unqualify_method_call.rs | 45 ++++++++++++++++++- crates/ide-assists/src/tests/generated.rs | 2 + 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/unqualify_method_call.rs b/crates/ide-assists/src/handlers/unqualify_method_call.rs index e9d4e270cdcf..e1f812b0bfda 100644 --- a/crates/ide-assists/src/handlers/unqualify_method_call.rs +++ b/crates/ide-assists/src/handlers/unqualify_method_call.rs @@ -1,3 +1,4 @@ +use ide_db::imports::insert_use::ImportScope; use syntax::{ ast::{self, make, AstNode, HasArgList}, TextRange, @@ -17,6 +18,8 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` // -> // ``` +// use std::ops::Add; +// // fn main() { // 1.add(2); // } @@ -38,7 +41,7 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) let first_arg = args_iter.next()?; let second_arg = args_iter.next(); - _ = path.qualifier()?; + let qualifier = path.qualifier()?; let method_name = path.segment()?.name_ref()?; let res = ctx.sema.resolve_path(&path)?; @@ -76,10 +79,44 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) edit.insert(close, ")"); } edit.replace(replace_comma, format!(".{method_name}(")); + add_import(qualifier, ctx, edit); }, ) } +fn add_import( + qualifier: ast::Path, + ctx: &AssistContext<'_>, + edit: &mut ide_db::source_change::SourceChangeBuilder, +) { + // for `` + let path_type = + qualifier.segment().unwrap().syntax().children().filter_map(ast::PathType::cast).last(); + let import = match path_type { + Some(it) => it.path().unwrap(), + None => qualifier, + }; + + // in case for `<_>` + if import.coloncolon_token().is_none() { + return; + } + + let scope = ide_db::imports::insert_use::ImportScope::find_insert_use_container( + import.syntax(), + &ctx.sema, + ); + + if let Some(scope) = scope { + let scope = match scope { + ImportScope::File(it) => ImportScope::File(edit.make_mut(it)), + ImportScope::Module(it) => ImportScope::Module(edit.make_mut(it)), + ImportScope::Block(it) => ImportScope::Block(edit.make_mut(it)), + }; + ide_db::imports::insert_use::insert_use(&scope, import, &ctx.config.insert_use); + } +} + fn needs_parens_as_receiver(expr: &ast::Expr) -> bool { // Make `(expr).dummy()` let dummy_call = make::expr_method_call( @@ -127,6 +164,8 @@ fn f() { S.f(S); }"#, //- minicore: add fn f() { ::$0add(2, 2); }"#, r#" +use core::ops::Add; + fn f() { 2.add(2); }"#, ); @@ -136,6 +175,8 @@ fn f() { 2.add(2); }"#, //- minicore: add fn f() { core::ops::Add::$0add(2, 2); }"#, r#" +use core::ops::Add; + fn f() { 2.add(2); }"#, ); @@ -179,6 +220,8 @@ impl core::ops::Deref for S { } fn f() { core::ops::Deref::$0deref(&S); }"#, r#" +use core::ops::Deref; + struct S; impl core::ops::Deref for S { type Target = S; diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 6b4a97440877..99624306b7ea 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -2948,6 +2948,8 @@ fn main() { mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for i32 {} } } "#####, r#####" +use std::ops::Add; + fn main() { 1.add(2); } From 94eb142e6d34192ab918d20f20905653cf86ebdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 19 Oct 2023 19:03:10 +0300 Subject: [PATCH 2330/2442] Free up some disk space on auto-publish --- .github/workflows/autopublish.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/autopublish.yaml b/.github/workflows/autopublish.yaml index 310a8a5be7ad..9a5015005b3d 100644 --- a/.github/workflows/autopublish.yaml +++ b/.github/workflows/autopublish.yaml @@ -19,6 +19,10 @@ jobs: with: fetch-depth: 0 + # https://github.com/jlumbroso/free-disk-space/blob/main/action.yml + - name: Free up some disk space + run: sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc /usr/local/.ghcup + - name: Install Rust toolchain run: rustup update --no-self-update stable From 094cecd3bdc4979f382de39ced770445fb147e38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sat, 21 Oct 2023 19:08:41 +0300 Subject: [PATCH 2331/2442] Fix VS Code detection for Insiders version --- crates/rust-analyzer/src/bin/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index b8875ef87a4c..9748990b7a3f 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -193,7 +193,7 @@ fn run_server() -> anyhow::Result<()> { let mut is_visual_studio_code = false; if let Some(client_info) = client_info { tracing::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); - is_visual_studio_code = client_info.name == "Visual Studio Code"; + is_visual_studio_code = client_info.name.starts_with("Visual Studio Code"); } let workspace_roots = workspace_folders From 4f5f7e280025783a0c9d3f82f4a4cb989255b7ca Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Sun, 22 Oct 2023 21:39:00 +0800 Subject: [PATCH 2332/2442] feat: import trait with alias --- .../ide-assists/src/handlers/auto_import.rs | 52 +++++++++++++++---- crates/ide-db/src/imports/insert_use.rs | 37 +++++++++++-- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs index 7acf2ea0a0de..a2efa4d10bd6 100644 --- a/crates/ide-assists/src/handlers/auto_import.rs +++ b/crates/ide-assists/src/handlers/auto_import.rs @@ -5,7 +5,7 @@ use ide_db::{ helpers::mod_path_to_ast, imports::{ import_assets::{ImportAssets, ImportCandidate, LocatedImport}, - insert_use::{insert_use, ImportScope}, + insert_use::{insert_use, insert_use_as_alias, ImportScope}, }, }; use syntax::{ast, AstNode, NodeOrToken, SyntaxElement}; @@ -129,10 +129,12 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< for import in proposed_imports { let import_path = import.import_path; + let (assist_id, import_name) = + (AssistId("auto_import", AssistKind::QuickFix), import_path.display(ctx.db())); acc.add_group( &group_label, - AssistId("auto_import", AssistKind::QuickFix), - format!("Import `{}`", import_path.display(ctx.db())), + assist_id, + format!("Import `{}`", import_name), range, |builder| { let scope = match scope.clone() { @@ -143,6 +145,38 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< insert_use(&scope, mod_path_to_ast(&import_path), &ctx.config.insert_use); }, ); + + match import_assets.import_candidate() { + ImportCandidate::TraitAssocItem(name) | ImportCandidate::TraitMethod(name) => { + let is_method = + matches!(import_assets.import_candidate(), ImportCandidate::TraitMethod(_)); + let type_ = if is_method { "method" } else { "item" }; + let group_label = GroupLabel(format!( + "Import a trait for {} {} by alias", + type_, + name.assoc_item_name.text() + )); + acc.add_group( + &group_label, + assist_id, + format!("Import `{} as _`", import_name), + range, + |builder| { + let scope = match scope.clone() { + ImportScope::File(it) => ImportScope::File(builder.make_mut(it)), + ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), + ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)), + }; + insert_use_as_alias( + &scope, + mod_path_to_ast(&import_path), + &ctx.config.insert_use, + ); + }, + ); + } + _ => {} + } } Some(()) } @@ -723,7 +757,7 @@ fn main() { } ", r" - use test_mod::TestTrait; + use test_mod::TestTrait as _; mod test_mod { pub trait TestTrait { @@ -794,7 +828,7 @@ fn main() { } ", r" - use test_mod::TestTrait; + use test_mod::TestTrait as _; mod test_mod { pub trait TestTrait { @@ -866,7 +900,7 @@ fn main() { } ", r" - use test_mod::TestTrait; + use test_mod::TestTrait as _; mod test_mod { pub trait TestTrait { @@ -908,7 +942,7 @@ fn main() { } ", r" - use dep::test_mod::TestTrait; + use dep::test_mod::TestTrait as _; fn main() { let test_struct = dep::test_mod::TestStruct {}; @@ -939,7 +973,7 @@ fn main() { } ", r" - use dep::test_mod::TestTrait; + use dep::test_mod::TestTrait as _; fn main() { dep::test_mod::TestStruct::test_function @@ -969,7 +1003,7 @@ fn main() { } ", r" - use dep::test_mod::TestTrait; + use dep::test_mod::TestTrait as _; fn main() { dep::test_mod::TestStruct::CONST diff --git a/crates/ide-db/src/imports/insert_use.rs b/crates/ide-db/src/imports/insert_use.rs index 9be1d3663493..6caa6e3511cd 100644 --- a/crates/ide-db/src/imports/insert_use.rs +++ b/crates/ide-db/src/imports/insert_use.rs @@ -9,7 +9,7 @@ use syntax::{ algo, ast::{ self, edit_in_place::Removable, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, - PathSegmentKind, + PathSegmentKind, Rename, UseTree, }, ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode, }; @@ -157,6 +157,33 @@ impl ImportScope { /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) { + insert_use_with_alias_option(scope, path, cfg, None); +} + +pub fn insert_use_as_alias(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) { + let text: &str = "use foo as _"; + let parse = syntax::SourceFile::parse(text); + let node = match parse.tree().syntax().descendants().find_map(UseTree::cast) { + Some(it) => it, + None => { + panic!( + "Failed to make ast node `{}` from text {}", + std::any::type_name::(), + text + ) + } + }; + let alias = node.rename(); + + insert_use_with_alias_option(scope, path, cfg, alias); +} + +fn insert_use_with_alias_option( + scope: &ImportScope, + path: ast::Path, + cfg: &InsertUseConfig, + alias: Option, +) { let _p = profile::span("insert_use"); let mut mb = match cfg.granularity { ImportGranularity::Crate => Some(MergeBehavior::Crate), @@ -175,8 +202,12 @@ pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) { }; } - let use_item = - make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); + let use_item = if alias.is_some() { + make::use_(None, make::use_tree(path.clone(), None, alias, false)).clone_for_update() + } else { + make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update() + }; + // merge into existing imports if possible if let Some(mb) = mb { let filter = |it: &_| !(cfg.skip_glob_imports && ast::Use::is_simple_glob(it)); From 8b82ea4f51b0288a2e318aca352cee6df06e244e Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sun, 22 Oct 2023 23:34:27 +0330 Subject: [PATCH 2333/2442] Store binding mode for each instance independently --- crates/hir-ty/src/consteval/tests.rs | 14 ++++++++++++++ crates/hir-ty/src/diagnostics/match_check.rs | 2 +- crates/hir-ty/src/infer.rs | 14 +++++++++++++- crates/hir-ty/src/infer/closure.rs | 6 +++--- crates/hir-ty/src/infer/pat.rs | 2 +- crates/hir-ty/src/mir/lower/pattern_matching.rs | 5 ++++- crates/hir/src/source_analyzer.rs | 4 ++-- .../src/handlers/moved_out_of_ref.rs | 15 +++++++++++++++ 8 files changed, 53 insertions(+), 9 deletions(-) diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 7ad3659a4f6d..b395e7f4a813 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -1159,6 +1159,20 @@ fn pattern_matching_slice() { "#, 33213, ); + check_number( + r#" + //- minicore: slice, index, coerce_unsized, copy + const fn f(mut slice: &[u32]) -> usize { + slice = match slice { + [0, rest @ ..] | rest => rest, + }; + slice.len() + } + const GOAL: usize = f(&[]) + f(&[10]) + f(&[0, 100]) + + f(&[1000, 1000, 1000]) + f(&[0, 57, 34, 46, 10000, 10000]); + "#, + 10, + ); } #[test] diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs index f8cdeaa5e354..2e04bbfee83b 100644 --- a/crates/hir-ty/src/diagnostics/match_check.rs +++ b/crates/hir-ty/src/diagnostics/match_check.rs @@ -147,7 +147,7 @@ impl<'a> PatCtxt<'a> { } hir_def::hir::Pat::Bind { id, subpat, .. } => { - let bm = self.infer.binding_modes[id]; + let bm = self.infer.binding_modes[pat]; ty = &self.infer[id]; let name = &self.body.bindings[id].name; match (bm, ty.kind(Interner)) { diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 78d3c667a1f8..3d5ed1f93c0f 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -420,7 +420,19 @@ pub struct InferenceResult { standard_types: InternedStandardTypes, /// Stores the types which were implicitly dereferenced in pattern binding modes. pub pat_adjustments: FxHashMap>, - pub binding_modes: ArenaMap, + /// Stores the binding mode (`ref` in `let ref x = 2`) of bindings. + /// + /// This one is tied to the `PatId` instead of `BindingId`, because in some rare cases, a binding in an + /// or pattern can have multiple binding modes. For example: + /// ``` + /// fn foo(mut slice: &[u32]) -> usize { + /// slice = match slice { + /// [0, rest @ ..] | rest => rest, + /// }; + /// } + /// ``` + /// the first `rest` has implicit `ref` binding mode, but the second `rest` binding mode is `move`. + pub binding_modes: ArenaMap, pub expr_adjustments: FxHashMap>, pub(crate) closure_info: FxHashMap, FnTrait)>, // FIXME: remove this field diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 13d6b5643ac4..0805e20447a7 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -679,7 +679,7 @@ impl InferenceContext<'_> { | Pat::Range { .. } => { update_result(CaptureKind::ByRef(BorrowKind::Shared)); } - Pat::Bind { id, .. } => match self.result.binding_modes[*id] { + Pat::Bind { id, .. } => match self.result.binding_modes[p] { crate::BindingMode::Move => { if self.is_ty_copy(self.result.type_of_binding[*id].clone()) { update_result(CaptureKind::ByRef(BorrowKind::Shared)); @@ -838,8 +838,8 @@ impl InferenceContext<'_> { | Pat::ConstBlock(_) | Pat::Path(_) | Pat::Lit(_) => self.consume_place(place, pat.into()), - Pat::Bind { id, subpat: _ } => { - let mode = self.result.binding_modes[*id]; + Pat::Bind { id: _, subpat: _ } => { + let mode = self.result.binding_modes[pat]; let capture_kind = match mode { BindingMode::Move => { self.consume_place(place, pat.into()); diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs index 4e28ec06023e..7ff12e5b7f85 100644 --- a/crates/hir-ty/src/infer/pat.rs +++ b/crates/hir-ty/src/infer/pat.rs @@ -421,7 +421,7 @@ impl InferenceContext<'_> { } else { BindingMode::convert(mode) }; - self.result.binding_modes.insert(binding, mode); + self.result.binding_modes.insert(pat, mode); let inner_ty = match subpat { Some(subpat) => self.infer_pat(subpat, &expected, default_bm), diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs index 270f75ad9674..1120bb1c1123 100644 --- a/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -284,6 +284,7 @@ impl MirLowerCtx<'_> { ); (current, current_else) = self.pattern_match_binding( id, + *slice, next_place, (*slice).into(), current, @@ -395,6 +396,7 @@ impl MirLowerCtx<'_> { if mode == MatchingMode::Bind { self.pattern_match_binding( *id, + pattern, cond_place, pattern.into(), current, @@ -431,13 +433,14 @@ impl MirLowerCtx<'_> { fn pattern_match_binding( &mut self, id: BindingId, + pat: PatId, cond_place: Place, span: MirSpan, current: BasicBlockId, current_else: Option, ) -> Result<(BasicBlockId, Option)> { let target_place = self.binding_local(id)?; - let mode = self.infer.binding_modes[id]; + let mode = self.infer.binding_modes[pat]; self.push_storage_live(id, current)?; self.push_assignment( current, diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 8d8ba48ad923..55c2f8324c6d 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -236,9 +236,9 @@ impl SourceAnalyzer { _db: &dyn HirDatabase, pat: &ast::IdentPat, ) -> Option { - let binding_id = self.binding_id_of_pat(pat)?; + let id = self.pat_id(&pat.clone().into())?; let infer = self.infer.as_ref()?; - infer.binding_modes.get(binding_id).map(|bm| match bm { + infer.binding_modes.get(id).map(|bm| match bm { hir_ty::BindingMode::Move => BindingMode::Move, hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut), hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => { diff --git a/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs index 20175b3fd535..886aefeb575f 100644 --- a/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs +++ b/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs @@ -175,4 +175,19 @@ fn main() { "#, ); } + + #[test] + fn regression_15787() { + check_diagnostics( + r#" +//- minicore: coerce_unsized, slice, copy +fn foo(mut slice: &[u32]) -> usize { + slice = match slice { + [0, rest @ ..] | rest => rest, + }; + slice.len() +} +"#, + ); + } } From 45ee88f9cb7536a725c359efc89b73c904d5d0aa Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Mon, 23 Oct 2023 23:12:07 +0800 Subject: [PATCH 2334/2442] fix: remove unwrap --- .../src/handlers/unqualify_method_call.rs | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/crates/ide-assists/src/handlers/unqualify_method_call.rs b/crates/ide-assists/src/handlers/unqualify_method_call.rs index e1f812b0bfda..0bf1782a489d 100644 --- a/crates/ide-assists/src/handlers/unqualify_method_call.rs +++ b/crates/ide-assists/src/handlers/unqualify_method_call.rs @@ -89,31 +89,38 @@ fn add_import( ctx: &AssistContext<'_>, edit: &mut ide_db::source_change::SourceChangeBuilder, ) { - // for `` - let path_type = - qualifier.segment().unwrap().syntax().children().filter_map(ast::PathType::cast).last(); - let import = match path_type { - Some(it) => it.path().unwrap(), - None => qualifier, - }; - - // in case for `<_>` - if import.coloncolon_token().is_none() { - return; - } - - let scope = ide_db::imports::insert_use::ImportScope::find_insert_use_container( - import.syntax(), - &ctx.sema, - ); - - if let Some(scope) = scope { - let scope = match scope { - ImportScope::File(it) => ImportScope::File(edit.make_mut(it)), - ImportScope::Module(it) => ImportScope::Module(edit.make_mut(it)), - ImportScope::Block(it) => ImportScope::Block(edit.make_mut(it)), + if let Some(path_segment) = qualifier.segment() { + // for `` + let path_type = path_segment.syntax().children().filter_map(ast::PathType::cast).last(); + let import = match path_type { + Some(it) => { + if let Some(path) = it.path() { + path + } else { + return; + } + } + None => qualifier, }; - ide_db::imports::insert_use::insert_use(&scope, import, &ctx.config.insert_use); + + // in case for `<_>` + if import.coloncolon_token().is_none() { + return; + } + + let scope = ide_db::imports::insert_use::ImportScope::find_insert_use_container( + import.syntax(), + &ctx.sema, + ); + + if let Some(scope) = scope { + let scope = match scope { + ImportScope::File(it) => ImportScope::File(edit.make_mut(it)), + ImportScope::Module(it) => ImportScope::Module(edit.make_mut(it)), + ImportScope::Block(it) => ImportScope::Block(edit.make_mut(it)), + }; + ide_db::imports::insert_use::insert_use(&scope, import, &ctx.config.insert_use); + } } } From 99ec3aa8a34695a9c6889959edf1691dd08bfcdb Mon Sep 17 00:00:00 2001 From: Roberto Bampi Date: Thu, 26 Oct 2023 16:16:38 +0200 Subject: [PATCH 2335/2442] scip: update crate to version 0.3.1. While the git repo has been updated constantly, crates.io has only now been updated after more than a year of activity. --- Cargo.lock | 12 ++++++------ crates/rust-analyzer/Cargo.toml | 2 +- crates/rust-analyzer/src/cli/scip.rs | 6 ++++++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a56bddb76ca..0a3d38645f52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1405,9 +1405,9 @@ dependencies = [ [[package]] name = "protobuf" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee4a7d8b91800c8f167a6268d1a1026607368e1adc84e98fe044aeb905302f7" +checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e" dependencies = [ "once_cell", "protobuf-support", @@ -1416,9 +1416,9 @@ dependencies = [ [[package]] name = "protobuf-support" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca157fe12fc7ee2e315f2f735e27df41b3d97cdd70ea112824dac1ffb08ee1c" +checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372" dependencies = [ "thiserror", ] @@ -1671,9 +1671,9 @@ dependencies = [ [[package]] name = "scip" -version = "0.1.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bfbb10286f69fad7c78db71004b7839bf957788359fe0c479f029f9849136b" +checksum = "3e84d21062a3ba08d58870c8c36b0c005b2b2261c6ad1bf7042585427c781883" dependencies = [ "protobuf", ] diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 0a5412c638c3..ee5df984b68e 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -23,7 +23,7 @@ anyhow = "1.0.62" crossbeam-channel = "0.5.5" dissimilar = "1.0.4" itertools = "0.10.5" -scip = "0.1.1" +scip = "0.3.1" lsp-types = { version = "=0.94.0", features = ["proposed"] } parking_lot = "0.12.1" xflags = "0.3.0" diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs index b058e6d153f0..30e11402cd8d 100644 --- a/crates/rust-analyzer/src/cli/scip.rs +++ b/crates/rust-analyzer/src/cli/scip.rs @@ -133,6 +133,10 @@ impl flags::Scip { documentation: documentation.unwrap_or_default(), relationships: Vec::new(), special_fields: Default::default(), + kind: Default::default(), + display_name: String::new(), + signature_documentation: Default::default(), + enclosing_symbol: String::new(), }; symbols.push(symbol_info) @@ -147,6 +151,7 @@ impl flags::Scip { syntax_kind: Default::default(), diagnostics: Vec::new(), special_fields: Default::default(), + enclosing_range: Vec::new(), }); }); @@ -160,6 +165,7 @@ impl flags::Scip { occurrences, symbols, special_fields: Default::default(), + text: String::new(), }); } From 00cdbe6c963310ce174e723ccf22262ab08b04f9 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Fri, 27 Oct 2023 21:16:34 +0800 Subject: [PATCH 2336/2442] feat: make extract_variable assist in place --- .../src/handlers/extract_variable.rs | 135 ++++++++++++++++-- 1 file changed, 125 insertions(+), 10 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_variable.rs b/crates/ide-assists/src/handlers/extract_variable.rs index 014c23197fac..7aaa8c0778fe 100644 --- a/crates/ide-assists/src/handlers/extract_variable.rs +++ b/crates/ide-assists/src/handlers/extract_variable.rs @@ -29,22 +29,31 @@ use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; // } // ``` pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - if ctx.has_empty_selection() { - return None; - } - - let node = match ctx.covering_element() { - NodeOrToken::Node(it) => it, - NodeOrToken::Token(it) if it.kind() == COMMENT => { - cov_mark::hit!(extract_var_in_comment_is_not_applicable); + let node = if ctx.has_empty_selection() { + if let Some(expr_stmt) = ctx.find_node_at_offset::() { + expr_stmt.syntax().clone() + } else if let Some(expr) = ctx.find_node_at_offset::() { + expr.syntax().ancestors().find_map(valid_target_expr)?.syntax().clone() + } else { return None; } - NodeOrToken::Token(it) => it.parent()?, + } else { + match ctx.covering_element() { + NodeOrToken::Node(it) => it, + NodeOrToken::Token(it) if it.kind() == COMMENT => { + cov_mark::hit!(extract_var_in_comment_is_not_applicable); + return None; + } + NodeOrToken::Token(it) => it.parent()?, + } }; + let node = node.ancestors().take_while(|anc| anc.text_range() == node.text_range()).last()?; + let range = node.text_range(); + let to_extract = node .descendants() - .take_while(|it| ctx.selection_trimmed().contains_range(it.text_range())) + .take_while(|it| range.contains_range(it.text_range())) .find_map(valid_target_expr)?; let ty = ctx.sema.type_of_expr(&to_extract).map(TypeInfo::adjusted); @@ -235,6 +244,112 @@ mod tests { use super::*; + #[test] + fn test_extract_var_simple_without_select() { + check_assist( + extract_variable, + r#" +fn main() -> i32 { + if true { + 1 + } else { + 2 + }$0 +} +"#, + r#" +fn main() -> i32 { + let $0var_name = if true { + 1 + } else { + 2 + }; + var_name +} +"#, + ); + + check_assist( + extract_variable, + r#" +fn foo() -> i32 { 1 } +fn main() { + foo();$0 +} +"#, + r#" +fn foo() -> i32 { 1 } +fn main() { + let $0foo = foo(); +} +"#, + ); + + check_assist( + extract_variable, + r#" +fn main() { + let a = Some(2); + a.is_some();$0 +} +"#, + r#" +fn main() { + let a = Some(2); + let $0is_some = a.is_some(); +} +"#, + ); + + check_assist( + extract_variable, + r#" +fn main() { + "hello"$0; +} +"#, + r#" +fn main() { + let $0var_name = "hello"; +} +"#, + ); + + check_assist( + extract_variable, + r#" +fn main() { + 1 + 2$0; +} +"#, + r#" +fn main() { + let $0var_name = 1 + 2; +} +"#, + ); + + check_assist( + extract_variable, + r#" +fn main() { + match () { + () if true => 1, + _ => 2, + };$0 +} +"#, + r#" +fn main() { + let $0var_name = match () { + () if true => 1, + _ => 2, + }; +} +"#, + ); + } + #[test] fn test_extract_var_simple() { check_assist( From 7186a287173cfa17c968b7b4248d58199d96ed14 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Sat, 28 Oct 2023 10:06:09 +0800 Subject: [PATCH 2337/2442] chore: add unapplicable test for extract_variable without select --- .../src/handlers/extract_variable.rs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/crates/ide-assists/src/handlers/extract_variable.rs b/crates/ide-assists/src/handlers/extract_variable.rs index 7aaa8c0778fe..e7c884dcb706 100644 --- a/crates/ide-assists/src/handlers/extract_variable.rs +++ b/crates/ide-assists/src/handlers/extract_variable.rs @@ -350,6 +350,32 @@ fn main() { ); } + #[test] + fn test_extract_var_unit_expr_without_select_not_applicable() { + check_assist_not_applicable( + extract_variable, + r#" +fn foo() {} +fn main() { + foo()$0; +} +"#, + ); + + check_assist_not_applicable( + extract_variable, + r#" +fn foo() { + let mut i = 3; + if i >= 0 { + i += 1; + } else { + i -= 1; + }$0 +}"#, + ); + } + #[test] fn test_extract_var_simple() { check_assist( From 3e4de963a2f932a4591b037e6b5933ac5903b7e3 Mon Sep 17 00:00:00 2001 From: jprochazk <1665677+jprochazk@users.noreply.github.com> Date: Sat, 28 Oct 2023 16:34:00 +0200 Subject: [PATCH 2338/2442] override language client --- editors/code/src/base_client.ts | 12 ++++++++++++ editors/code/src/client.ts | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 editors/code/src/base_client.ts diff --git a/editors/code/src/base_client.ts b/editors/code/src/base_client.ts new file mode 100644 index 000000000000..085920fb6603 --- /dev/null +++ b/editors/code/src/base_client.ts @@ -0,0 +1,12 @@ +import * as lc from "vscode-languageclient/node"; + +export class RaLanguageClient extends lc.LanguageClient { + override error(message: string, data?: any, showNotification?: boolean | "force"): void { + // ignore `Request TYPE failed.` errors + if (message.startsWith("Request") && message.endsWith("failed.")) { + return; + } + + super.error(message, data, showNotification); + } +} diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 96e888402baf..ed7066a1b7ba 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -10,6 +10,7 @@ import { type Config, prepareVSCodeConfig } from "./config"; import { randomUUID } from "crypto"; import { sep as pathSeparator } from "path"; import { unwrapUndefinable } from "./undefinable"; +import { RaLanguageClient } from "./base_client"; export interface Env { [name: string]: string; @@ -363,7 +364,7 @@ export async function createClient( }, }; - const client = new lc.LanguageClient( + const client = new RaLanguageClient( "rust-analyzer", "Rust Analyzer Language Server", serverOptions, From 9c99afe3aa4bbab8da3d69fef66b399cb8c15304 Mon Sep 17 00:00:00 2001 From: cui fliter Date: Sun, 29 Oct 2023 11:50:40 +0800 Subject: [PATCH 2339/2442] Fix some typos Signed-off-by: cui fliter --- crates/hir-ty/src/mir/eval.rs | 4 ++-- crates/rust-analyzer/src/handlers/request.rs | 2 +- crates/syntax/src/tests/sourcegen_ast.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 7823c3203413..62efb858511b 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -162,7 +162,7 @@ pub struct Evaluator<'a> { not_special_fn_cache: RefCell>, mir_or_dyn_index_cache: RefCell>, /// Constantly dropping and creating `Locals` is very costly. We store - /// old locals that we normaly want to drop here, to reuse their allocations + /// old locals that we normally want to drop here, to reuse their allocations /// later. unused_locals_store: RefCell>>, cached_ptr_size: usize, @@ -2299,7 +2299,7 @@ impl Evaluator<'_> { match self.get_mir_or_dyn_index(def, generic_args.clone(), locals, span)? { MirOrDynIndex::Dyn(self_ty_idx) => { // In the layout of current possible receiver, which at the moment of writing this code is one of - // `&T`, `&mut T`, `Box`, `Rc`, `Arc`, and `Pin

` where `P` is one of possible recievers, + // `&T`, `&mut T`, `Box`, `Rc`, `Arc`, and `Pin

` where `P` is one of possible receivers, // the vtable is exactly in the `[ptr_size..2*ptr_size]` bytes. So we can use it without branching on // the type. let first_arg = arg_bytes.clone().next().unwrap(); diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index 6c2f1ec3fede..06c27332d440 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -2000,7 +2000,7 @@ fn run_rustfmt( let workspace = CargoTargetSpec::for_file(&snap, file_id)?; let mut cmd = match workspace { Some(spec) => { - // approach: if the command name contains a path seperator, join it with the workspace root. + // approach: if the command name contains a path separator, join it with the workspace root. // however, if the path is absolute, joining will result in the absolute path being preserved. // as a fallback, rely on $PATH-based discovery. let cmd_path = diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs index 56227fce9b5c..74798952a3ff 100644 --- a/crates/syntax/src/tests/sourcegen_ast.rs +++ b/crates/syntax/src/tests/sourcegen_ast.rs @@ -623,7 +623,7 @@ fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option> { } fn lower_rule(acc: &mut Vec, grammar: &Grammar, label: Option<&String>, rule: &Rule) { - if lower_seperated_list(acc, grammar, label, rule) { + if lower_separated_list(acc, grammar, label, rule) { return; } @@ -689,7 +689,7 @@ fn lower_rule(acc: &mut Vec, grammar: &Grammar, label: Option<&String>, r } // (T (',' T)* ','?) -fn lower_seperated_list( +fn lower_separated_list( acc: &mut Vec, grammar: &Grammar, label: Option<&String>, From 9d290f1d4c45d4459b51f26c3df26025e23e21b1 Mon Sep 17 00:00:00 2001 From: Sarrus1 Date: Mon, 30 Oct 2023 19:40:24 +0100 Subject: [PATCH 2340/2442] chore: fix urls in guide.md --- docs/dev/guide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dev/guide.md b/docs/dev/guide.md index 56a68ef04379..a5f1811bf24a 100644 --- a/docs/dev/guide.md +++ b/docs/dev/guide.md @@ -272,7 +272,7 @@ several times, with different sets of `cfg`s enabled. The IDE-specific task of mapping source code into a semantic model is inherently imprecise for this reason and gets handled by the [`source_binder`]. -[`source_binder`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/source_binder.rs +[`source_binder`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/source_binder.rs The semantic interface is declared in the [`code_model_api`] module. Each entity is identified by an integer ID and has a bunch of methods which take a salsa database @@ -280,8 +280,8 @@ as an argument and returns other entities (which are also IDs). Internally, thes methods invoke various queries on the database to build the model on demand. Here's [the list of queries]. -[`code_model_api`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/code_model_api.rs -[the list of queries]: https://github.com/rust-lang/rust-analyzer/blob/7e84440e25e19529e4ff8a66e521d1b06349c6ec/crates/hir/src/db.rs#L20-L106 +[`code_model_api`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/code_model_api.rs +[the list of queries]: https://github.com/rust-lang/rust-analyzer/blob/7e84440e25e19529e4ff8a66e521d1b06349c6ec/crates/ra_hir/src/db.rs#L20-L106 The first step of building the model is parsing the source code. From a723acf3469e4585a3da2b230e67afe4683d92a2 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Tue, 31 Oct 2023 21:03:26 +0800 Subject: [PATCH 2341/2442] simplify the code --- crates/ide-db/src/imports/insert_use.rs | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/crates/ide-db/src/imports/insert_use.rs b/crates/ide-db/src/imports/insert_use.rs index 6caa6e3511cd..a0cfd3836ddf 100644 --- a/crates/ide-db/src/imports/insert_use.rs +++ b/crates/ide-db/src/imports/insert_use.rs @@ -9,7 +9,7 @@ use syntax::{ algo, ast::{ self, edit_in_place::Removable, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, - PathSegmentKind, Rename, UseTree, + PathSegmentKind, UseTree, }, ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode, }; @@ -163,16 +163,12 @@ pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) { pub fn insert_use_as_alias(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) { let text: &str = "use foo as _"; let parse = syntax::SourceFile::parse(text); - let node = match parse.tree().syntax().descendants().find_map(UseTree::cast) { - Some(it) => it, - None => { - panic!( - "Failed to make ast node `{}` from text {}", - std::any::type_name::(), - text - ) - } - }; + let node = parse + .tree() + .syntax() + .descendants() + .find_map(UseTree::cast) + .expect("Failed to make ast node `Rename`"); let alias = node.rename(); insert_use_with_alias_option(scope, path, cfg, alias); @@ -202,11 +198,8 @@ fn insert_use_with_alias_option( }; } - let use_item = if alias.is_some() { - make::use_(None, make::use_tree(path.clone(), None, alias, false)).clone_for_update() - } else { - make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update() - }; + let use_item = + make::use_(None, make::use_tree(path.clone(), None, alias, false)).clone_for_update(); // merge into existing imports if possible if let Some(mb) = mb { From 929544ef2886a0823868ac9b7011c516ce697476 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Tue, 31 Oct 2023 22:13:07 +0800 Subject: [PATCH 2342/2442] use `check_assist_by_label` to pick assist --- .../ide-assists/src/handlers/auto_import.rs | 220 +++++++++++++++++- 1 file changed, 213 insertions(+), 7 deletions(-) diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs index a2efa4d10bd6..cafd57a97727 100644 --- a/crates/ide-assists/src/handlers/auto_import.rs +++ b/crates/ide-assists/src/handlers/auto_import.rs @@ -287,7 +287,8 @@ mod tests { }; use crate::tests::{ - check_assist, check_assist_not_applicable, check_assist_target, TEST_CONFIG, + check_assist, check_assist_by_label, check_assist_not_applicable, check_assist_target, + TEST_CONFIG, }; fn check_auto_import_order(before: &str, order: &[&str]) { @@ -739,7 +740,44 @@ fn main() { #[test] fn associated_trait_function() { - check_assist( + check_assist_by_label( + auto_import, + r" + mod test_mod { + pub trait TestTrait { + fn test_function(); + } + pub struct TestStruct {} + impl TestTrait for TestStruct { + fn test_function() {} + } + } + + fn main() { + test_mod::TestStruct::test_function$0 + } + ", + r" + use test_mod::TestTrait; + + mod test_mod { + pub trait TestTrait { + fn test_function(); + } + pub struct TestStruct {} + impl TestTrait for TestStruct { + fn test_function() {} + } + } + + fn main() { + test_mod::TestStruct::test_function + } + ", + "Import `test_mod::TestTrait`", + ); + + check_assist_by_label( auto_import, r" mod test_mod { @@ -773,6 +811,7 @@ fn main() { test_mod::TestStruct::test_function } ", + "Import `test_mod::TestTrait as _`", ); } @@ -810,7 +849,7 @@ fn main() { #[test] fn associated_trait_const() { - check_assist( + check_assist_by_label( auto_import, r" mod test_mod { @@ -844,6 +883,44 @@ fn main() { test_mod::TestStruct::TEST_CONST } ", + "Import `test_mod::TestTrait as _`", + ); + + check_assist_by_label( + auto_import, + r" + mod test_mod { + pub trait TestTrait { + const TEST_CONST: u8; + } + pub struct TestStruct {} + impl TestTrait for TestStruct { + const TEST_CONST: u8 = 42; + } + } + + fn main() { + test_mod::TestStruct::TEST_CONST$0 + } + ", + r" + use test_mod::TestTrait; + + mod test_mod { + pub trait TestTrait { + const TEST_CONST: u8; + } + pub struct TestStruct {} + impl TestTrait for TestStruct { + const TEST_CONST: u8 = 42; + } + } + + fn main() { + test_mod::TestStruct::TEST_CONST + } + ", + "Import `test_mod::TestTrait`", ); } @@ -881,7 +958,7 @@ fn main() { #[test] fn trait_method() { - check_assist( + check_assist_by_label( auto_import, r" mod test_mod { @@ -917,12 +994,52 @@ fn main() { test_struct.test_method() } ", + "Import `test_mod::TestTrait as _`", + ); + + check_assist_by_label( + auto_import, + r" + mod test_mod { + pub trait TestTrait { + fn test_method(&self); + } + pub struct TestStruct {} + impl TestTrait for TestStruct { + fn test_method(&self) {} + } + } + + fn main() { + let test_struct = test_mod::TestStruct {}; + test_struct.test_meth$0od() + } + ", + r" + use test_mod::TestTrait; + + mod test_mod { + pub trait TestTrait { + fn test_method(&self); + } + pub struct TestStruct {} + impl TestTrait for TestStruct { + fn test_method(&self) {} + } + } + + fn main() { + let test_struct = test_mod::TestStruct {}; + test_struct.test_method() + } + ", + "Import `test_mod::TestTrait`", ); } #[test] fn trait_method_cross_crate() { - check_assist( + check_assist_by_label( auto_import, r" //- /main.rs crate:main deps:dep @@ -949,12 +1066,43 @@ fn main() { test_struct.test_method() } ", + "Import `dep::test_mod::TestTrait as _`", + ); + + check_assist_by_label( + auto_import, + r" + //- /main.rs crate:main deps:dep + fn main() { + let test_struct = dep::test_mod::TestStruct {}; + test_struct.test_meth$0od() + } + //- /dep.rs crate:dep + pub mod test_mod { + pub trait TestTrait { + fn test_method(&self); + } + pub struct TestStruct {} + impl TestTrait for TestStruct { + fn test_method(&self) {} + } + } + ", + r" + use dep::test_mod::TestTrait; + + fn main() { + let test_struct = dep::test_mod::TestStruct {}; + test_struct.test_method() + } + ", + "Import `dep::test_mod::TestTrait`", ); } #[test] fn assoc_fn_cross_crate() { - check_assist( + check_assist_by_label( auto_import, r" //- /main.rs crate:main deps:dep @@ -979,12 +1127,41 @@ fn main() { dep::test_mod::TestStruct::test_function } ", + "Import `dep::test_mod::TestTrait as _`", + ); + + check_assist_by_label( + auto_import, + r" + //- /main.rs crate:main deps:dep + fn main() { + dep::test_mod::TestStruct::test_func$0tion + } + //- /dep.rs crate:dep + pub mod test_mod { + pub trait TestTrait { + fn test_function(); + } + pub struct TestStruct {} + impl TestTrait for TestStruct { + fn test_function() {} + } + } + ", + r" + use dep::test_mod::TestTrait; + + fn main() { + dep::test_mod::TestStruct::test_function + } + ", + "Import `dep::test_mod::TestTrait`", ); } #[test] fn assoc_const_cross_crate() { - check_assist( + check_assist_by_label( auto_import, r" //- /main.rs crate:main deps:dep @@ -1009,6 +1186,35 @@ fn main() { dep::test_mod::TestStruct::CONST } ", + "Import `dep::test_mod::TestTrait as _`", + ); + + check_assist_by_label( + auto_import, + r" + //- /main.rs crate:main deps:dep + fn main() { + dep::test_mod::TestStruct::CONST$0 + } + //- /dep.rs crate:dep + pub mod test_mod { + pub trait TestTrait { + const CONST: bool; + } + pub struct TestStruct {} + impl TestTrait for TestStruct { + const CONST: bool = true; + } + } + ", + r" + use dep::test_mod::TestTrait; + + fn main() { + dep::test_mod::TestStruct::CONST + } + ", + "Import `dep::test_mod::TestTrait`", ); } From 740a864b7cd7b3f0981f2562519483b0350550a5 Mon Sep 17 00:00:00 2001 From: "luoyangze.ptrl" Date: Thu, 2 Nov 2023 00:27:11 +0800 Subject: [PATCH 2343/2442] feat: skip checking tt count for include macro call --- crates/hir-expand/src/db.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 5292a5fa1b16..80450afc331a 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -614,9 +614,25 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult { + if let Some(name_ref) = + ast_id.to_node(db).path().and_then(|p| p.segment()).and_then(|s| s.name_ref()) + { + name_ref.text() == "include" + } else { + false + } + } + _ => false, + }; + + if !skip_check_tt_count { + // Set a hard limit for the expanded tt + if let Err(value) = check_tt_count(&tt) { + return value; + } } ExpandResult { value: Arc::new(tt), err } From b76f2c8ee0d9bc5517e6d8a01d62f1add8b12c35 Mon Sep 17 00:00:00 2001 From: "luoyangze.ptrl" Date: Thu, 2 Nov 2023 10:14:54 +0800 Subject: [PATCH 2344/2442] fix: using name(include) instead of str --- crates/hir-expand/src/db.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 80450afc331a..204227e33873 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -12,11 +12,15 @@ use syntax::{ use triomphe::Arc; use crate::{ - ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, - builtin_fn_macro::EagerExpander, fixup, hygiene::HygieneFrame, tt, AstId, BuiltinAttrExpander, - BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, ExpandError, ExpandResult, - ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, - MacroDefKind, MacroFile, ProcMacroExpander, + ast_id_map::AstIdMap, + builtin_attr_macro::pseudo_derive_attr_expansion, + builtin_fn_macro::EagerExpander, + fixup, + hygiene::HygieneFrame, + name::{name, AsName}, + tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, + ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, + MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, }; /// Total limit on the number of tokens produced by any macro invocation. @@ -620,7 +624,7 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult Date: Thu, 2 Nov 2023 15:53:33 -0400 Subject: [PATCH 2345/2442] VSCode search: 'category:formatters rust' metadata. --- editors/code/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/editors/code/package.json b/editors/code/package.json index 2dde66c97006..b3e4a9ff5135 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -17,6 +17,8 @@ "rust" ], "categories": [ + "Formatters", + "Linters", "Programming Languages" ], "capabilities": { From fccdde63c9764d6332721c06247b4fc78a847d37 Mon Sep 17 00:00:00 2001 From: Peter Tripp Date: Thu, 2 Nov 2023 18:21:31 -0400 Subject: [PATCH 2346/2442] Maybe not a linter. --- editors/code/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/editors/code/package.json b/editors/code/package.json index b3e4a9ff5135..c7b877b2897c 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -18,7 +18,6 @@ ], "categories": [ "Formatters", - "Linters", "Programming Languages" ], "capabilities": { From 19bf0da9d7b35327972683ad317cb405b2e2a2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sat, 4 Nov 2023 13:33:19 +0200 Subject: [PATCH 2347/2442] Fix docs path for derive macros --- crates/ide/src/doc_links.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 37a177622162..ac15b6aba618 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -602,7 +602,17 @@ fn filename_and_frag_for_def( } Definition::Const(c) => format!("const.{}.html", c.name(db)?.display(db.upcast())), Definition::Static(s) => format!("static.{}.html", s.name(db).display(db.upcast())), - Definition::Macro(mac) => format!("macro.{}.html", mac.name(db).display(db.upcast())), + Definition::Macro(mac) => match mac.kind(db) { + hir::MacroKind::Declarative + | hir::MacroKind::BuiltIn + | hir::MacroKind::Attr + | hir::MacroKind::ProcMacro => { + format!("macro.{}.html", mac.name(db).display(db.upcast())) + } + hir::MacroKind::Derive => { + format!("derive.{}.html", mac.name(db).display(db.upcast())) + } + }, Definition::Field(field) => { let def = match field.parent_def(db) { hir::VariantDef::Struct(it) => Definition::Adt(it.into()), From 8d8d12120d057f4b0b6585147695a177178d1f70 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Sat, 4 Nov 2023 11:32:15 +0800 Subject: [PATCH 2348/2442] feat: add generate_mut_trait_impl assist --- .../src/handlers/generate_mut_trait_impl.rs | 195 ++++++++++++++++++ crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 35 ++++ crates/syntax/src/ast/make.rs | 4 + 4 files changed, 236 insertions(+) create mode 100644 crates/ide-assists/src/handlers/generate_mut_trait_impl.rs diff --git a/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs new file mode 100644 index 000000000000..ceb9d22c1b9f --- /dev/null +++ b/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs @@ -0,0 +1,195 @@ +use syntax::{ + ast::{self, make}, + ted, AstNode, +}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Generate proper `index_mut` method body refer to `index` method body may impossible due to the unpredicable case [#15581]. +// Here just leave the `index_mut` method body be same as `index` method body, user can modify it manually to meet their need. + +// Assist: generate_mut_trait_impl +// +// Adds a IndexMut impl from the `Index` trait. +// +// ``` +// pub enum Axis { X = 0, Y = 1, Z = 2 } +// +// impl Index$0 for [T; 3] { +// type Output = T; +// +// fn index(&self, index: Axis) -> &Self::Output { +// &self[index as usize] +// } +// } +// ``` +// -> +// ``` +// pub enum Axis { X = 0, Y = 1, Z = 2 } +// +// $0impl IndexMut for [T; 3] { +// fn index_mut(&mut self, index: Axis) -> &mut Self::Output { +// &self[index as usize] +// } +// } +// +// impl Index for [T; 3] { +// type Output = T; +// +// fn index(&self, index: Axis) -> &Self::Output { +// &self[index as usize] +// } +// } +// ``` +pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let impl_def = ctx.find_node_at_offset::()?.clone_for_update(); + + let trait_ = impl_def.trait_()?; + if let ast::Type::PathType(trait_type) = trait_.clone() { + let trait_name = trait_type.path()?.segment()?.name_ref()?.to_string(); + if trait_name != "Index" { + return None; + } + } + + // Index -> IndexMut + let index_trait = impl_def + .syntax() + .descendants() + .filter_map(ast::NameRef::cast) + .find(|it| it.text() == "Index")?; + ted::replace( + index_trait.syntax(), + make::path_segment(make::name_ref("IndexMut")).clone_for_update().syntax(), + ); + + // index -> index_mut + let trait_method_name = impl_def + .syntax() + .descendants() + .filter_map(ast::Name::cast) + .find(|it| it.text() == "index")?; + ted::replace(trait_method_name.syntax(), make::name("index_mut").clone_for_update().syntax()); + + let type_alias = impl_def.syntax().descendants().find_map(ast::TypeAlias::cast)?; + ted::remove(type_alias.syntax()); + + // &self -> &mut self + let mut_self_param = make::mut_self_param(); + let self_param: ast::SelfParam = + impl_def.syntax().descendants().find_map(ast::SelfParam::cast)?; + ted::replace(self_param.syntax(), mut_self_param.clone_for_update().syntax()); + + // &Self::Output -> &mut Self::Output + let ret_type = impl_def.syntax().descendants().find_map(ast::RetType::cast)?; + ted::replace( + ret_type.syntax(), + make::ret_type(make::ty("&mut Self::Output")).clone_for_update().syntax(), + ); + + let fn_ = impl_def.assoc_item_list()?.assoc_items().find_map(|it| match it { + ast::AssocItem::Fn(f) => Some(f), + _ => None, + })?; + + let assoc_list = make::assoc_item_list().clone_for_update(); + assoc_list.add_item(syntax::ast::AssocItem::Fn(fn_)); + ted::replace(impl_def.assoc_item_list()?.syntax(), assoc_list.syntax()); + + let target = impl_def.syntax().text_range(); + acc.add( + AssistId("generate_mut_trait_impl", AssistKind::Generate), + "Generate `IndexMut` impl from this `Index` trait", + target, + |edit| { + edit.insert(target.start(), format!("$0{}\n\n", impl_def.to_string())); + }, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn test_generate_mut_trait_impl() { + check_assist( + generate_mut_trait_impl, + r#" +pub enum Axis { X = 0, Y = 1, Z = 2 } + +impl Index$0 for [T; 3] { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + &self[index as usize] + } +} +"#, + r#" +pub enum Axis { X = 0, Y = 1, Z = 2 } + +$0impl IndexMut for [T; 3] { + fn index_mut(&mut self, index: Axis) -> &mut Self::Output { + &self[index as usize] + } +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + &self[index as usize] + } +} +"#, + ); + + check_assist( + generate_mut_trait_impl, + r#" +pub enum Axis { X = 0, Y = 1, Z = 2 } + +impl Index$0 for [T; 3] where T: Copy { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + let var_name = &self[index as usize]; + var_name + } +} +"#, + r#" +pub enum Axis { X = 0, Y = 1, Z = 2 } + +$0impl IndexMut for [T; 3] where T: Copy { + fn index_mut(&mut self, index: Axis) -> &mut Self::Output { + let var_name = &self[index as usize]; + var_name + } +} + +impl Index for [T; 3] where T: Copy { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + let var_name = &self[index as usize]; + var_name + } +} +"#, + ); + } + + #[test] + fn test_generate_mut_trait_impl_not_applicable() { + check_assist_not_applicable( + generate_mut_trait_impl, + r#" +impl Add$0 for [T; 3] {} +"#, + ); + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index d2b291631c8a..e6f03214ed30 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -160,6 +160,7 @@ mod handlers { mod generate_getter_or_setter; mod generate_impl; mod generate_is_empty_from_len; + mod generate_mut_trait_impl; mod generate_new; mod generate_delegate_methods; mod generate_trait_from_impl; @@ -274,6 +275,7 @@ mod handlers { generate_function::generate_function, generate_impl::generate_impl, generate_impl::generate_trait_impl, + generate_mut_trait_impl::generate_mut_trait_impl, generate_is_empty_from_len::generate_is_empty_from_len, generate_new::generate_new, generate_trait_from_impl::generate_trait_from_impl, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 8523632acfbd..f7b394d481cc 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1538,6 +1538,41 @@ impl MyStruct { ) } +#[test] +fn doctest_generate_mut_trait_impl() { + check_doc_test( + "generate_mut_trait_impl", + r#####" +pub enum Axis { X = 0, Y = 1, Z = 2 } + +impl Index$0 for [T; 3] { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + &self[index as usize] + } +} +"#####, + r#####" +pub enum Axis { X = 0, Y = 1, Z = 2 } + +$0impl IndexMut for [T; 3] { + fn index_mut(&mut self, index: Axis) -> &mut Self::Output { + &self[index as usize] + } +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + &self[index as usize] + } +} +"#####, + ) +} + #[test] fn doctest_generate_new() { check_doc_test( diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 96f685d8d6d8..31a858b91a7d 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -852,6 +852,10 @@ pub fn self_param() -> ast::SelfParam { ast_from_text("fn f(&self) { }") } +pub fn mut_self_param() -> ast::SelfParam { + ast_from_text("fn f(&mut self) { }") +} + pub fn ret_type(ty: ast::Type) -> ast::RetType { ast_from_text(&format!("fn f() -> {ty} {{ }}")) } From b84940b199c45799fc9b6b01ed30615c28e98546 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Sun, 5 Nov 2023 12:20:32 +0800 Subject: [PATCH 2349/2442] make generate_mut_trait_impl assist trigged for std trait only --- .../src/handlers/generate_mut_trait_impl.rs | 35 +++++++++++-------- crates/ide-assists/src/tests/generated.rs | 7 ++-- crates/ide-db/src/famous_defs.rs | 4 +++ 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs index ceb9d22c1b9f..cb8ef395650b 100644 --- a/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs +++ b/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs @@ -1,3 +1,4 @@ +use ide_db::famous_defs::FamousDefs; use syntax::{ ast::{self, make}, ted, AstNode, @@ -5,7 +6,7 @@ use syntax::{ use crate::{AssistContext, AssistId, AssistKind, Assists}; -// Generate proper `index_mut` method body refer to `index` method body may impossible due to the unpredicable case [#15581]. +// FIXME: Generate proper `index_mut` method body refer to `index` method body may impossible due to the unpredicable case [#15581]. // Here just leave the `index_mut` method body be same as `index` method body, user can modify it manually to meet their need. // Assist: generate_mut_trait_impl @@ -13,9 +14,10 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // Adds a IndexMut impl from the `Index` trait. // // ``` +// # //- minicore: index // pub enum Axis { X = 0, Y = 1, Z = 2 } // -// impl Index$0 for [T; 3] { +// impl core::ops::Index$0 for [T; 3] { // type Output = T; // // fn index(&self, index: Axis) -> &Self::Output { @@ -27,13 +29,13 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` // pub enum Axis { X = 0, Y = 1, Z = 2 } // -// $0impl IndexMut for [T; 3] { +// $0impl core::ops::IndexMut for [T; 3] { // fn index_mut(&mut self, index: Axis) -> &mut Self::Output { // &self[index as usize] // } // } // -// impl Index for [T; 3] { +// impl core::ops::Index for [T; 3] { // type Output = T; // // fn index(&self, index: Axis) -> &Self::Output { @@ -45,9 +47,10 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_> let impl_def = ctx.find_node_at_offset::()?.clone_for_update(); let trait_ = impl_def.trait_()?; - if let ast::Type::PathType(trait_type) = trait_.clone() { - let trait_name = trait_type.path()?.segment()?.name_ref()?.to_string(); - if trait_name != "Index" { + if let ast::Type::PathType(trait_path) = trait_.clone() { + let trait_type = ctx.sema.resolve_trait(&trait_path.path()?)?; + let scope = ctx.sema.scope(trait_path.syntax())?; + if trait_type != FamousDefs(&ctx.sema, scope.krate()).core_convert_Index()? { return None; } } @@ -118,9 +121,10 @@ mod tests { check_assist( generate_mut_trait_impl, r#" +//- minicore: index pub enum Axis { X = 0, Y = 1, Z = 2 } -impl Index$0 for [T; 3] { +impl core::ops::Index$0 for [T; 3] { type Output = T; fn index(&self, index: Axis) -> &Self::Output { @@ -131,13 +135,13 @@ impl Index$0 for [T; 3] { r#" pub enum Axis { X = 0, Y = 1, Z = 2 } -$0impl IndexMut for [T; 3] { +$0impl core::ops::IndexMut for [T; 3] { fn index_mut(&mut self, index: Axis) -> &mut Self::Output { &self[index as usize] } } -impl Index for [T; 3] { +impl core::ops::Index for [T; 3] { type Output = T; fn index(&self, index: Axis) -> &Self::Output { @@ -150,9 +154,10 @@ impl Index for [T; 3] { check_assist( generate_mut_trait_impl, r#" +//- minicore: index pub enum Axis { X = 0, Y = 1, Z = 2 } -impl Index$0 for [T; 3] where T: Copy { +impl core::ops::Index$0 for [T; 3] where T: Copy { type Output = T; fn index(&self, index: Axis) -> &Self::Output { @@ -164,14 +169,14 @@ impl Index$0 for [T; 3] where T: Copy { r#" pub enum Axis { X = 0, Y = 1, Z = 2 } -$0impl IndexMut for [T; 3] where T: Copy { +$0impl core::ops::IndexMut for [T; 3] where T: Copy { fn index_mut(&mut self, index: Axis) -> &mut Self::Output { let var_name = &self[index as usize]; var_name } } -impl Index for [T; 3] where T: Copy { +impl core::ops::Index for [T; 3] where T: Copy { type Output = T; fn index(&self, index: Axis) -> &Self::Output { @@ -188,7 +193,9 @@ impl Index for [T; 3] where T: Copy { check_assist_not_applicable( generate_mut_trait_impl, r#" -impl Add$0 for [T; 3] {} +pub trait Index {} + +impl Index$0 for [T; 3] {} "#, ); } diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index f7b394d481cc..da5822bba9c8 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1543,9 +1543,10 @@ fn doctest_generate_mut_trait_impl() { check_doc_test( "generate_mut_trait_impl", r#####" +//- minicore: index pub enum Axis { X = 0, Y = 1, Z = 2 } -impl Index$0 for [T; 3] { +impl core::ops::Index$0 for [T; 3] { type Output = T; fn index(&self, index: Axis) -> &Self::Output { @@ -1556,13 +1557,13 @@ impl Index$0 for [T; 3] { r#####" pub enum Axis { X = 0, Y = 1, Z = 2 } -$0impl IndexMut for [T; 3] { +$0impl core::ops::IndexMut for [T; 3] { fn index_mut(&mut self, index: Axis) -> &mut Self::Output { &self[index as usize] } } -impl Index for [T; 3] { +impl core::ops::Index for [T; 3] { type Output = T; fn index(&self, index: Axis) -> &Self::Output { diff --git a/crates/ide-db/src/famous_defs.rs b/crates/ide-db/src/famous_defs.rs index b63dde2c21e7..722517a7677b 100644 --- a/crates/ide-db/src/famous_defs.rs +++ b/crates/ide-db/src/famous_defs.rs @@ -54,6 +54,10 @@ impl FamousDefs<'_, '_> { self.find_trait("core:convert:Into") } + pub fn core_convert_Index(&self) -> Option { + self.find_trait("core:ops:Index") + } + pub fn core_option_Option(&self) -> Option { self.find_enum("core:option:Option") } From 13249b7dd9f6fb9acbd8629093226407d3a38690 Mon Sep 17 00:00:00 2001 From: roife Date: Tue, 7 Nov 2023 14:51:34 +0800 Subject: [PATCH 2350/2442] fix: correct a typo in a comment in base-db/lib.rs --- crates/base-db/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index af204e44e6ee..c5c4afa30f79 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -75,7 +75,7 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug { #[salsa::input] fn crate_graph(&self) -> Arc; - /// The crate graph. + /// The proc macros. #[salsa::input] fn proc_macros(&self) -> Arc; } From c566136854734ff32ddaaed107c74759a3a3862f Mon Sep 17 00:00:00 2001 From: jprochazk <1665677+jprochazk@users.noreply.github.com> Date: Tue, 7 Nov 2023 16:33:45 +0100 Subject: [PATCH 2351/2442] add configuration option --- editors/code/package.json | 5 +++++ editors/code/src/client.ts | 2 +- editors/code/src/{base_client.ts => lang_client.ts} | 6 +++++- 3 files changed, 11 insertions(+), 2 deletions(-) rename editors/code/src/{base_client.ts => lang_client.ts} (56%) diff --git a/editors/code/package.json b/editors/code/package.json index 2dde66c97006..59f89cebdeaa 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -502,6 +502,11 @@ "default": true, "type": "boolean" }, + "rust-analyzer.showRequestFailedErrorNotification": { + "markdownDescription": "Whether to show panic error notifications.", + "default": true, + "type": "boolean" + }, "rust-analyzer.showDependenciesExplorer": { "markdownDescription": "Whether to show the dependencies view.", "default": true, diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index ed7066a1b7ba..c27a446b3804 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -10,7 +10,7 @@ import { type Config, prepareVSCodeConfig } from "./config"; import { randomUUID } from "crypto"; import { sep as pathSeparator } from "path"; import { unwrapUndefinable } from "./undefinable"; -import { RaLanguageClient } from "./base_client"; +import { RaLanguageClient } from "./lang_client"; export interface Env { [name: string]: string; diff --git a/editors/code/src/base_client.ts b/editors/code/src/lang_client.ts similarity index 56% rename from editors/code/src/base_client.ts rename to editors/code/src/lang_client.ts index 085920fb6603..e28330e6dba6 100644 --- a/editors/code/src/base_client.ts +++ b/editors/code/src/lang_client.ts @@ -1,9 +1,13 @@ import * as lc from "vscode-languageclient/node"; +import * as vscode from "vscode"; export class RaLanguageClient extends lc.LanguageClient { override error(message: string, data?: any, showNotification?: boolean | "force"): void { // ignore `Request TYPE failed.` errors - if (message.startsWith("Request") && message.endsWith("failed.")) { + const showError = vscode.workspace + .getConfiguration("rust-analyzer") + .get("showRequestFailedErrorNotification"); + if (!showError && message.startsWith("Request") && message.endsWith("failed.")) { return; } From 1086b294c26a55542b65377970fc0ba23b61d7bd Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Wed, 8 Nov 2023 01:16:47 +0330 Subject: [PATCH 2352/2442] update rustc dependencies --- Cargo.lock | 34 ++++++++++++++++++++++------ crates/hir-def/src/data/adt.rs | 2 +- crates/rustc-dependencies/Cargo.toml | 6 ++--- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a3d38645f52..fcb188c0dfab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1454,12 +1454,12 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.14.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a51b7a02377b3246ec5c095b852b5cf1678bd9ed6b572b2a79efbf7ad711c292" +checksum = "7082716cb2bbcd8b5f062fe950cbbc87f3aba022d6da4168db35af6732a7f15d" dependencies = [ "bitflags 1.3.2", - "ra-ap-rustc_index", + "ra-ap-rustc_index 0.18.0", "tracing", ] @@ -1473,6 +1473,16 @@ dependencies = [ "smallvec", ] +[[package]] +name = "ra-ap-rustc_index" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e14b1fc835d6992b128a03a3f3a8365ba9f03e1c656a1670305f63f30d786d" +dependencies = [ + "arrayvec", + "smallvec", +] + [[package]] name = "ra-ap-rustc_lexer" version = "0.14.0" @@ -1483,14 +1493,24 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "ra-ap-rustc_lexer" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1762abb25eb1e37c1823f62b5da0821bbcd870812318db084c9516c2f78d2dcd" +dependencies = [ + "unicode-properties", + "unicode-xid", +] + [[package]] name = "ra-ap-rustc_parse_format" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "207b5ac1a21d4926695e03b605ffb9f63d4968e0488e9197c04c512c37303aa7" dependencies = [ - "ra-ap-rustc_index", - "ra-ap-rustc_lexer", + "ra-ap-rustc_index 0.14.0", + "ra-ap-rustc_lexer 0.14.0", ] [[package]] @@ -1614,8 +1634,8 @@ name = "rustc-dependencies" version = "0.0.0" dependencies = [ "ra-ap-rustc_abi", - "ra-ap-rustc_index", - "ra-ap-rustc_lexer", + "ra-ap-rustc_index 0.18.0", + "ra-ap-rustc_lexer 0.18.0", "ra-ap-rustc_parse_format", ] diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index 76c8d9a0c367..b163112db918 100644 --- a/crates/hir-def/src/data/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -178,7 +178,7 @@ fn parse_repr_tt(tt: &Subtree) -> Option { } } - Some(ReprOptions { int, align: max_align, pack: min_pack, flags }) + Some(ReprOptions { int, align: max_align, pack: min_pack, flags, field_shuffle_seed: 0 }) } impl StructData { diff --git a/crates/rustc-dependencies/Cargo.toml b/crates/rustc-dependencies/Cargo.toml index 7ead3d84cd3c..a313507bff31 100644 --- a/crates/rustc-dependencies/Cargo.toml +++ b/crates/rustc-dependencies/Cargo.toml @@ -11,10 +11,10 @@ authors.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ra-ap-rustc_lexer = { version = "0.14.0" } +ra-ap-rustc_lexer = { version = "0.18.0" } ra-ap-rustc_parse_format = { version = "0.14.0", default-features = false } -ra-ap-rustc_index = { version = "0.14.0", default-features = false } -ra-ap-rustc_abi = { version = "0.14.0", default-features = false } +ra-ap-rustc_index = { version = "0.18.0", default-features = false } +ra-ap-rustc_abi = { version = "0.18.0", default-features = false } [features] in-rust-tree = [] From 41bcd542e21f6f51446362b645474517610b3f85 Mon Sep 17 00:00:00 2001 From: YangzeLuo Date: Wed, 8 Nov 2023 21:45:32 +0800 Subject: [PATCH 2353/2442] feat: preview adt field when hover --- crates/hir/src/display.rs | 59 ++++++++++++++++++++++++++++++++- crates/ide/src/hover/tests.rs | 61 +++++++++++++++++++++-------------- 2 files changed, 94 insertions(+), 26 deletions(-) diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index ac171026d5d7..cf3ff62fc6c5 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -1,6 +1,6 @@ //! HirDisplay implementations for various hir types. use hir_def::{ - data::adt::VariantData, + data::adt::{StructKind, VariantData}, generics::{ TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, }, @@ -163,7 +163,40 @@ impl HirDisplay for Struct { write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let def_id = GenericDefId::AdtId(AdtId::StructId(self.id)); write_generic_params(def_id, f)?; + + let variant_data = self.variant_data(f.db); + if let StructKind::Tuple = variant_data.kind() { + f.write_char('(')?; + let mut it = variant_data.fields().iter().peekable(); + + while let Some((id, _)) = it.next() { + let field = Field { parent: (*self).into(), id }; + field.ty(f.db).hir_fmt(f)?; + if it.peek().is_some() { + f.write_str(", ")?; + } + } + + f.write_str(");")?; + } + write_where_clause(def_id, f)?; + + if let StructKind::Record = variant_data.kind() { + let fields = self.fields(f.db); + if fields.is_empty() { + f.write_str(" {}")?; + } else { + f.write_str(" {\n")?; + for field in self.fields(f.db) { + f.write_str(" ")?; + field.hir_fmt(f)?; + f.write_str(",\n")?; + } + f.write_str("}")?; + } + } + Ok(()) } } @@ -176,6 +209,18 @@ impl HirDisplay for Enum { let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id)); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; + + let variants = self.variants(f.db); + if !variants.is_empty() { + f.write_str(" {\n")?; + for variant in variants { + f.write_str(" ")?; + variant.hir_fmt(f)?; + f.write_str(",\n")?; + } + f.write_str("}")?; + } + Ok(()) } } @@ -188,6 +233,18 @@ impl HirDisplay for Union { let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id)); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; + + let fields = self.fields(f.db); + if !fields.is_empty() { + f.write_str(" {\n")?; + for field in self.fields(f.db) { + f.write_str(" ")?; + field.hir_fmt(f)?; + f.write_str(",\n")?; + } + f.write_str("}")?; + } + Ok(()) } } diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index e54bc48d555b..d3d492f3fdef 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -1136,7 +1136,9 @@ impl Thing { ``` ```rust - struct Thing + struct Thing { + x: u32, + } ``` "#]], ); @@ -1155,7 +1157,9 @@ impl Thing { ``` ```rust - struct Thing + struct Thing { + x: u32, + } ``` "#]], ); @@ -1174,7 +1178,9 @@ impl Thing { ``` ```rust - enum Thing + enum Thing { + A, + } ``` "#]], ); @@ -1193,7 +1199,9 @@ impl Thing { ``` ```rust - enum Thing + enum Thing { + A, + } ``` "#]], ); @@ -2005,7 +2013,10 @@ fn test_hover_layout_of_enum() { ``` ```rust - enum Foo // size = 16 (0x10), align = 8, niches = 254 + enum Foo { + Variant1(u8, u16), + Variant2(i32, u8, i64), + } // size = 16 (0x10), align = 8, niches = 254 ``` "#]], ); @@ -2346,7 +2357,7 @@ fn main() { let s$0t = S{ f1:0 }; } focus_range: 7..8, name: "S", kind: Struct, - description: "struct S", + description: "struct S {\n f1: u32,\n}", }, }, ], @@ -2379,7 +2390,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; } focus_range: 24..25, name: "S", kind: Struct, - description: "struct S", + description: "struct S {\n f1: T,\n}", }, }, HoverGotoTypeData { @@ -2392,7 +2403,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; } focus_range: 7..10, name: "Arg", kind: Struct, - description: "struct Arg", + description: "struct Arg(u32);", }, }, ], @@ -2438,7 +2449,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } focus_range: 24..25, name: "S", kind: Struct, - description: "struct S", + description: "struct S {\n f1: T,\n}", }, }, HoverGotoTypeData { @@ -2451,7 +2462,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } focus_range: 7..10, name: "Arg", kind: Struct, - description: "struct Arg", + description: "struct Arg(u32);", }, }, ], @@ -2487,7 +2498,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); } focus_range: 7..8, name: "A", kind: Struct, - description: "struct A", + description: "struct A(u32);", }, }, HoverGotoTypeData { @@ -2500,7 +2511,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); } focus_range: 22..23, name: "B", kind: Struct, - description: "struct B", + description: "struct B(u32);", }, }, HoverGotoTypeData { @@ -2514,7 +2525,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); } name: "C", kind: Struct, container_name: "M", - description: "pub struct C", + description: "pub struct C(u32);", }, }, ], @@ -2704,7 +2715,7 @@ fn main() { let s$0t = foo(); } focus_range: 39..41, name: "S1", kind: Struct, - description: "struct S1", + description: "struct S1 {}", }, }, HoverGotoTypeData { @@ -2717,7 +2728,7 @@ fn main() { let s$0t = foo(); } focus_range: 52..54, name: "S2", kind: Struct, - description: "struct S2", + description: "struct S2 {}", }, }, ], @@ -2808,7 +2819,7 @@ fn foo(ar$0g: &impl Foo + Bar) {} focus_range: 36..37, name: "S", kind: Struct, - description: "struct S", + description: "struct S {}", }, }, ], @@ -2908,7 +2919,7 @@ fn foo(ar$0g: &impl Foo) {} focus_range: 23..24, name: "S", kind: Struct, - description: "struct S", + description: "struct S {}", }, }, ], @@ -2945,7 +2956,7 @@ fn main() { let s$0t = foo(); } focus_range: 49..50, name: "B", kind: Struct, - description: "struct B", + description: "struct B {}", }, }, HoverGotoTypeData { @@ -3034,7 +3045,7 @@ fn foo(ar$0g: &dyn Foo) {} focus_range: 23..24, name: "S", kind: Struct, - description: "struct S", + description: "struct S {}", }, }, ], @@ -3082,7 +3093,7 @@ fn foo(a$0rg: &impl ImplTrait>>>) {} focus_range: 50..51, name: "B", kind: Struct, - description: "struct B", + description: "struct B {}", }, }, HoverGotoTypeData { @@ -3108,7 +3119,7 @@ fn foo(a$0rg: &impl ImplTrait>>>) {} focus_range: 65..66, name: "S", kind: Struct, - description: "struct S", + description: "struct S {}", }, }, ], @@ -3335,7 +3346,7 @@ struct S$0T(T); ``` ```rust - struct ST + struct ST(T); ``` "#]], ); @@ -3356,7 +3367,7 @@ struct S$0T(T); ``` ```rust - struct ST + struct ST(T); ``` "#]], ); @@ -3378,7 +3389,7 @@ struct S$0T(T); ``` ```rust - struct ST + struct ST(T); ``` "#]], ); @@ -5935,7 +5946,7 @@ pub struct Foo(i32); ``` ```rust - pub struct Foo // size = 4, align = 4 + pub struct Foo(i32); // size = 4, align = 4 ``` --- From fa7a91844aead43eaee397f972faed1ac43591c6 Mon Sep 17 00:00:00 2001 From: Gaxx Date: Wed, 8 Nov 2023 16:29:21 -0800 Subject: [PATCH 2354/2442] Try to update parser doc --- crates/parser/src/event.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/crates/parser/src/event.rs b/crates/parser/src/event.rs index 577eb0967b42..e38571dd3ec6 100644 --- a/crates/parser/src/event.rs +++ b/crates/parser/src/event.rs @@ -2,11 +2,6 @@ //! It is intended to be completely decoupled from the //! parser, so as to allow to evolve the tree representation //! and the parser algorithm independently. -//! -//! The `TreeSink` trait is the bridge between the parser and the -//! tree builder: the parser produces a stream of events like -//! `start node`, `finish node`, and `FileBuilder` converts -//! this stream to a real tree. use std::mem; use crate::{ From b0101da1166b1a813b3853b3043dfe85f1081fdb Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Thu, 9 Nov 2023 02:12:53 +0100 Subject: [PATCH 2355/2442] Ignore doc(hidden) attr if no body is present --- .../src/handlers/add_missing_impl_members.rs | 31 +++++++++++++++++++ crates/ide-assists/src/utils.rs | 14 +++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index c0e5429a22c9..410c623109ea 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -2245,6 +2245,37 @@ impl b::LocalTrait for B { fn no_skip_default_2() -> Option<()> { todo!() } +} + "#, + ) + } + + #[test] + fn doc_hidden_nondefault_member() { + check_assist( + add_missing_impl_members, + r#" +//- /lib.rs crate:b new_source_root:local +trait LocalTrait { + #[doc(hidden)] + fn no_skip_non_default() -> Option<()>; + + #[doc(hidden)] + fn skip_default() -> Option<()> { + todo!() + } +} + +//- /main.rs crate:a deps:b +struct B; +impl b::Loc$0alTrait for B {} + "#, + r#" +struct B; +impl b::LocalTrait for B { + fn no_skip_non_default() -> Option<()> { + ${0:todo!()} + } } "#, ) diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index a262570d94e7..f51e99a914e2 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -106,8 +106,18 @@ pub fn filter_assoc_items( .iter() .copied() .filter(|assoc_item| { - !(ignore_items == IgnoreAssocItems::DocHiddenAttrPresent - && assoc_item.attrs(sema.db).has_doc_hidden()) + if ignore_items == IgnoreAssocItems::DocHiddenAttrPresent + && assoc_item.attrs(sema.db).has_doc_hidden() + { + if let hir::AssocItem::Function(f) = assoc_item { + if !f.has_body(sema.db) { + return true; + } + } + return false; + } + + return true; }) // Note: This throws away items with no source. .filter_map(|assoc_item| { From 3bcdb7d886f0673799ea961220b557c28b6213b4 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Thu, 9 Nov 2023 20:59:17 +0330 Subject: [PATCH 2356/2442] Truncate closure capture place for raw pointer --- crates/hir-ty/src/chalk_ext.rs | 5 ++++ crates/hir-ty/src/infer/closure.rs | 27 +++++++++++++++++++ .../src/handlers/mutability_errors.rs | 16 +++++++++++ 3 files changed, 48 insertions(+) diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index c0b243ea2485..c9ab356854b8 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -28,6 +28,7 @@ pub trait TyExt { fn is_unknown(&self) -> bool; fn contains_unknown(&self) -> bool; fn is_ty_var(&self) -> bool; + fn is_union(&self) -> bool; fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; fn as_builtin(&self) -> Option; @@ -96,6 +97,10 @@ impl TyExt for Ty { matches!(self.kind(Interner), TyKind::InferenceVar(_, _)) } + fn is_union(&self) -> bool { + matches!(self.adt_id(Interner), Some(AdtId(hir_def::AdtId::UnionId(_)))) + } + fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> { match self.kind(Interner) { TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)), diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 0805e20447a7..af74df1032cb 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -735,6 +735,32 @@ impl InferenceContext<'_> { self.walk_expr(expr); } + fn restrict_precision_for_unsafe(&mut self) { + for capture in &mut self.current_captures { + let mut ty = self.table.resolve_completely(self.result[capture.place.local].clone()); + if ty.as_raw_ptr().is_some() || ty.is_union() { + capture.kind = CaptureKind::ByRef(BorrowKind::Shared); + capture.place.projections.truncate(0); + continue; + } + for (i, p) in capture.place.projections.iter().enumerate() { + ty = p.projected_ty( + ty, + self.db, + |_, _, _| { + unreachable!("Closure field only happens in MIR"); + }, + self.owner.module(self.db.upcast()).krate(), + ); + if ty.as_raw_ptr().is_some() || ty.is_union() { + capture.kind = CaptureKind::ByRef(BorrowKind::Shared); + capture.place.projections.truncate(i + 1); + break; + } + } + } + } + fn adjust_for_move_closure(&mut self) { for capture in &mut self.current_captures { if let Some(first_deref) = @@ -924,6 +950,7 @@ impl InferenceContext<'_> { self.result.mutated_bindings_in_closure.insert(item.place.local); } } + self.restrict_precision_for_unsafe(); // closure_kind should be done before adjust_for_move_closure let closure_kind = self.closure_kind(); match capture_by { diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs index ee096a100aaa..1875111492c6 100644 --- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -1225,6 +1225,22 @@ fn foo(mut foo: Foo) { }; call_me(); } +"#, + ); + } + + #[test] + fn regression_15670() { + check_diagnostics( + r#" +//- minicore: fn + +pub struct A {} +pub unsafe fn foo(a: *mut A) { + let mut b = || -> *mut A { &mut *a }; + //^^^^^ 💡 warn: variable does not need to be mutable + let _ = b(); +} "#, ); } From e0276dc5ddc38c65240edb408522bb869f15afb4 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Fri, 10 Nov 2023 19:54:43 +0800 Subject: [PATCH 2357/2442] fix: find `Self` reference --- crates/ide-db/src/search.rs | 2 +- crates/ide/src/references.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 9c4f0ac8c9fc..22438a203bd7 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -584,7 +584,7 @@ impl<'a> FindUsages<'a> { ) -> bool { match NameRefClass::classify(self.sema, name_ref) { Some(NameRefClass::Definition(Definition::SelfType(impl_))) - if impl_.self_ty(self.sema.db) == *self_ty => + if impl_.self_ty(self.sema.db).as_adt() == self_ty.as_adt() => { let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 2d0295692ac0..f387bbf6b014 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -683,6 +683,32 @@ enum Foo { ); } + #[test] + fn test_self() { + check( + r#" +struct S$0 { + t: PhantomData, +} + +impl S { + fn new() -> Self { + Self { + t: Default::default(), + } + } +} +"#, + expect![[r#" + S Struct FileId(0) 0..38 7..8 + + FileId(0) 48..49 + FileId(0) 71..75 + FileId(0) 86..90 + "#]], + ) + } + #[test] fn test_find_all_refs_two_modules() { check( From 9826717550e9059cb15372b72cb9ee97516945ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Fri, 10 Nov 2023 16:48:47 +0200 Subject: [PATCH 2358/2442] Improve check for include macro --- crates/hir-expand/src/db.rs | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 204227e33873..ff0d279d8cce 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -12,15 +12,11 @@ use syntax::{ use triomphe::Arc; use crate::{ - ast_id_map::AstIdMap, - builtin_attr_macro::pseudo_derive_attr_expansion, - builtin_fn_macro::EagerExpander, - fixup, - hygiene::HygieneFrame, - name::{name, AsName}, - tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, - ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, - MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, + ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, + builtin_fn_macro::EagerExpander, fixup, hygiene::HygieneFrame, tt, AstId, BuiltinAttrExpander, + BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, ExpandError, ExpandResult, + ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, + MacroDefKind, MacroFile, ProcMacroExpander, }; /// Total limit on the number of tokens produced by any macro invocation. @@ -619,20 +615,7 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult { - if let Some(name_ref) = - ast_id.to_node(db).path().and_then(|p| p.segment()).and_then(|s| s.name_ref()) - { - name_ref.as_name() == name!(include) - } else { - false - } - } - _ => false, - }; - - if !skip_check_tt_count { + if !loc.def.is_include() { // Set a hard limit for the expanded tt if let Err(value) = check_tt_count(&tt) { return value; From 0647b645cd7bc83686065796f9cd8f3b44448711 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Fri, 10 Nov 2023 17:39:32 +0100 Subject: [PATCH 2359/2442] ensure renames happen after edit --- crates/rust-analyzer/src/lsp/to_proto.rs | 23 ++++++++++++---- crates/rust-analyzer/tests/slow-tests/main.rs | 26 +++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs index aca91570f7c2..4e3dce35ec39 100644 --- a/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/crates/rust-analyzer/src/lsp/to_proto.rs @@ -1,7 +1,7 @@ //! Conversion of rust-analyzer specific types to lsp_types equivalents. use std::{ iter::once, - path, + mem, path, sync::atomic::{AtomicU32, Ordering}, }; @@ -1123,13 +1123,20 @@ pub(crate) fn snippet_text_document_ops( pub(crate) fn snippet_workspace_edit( snap: &GlobalStateSnapshot, - source_change: SourceChange, + mut source_change: SourceChange, ) -> Cancellable { let mut document_changes: Vec = Vec::new(); - for op in source_change.file_system_edits { - let ops = snippet_text_document_ops(snap, op)?; - document_changes.extend_from_slice(&ops); + for op in &mut source_change.file_system_edits { + if let FileSystemEdit::CreateFile { dst, initial_contents } = op { + // replace with a placeholder to avoid cloneing the edit + let op = FileSystemEdit::CreateFile { + dst: dst.clone(), + initial_contents: mem::take(initial_contents), + }; + let ops = snippet_text_document_ops(snap, op)?; + document_changes.extend_from_slice(&ops); + } } for (file_id, (edit, snippet_edit)) in source_change.source_file_edits { let edit = snippet_text_document_edit( @@ -1141,6 +1148,12 @@ pub(crate) fn snippet_workspace_edit( )?; document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit)); } + for op in source_change.file_system_edits { + if !matches!(op, FileSystemEdit::CreateFile { .. }) { + let ops = snippet_text_document_ops(snap, op)?; + document_changes.extend_from_slice(&ops); + } + } let mut workspace_edit = lsp_ext::SnippetWorkspaceEdit { changes: None, document_changes: Some(document_changes), diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs index d59914298991..5cd02f784046 100644 --- a/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/crates/rust-analyzer/tests/slow-tests/main.rs @@ -984,6 +984,11 @@ fn main() {} //- /src/old_file.rs //- /src/old_folder/mod.rs +mod nested; + +//- /src/old_folder/nested.rs +struct foo; +use crate::old_folder::nested::foo as bar; //- /src/from_mod/mod.rs @@ -1080,6 +1085,27 @@ fn main() {} "newText": "new_folder" } ] + }, + { + "textDocument": { + "uri": format!("file://{}", tmp_dir_path.join("src").join("old_folder").join("nested.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace('\\', "/")), + "version": null + }, + "edits": [ + { + "range": { + "start": { + "line": 1, + "character": 11 + }, + "end": { + "line": 1, + "character": 21 + } + }, + "newText": "new_folder" + } + ] } ] }), From 2339ba4440bc8b23f3705efb57a439b4ec8d3505 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 11 Nov 2023 14:04:24 +0100 Subject: [PATCH 2360/2442] Prepare ImportMap for supportin multiple import paths per item --- crates/hir-def/src/find_path.rs | 35 ++++---- crates/hir-def/src/import_map.rs | 132 ++++++++++++++++++++----------- 2 files changed, 105 insertions(+), 62 deletions(-) diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index b9c5ff72792a..2a0a45009712 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -367,18 +367,18 @@ fn calculate_best_path( // too (unless we can't name it at all). It could *also* be (re)exported by the same crate // that wants to import it here, but we always prefer to use the external path here. - let crate_graph = db.crate_graph(); - let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| { + for dep in &db.crate_graph()[from.krate].dependencies { let import_map = db.import_map(dep.crate_id); - import_map.import_info_for(item).and_then(|info| { + let Some(import_info_for) = import_map.import_info_for(item) else { continue }; + for info in import_info_for { if info.is_doc_hidden { // the item or import is `#[doc(hidden)]`, so skip it as it is in an external crate - return None; + continue; } // Determine best path for containing module and append last segment from `info`. // FIXME: we should guide this to look up the path locally, or from the same crate again? - let (mut path, path_stability) = find_path_for_module( + let Some((mut path, path_stability)) = find_path_for_module( db, def_map, visited_modules, @@ -388,22 +388,23 @@ fn calculate_best_path( max_len - 1, prefixed, prefer_no_std, - )?; + ) else { + continue; + }; cov_mark::hit!(partially_imported); path.push_segment(info.name.clone()); - Some(( + + let path_with_stab = ( path, zip_stability(path_stability, if info.is_unstable { Unstable } else { Stable }), - )) - }) - }); + ); - for path in extern_paths { - let new_path = match best_path.take() { - Some(best_path) => select_best_path(best_path, path, prefer_no_std), - None => path, - }; - update_best_path(&mut best_path, new_path); + let new_path_with_stab = match best_path.take() { + Some(best_path) => select_best_path(best_path, path_with_stab, prefer_no_std), + None => path_with_stab, + }; + update_best_path(&mut best_path, new_path_with_stab); + } } } if let Some(module) = item.module(db) { @@ -593,7 +594,7 @@ mod tests { let found_path = find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind, false); - assert_eq!(found_path, Some(mod_path), "{prefix_kind:?}"); + assert_eq!(found_path, Some(mod_path), "on kind: {prefix_kind:?}"); } fn check_found_path( diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs index 6461439bb713..d3dee8e7c738 100644 --- a/crates/hir-def/src/import_map.rs +++ b/crates/hir-def/src/import_map.rs @@ -3,11 +3,12 @@ use std::{collections::hash_map::Entry, fmt, hash::BuildHasherDefault}; use base_db::CrateId; -use fst::{self, Streamer}; +use fst::{self, raw::IndexedValue, Streamer}; use hir_expand::name::Name; use indexmap::IndexMap; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; +use smallvec::{smallvec, SmallVec}; use triomphe::Arc; use crate::{ @@ -20,8 +21,6 @@ use crate::{ type FxIndexMap = IndexMap>; -// FIXME: Support aliases: an item may be exported under multiple names, so `ImportInfo` should -// have `Vec<(Name, ModuleId)>` instead of `(Name, ModuleId)`. /// Item import details stored in the `ImportMap`. #[derive(Debug, Clone, Eq, PartialEq)] pub struct ImportInfo { @@ -29,22 +28,21 @@ pub struct ImportInfo { pub name: Name, /// The module containing this item. pub container: ModuleId, - /// Whether the import is a trait associated item or not. - pub is_trait_assoc_item: bool, /// Whether this item is annotated with `#[doc(hidden)]`. pub is_doc_hidden: bool, /// Whether this item is annotated with `#[unstable(..)]`. pub is_unstable: bool, } +type ImportMapIndex = FxIndexMap, IsTraitAssocItem)>; + /// A map from publicly exported items to its name. /// /// Reexports of items are taken into account, ie. if something is exported under multiple /// names, the one with the shortest import path will be used. #[derive(Default)] pub struct ImportMap { - map: FxIndexMap, - + map: ImportMapIndex, /// List of keys stored in `map`, sorted lexicographically by their `ModPath`. Indexed by the /// values returned by running `fst`. /// @@ -55,6 +53,12 @@ pub struct ImportMap { fst: fst::Map>, } +#[derive(Copy, Clone, PartialEq, Eq)] +enum IsTraitAssocItem { + Yes, + No, +} + impl ImportMap { pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { let _p = profile::span("import_map_query"); @@ -64,9 +68,13 @@ impl ImportMap { let mut importables: Vec<_> = map .iter() // We've only collected items, whose name cannot be tuple field. - .map(|(&item, info)| (item, info.name.as_str().unwrap().to_ascii_lowercase())) + .flat_map(|(&item, (info, _))| { + info.iter() + .map(move |info| (item, info.name.as_str().unwrap().to_ascii_lowercase())) + }) .collect(); importables.sort_by(|(_, lhs_name), (_, rhs_name)| lhs_name.cmp(rhs_name)); + importables.dedup(); // Build the FST, taking care not to insert duplicate values. let mut builder = fst::MapBuilder::memory(); @@ -82,12 +90,12 @@ impl ImportMap { }) } - pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> { - self.map.get(&item) + pub fn import_info_for(&self, item: ItemInNs) -> Option<&[ImportInfo]> { + self.map.get(&item).map(|(info, _)| &**info) } } -fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> FxIndexMap { +fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex { let _p = profile::span("collect_import_map"); let def_map = db.crate_def_map(krate); @@ -140,7 +148,6 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> FxIndexMap FxIndexMap FxIndexMap FxIndexMap, + map: &mut ImportMapIndex, tr: TraitId, is_type_in_ns: bool, trait_import_info: &ImportInfo, @@ -241,11 +250,10 @@ fn collect_trait_assoc_items( let assoc_item_info = ImportInfo { container: trait_import_info.container, name: assoc_item_name.clone(), - is_trait_assoc_item: true, is_doc_hidden: attrs.has_doc_hidden(), is_unstable: attrs.is_unstable(), }; - map.insert(assoc_item, assoc_item_info); + map.insert(assoc_item, (smallvec![assoc_item_info], IsTraitAssocItem::Yes)); } } @@ -349,6 +357,15 @@ impl Query { Self { case_sensitive: true, ..self } } + fn matches_assoc_mode(&self, is_trait_assoc_item: IsTraitAssocItem) -> bool { + match (is_trait_assoc_item, self.assoc_mode) { + (IsTraitAssocItem::Yes, AssocSearchMode::Exclude) + | (IsTraitAssocItem::No, AssocSearchMode::AssocItemsOnly) => false, + _ => true, + } + } + + /// Checks whether the import map entry matches the query. fn import_matches( &self, db: &dyn DefDatabase, @@ -356,12 +373,8 @@ impl Query { enforce_lowercase: bool, ) -> bool { let _p = profile::span("import_map::Query::import_matches"); - match (import.is_trait_assoc_item, self.assoc_mode) { - (true, AssocSearchMode::Exclude) => return false, - (false, AssocSearchMode::AssocItemsOnly) => return false, - _ => {} - } + // FIXME: Can we get rid of the alloc here? let mut input = import.name.display(db.upcast()).to_string(); let case_insensitive = enforce_lowercase || !self.case_sensitive; if case_insensitive { @@ -411,32 +424,55 @@ pub fn search_dependencies( let mut res = FxHashSet::default(); while let Some((_, indexed_values)) = stream.next() { - for indexed_value in indexed_values { - let import_map = &import_maps[indexed_value.index]; - let importables = &import_map.importables[indexed_value.value as usize..]; + for &IndexedValue { index, value } in indexed_values { + let import_map = &import_maps[index]; + let [importable, importables @ ..] = &import_map.importables[value as usize..] else { + continue; + }; - let common_importable_data = &import_map.map[&importables[0]]; - if !query.import_matches(db, common_importable_data, true) { + let &(ref importable_data, is_trait_assoc_item) = &import_map.map[importable]; + if !query.matches_assoc_mode(is_trait_assoc_item) { continue; } - // Name shared by the importable items in this group. - let common_importable_name = - common_importable_data.name.to_smol_str().to_ascii_lowercase(); - // Add the items from this name group. Those are all subsequent items in - // `importables` whose name match `common_importable_name`. - let iter = importables - .iter() - .copied() - .take_while(|item| { - common_importable_name - == import_map.map[item].name.to_smol_str().to_ascii_lowercase() - }) - .filter(|item| { - !query.case_sensitive // we've already checked the common importables name case-insensitively - || query.import_matches(db, &import_map.map[item], false) - }); - res.extend(iter); + // FIXME: We probably need to account for other possible matches in this alias group? + let Some(common_importable_data) = + importable_data.iter().find(|&info| query.import_matches(db, info, true)) + else { + continue; + }; + res.insert(*importable); + + if !importables.is_empty() { + // FIXME: so many allocs... + // Name shared by the importable items in this group. + let common_importable_name = + common_importable_data.name.to_smol_str().to_ascii_lowercase(); + // Add the items from this name group. Those are all subsequent items in + // `importables` whose name match `common_importable_name`. + let iter = importables + .iter() + .copied() + .take_while(|item| { + let &(ref import_infos, assoc_mode) = &import_map.map[item]; + query.matches_assoc_mode(assoc_mode) + && import_infos.iter().any(|info| { + info.name.to_smol_str().to_ascii_lowercase() + == common_importable_name + }) + }) + .filter(|item| { + !query.case_sensitive || { + // we've already checked the common importables name case-insensitively + let &(ref import_infos, assoc_mode) = &import_map.map[item]; + query.matches_assoc_mode(assoc_mode) + && import_infos + .iter() + .any(|info| query.import_matches(db, info, false)) + } + }); + res.extend(iter); + } if res.len() >= query.limit { return res; @@ -461,6 +497,7 @@ mod tests { let mut importable_paths: Vec<_> = self .map .iter() + .flat_map(|(item, (info, _))| info.iter().map(move |info| (item, info))) .map(|(item, info)| { let path = render_path(db, info); let ns = match item { @@ -499,7 +536,7 @@ mod tests { let (path, mark) = match assoc_item_path(&db, &dependency_imports, dependency) { Some(assoc_item_path) => (assoc_item_path, "a"), None => ( - render_path(&db, dependency_imports.import_info_for(dependency)?), + render_path(&db, &dependency_imports.import_info_for(dependency)?[0]), match dependency { ItemInNs::Types(ModuleDefId::FunctionId(_)) | ItemInNs::Values(ModuleDefId::FunctionId(_)) => "f", @@ -547,7 +584,12 @@ mod tests { .items .iter() .find(|(_, assoc_item_id)| &dependency_assoc_item_id == assoc_item_id)?; - Some(format!("{}::{}", render_path(db, trait_info), assoc_item_name.display(db.upcast()))) + // FIXME: This should check all import infos, not just the first + Some(format!( + "{}::{}", + render_path(db, &trait_info[0]), + assoc_item_name.display(db.upcast()) + )) } fn check(ra_fixture: &str, expect: Expect) { From 801a887954fd985901c326ba25bc39256f2477e7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 11 Nov 2023 14:48:44 +0100 Subject: [PATCH 2361/2442] Record all import paths per item in ImportMap --- crates/hir-def/src/import_map.rs | 147 ++++++++++++------------------- 1 file changed, 54 insertions(+), 93 deletions(-) diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs index d3dee8e7c738..b857392f3705 100644 --- a/crates/hir-def/src/import_map.rs +++ b/crates/hir-def/src/import_map.rs @@ -1,14 +1,14 @@ //! A map of all publicly exported items in a crate. -use std::{collections::hash_map::Entry, fmt, hash::BuildHasherDefault}; +use std::{fmt, hash::BuildHasherDefault}; use base_db::CrateId; use fst::{self, raw::IndexedValue, Streamer}; use hir_expand::name::Name; use indexmap::IndexMap; use itertools::Itertools; -use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; -use smallvec::{smallvec, SmallVec}; +use rustc_hash::{FxHashSet, FxHasher}; +use smallvec::SmallVec; use triomphe::Arc; use crate::{ @@ -103,11 +103,13 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex { // We look only into modules that are public(ly reexported), starting with the crate root. let root = def_map.module_id(DefMap::ROOT); - let mut worklist = vec![(root, 0u32)]; - // Records items' minimum module depth. - let mut depth_map = FxHashMap::default(); + let mut worklist = vec![root]; + let mut visited = FxHashSet::default(); - while let Some((module, depth)) = worklist.pop() { + while let Some(module) = worklist.pop() { + if !visited.insert(module) { + continue; + } let ext_def_map; let mod_data = if module.krate == krate { &def_map[module.local_id] @@ -126,6 +128,7 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex { } }); + // FIXME: This loop might add the same entry up to 3 times per item! dedup for (name, per_ns) in visible_items { for (item, import) in per_ns.iter_items() { let attr_id = if let Some(import) = import { @@ -139,11 +142,10 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex { ItemInNs::Macros(id) => Some(id.into()), } }; - let status @ (is_doc_hidden, is_unstable) = - attr_id.map_or((false, false), |attr_id| { - let attrs = db.attrs(attr_id); - (attrs.has_doc_hidden(), attrs.is_unstable()) - }); + let (is_doc_hidden, is_unstable) = attr_id.map_or((false, false), |attr_id| { + let attrs = db.attrs(attr_id); + (attrs.has_doc_hidden(), attrs.is_unstable()) + }); let import_info = ImportInfo { name: name.clone(), @@ -152,50 +154,6 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex { is_unstable, }; - match depth_map.entry(item) { - Entry::Vacant(entry) => _ = entry.insert((depth, status)), - Entry::Occupied(mut entry) => { - let &(occ_depth, (occ_is_doc_hidden, occ_is_unstable)) = entry.get(); - (depth, occ_depth); - let overwrite = match ( - is_doc_hidden, - occ_is_doc_hidden, - is_unstable, - occ_is_unstable, - ) { - // no change of hiddeness or unstableness - (true, true, true, true) - | (true, true, false, false) - | (false, false, true, true) - | (false, false, false, false) => depth < occ_depth, - - // either less hidden or less unstable, accept - (true, true, false, true) - | (false, true, true, true) - | (false, true, false, true) - | (false, true, false, false) - | (false, false, false, true) => true, - // more hidden or unstable, discard - (true, true, true, false) - | (true, false, true, true) - | (true, false, true, false) - | (true, false, false, false) - | (false, false, true, false) => false, - - // exchanges doc(hidden) for unstable (and vice-versa), - (true, false, false, true) | (false, true, true, false) => { - depth < occ_depth - } - }; - // FIXME: Remove the overwrite rules as we can now record exports and - // aliases for the same item - if !overwrite { - continue; - } - entry.insert((depth, status)); - } - } - if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() { collect_trait_assoc_items( db, @@ -206,13 +164,14 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex { ); } - map.insert(item, (smallvec![import_info], IsTraitAssocItem::No)); + map.entry(item) + .or_insert_with(|| (SmallVec::new(), IsTraitAssocItem::No)) + .0 + .push(import_info); - // If we've just added a module, descend into it. We might traverse modules - // multiple times, but only if the module depth is smaller (else we `continue` - // above). + // If we've just added a module, descend into it. if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { - worklist.push((mod_id, depth + 1)); + worklist.push(mod_id); } } } @@ -253,7 +212,11 @@ fn collect_trait_assoc_items( is_doc_hidden: attrs.has_doc_hidden(), is_unstable: attrs.is_unstable(), }; - map.insert(assoc_item, (smallvec![assoc_item_info], IsTraitAssocItem::Yes)); + + map.entry(assoc_item) + .or_insert_with(|| (SmallVec::new(), IsTraitAssocItem::Yes)) + .0 + .push(assoc_item_info); } } @@ -284,7 +247,7 @@ impl fmt::Debug for ImportMap { } /// A way to match import map contents against the search query. -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] enum SearchMode { /// Import map entry should strictly match the query string. Exact, @@ -426,7 +389,7 @@ pub fn search_dependencies( while let Some((_, indexed_values)) = stream.next() { for &IndexedValue { index, value } in indexed_values { let import_map = &import_maps[index]; - let [importable, importables @ ..] = &import_map.importables[value as usize..] else { + let importables @ [importable, ..] = &import_map.importables[value as usize..] else { continue; }; @@ -441,38 +404,32 @@ pub fn search_dependencies( else { continue; }; - res.insert(*importable); - if !importables.is_empty() { - // FIXME: so many allocs... - // Name shared by the importable items in this group. - let common_importable_name = - common_importable_data.name.to_smol_str().to_ascii_lowercase(); - // Add the items from this name group. Those are all subsequent items in - // `importables` whose name match `common_importable_name`. - let iter = importables - .iter() - .copied() - .take_while(|item| { + // FIXME: so many allocs... + // Name shared by the importable items in this group. + let common_importable_name = + common_importable_data.name.to_smol_str().to_ascii_lowercase(); + // Add the items from this name group. Those are all subsequent items in + // `importables` whose name match `common_importable_name`. + let iter = importables + .iter() + .copied() + .take_while(|item| { + let &(ref import_infos, assoc_mode) = &import_map.map[item]; + query.matches_assoc_mode(assoc_mode) + && import_infos.iter().any(|info| { + info.name.to_smol_str().to_ascii_lowercase() == common_importable_name + }) + }) + .filter(|item| { + !query.case_sensitive || { + // we've already checked the common importables name case-insensitively let &(ref import_infos, assoc_mode) = &import_map.map[item]; query.matches_assoc_mode(assoc_mode) - && import_infos.iter().any(|info| { - info.name.to_smol_str().to_ascii_lowercase() - == common_importable_name - }) - }) - .filter(|item| { - !query.case_sensitive || { - // we've already checked the common importables name case-insensitively - let &(ref import_infos, assoc_mode) = &import_map.map[item]; - query.matches_assoc_mode(assoc_mode) - && import_infos - .iter() - .any(|info| query.import_matches(db, info, false)) - } - }); - res.extend(iter); - } + && import_infos.iter().any(|info| query.import_matches(db, info, false)) + } + }); + res.extend(iter); if res.len() >= query.limit { return res; @@ -665,6 +622,7 @@ mod tests { main: - publ1 (t) - real_pu2 (t) + - real_pu2::Pub (t) - real_pub (t) - real_pub::Pub (t) "#]], @@ -690,6 +648,7 @@ mod tests { - sub (t) - sub::Def (t) - sub::subsub (t) + - sub::subsub::Def (t) "#]], ); } @@ -789,7 +748,9 @@ mod tests { - module (t) - module::S (t) - module::S (v) + - module::module (t) - sub (t) + - sub::module (t) "#]], ); } From ba61766217444d980a3a20f378181e2ad388ab0e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 11 Nov 2023 14:52:11 +0100 Subject: [PATCH 2362/2442] Add config for preferring / ignoring prelude modules in find_path --- crates/hir-def/src/find_path.rs | 138 ++++++++++++++---- crates/hir-ty/src/display.rs | 1 + crates/hir/src/lib.rs | 11 +- crates/ide-assists/src/assist_config.rs | 1 + .../src/handlers/add_missing_match_arms.rs | 33 ++++- .../ide-assists/src/handlers/auto_import.rs | 1 + .../ide-assists/src/handlers/bool_to_enum.rs | 1 + .../src/handlers/convert_into_to_from.rs | 7 +- .../convert_tuple_return_type_to_struct.rs | 1 + .../src/handlers/extract_function.rs | 1 + .../extract_struct_from_enum_variant.rs | 1 + .../src/handlers/generate_deref.rs | 16 +- .../ide-assists/src/handlers/generate_new.rs | 1 + .../src/handlers/qualify_method_call.rs | 1 + .../ide-assists/src/handlers/qualify_path.rs | 7 +- .../replace_derive_with_manual_impl.rs | 7 +- .../replace_qualified_name_with_use.rs | 1 + crates/ide-assists/src/tests.rs | 2 + crates/ide-completion/src/completions.rs | 1 + crates/ide-completion/src/completions/expr.rs | 2 + .../src/completions/flyimport.rs | 21 ++- crates/ide-completion/src/config.rs | 1 + crates/ide-completion/src/lib.rs | 1 + crates/ide-completion/src/snippet.rs | 1 + crates/ide-completion/src/tests.rs | 1 + crates/ide-db/src/imports/import_assets.rs | 19 ++- crates/ide-db/src/path_transform.rs | 9 +- .../src/handlers/json_is_not_rust.rs | 2 + .../src/handlers/missing_fields.rs | 1 + crates/ide-diagnostics/src/lib.rs | 2 + crates/ide-ssr/src/matching.rs | 2 +- .../rust-analyzer/src/cli/analysis_stats.rs | 3 +- crates/rust-analyzer/src/config.rs | 5 + .../src/integrated_benchmarks.rs | 2 + docs/user/generated_config.adoc | 5 + editors/code/package.json | 5 + 36 files changed, 260 insertions(+), 54 deletions(-) diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index 2a0a45009712..1ebd1ba0e66d 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -21,9 +21,10 @@ pub fn find_path( item: ItemInNs, from: ModuleId, prefer_no_std: bool, + prefer_prelude: bool, ) -> Option { let _p = profile::span("find_path"); - find_path_inner(db, item, from, None, prefer_no_std) + find_path_inner(db, item, from, None, prefer_no_std, prefer_prelude) } pub fn find_path_prefixed( @@ -32,9 +33,10 @@ pub fn find_path_prefixed( from: ModuleId, prefix_kind: PrefixKind, prefer_no_std: bool, + prefer_prelude: bool, ) -> Option { let _p = profile::span("find_path_prefixed"); - find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std) + find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std, prefer_prelude) } #[derive(Copy, Clone, Debug)] @@ -88,6 +90,7 @@ fn find_path_inner( from: ModuleId, prefixed: Option, prefer_no_std: bool, + prefer_prelude: bool, ) -> Option { // - if the item is a builtin, it's in scope if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item { @@ -109,6 +112,7 @@ fn find_path_inner( MAX_PATH_LEN, prefixed, prefer_no_std || db.crate_supports_no_std(crate_root.krate), + prefer_prelude, ) .map(|(item, _)| item); } @@ -134,6 +138,7 @@ fn find_path_inner( from, prefixed, prefer_no_std, + prefer_prelude, ) { let data = db.enum_data(variant.parent); path.push_segment(data.variants[variant.local_id].name.clone()); @@ -156,6 +161,7 @@ fn find_path_inner( from, prefixed, prefer_no_std || db.crate_supports_no_std(crate_root.krate), + prefer_prelude, scope_name, ) .map(|(item, _)| item) @@ -171,6 +177,7 @@ fn find_path_for_module( max_len: usize, prefixed: Option, prefer_no_std: bool, + prefer_prelude: bool, ) -> Option<(ModPath, Stability)> { if max_len == 0 { return None; @@ -236,6 +243,7 @@ fn find_path_for_module( from, prefixed, prefer_no_std, + prefer_prelude, scope_name, ) } @@ -316,6 +324,7 @@ fn calculate_best_path( from: ModuleId, mut prefixed: Option, prefer_no_std: bool, + prefer_prelude: bool, scope_name: Option, ) -> Option<(ModPath, Stability)> { if max_len <= 1 { @@ -351,11 +360,14 @@ fn calculate_best_path( best_path_len - 1, prefixed, prefer_no_std, + prefer_prelude, ) { path.0.push_segment(name); let new_path = match best_path.take() { - Some(best_path) => select_best_path(best_path, path, prefer_no_std), + Some(best_path) => { + select_best_path(best_path, path, prefer_no_std, prefer_prelude) + } None => path, }; best_path_len = new_path.0.len(); @@ -388,6 +400,7 @@ fn calculate_best_path( max_len - 1, prefixed, prefer_no_std, + prefer_prelude, ) else { continue; }; @@ -400,7 +413,9 @@ fn calculate_best_path( ); let new_path_with_stab = match best_path.take() { - Some(best_path) => select_best_path(best_path, path_with_stab, prefer_no_std), + Some(best_path) => { + select_best_path(best_path, path_with_stab, prefer_no_std, prefer_prelude) + } None => path_with_stab, }; update_best_path(&mut best_path, new_path_with_stab); @@ -421,17 +436,39 @@ fn calculate_best_path( } } +/// Select the best (most relevant) path between two paths. +/// This accounts for stability, path length whether std should be chosen over alloc/core paths as +/// well as ignoring prelude like paths or not. fn select_best_path( - old_path: (ModPath, Stability), - new_path: (ModPath, Stability), + old_path @ (_, old_stability): (ModPath, Stability), + new_path @ (_, new_stability): (ModPath, Stability), prefer_no_std: bool, + prefer_prelude: bool, ) -> (ModPath, Stability) { - match (old_path.1, new_path.1) { + match (old_stability, new_stability) { (Stable, Unstable) => return old_path, (Unstable, Stable) => return new_path, _ => {} } const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc]; + + let choose = |new_path: (ModPath, _), old_path: (ModPath, _)| { + let new_has_prelude = new_path.0.segments().iter().any(|seg| seg == &known::prelude); + let old_has_prelude = old_path.0.segments().iter().any(|seg| seg == &known::prelude); + match (new_has_prelude, old_has_prelude, prefer_prelude) { + (true, false, true) | (false, true, false) => new_path, + (true, false, false) | (false, true, true) => old_path, + // no prelude difference in the paths, so pick the smaller one + (true, true, _) | (false, false, _) => { + if new_path.0.len() < old_path.0.len() { + new_path + } else { + old_path + } + } + } + }; + match (old_path.0.segments().first(), new_path.0.segments().first()) { (Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => { let rank = match prefer_no_std { @@ -452,23 +489,11 @@ fn select_best_path( let orank = rank(old); match nrank.cmp(&orank) { Ordering::Less => old_path, - Ordering::Equal => { - if new_path.0.len() < old_path.0.len() { - new_path - } else { - old_path - } - } + Ordering::Equal => choose(new_path, old_path), Ordering::Greater => new_path, } } - _ => { - if new_path.0.len() < old_path.0.len() { - new_path - } else { - old_path - } - } + _ => choose(new_path, old_path), } } @@ -571,7 +596,13 @@ mod tests { /// `code` needs to contain a cursor marker; checks that `find_path` for the /// item the `path` refers to returns that same path when called from the /// module the cursor is in. - fn check_found_path_(ra_fixture: &str, path: &str, prefix_kind: Option) { + #[track_caller] + fn check_found_path_( + ra_fixture: &str, + path: &str, + prefix_kind: Option, + prefer_prelude: bool, + ) { let (db, pos) = TestDB::with_position(ra_fixture); let module = db.module_at_position(pos); let parsed_path_file = syntax::SourceFile::parse(&format!("use {path};")); @@ -590,10 +621,16 @@ mod tests { ) .0 .take_types() - .unwrap(); + .expect("path does not resolve to a type"); - let found_path = - find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind, false); + let found_path = find_path_inner( + &db, + ItemInNs::Types(resolved), + module, + prefix_kind, + false, + prefer_prelude, + ); assert_eq!(found_path, Some(mod_path), "on kind: {prefix_kind:?}"); } @@ -604,10 +641,23 @@ mod tests { absolute: &str, self_prefixed: &str, ) { - check_found_path_(ra_fixture, unprefixed, None); - check_found_path_(ra_fixture, prefixed, Some(PrefixKind::Plain)); - check_found_path_(ra_fixture, absolute, Some(PrefixKind::ByCrate)); - check_found_path_(ra_fixture, self_prefixed, Some(PrefixKind::BySelf)); + check_found_path_(ra_fixture, unprefixed, None, false); + check_found_path_(ra_fixture, prefixed, Some(PrefixKind::Plain), false); + check_found_path_(ra_fixture, absolute, Some(PrefixKind::ByCrate), false); + check_found_path_(ra_fixture, self_prefixed, Some(PrefixKind::BySelf), false); + } + + fn check_found_path_prelude( + ra_fixture: &str, + unprefixed: &str, + prefixed: &str, + absolute: &str, + self_prefixed: &str, + ) { + check_found_path_(ra_fixture, unprefixed, None, true); + check_found_path_(ra_fixture, prefixed, Some(PrefixKind::Plain), true); + check_found_path_(ra_fixture, absolute, Some(PrefixKind::ByCrate), true); + check_found_path_(ra_fixture, self_prefixed, Some(PrefixKind::BySelf), true); } #[test] @@ -1422,4 +1472,34 @@ pub mod error { "std::error::Error", ); } + + #[test] + fn respects_prelude_setting() { + let ra_fixture = r#" +//- /main.rs crate:main deps:krate +$0 +//- /krate.rs crate:krate +pub mod prelude { + pub use crate::foo::*; +} + +pub mod foo { + pub struct Foo; +} +"#; + check_found_path( + ra_fixture, + "krate::foo::Foo", + "krate::foo::Foo", + "krate::foo::Foo", + "krate::foo::Foo", + ); + check_found_path_prelude( + ra_fixture, + "krate::prelude::Foo", + "krate::prelude::Foo", + "krate::prelude::Foo", + "krate::prelude::Foo", + ); + } } diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index f6d6b00d740a..9ccf467358ec 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -945,6 +945,7 @@ impl HirDisplay for Ty { ItemInNs::Types((*def_id).into()), module_id, false, + true, ) { write!(f, "{}", path.display(f.db.upcast()))?; } else { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 17ffb9acbd19..6fcc02fb9dac 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -664,8 +664,15 @@ impl Module { db: &dyn DefDatabase, item: impl Into, prefer_no_std: bool, + prefer_prelude: bool, ) -> Option { - hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_no_std) + hir_def::find_path::find_path( + db, + item.into().into(), + self.into(), + prefer_no_std, + prefer_prelude, + ) } /// Finds a path that can be used to refer to the given item from within @@ -676,6 +683,7 @@ impl Module { item: impl Into, prefix_kind: PrefixKind, prefer_no_std: bool, + prefer_prelude: bool, ) -> Option { hir_def::find_path::find_path_prefixed( db, @@ -683,6 +691,7 @@ impl Module { self.into(), prefix_kind, prefer_no_std, + prefer_prelude, ) } } diff --git a/crates/ide-assists/src/assist_config.rs b/crates/ide-assists/src/assist_config.rs index b273ebc85a50..fbe17dbfd771 100644 --- a/crates/ide-assists/src/assist_config.rs +++ b/crates/ide-assists/src/assist_config.rs @@ -14,5 +14,6 @@ pub struct AssistConfig { pub allowed: Option>, pub insert_use: InsertUseConfig, pub prefer_no_std: bool, + pub prefer_prelude: bool, pub assist_emit_must_use: bool, } diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs index c8b78b094169..2374da9a343f 100644 --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -88,7 +88,13 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) .into_iter() .filter_map(|variant| { Some(( - build_pat(ctx.db(), module, variant, ctx.config.prefer_no_std)?, + build_pat( + ctx.db(), + module, + variant, + ctx.config.prefer_no_std, + ctx.config.prefer_prelude, + )?, variant.should_be_hidden(ctx.db(), module.krate()), )) }) @@ -140,7 +146,13 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) .iter() .any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); let patterns = variants.into_iter().filter_map(|variant| { - build_pat(ctx.db(), module, variant, ctx.config.prefer_no_std) + build_pat( + ctx.db(), + module, + variant, + ctx.config.prefer_no_std, + ctx.config.prefer_prelude, + ) }); (ast::Pat::from(make::tuple_pat(patterns)), is_hidden) @@ -173,7 +185,13 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) .iter() .any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); let patterns = variants.into_iter().filter_map(|variant| { - build_pat(ctx.db(), module, variant.clone(), ctx.config.prefer_no_std) + build_pat( + ctx.db(), + module, + variant.clone(), + ctx.config.prefer_no_std, + ctx.config.prefer_prelude, + ) }); (ast::Pat::from(make::slice_pat(patterns)), is_hidden) }) @@ -440,11 +458,16 @@ fn build_pat( module: hir::Module, var: ExtendedVariant, prefer_no_std: bool, + prefer_prelude: bool, ) -> Option { match var { ExtendedVariant::Variant(var) => { - let path = - mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var), prefer_no_std)?); + let path = mod_path_to_ast(&module.find_use_path( + db, + ModuleDef::from(var), + prefer_no_std, + prefer_prelude, + )?); // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though Some(match var.source(db)?.value.kind() { diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs index cafd57a97727..f508c42c53e4 100644 --- a/crates/ide-assists/src/handlers/auto_import.rs +++ b/crates/ide-assists/src/handlers/auto_import.rs @@ -93,6 +93,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< &ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std, + ctx.config.prefer_no_std, ); if proposed_imports.is_empty() { return None; diff --git a/crates/ide-assists/src/handlers/bool_to_enum.rs b/crates/ide-assists/src/handlers/bool_to_enum.rs index 082839118c58..11facc5bee2a 100644 --- a/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/crates/ide-assists/src/handlers/bool_to_enum.rs @@ -348,6 +348,7 @@ fn augment_references_with_imports( ModuleDef::Module(*target_module), ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std, + ctx.config.prefer_prelude, ) .map(|mod_path| { make::path_concat(mod_path_to_ast(&mod_path), make::path_from_text("Bool")) diff --git a/crates/ide-assists/src/handlers/convert_into_to_from.rs b/crates/ide-assists/src/handlers/convert_into_to_from.rs index 872b52c98fff..d649f13d6ee3 100644 --- a/crates/ide-assists/src/handlers/convert_into_to_from.rs +++ b/crates/ide-assists/src/handlers/convert_into_to_from.rs @@ -50,7 +50,12 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) - _ => return None, }; - mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def, ctx.config.prefer_no_std)?) + mod_path_to_ast(&module.find_use_path( + ctx.db(), + src_type_def, + ctx.config.prefer_no_std, + ctx.config.prefer_prelude, + )?) }; let dest_type = match &ast_trait { diff --git a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs index 32db5ee8dabf..1f3caa7db33f 100644 --- a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs +++ b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs @@ -205,6 +205,7 @@ fn augment_references_with_imports( ModuleDef::Module(*target_module), ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std, + ctx.config.prefer_prelude, ) .map(|mod_path| { make::path_concat( diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index de591cfde949..6b48d1588152 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -163,6 +163,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op ModuleDef::from(control_flow_enum), ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std, + ctx.config.prefer_prelude, ); if let Some(mod_path) = mod_path { diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index e4f64ccc754e..37db27a8fc02 100644 --- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -384,6 +384,7 @@ fn process_references( *enum_module_def, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std, + ctx.config.prefer_prelude, ); if let Some(mut mod_path) = mod_path { mod_path.pop_segment(); diff --git a/crates/ide-assists/src/handlers/generate_deref.rs b/crates/ide-assists/src/handlers/generate_deref.rs index 81545396175b..473c699b595c 100644 --- a/crates/ide-assists/src/handlers/generate_deref.rs +++ b/crates/ide-assists/src/handlers/generate_deref.rs @@ -58,8 +58,12 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( let module = ctx.sema.to_def(&strukt)?.module(ctx.db()); let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?; - let trait_path = - module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_no_std)?; + let trait_path = module.find_use_path( + ctx.db(), + ModuleDef::Trait(trait_), + ctx.config.prefer_no_std, + ctx.config.prefer_prelude, + )?; let field_type = field.ty()?; let field_name = field.name()?; @@ -99,8 +103,12 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() let module = ctx.sema.to_def(&strukt)?.module(ctx.db()); let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?; - let trait_path = - module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_no_std)?; + let trait_path = module.find_use_path( + ctx.db(), + ModuleDef::Trait(trait_), + ctx.config.prefer_no_std, + ctx.config.prefer_prelude, + )?; let field_type = field.ty()?; let target = field.syntax().text_range(); diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs index 824255e4f8e3..7bfd599660db 100644 --- a/crates/ide-assists/src/handlers/generate_new.rs +++ b/crates/ide-assists/src/handlers/generate_new.rs @@ -67,6 +67,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?, ctx.config.prefer_no_std, + ctx.config.prefer_prelude, )?; let expr = use_trivial_constructor( diff --git a/crates/ide-assists/src/handlers/qualify_method_call.rs b/crates/ide-assists/src/handlers/qualify_method_call.rs index 4bf974a5655a..ff65aac82e07 100644 --- a/crates/ide-assists/src/handlers/qualify_method_call.rs +++ b/crates/ide-assists/src/handlers/qualify_method_call.rs @@ -48,6 +48,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?, ctx.config.prefer_no_std, + ctx.config.prefer_prelude, )?; let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call, resolved_call); diff --git a/crates/ide-assists/src/handlers/qualify_path.rs b/crates/ide-assists/src/handlers/qualify_path.rs index 239149dc411d..fde46db3058e 100644 --- a/crates/ide-assists/src/handlers/qualify_path.rs +++ b/crates/ide-assists/src/handlers/qualify_path.rs @@ -37,8 +37,11 @@ use crate::{ // ``` pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let (import_assets, syntax_under_caret) = find_importable_node(ctx)?; - let mut proposed_imports = - import_assets.search_for_relative_paths(&ctx.sema, ctx.config.prefer_no_std); + let mut proposed_imports = import_assets.search_for_relative_paths( + &ctx.sema, + ctx.config.prefer_no_std, + ctx.config.prefer_prelude, + ); if proposed_imports.is_empty() { return None; } diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index ac45581b7b44..69a4e748b7c5 100644 --- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -82,7 +82,12 @@ pub(crate) fn replace_derive_with_manual_impl( }) .flat_map(|trait_| { current_module - .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.prefer_no_std) + .find_use_path( + ctx.sema.db, + hir::ModuleDef::Trait(trait_), + ctx.config.prefer_no_std, + ctx.config.prefer_prelude, + ) .as_ref() .map(mod_path_to_ast) .zip(Some(trait_)) diff --git a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index dbbc56958f1e..f03eb6118a52 100644 --- a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -68,6 +68,7 @@ pub(crate) fn replace_qualified_name_with_use( module, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std, + ctx.config.prefer_prelude, ) }) .flatten(); diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs index cc3e251a8f2a..566384615bb3 100644 --- a/crates/ide-assists/src/tests.rs +++ b/crates/ide-assists/src/tests.rs @@ -30,6 +30,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { skip_glob_imports: true, }, prefer_no_std: false, + prefer_prelude: true, assist_emit_must_use: false, }; @@ -44,6 +45,7 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig { skip_glob_imports: true, }, prefer_no_std: false, + prefer_prelude: true, assist_emit_must_use: false, }; diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index f60ac150164c..7d38c638a8ed 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -626,6 +626,7 @@ fn enum_variants_with_paths( ctx.db, hir::ModuleDef::from(variant), ctx.config.prefer_no_std, + ctx.config.prefer_prelude, ) { // Variants with trivial paths are already added by the existing completion logic, // so we should avoid adding these twice diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index 9daa6984c3e3..d3c817d4b43a 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -175,6 +175,7 @@ pub(crate) fn complete_expr_path( ctx.db, hir::ModuleDef::from(strukt), ctx.config.prefer_no_std, + ctx.config.prefer_prelude, ) .filter(|it| it.len() > 1); @@ -197,6 +198,7 @@ pub(crate) fn complete_expr_path( ctx.db, hir::ModuleDef::from(un), ctx.config.prefer_no_std, + ctx.config.prefer_prelude, ) .filter(|it| it.len() > 1); diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs index 0961021e48e0..d74d3b264ae5 100644 --- a/crates/ide-completion/src/completions/flyimport.rs +++ b/crates/ide-completion/src/completions/flyimport.rs @@ -257,7 +257,12 @@ fn import_on_the_fly( let user_input_lowercased = potential_import_name.to_lowercase(); import_assets - .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std) + .search_for_imports( + &ctx.sema, + ctx.config.insert_use.prefix_kind, + ctx.config.prefer_no_std, + ctx.config.prefer_prelude, + ) .into_iter() .filter(ns_filter) .filter(|import| { @@ -299,7 +304,12 @@ fn import_on_the_fly_pat_( let user_input_lowercased = potential_import_name.to_lowercase(); import_assets - .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std) + .search_for_imports( + &ctx.sema, + ctx.config.insert_use.prefix_kind, + ctx.config.prefer_no_std, + ctx.config.prefer_prelude, + ) .into_iter() .filter(ns_filter) .filter(|import| { @@ -336,7 +346,12 @@ fn import_on_the_fly_method( let user_input_lowercased = potential_import_name.to_lowercase(); import_assets - .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std) + .search_for_imports( + &ctx.sema, + ctx.config.insert_use.prefix_kind, + ctx.config.prefer_no_std, + ctx.config.prefer_prelude, + ) .into_iter() .filter(|import| { !ctx.is_item_hidden(&import.item_to_import) diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs index 3d025f284bbb..ed5ddde8fbfe 100644 --- a/crates/ide-completion/src/config.rs +++ b/crates/ide-completion/src/config.rs @@ -19,6 +19,7 @@ pub struct CompletionConfig { pub snippet_cap: Option, pub insert_use: InsertUseConfig, pub prefer_no_std: bool, + pub prefer_prelude: bool, pub snippets: Vec, pub limit: Option, } diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs index 2fad293d16d7..aaf7cd7843af 100644 --- a/crates/ide-completion/src/lib.rs +++ b/crates/ide-completion/src/lib.rs @@ -263,6 +263,7 @@ pub fn resolve_completion_edits( candidate, config.insert_use.prefix_kind, config.prefer_no_std, + config.prefer_prelude, ) }) .find(|mod_path| mod_path.display(db).to_string() == full_import_path); diff --git a/crates/ide-completion/src/snippet.rs b/crates/ide-completion/src/snippet.rs index 343719c53694..50618296ee43 100644 --- a/crates/ide-completion/src/snippet.rs +++ b/crates/ide-completion/src/snippet.rs @@ -179,6 +179,7 @@ fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option 1).then(|| LocatedImport::new(path.clone(), item, item, None))) }; diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs index 284bdd8af21f..9db8e972dd4b 100644 --- a/crates/ide-completion/src/tests.rs +++ b/crates/ide-completion/src/tests.rs @@ -68,6 +68,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { callable: Some(CallableSnippets::FillArguments), snippet_cap: SnippetCap::new(true), prefer_no_std: false, + prefer_prelude: true, insert_use: InsertUseConfig { granularity: ImportGranularity::Crate, prefix_kind: PrefixKind::Plain, diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs index da5a951f0b7b..04263d15d0a5 100644 --- a/crates/ide-db/src/imports/import_assets.rs +++ b/crates/ide-db/src/imports/import_assets.rs @@ -220,9 +220,10 @@ impl ImportAssets { sema: &Semantics<'_, RootDatabase>, prefix_kind: PrefixKind, prefer_no_std: bool, + prefer_prelude: bool, ) -> Vec { let _p = profile::span("import_assets::search_for_imports"); - self.search_for(sema, Some(prefix_kind), prefer_no_std) + self.search_for(sema, Some(prefix_kind), prefer_no_std, prefer_prelude) } /// This may return non-absolute paths if a part of the returned path is already imported into scope. @@ -230,9 +231,10 @@ impl ImportAssets { &self, sema: &Semantics<'_, RootDatabase>, prefer_no_std: bool, + prefer_prelude: bool, ) -> Vec { let _p = profile::span("import_assets::search_for_relative_paths"); - self.search_for(sema, None, prefer_no_std) + self.search_for(sema, None, prefer_no_std, prefer_prelude) } /// Requires imports to by prefix instead of fuzzily. @@ -270,6 +272,7 @@ impl ImportAssets { sema: &Semantics<'_, RootDatabase>, prefixed: Option, prefer_no_std: bool, + prefer_prelude: bool, ) -> Vec { let _p = profile::span("import_assets::search_for"); @@ -281,6 +284,7 @@ impl ImportAssets { &self.module_with_candidate, prefixed, prefer_no_std, + prefer_prelude, ) }; @@ -594,11 +598,18 @@ fn get_mod_path( module_with_candidate: &Module, prefixed: Option, prefer_no_std: bool, + prefer_prelude: bool, ) -> Option { if let Some(prefix_kind) = prefixed { - module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind, prefer_no_std) + module_with_candidate.find_use_path_prefixed( + db, + item_to_search, + prefix_kind, + prefer_no_std, + prefer_prelude, + ) } else { - module_with_candidate.find_use_path(db, item_to_search, prefer_no_std) + module_with_candidate.find_use_path(db, item_to_search, prefer_no_std, prefer_prelude) } } diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index fb75b5b45848..fa9339f30f20 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -277,6 +277,7 @@ impl Ctx<'_> { self.source_scope.db.upcast(), hir::ModuleDef::Trait(trait_ref), false, + true, )?; match make::ty_path(mod_path_to_ast(&found_path)) { ast::Type::PathType(path_ty) => Some(path_ty), @@ -311,8 +312,12 @@ impl Ctx<'_> { } } - let found_path = - self.target_module.find_use_path(self.source_scope.db.upcast(), def, false)?; + let found_path = self.target_module.find_use_path( + self.source_scope.db.upcast(), + def, + false, + true, + )?; let res = mod_path_to_ast(&found_path).clone_for_update(); if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) { if let Some(segment) = res.segment() { diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index a337e2660d6a..659b74445f8f 100644 --- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -136,6 +136,7 @@ pub(crate) fn json_in_items( it, config.insert_use.prefix_kind, config.prefer_no_std, + config.prefer_prelude, ) { insert_use(&scope, mod_path_to_ast(&it), &config.insert_use); } @@ -148,6 +149,7 @@ pub(crate) fn json_in_items( it, config.insert_use.prefix_kind, config.prefer_no_std, + config.prefer_prelude, ) { insert_use(&scope, mod_path_to_ast(&it), &config.insert_use); } diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index c09be3fee7e1..d7dca1083a07 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -122,6 +122,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option Date: Sat, 11 Nov 2023 15:42:09 +0100 Subject: [PATCH 2363/2442] Fix some FIXMEs --- crates/hir-def/src/import_map.rs | 99 ++++++++++++++++++-------------- crates/hir-def/src/lib.rs | 2 +- 2 files changed, 57 insertions(+), 44 deletions(-) diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs index b857392f3705..649ea13888dd 100644 --- a/crates/hir-def/src/import_map.rs +++ b/crates/hir-def/src/import_map.rs @@ -22,7 +22,7 @@ use crate::{ type FxIndexMap = IndexMap>; /// Item import details stored in the `ImportMap`. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct ImportInfo { /// A name that can be used to import the item, relative to the crate's root. pub name: Name, @@ -78,7 +78,8 @@ impl ImportMap { // Build the FST, taking care not to insert duplicate values. let mut builder = fst::MapBuilder::memory(); - let iter = importables.iter().enumerate().dedup_by(|lhs, rhs| lhs.1 .1 == rhs.1 .1); + let iter = + importables.iter().enumerate().dedup_by(|(_, (_, lhs)), (_, (_, rhs))| lhs == rhs); for (start_idx, (_, name)) in iter { let _ = builder.insert(name, start_idx as u64); } @@ -128,7 +129,6 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex { } }); - // FIXME: This loop might add the same entry up to 3 times per item! dedup for (name, per_ns) in visible_items { for (item, import) in per_ns.iter_items() { let attr_id = if let Some(import) = import { @@ -164,10 +164,10 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex { ); } - map.entry(item) - .or_insert_with(|| (SmallVec::new(), IsTraitAssocItem::No)) - .0 - .push(import_info); + let (infos, _) = + map.entry(item).or_insert_with(|| (SmallVec::new(), IsTraitAssocItem::No)); + infos.reserve_exact(1); + infos.push(import_info); // If we've just added a module, descend into it. if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { @@ -213,10 +213,10 @@ fn collect_trait_assoc_items( is_unstable: attrs.is_unstable(), }; - map.entry(assoc_item) - .or_insert_with(|| (SmallVec::new(), IsTraitAssocItem::Yes)) - .0 - .push(assoc_item_info); + let (infos, _) = + map.entry(assoc_item).or_insert_with(|| (SmallVec::new(), IsTraitAssocItem::Yes)); + infos.reserve_exact(1); + infos.push(assoc_item_info); } } @@ -234,10 +234,13 @@ impl fmt::Debug for ImportMap { let mut importable_names: Vec<_> = self .map .iter() - .map(|(item, _)| match item { - ItemInNs::Types(it) => format!("- {it:?} (t)",), - ItemInNs::Values(it) => format!("- {it:?} (v)",), - ItemInNs::Macros(it) => format!("- {it:?} (m)",), + .map(|(item, (infos, _))| { + let l = infos.len(); + match item { + ItemInNs::Types(it) => format!("- {it:?} (t) [{l}]",), + ItemInNs::Values(it) => format!("- {it:?} (v) [{l}]",), + ItemInNs::Macros(it) => format!("- {it:?} (m) [{l}]",), + } }) .collect(); @@ -368,7 +371,7 @@ impl Query { pub fn search_dependencies( db: &dyn DefDatabase, krate: CrateId, - query: Query, + ref query: Query, ) -> FxHashSet { let _p = profile::span("search_dependencies").detail(|| format!("{query:?}")); @@ -386,6 +389,7 @@ pub fn search_dependencies( let mut stream = op.union(); let mut res = FxHashSet::default(); + let mut common_importable_data_scratch = vec![]; while let Some((_, indexed_values)) = stream.next() { for &IndexedValue { index, value } in indexed_values { let import_map = &import_maps[index]; @@ -398,36 +402,45 @@ pub fn search_dependencies( continue; } - // FIXME: We probably need to account for other possible matches in this alias group? - let Some(common_importable_data) = - importable_data.iter().find(|&info| query.import_matches(db, info, true)) - else { + common_importable_data_scratch.extend( + importable_data + .iter() + .filter(|&info| query.import_matches(db, info, true)) + // Name shared by the importable items in this group. + .map(|info| info.name.to_smol_str()), + ); + if common_importable_data_scratch.is_empty() { continue; - }; + } + common_importable_data_scratch.sort(); + common_importable_data_scratch.dedup(); - // FIXME: so many allocs... - // Name shared by the importable items in this group. - let common_importable_name = - common_importable_data.name.to_smol_str().to_ascii_lowercase(); - // Add the items from this name group. Those are all subsequent items in - // `importables` whose name match `common_importable_name`. - let iter = importables - .iter() - .copied() - .take_while(|item| { - let &(ref import_infos, assoc_mode) = &import_map.map[item]; - query.matches_assoc_mode(assoc_mode) - && import_infos.iter().any(|info| { - info.name.to_smol_str().to_ascii_lowercase() == common_importable_name + let iter = + common_importable_data_scratch.drain(..).flat_map(|common_importable_name| { + // Add the items from this name group. Those are all subsequent items in + // `importables` whose name match `common_importable_name`. + importables + .iter() + .copied() + .take_while(move |item| { + let &(ref import_infos, assoc_mode) = &import_map.map[item]; + query.matches_assoc_mode(assoc_mode) + && import_infos.iter().any(|info| { + info.name + .to_smol_str() + .eq_ignore_ascii_case(&common_importable_name) + }) + }) + .filter(move |item| { + !query.case_sensitive || { + // we've already checked the common importables name case-insensitively + let &(ref import_infos, assoc_mode) = &import_map.map[item]; + query.matches_assoc_mode(assoc_mode) + && import_infos + .iter() + .any(|info| query.import_matches(db, info, false)) + } }) - }) - .filter(|item| { - !query.case_sensitive || { - // we've already checked the common importables name case-insensitively - let &(ref import_infos, assoc_mode) = &import_map.map[item]; - query.matches_assoc_mode(assoc_mode) - && import_infos.iter().any(|info| query.import_matches(db, info, false)) - } }); res.extend(iter); diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 495e2d476970..fd8f64d6705b 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -152,7 +152,7 @@ impl TryFrom for CrateRootModuleId { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct ModuleId { krate: CrateId, /// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the From b6f0994ee61370b42fa2d834259311eb1355c7ff Mon Sep 17 00:00:00 2001 From: nokazn <41154684+nokazn@users.noreply.github.com> Date: Sun, 12 Nov 2023 10:29:56 +0900 Subject: [PATCH 2364/2442] docs: fix VS Code setting samples --- docs/user/manual.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index b605de4c7b82..18d5ddd4d0af 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -946,7 +946,7 @@ Or it is possible to specify vars more granularly: "rust-analyzer.runnables.extraEnv": [ { // "mask": null, // null mask means that this rule will be applied for all runnables - env: { + "env": { "APP_ID": "1", "APP_DATA": "asdf" } @@ -968,7 +968,7 @@ If needed, you can set different values for different platforms: "rust-analyzer.runnables.extraEnv": [ { "platform": "win32", // windows only - env: { + "env": { "APP_DATA": "windows specific data" } }, From 02c7b8b9ba184850d1857cf5b3cf534c9ea95179 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Mon, 10 Jul 2023 23:56:59 -0400 Subject: [PATCH 2365/2442] Add `MethodCallExpr::get_or_create_generic_arg_list` Mirrors `PathSegment's` version, except that it always generates a turbofish --- crates/syntax/src/ast/edit_in_place.rs | 20 +++++++++++++++++++- crates/syntax/src/ast/make.rs | 7 +++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index a85e1d1d9d0e..097c444797ed 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -14,7 +14,7 @@ use crate::{ SyntaxNode, SyntaxToken, }; -use super::HasName; +use super::{HasArgList, HasName}; pub trait GenericParamsOwnerEdit: ast::HasGenericParams { fn get_or_create_generic_param_list(&self) -> ast::GenericParamList; @@ -362,6 +362,24 @@ impl ast::PathSegment { } } +impl ast::MethodCallExpr { + pub fn get_or_create_generic_arg_list(&self) -> ast::GenericArgList { + if self.generic_arg_list().is_none() { + let generic_arg_list = make::turbofish_generic_arg_list(empty()).clone_for_update(); + + if let Some(arg_list) = self.arg_list() { + ted::insert_raw( + ted::Position::before(arg_list.syntax()), + generic_arg_list.syntax(), + ); + } else { + ted::append_child(self.syntax(), generic_arg_list.syntax()); + } + } + self.generic_arg_list().unwrap() + } +} + impl Removable for ast::UseTree { fn remove(&self) { for dir in [Direction::Next, Direction::Prev] { diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 31a858b91a7d..8a701f6292ae 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -941,6 +941,13 @@ pub fn lifetime_arg(lifetime: ast::Lifetime) -> ast::LifetimeArg { ast_from_text(&format!("const S: T<{lifetime}> = ();")) } +pub fn turbofish_generic_arg_list( + args: impl IntoIterator, +) -> ast::GenericArgList { + let args = args.into_iter().join(", "); + ast_from_text(&format!("const S: T::<{args}> = ();")) +} + pub(crate) fn generic_arg_list( args: impl IntoIterator, ) -> ast::GenericArgList { From cc4e06f04bf68284f9152e77312ddfc14de613b4 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Tue, 11 Jul 2023 00:02:46 -0400 Subject: [PATCH 2366/2442] Migrate `add_turbo_fish` to mutable ast `add_type_ascription` is still left as-is since it's a different assist --- .../src/handlers/add_turbo_fish.rs | 100 ++++++++++++------ 1 file changed, 66 insertions(+), 34 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_turbo_fish.rs b/crates/ide-assists/src/handlers/add_turbo_fish.rs index 36f68d176773..6d973a24c443 100644 --- a/crates/ide-assists/src/handlers/add_turbo_fish.rs +++ b/crates/ide-assists/src/handlers/add_turbo_fish.rs @@ -1,6 +1,9 @@ +use either::Either; use ide_db::defs::{Definition, NameRefClass}; -use itertools::Itertools; -use syntax::{ast, AstNode, SyntaxKind, T}; +use syntax::{ + ast::{self, make, HasArgList}, + ted, AstNode, +}; use crate::{ assist_context::{AssistContext, Assists}, @@ -25,21 +28,45 @@ use crate::{ // } // ``` pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let ident = ctx.find_token_syntax_at_offset(SyntaxKind::IDENT).or_else(|| { - let arg_list = ctx.find_node_at_offset::()?; - if arg_list.args().next().is_some() { - return None; - } - cov_mark::hit!(add_turbo_fish_after_call); - cov_mark::hit!(add_type_ascription_after_call); - arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT) - })?; - let next_token = ident.next_token()?; - if next_token.kind() == T![::] { + let turbofish_target = + ctx.find_node_at_offset::().map(Either::Left).or_else(|| { + let callable_expr = ctx.find_node_at_offset::()?; + + if callable_expr.arg_list()?.args().next().is_some() { + return None; + } + + cov_mark::hit!(add_turbo_fish_after_call); + cov_mark::hit!(add_type_ascription_after_call); + + match callable_expr { + ast::CallableExpr::Call(it) => { + let ast::Expr::PathExpr(path) = it.expr()? else { + return None; + }; + + Some(Either::Left(path.path()?.segment()?)) + } + ast::CallableExpr::MethodCall(it) => Some(Either::Right(it)), + } + })?; + + let already_has_turbofish = match &turbofish_target { + Either::Left(path_segment) => path_segment.generic_arg_list().is_some(), + Either::Right(method_call) => method_call.generic_arg_list().is_some(), + }; + + if already_has_turbofish { cov_mark::hit!(add_turbo_fish_one_fish_is_enough); return None; } - let name_ref = ast::NameRef::cast(ident.parent()?)?; + + let name_ref = match &turbofish_target { + Either::Left(path_segment) => path_segment.name_ref()?, + Either::Right(method_call) => method_call.name_ref()?, + }; + let ident = name_ref.ident_token()?; + let def = match NameRefClass::classify(&ctx.sema, &name_ref)? { NameRefClass::Definition(def) => def, NameRefClass::FieldShorthand { .. } | NameRefClass::ExternCrateShorthand { .. } => { @@ -91,33 +118,38 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti AssistId("add_turbo_fish", AssistKind::RefactorRewrite), "Add `::<>`", ident.text_range(), - |builder| { - builder.trigger_signature_help(); - match ctx.config.snippet_cap { - Some(cap) => { - let fish_head = get_snippet_fish_head(number_of_arguments); - let snip = format!("::<{fish_head}>"); - builder.insert_snippet(cap, ident.text_range().end(), snip) + |edit| { + edit.trigger_signature_help(); + + let new_arg_list = match turbofish_target { + Either::Left(path_segment) => { + edit.make_mut(path_segment).get_or_create_generic_arg_list() } - None => { - let fish_head = std::iter::repeat("_").take(number_of_arguments).format(", "); - let snip = format!("::<{fish_head}>"); - builder.insert(ident.text_range().end(), snip); + Either::Right(method_call) => { + edit.make_mut(method_call).get_or_create_generic_arg_list() + } + }; + + let fish_head = get_fish_head(number_of_arguments).clone_for_update(); + + // Note: we need to replace the `new_arg_list` instead of being able to use something like + // `GenericArgList::add_generic_arg` as `PathSegment::get_or_create_generic_arg_list` + // always creates a non-turbofish form generic arg list. + ted::replace(new_arg_list.syntax(), fish_head.syntax()); + + if let Some(cap) = ctx.config.snippet_cap { + for arg in fish_head.generic_args() { + edit.add_placeholder_snippet(cap, arg) } } }, ) } -/// This will create a snippet string with tabstops marked -fn get_snippet_fish_head(number_of_arguments: usize) -> String { - let mut fish_head = (1..number_of_arguments) - .format_with("", |i, f| f(&format_args!("${{{i}:_}}, "))) - .to_string(); - - // tabstop 0 is a special case and always the last one - fish_head.push_str("${0:_}"); - fish_head +/// This will create a turbofish generic arg list corresponding to the number of arguments +fn get_fish_head(number_of_arguments: usize) -> ast::GenericArgList { + let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into()); + make::turbofish_generic_arg_list(args) } #[cfg(test)] From 92422f7488888c3868c9f5ddb080f26566f9f382 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sun, 16 Jul 2023 16:21:49 -0400 Subject: [PATCH 2367/2442] Use syntax's version of `SyntaxElement` --- crates/syntax/src/ast/edit_in_place.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index 097c444797ed..6c6a2bc71eb6 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -3,13 +3,12 @@ use std::iter::{empty, successors}; use parser::{SyntaxKind, T}; -use rowan::SyntaxElement; use crate::{ algo::{self, neighbor}, ast::{self, edit::IndentLevel, make, HasGenericParams}, ted::{self, Position}, - AstNode, AstToken, Direction, + AstNode, AstToken, Direction, SyntaxElement, SyntaxKind::{ATTR, COMMENT, WHITESPACE}, SyntaxNode, SyntaxToken, }; @@ -577,7 +576,7 @@ impl ast::AssocItemList { None => (IndentLevel::single(), Position::last_child_of(self.syntax()), "\n"), }, }; - let elements: Vec> = vec![ + let elements: Vec = vec![ make::tokens::whitespace(&format!("{whitespace}{indent}")).into(), item.syntax().clone().into(), ]; @@ -771,7 +770,7 @@ impl ast::VariantList { None => (IndentLevel::single(), Position::last_child_of(self.syntax())), }, }; - let elements: Vec> = vec![ + let elements: Vec = vec![ make::tokens::whitespace(&format!("{}{indent}", "\n")).into(), variant.syntax().clone().into(), ast::make::token(T![,]).into(), From 5fc8cc52e2ebc30d720873236293f5469bf5cfd8 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sun, 16 Jul 2023 16:22:29 -0400 Subject: [PATCH 2368/2442] Add `LetStmt::set_ty` Way for setting and removing the type ascription of a let stmt --- crates/syntax/src/ast/edit_in_place.rs | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index 6c6a2bc71eb6..b9059a527d0c 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -646,6 +646,47 @@ impl ast::MatchArmList { } } +impl ast::LetStmt { + pub fn set_ty(&self, ty: Option) { + match ty { + None => { + if let Some(colon_token) = self.colon_token() { + ted::remove(colon_token); + } + + if let Some(existing_ty) = self.ty() { + if let Some(sibling) = existing_ty.syntax().prev_sibling_or_token() { + if sibling.kind() == SyntaxKind::WHITESPACE { + ted::remove(sibling); + } + } + + ted::remove(existing_ty.syntax()); + } + } + Some(new_ty) => { + if self.colon_token().is_none() { + let mut to_insert: Vec = vec![]; + + let position = match self.pat() { + Some(pat) => Position::after(pat.syntax()), + None => { + to_insert.push(make::tokens::single_space().into()); + Position::after(self.let_token().unwrap()) + } + }; + + to_insert.push(make::token(T![:]).into()); + + ted::insert_all_raw(position, to_insert); + } + + ted::insert(Position::after(self.colon_token().unwrap()), new_ty.syntax()); + } + } + } +} + impl ast::RecordExprFieldList { pub fn add_field(&self, field: ast::RecordExprField) { let is_multiline = self.syntax().text().contains_char('\n'); From f3dcc67dfa62ac0950352c719e657687428f79f6 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sun, 16 Jul 2023 16:24:13 -0400 Subject: [PATCH 2369/2442] Migrate `add_type_ascription` --- .../src/handlers/add_turbo_fish.rs | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_turbo_fish.rs b/crates/ide-assists/src/handlers/add_turbo_fish.rs index 6d973a24c443..6afc1693fab0 100644 --- a/crates/ide-assists/src/handlers/add_turbo_fish.rs +++ b/crates/ide-assists/src/handlers/add_turbo_fish.rs @@ -85,20 +85,23 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti if let Some(let_stmt) = ctx.find_node_at_offset::() { if let_stmt.colon_token().is_none() { - let type_pos = let_stmt.pat()?.syntax().last_token()?.text_range().end(); - let semi_pos = let_stmt.syntax().last_token()?.text_range().end(); - acc.add( AssistId("add_type_ascription", AssistKind::RefactorRewrite), "Add `: _` before assignment operator", ident.text_range(), - |builder| { + |edit| { + let let_stmt = edit.make_mut(let_stmt); + if let_stmt.semicolon_token().is_none() { - builder.insert(semi_pos, ";"); + ted::append_child(let_stmt.syntax(), make::tokens::semicolon()); } - match ctx.config.snippet_cap { - Some(cap) => builder.insert_snippet(cap, type_pos, ": ${0:_}"), - None => builder.insert(type_pos, ": _"), + + let placeholder_ty = make::ty_placeholder().clone_for_update(); + + let_stmt.set_ty(Some(placeholder_ty.clone())); + + if let Some(cap) = ctx.config.snippet_cap { + edit.add_placeholder_snippet(cap, placeholder_ty); } }, )? @@ -395,6 +398,26 @@ fn main() { ); } + #[test] + fn add_type_ascription_missing_pattern() { + check_assist_by_label( + add_turbo_fish, + r#" +fn make() -> T {} +fn main() { + let = make$0() +} +"#, + r#" +fn make() -> T {} +fn main() { + let : ${0:_} = make(); +} +"#, + "Add `: _` before assignment operator", + ); + } + #[test] fn add_turbo_fish_function_lifetime_parameter() { check_assist( From 4aaa592a9a7461cf844e70bcc39a16173affab26 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sun, 16 Jul 2023 23:03:39 -0400 Subject: [PATCH 2370/2442] Migrate `destructure_tuple_binding` to mutable ast Due to the way the current tree mutation api works, we need to collect changes before we can apply them to the real syntax tree, and also can only switch to a file once. `destructure_tuple_binding_in_sub_pattern` also gets migrated even though can't be used. --- .../src/handlers/destructure_tuple_binding.rs | 249 +++++++++++------- crates/syntax/src/ast/make.rs | 2 +- 2 files changed, 157 insertions(+), 94 deletions(-) diff --git a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index f30ca2552d36..6a012d30bf78 100644 --- a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -3,10 +3,12 @@ use ide_db::{ defs::Definition, search::{FileReference, SearchScope, UsageSearchResult}, }; +use itertools::Itertools; use syntax::{ - ast::{self, AstNode, FieldExpr, HasName, IdentPat, MethodCallExpr}, - TextRange, + ast::{self, make, AstNode, FieldExpr, HasName, IdentPat, MethodCallExpr}, + ted, T, }; +use text_edit::TextRange; use crate::assist_context::{AssistContext, Assists, SourceChangeBuilder}; @@ -61,27 +63,36 @@ pub(crate) fn destructure_tuple_binding_impl( acc.add( AssistId("destructure_tuple_binding_in_sub_pattern", AssistKind::RefactorRewrite), "Destructure tuple in sub-pattern", - data.range, - |builder| { - edit_tuple_assignment(ctx, builder, &data, true); - edit_tuple_usages(&data, builder, ctx, true); - }, + data.ident_pat.syntax().text_range(), + |edit| destructure_tuple_edit_impl(ctx, edit, &data, true), ); } acc.add( AssistId("destructure_tuple_binding", AssistKind::RefactorRewrite), if with_sub_pattern { "Destructure tuple in place" } else { "Destructure tuple" }, - data.range, - |builder| { - edit_tuple_assignment(ctx, builder, &data, false); - edit_tuple_usages(&data, builder, ctx, false); - }, + data.ident_pat.syntax().text_range(), + |edit| destructure_tuple_edit_impl(ctx, edit, &data, false), ); Some(()) } +fn destructure_tuple_edit_impl( + ctx: &AssistContext<'_>, + edit: &mut SourceChangeBuilder, + data: &TupleData, + in_sub_pattern: bool, +) { + let assignment_edit = edit_tuple_assignment(ctx, edit, &data, in_sub_pattern); + let current_file_usages_edit = edit_tuple_usages(&data, edit, ctx, in_sub_pattern); + + assignment_edit.apply(); + if let Some(usages_edit) = current_file_usages_edit { + usages_edit.into_iter().for_each(|usage_edit| usage_edit.apply(edit)) + } +} + fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option { if ident_pat.at_token().is_some() { // Cannot destructure pattern with sub-pattern: @@ -109,7 +120,6 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option) -> Option>(); - Some(TupleData { ident_pat, range, ref_type, field_names, usages }) + Some(TupleData { ident_pat, ref_type, field_names, usages }) } fn generate_name( @@ -142,72 +152,106 @@ enum RefType { } struct TupleData { ident_pat: IdentPat, - // name: String, - range: TextRange, ref_type: Option, field_names: Vec, - // field_types: Vec, usages: Option, } fn edit_tuple_assignment( ctx: &AssistContext<'_>, - builder: &mut SourceChangeBuilder, + edit: &mut SourceChangeBuilder, data: &TupleData, in_sub_pattern: bool, -) { +) -> AssignmentEdit { + let ident_pat = edit.make_mut(data.ident_pat.clone()); + let tuple_pat = { let original = &data.ident_pat; let is_ref = original.ref_token().is_some(); let is_mut = original.mut_token().is_some(); - let fields = data.field_names.iter().map(|name| { - ast::Pat::from(ast::make::ident_pat(is_ref, is_mut, ast::make::name(name))) - }); - ast::make::tuple_pat(fields) + let fields = data + .field_names + .iter() + .map(|name| ast::Pat::from(make::ident_pat(is_ref, is_mut, make::name(name)))); + make::tuple_pat(fields).clone_for_update() }; - let add_cursor = |text: &str| { - // place cursor on first tuple item - let first_tuple = &data.field_names[0]; - text.replacen(first_tuple, &format!("$0{first_tuple}"), 1) - }; + if let Some(cap) = ctx.config.snippet_cap { + // place cursor on first tuple name + let ast::Pat::IdentPat(first_pat) = tuple_pat.fields().next().unwrap() else { + unreachable!() + }; + edit.add_tabstop_before(cap, first_pat.name().unwrap()) + } - // with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)` - if in_sub_pattern { - let text = format!(" @ {tuple_pat}"); - match ctx.config.snippet_cap { - Some(cap) => { - let snip = add_cursor(&text); - builder.insert_snippet(cap, data.range.end(), snip); - } - None => builder.insert(data.range.end(), text), - }; - } else { - let text = tuple_pat.to_string(); - match ctx.config.snippet_cap { - Some(cap) => { - let snip = add_cursor(&text); - builder.replace_snippet(cap, data.range, snip); - } - None => builder.replace(data.range, text), - }; + AssignmentEdit { ident_pat, tuple_pat, in_sub_pattern } +} +struct AssignmentEdit { + ident_pat: ast::IdentPat, + tuple_pat: ast::TuplePat, + in_sub_pattern: bool, +} + +impl AssignmentEdit { + fn apply(self) { + // with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)` + if self.in_sub_pattern { + ted::insert_all_raw( + ted::Position::after(self.ident_pat.syntax()), + vec![ + make::tokens::single_space().into(), + make::token(T![@]).into(), + make::tokens::single_space().into(), + self.tuple_pat.syntax().clone().into(), + ], + ) + } else { + ted::replace(self.ident_pat.syntax(), self.tuple_pat.syntax()) + } } } fn edit_tuple_usages( data: &TupleData, - builder: &mut SourceChangeBuilder, + edit: &mut SourceChangeBuilder, ctx: &AssistContext<'_>, in_sub_pattern: bool, -) { - if let Some(usages) = data.usages.as_ref() { - for (file_id, refs) in usages.iter() { - builder.edit_file(*file_id); +) -> Option> { + let mut current_file_usages = None; - for r in refs { - edit_tuple_usage(ctx, builder, r, data, in_sub_pattern); + if let Some(usages) = data.usages.as_ref() { + // We need to collect edits first before actually applying them + // as mapping nodes to their mutable node versions requires an + // unmodified syntax tree. + // + // We also defer editing usages in the current file first since + // tree mutation in the same file breaks when `builder.edit_file` + // is called + + if let Some((_, refs)) = usages.iter().find(|(file_id, _)| **file_id == ctx.file_id()) { + current_file_usages = Some( + refs.iter() + .filter_map(|r| edit_tuple_usage(ctx, edit, r, data, in_sub_pattern)) + .collect_vec(), + ); + } + + for (file_id, refs) in usages.iter() { + if *file_id == ctx.file_id() { + continue; } + + edit.edit_file(*file_id); + + let tuple_edits = refs + .iter() + .filter_map(|r| edit_tuple_usage(ctx, edit, r, data, in_sub_pattern)) + .collect_vec(); + + tuple_edits.into_iter().for_each(|tuple_edit| tuple_edit.apply(edit)) } } + + current_file_usages } fn edit_tuple_usage( ctx: &AssistContext<'_>, @@ -215,25 +259,14 @@ fn edit_tuple_usage( usage: &FileReference, data: &TupleData, in_sub_pattern: bool, -) { +) -> Option { match detect_tuple_index(usage, data) { - Some(index) => edit_tuple_field_usage(ctx, builder, data, index), - None => { - if in_sub_pattern { - cov_mark::hit!(destructure_tuple_call_with_subpattern); - return; - } - - // no index access -> make invalid -> requires handling by user - // -> put usage in block comment - // - // Note: For macro invocations this might result in still valid code: - // When a macro accepts the tuple as argument, as well as no arguments at all, - // uncommenting the tuple still leaves the macro call working (see `tests::in_macro_call::empty_macro`). - // But this is an unlikely case. Usually the resulting macro call will become erroneous. - builder.insert(usage.range.start(), "/*"); - builder.insert(usage.range.end(), "*/"); + Some(index) => Some(edit_tuple_field_usage(ctx, builder, data, index)), + None if in_sub_pattern => { + cov_mark::hit!(destructure_tuple_call_with_subpattern); + return None; } + None => Some(EditTupleUsage::NoIndex(usage.range)), } } @@ -242,19 +275,47 @@ fn edit_tuple_field_usage( builder: &mut SourceChangeBuilder, data: &TupleData, index: TupleIndex, -) { +) -> EditTupleUsage { let field_name = &data.field_names[index.index]; + let field_name = make::expr_path(make::ext::ident_path(field_name)); if data.ref_type.is_some() { - let ref_data = handle_ref_field_usage(ctx, &index.field_expr); - builder.replace(ref_data.range, ref_data.format(field_name)); + let (replace_expr, ref_data) = handle_ref_field_usage(ctx, &index.field_expr); + let replace_expr = builder.make_mut(replace_expr); + EditTupleUsage::ReplaceExpr(replace_expr, ref_data.wrap_expr(field_name)) } else { - builder.replace(index.range, field_name); + let field_expr = builder.make_mut(index.field_expr); + EditTupleUsage::ReplaceExpr(field_expr.into(), field_name) } } +enum EditTupleUsage { + /// no index access -> make invalid -> requires handling by user + /// -> put usage in block comment + /// + /// Note: For macro invocations this might result in still valid code: + /// When a macro accepts the tuple as argument, as well as no arguments at all, + /// uncommenting the tuple still leaves the macro call working (see `tests::in_macro_call::empty_macro`). + /// But this is an unlikely case. Usually the resulting macro call will become erroneous. + NoIndex(TextRange), + ReplaceExpr(ast::Expr, ast::Expr), +} + +impl EditTupleUsage { + fn apply(self, edit: &mut SourceChangeBuilder) { + match self { + EditTupleUsage::NoIndex(range) => { + edit.insert(range.start(), "/*"); + edit.insert(range.end(), "*/"); + } + EditTupleUsage::ReplaceExpr(target_expr, replace_with) => { + ted::replace(target_expr.syntax(), replace_with.clone_for_update().syntax()) + } + } + } +} + struct TupleIndex { index: usize, - range: TextRange, field_expr: FieldExpr, } fn detect_tuple_index(usage: &FileReference, data: &TupleData) -> Option { @@ -296,7 +357,7 @@ fn detect_tuple_index(usage: &FileReference, data: &TupleData) -> Option Option String { - match (self.needs_deref, self.needs_parentheses) { - (true, true) => format!("(*{field_name})"), - (true, false) => format!("*{field_name}"), - (false, true) => format!("({field_name})"), - (false, false) => field_name.to_string(), + fn wrap_expr(&self, mut expr: ast::Expr) -> ast::Expr { + if self.needs_deref { + expr = make::expr_prefix(T![*], expr); } + + if self.needs_parentheses { + expr = make::expr_paren(expr); + } + + return expr; } } -fn handle_ref_field_usage(ctx: &AssistContext<'_>, field_expr: &FieldExpr) -> RefData { +fn handle_ref_field_usage(ctx: &AssistContext<'_>, field_expr: &FieldExpr) -> (ast::Expr, RefData) { let s = field_expr.syntax(); - let mut ref_data = - RefData { range: s.text_range(), needs_deref: true, needs_parentheses: true }; + let mut ref_data = RefData { needs_deref: true, needs_parentheses: true }; + let mut target_node = field_expr.clone().into(); let parent = match s.parent().map(ast::Expr::cast) { Some(Some(parent)) => parent, Some(None) => { ref_data.needs_parentheses = false; - return ref_data; + return (target_node, ref_data); } - None => return ref_data, + None => return (target_node, ref_data), }; match parent { @@ -342,7 +405,7 @@ fn handle_ref_field_usage(ctx: &AssistContext<'_>, field_expr: &FieldExpr) -> Re // there might be a ref outside: `&(t.0)` -> can be removed if let Some(it) = it.syntax().parent().and_then(ast::RefExpr::cast) { ref_data.needs_deref = false; - ref_data.range = it.syntax().text_range(); + target_node = it.into(); } } ast::Expr::RefExpr(it) => { @@ -351,8 +414,8 @@ fn handle_ref_field_usage(ctx: &AssistContext<'_>, field_expr: &FieldExpr) -> Re ref_data.needs_parentheses = false; // might be surrounded by parens -> can be removed too match it.syntax().parent().and_then(ast::ParenExpr::cast) { - Some(parent) => ref_data.range = parent.syntax().text_range(), - None => ref_data.range = it.syntax().text_range(), + Some(parent) => target_node = parent.into(), + None => target_node = it.into(), }; } // higher precedence than deref `*` @@ -414,7 +477,7 @@ fn handle_ref_field_usage(ctx: &AssistContext<'_>, field_expr: &FieldExpr) -> Re } }; - ref_data + (target_node, ref_data) } #[cfg(test)] diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 8a701f6292ae..ad63cc558629 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -1133,7 +1133,7 @@ pub mod tokens { pub(super) static SOURCE_FILE: Lazy> = Lazy::new(|| { SourceFile::parse( - "const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p)\n;\n\n", + "const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, { let a @ [] })\n;\n\n", ) }); From 1e4686865efbe5c3a305708d3aceacc181081be8 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sat, 11 Nov 2023 22:10:21 -0500 Subject: [PATCH 2371/2442] Allow multiple snippet edits in a `TextDocumentEdit` --- docs/dev/lsp-extensions.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 0801e988f5ce..b66c9c943a16 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -57,8 +57,9 @@ export interface TextDocumentEdit { } ``` -When applying such code action or text edit, the editor should insert snippet, with tab stops and placeholder. -At the moment, rust-analyzer guarantees that only a single edit will have `InsertTextFormat.Snippet`. +When applying such code action or text edit, the editor should insert snippet, with tab stops and placeholders. +At the moment, rust-analyzer guarantees that only a single `TextDocumentEdit` will have edits which can be `InsertTextFormat.Snippet`. +Any additional `TextDocumentEdit`s will only have edits which are `InsertTextFormat.PlainText`. ### Example From 23fde40feddaca9359414dc90cc446d8adabe0dd Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Sun, 12 Nov 2023 11:20:14 +0800 Subject: [PATCH 2372/2442] fix `PathSegment` grammar --- crates/syntax/rust.ungram | 2 +- crates/syntax/src/ast/generated/nodes.rs | 93 ++++++++++++------------ crates/syntax/src/ast/node_ext.rs | 12 +++ 3 files changed, 60 insertions(+), 47 deletions(-) diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 3603560d35c3..c3010d090c6b 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -36,7 +36,7 @@ PathSegment = '::'? NameRef | NameRef GenericArgList? | NameRef ParamList RetType? -| '<' PathType ('as' PathType)? '>' +| '<' Type ('as' PathType)? '>' GenericArgList = '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>' diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 7ba0d4dc656f..6c86e591044a 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -59,8 +59,9 @@ impl PathSegment { pub fn param_list(&self) -> Option { support::child(&self.syntax) } pub fn ret_type(&self) -> Option { support::child(&self.syntax) } pub fn l_angle_token(&self) -> Option { support::token(&self.syntax, T![<]) } - pub fn path_type(&self) -> Option { support::child(&self.syntax) } + pub fn ty(&self) -> Option { support::child(&self.syntax) } pub fn as_token(&self) -> Option { support::token(&self.syntax, T![as]) } + pub fn path_type(&self) -> Option { support::child(&self.syntax) } pub fn r_angle_token(&self) -> Option { support::token(&self.syntax, T![>]) } } @@ -1576,14 +1577,6 @@ impl RecordPatField { pub fn pat(&self) -> Option { support::child(&self.syntax) } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum GenericArg { - TypeArg(TypeArg), - AssocTypeArg(AssocTypeArg), - LifetimeArg(LifetimeArg), - ConstArg(ConstArg), -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Type { ArrayType(ArrayType), @@ -1602,6 +1595,14 @@ pub enum Type { TupleType(TupleType), } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum GenericArg { + TypeArg(TypeArg), + AssocTypeArg(AssocTypeArg), + LifetimeArg(LifetimeArg), + ConstArg(ConstArg), +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Expr { ArrayExpr(ArrayExpr), @@ -3319,41 +3320,6 @@ impl AstNode for RecordPatField { } fn syntax(&self) -> &SyntaxNode { &self.syntax } } -impl From for GenericArg { - fn from(node: TypeArg) -> GenericArg { GenericArg::TypeArg(node) } -} -impl From for GenericArg { - fn from(node: AssocTypeArg) -> GenericArg { GenericArg::AssocTypeArg(node) } -} -impl From for GenericArg { - fn from(node: LifetimeArg) -> GenericArg { GenericArg::LifetimeArg(node) } -} -impl From for GenericArg { - fn from(node: ConstArg) -> GenericArg { GenericArg::ConstArg(node) } -} -impl AstNode for GenericArg { - fn can_cast(kind: SyntaxKind) -> bool { - matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG) - } - fn cast(syntax: SyntaxNode) -> Option { - let res = match syntax.kind() { - TYPE_ARG => GenericArg::TypeArg(TypeArg { syntax }), - ASSOC_TYPE_ARG => GenericArg::AssocTypeArg(AssocTypeArg { syntax }), - LIFETIME_ARG => GenericArg::LifetimeArg(LifetimeArg { syntax }), - CONST_ARG => GenericArg::ConstArg(ConstArg { syntax }), - _ => return None, - }; - Some(res) - } - fn syntax(&self) -> &SyntaxNode { - match self { - GenericArg::TypeArg(it) => &it.syntax, - GenericArg::AssocTypeArg(it) => &it.syntax, - GenericArg::LifetimeArg(it) => &it.syntax, - GenericArg::ConstArg(it) => &it.syntax, - } - } -} impl From for Type { fn from(node: ArrayType) -> Type { Type::ArrayType(node) } } @@ -3455,6 +3421,41 @@ impl AstNode for Type { } } } +impl From for GenericArg { + fn from(node: TypeArg) -> GenericArg { GenericArg::TypeArg(node) } +} +impl From for GenericArg { + fn from(node: AssocTypeArg) -> GenericArg { GenericArg::AssocTypeArg(node) } +} +impl From for GenericArg { + fn from(node: LifetimeArg) -> GenericArg { GenericArg::LifetimeArg(node) } +} +impl From for GenericArg { + fn from(node: ConstArg) -> GenericArg { GenericArg::ConstArg(node) } +} +impl AstNode for GenericArg { + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG) + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + TYPE_ARG => GenericArg::TypeArg(TypeArg { syntax }), + ASSOC_TYPE_ARG => GenericArg::AssocTypeArg(AssocTypeArg { syntax }), + LIFETIME_ARG => GenericArg::LifetimeArg(LifetimeArg { syntax }), + CONST_ARG => GenericArg::ConstArg(ConstArg { syntax }), + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + GenericArg::TypeArg(it) => &it.syntax, + GenericArg::AssocTypeArg(it) => &it.syntax, + GenericArg::LifetimeArg(it) => &it.syntax, + GenericArg::ConstArg(it) => &it.syntax, + } + } +} impl From for Expr { fn from(node: ArrayExpr) -> Expr { Expr::ArrayExpr(node) } } @@ -4340,12 +4341,12 @@ impl AstNode for AnyHasVisibility { } fn syntax(&self) -> &SyntaxNode { &self.syntax } } -impl std::fmt::Display for GenericArg { +impl std::fmt::Display for Type { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for Type { +impl std::fmt::Display for GenericArg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 691d0c618f38..457c3c1996fe 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -361,6 +361,18 @@ impl ast::Impl { } } +// for `PathSegment` '', call `first_path_type` will get `i32` and `last_path_type` will get `core::ops::Add` +// for '<&i32 as core::ops::Add>', call `first_path_type` and `last_path_type` will both get `core::ops::Add` cause `&i32` is `Type(RefType)` +impl ast::PathSegment { + pub fn first_path_type(&self) -> Option { + self.syntax().children().find_map(ast::PathType::cast) + } + + pub fn last_path_type(&self) -> Option { + self.syntax().children().filter_map(ast::PathType::cast).last() + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum StructKind { Record(ast::RecordFieldList), From cace36cadec95e976867841b25563c66b5c7652d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sat, 11 Nov 2023 12:10:38 +0200 Subject: [PATCH 2373/2442] Make Expand macro command title more explicit --- crates/ide/src/expand_macro.rs | 4 ++-- editors/code/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index 119a9c7c3f40..322077456775 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs @@ -14,12 +14,12 @@ pub struct ExpandedMacro { // Feature: Expand Macro Recursively // -// Shows the full macro expansion of the macro at current cursor. +// Shows the full macro expansion of the macro at the current caret position. // // |=== // | Editor | Action Name // -// | VS Code | **rust-analyzer: Expand macro recursively** +// | VS Code | **rust-analyzer: Expand macro recursively at caret** // |=== // // image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[] diff --git a/editors/code/package.json b/editors/code/package.json index c7b877b2897c..b469c5ec1477 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -156,7 +156,7 @@ }, { "command": "rust-analyzer.expandMacro", - "title": "Expand macro recursively", + "title": "Expand macro recursively at caret", "category": "rust-analyzer" }, { From bad3d9e766b343a14b5ee52ab169743a9f8fb225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sun, 12 Nov 2023 16:45:47 +0200 Subject: [PATCH 2374/2442] Include toml files in the vfs --- crates/load-cargo/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index 7a795dd62ab7..68b592ffaa4d 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -208,6 +208,7 @@ impl ProjectFolders { let entry = { let mut dirs = vfs::loader::Directories::default(); dirs.extensions.push("rs".into()); + dirs.extensions.push("toml".into()); dirs.include.extend(root.include); dirs.exclude.extend(root.exclude); for excl in global_excludes { From d6b908ec41df85bb3d557f7be6637968611c58a0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 12 Nov 2023 17:48:40 +0100 Subject: [PATCH 2375/2442] Fix import preference config keys --- crates/rust-analyzer/src/config.rs | 16 ++++++++-------- docs/user/generated_config.adoc | 4 ++-- editors/code/package.json | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 6b8de861db95..f28f6ffb8748 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -352,9 +352,9 @@ config_data! { /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`. imports_merge_glob: bool = "true", /// Prefer to unconditionally use imports of the core and alloc crate, over the std crate. - imports_prefer_no_std: bool = "false", + imports_preferNoStd | imports_prefer_no_std: bool = "false", /// Whether to prefer import paths containing a `prelude` module. - imports_prefer_prelude: bool = "false", + imports_preferPrelude: bool = "false", /// The path structure for newly inserted paths to use. imports_prefix: ImportPrefixDef = "\"plain\"", @@ -1119,8 +1119,8 @@ impl Config { ExprFillDefaultDef::Default => ExprFillDefaultMode::Default, }, insert_use: self.insert_use_config(), - prefer_no_std: self.data.imports_prefer_no_std, - prefer_prelude: self.data.imports_prefer_prelude, + prefer_no_std: self.data.imports_preferNoStd, + prefer_prelude: self.data.imports_preferPrelude, } } @@ -1489,8 +1489,8 @@ impl Config { CallableCompletionDef::None => None, }, insert_use: self.insert_use_config(), - prefer_no_std: self.data.imports_prefer_no_std, - prefer_prelude: self.data.imports_prefer_prelude, + prefer_no_std: self.data.imports_preferNoStd, + prefer_prelude: self.data.imports_preferPrelude, snippet_cap: SnippetCap::new(try_or_def!( self.caps .text_document @@ -1519,8 +1519,8 @@ impl Config { snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")), allowed: None, insert_use: self.insert_use_config(), - prefer_no_std: self.data.imports_prefer_no_std, - prefer_prelude: self.data.imports_prefer_prelude, + prefer_no_std: self.data.imports_preferNoStd, + prefer_prelude: self.data.imports_preferPrelude, assist_emit_must_use: self.data.assist_emitMustUse, } } diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 7460df49fc00..7091ea1ce9a7 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -493,12 +493,12 @@ Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-i -- Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`. -- -[[rust-analyzer.imports.prefer.no.std]]rust-analyzer.imports.prefer.no.std (default: `false`):: +[[rust-analyzer.imports.preferNoStd]]rust-analyzer.imports.preferNoStd (default: `false`):: + -- Prefer to unconditionally use imports of the core and alloc crate, over the std crate. -- -[[rust-analyzer.imports.prefer.prelude]]rust-analyzer.imports.prefer.prelude (default: `false`):: +[[rust-analyzer.imports.preferPrelude]]rust-analyzer.imports.preferPrelude (default: `false`):: + -- Whether to prefer import paths containing a `prelude` module. diff --git a/editors/code/package.json b/editors/code/package.json index 1497b61e67b5..a4ce7314dd49 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1129,12 +1129,12 @@ "default": true, "type": "boolean" }, - "rust-analyzer.imports.prefer.no.std": { + "rust-analyzer.imports.preferNoStd": { "markdownDescription": "Prefer to unconditionally use imports of the core and alloc crate, over the std crate.", "default": false, "type": "boolean" }, - "rust-analyzer.imports.prefer.prelude": { + "rust-analyzer.imports.preferPrelude": { "markdownDescription": "Whether to prefer import paths containing a `prelude` module.", "default": false, "type": "boolean" From 3e5bc9a9c8bfd01e827e7f4062356e484e33387a Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Mon, 13 Nov 2023 18:14:00 +0800 Subject: [PATCH 2376/2442] impl `qualifying_trait` for `PathSegment` --- crates/syntax/src/ast/node_ext.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 457c3c1996fe..be5b954ad345 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -361,15 +361,12 @@ impl ast::Impl { } } -// for `PathSegment` '', call `first_path_type` will get `i32` and `last_path_type` will get `core::ops::Add` -// for '<&i32 as core::ops::Add>', call `first_path_type` and `last_path_type` will both get `core::ops::Add` cause `&i32` is `Type(RefType)` +// [#15778](https://github.com/rust-lang/rust-analyzer/issues/15778) impl ast::PathSegment { - pub fn first_path_type(&self) -> Option { - self.syntax().children().find_map(ast::PathType::cast) - } - - pub fn last_path_type(&self) -> Option { - self.syntax().children().filter_map(ast::PathType::cast).last() + pub fn qualifying_trait(&self) -> Option { + let mut path_types = support::children(self.syntax()); + let first = path_types.next()?; + path_types.next().or(Some(first)) } } From 67058605d82f645582ebc3a96186efe50eeb9593 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 13 Nov 2023 13:13:39 +0100 Subject: [PATCH 2377/2442] FIxed typo in highlight_related.rs --- crates/ide/src/highlight_related.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs index 46a0464e9e6e..a7f5ae92a4ca 100644 --- a/crates/ide/src/highlight_related.rs +++ b/crates/ide/src/highlight_related.rs @@ -43,7 +43,7 @@ pub struct HighlightRelatedConfig { // // . if on an identifier, highlights all references to that identifier in the current file // .. additionally, if the identifier is a trait in a where clause, type parameter trait bound or use item, highlights all references to that trait's assoc items in the corresponding scope -// . if on an `async` or `await token, highlights all yield points for that async context +// . if on an `async` or `await` token, highlights all yield points for that async context // . if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context // . if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context // . if on a `move` or `|` token that belongs to a closure, highlights all captures of the closure. From 6f68cd33947c3f361e47c24904605e49e5637eba Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Mon, 13 Nov 2023 18:42:58 -0500 Subject: [PATCH 2378/2442] Remove unwraps from `destructure_tuple_binding` --- .../src/handlers/destructure_tuple_binding.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index 6a012d30bf78..2dc30e685a10 100644 --- a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -177,10 +177,12 @@ fn edit_tuple_assignment( if let Some(cap) = ctx.config.snippet_cap { // place cursor on first tuple name - let ast::Pat::IdentPat(first_pat) = tuple_pat.fields().next().unwrap() else { - unreachable!() - }; - edit.add_tabstop_before(cap, first_pat.name().unwrap()) + if let Some(ast::Pat::IdentPat(first_pat)) = tuple_pat.fields().next() { + edit.add_tabstop_before( + cap, + first_pat.name().expect("first ident pattern should have a name"), + ) + } } AssignmentEdit { ident_pat, tuple_pat, in_sub_pattern } From 787ca888e35eaa351c9755f4f4de75acca8bf836 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Mon, 13 Nov 2023 20:30:58 -0500 Subject: [PATCH 2379/2442] Add `IdentPat::set_pat` Needed so that the `tuple_pat` node gets added to the syntax tree, which is required as we're using structured snippets. --- .../src/handlers/destructure_tuple_binding.rs | 10 +-- crates/syntax/src/ast/edit_in_place.rs | 75 +++++++++++++++++++ 2 files changed, 76 insertions(+), 9 deletions(-) diff --git a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index 2dc30e685a10..65b497e83aa2 100644 --- a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -197,15 +197,7 @@ impl AssignmentEdit { fn apply(self) { // with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)` if self.in_sub_pattern { - ted::insert_all_raw( - ted::Position::after(self.ident_pat.syntax()), - vec![ - make::tokens::single_space().into(), - make::token(T![@]).into(), - make::tokens::single_space().into(), - self.tuple_pat.syntax().clone().into(), - ], - ) + self.ident_pat.set_pat(Some(self.tuple_pat.into())) } else { ted::replace(self.ident_pat.syntax(), self.tuple_pat.syntax()) } diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index b9059a527d0c..edb55a2f1360 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -846,6 +846,53 @@ fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> { Some(()) } +impl ast::IdentPat { + pub fn set_pat(&self, pat: Option) { + match pat { + None => { + if let Some(at_token) = self.at_token() { + // Remove `@ Pat` + let start = at_token.clone().into(); + let end = self + .pat() + .map(|it| it.syntax().clone().into()) + .unwrap_or_else(|| at_token.into()); + + ted::remove_all(start..=end); + + // Remove any trailing ws + if let Some(last) = + self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) + { + last.detach(); + } + } + } + Some(pat) => { + if let Some(old_pat) = self.pat() { + // Replace existing pattern + ted::replace(old_pat.syntax(), pat.syntax()) + } else if let Some(at_token) = self.at_token() { + // Have an `@` token but not a pattern yet + ted::insert(ted::Position::after(at_token), pat.syntax()); + } else { + // Don't have an `@`, should have a name + let name = self.name().unwrap(); + + ted::insert_all( + ted::Position::after(name.syntax()), + vec![ + make::token(T![@]).into(), + make::tokens::single_space().into(), + pat.syntax().clone().into(), + ], + ) + } + } + } + } +} + pub trait HasVisibilityEdit: ast::HasVisibility { fn set_visibility(&self, visbility: ast::Visibility) { match self.visibility() { @@ -947,6 +994,34 @@ mod tests { ); } + #[test] + fn test_ident_pat_set_pat() { + #[track_caller] + fn check(before: &str, expected: &str, pat: Option) { + let pat = pat.map(|it| it.clone_for_update()); + + let ident_pat = ast_mut_from_text::(&format!("fn f() {{ {before} }}")); + ident_pat.set_pat(pat); + + let after = ast_mut_from_text::(&format!("fn f() {{ {expected} }}")); + assert_eq!(ident_pat.to_string(), after.to_string()); + } + + // replacing + check("let a @ _;", "let a @ ();", Some(make::tuple_pat([]).into())); + + // note: no trailing semicolon is added for the below tests since it + // seems to be picked up by the ident pat during error recovery? + + // adding + check("let a ", "let a @ ()", Some(make::tuple_pat([]).into())); + check("let a @ ", "let a @ ()", Some(make::tuple_pat([]).into())); + + // removing + check("let a @ ()", "let a", None); + check("let a @ ", "let a", None); + } + #[test] fn add_variant_to_empty_enum() { let variant = make::variant(make::name("Bar"), None).clone_for_update(); From e844784d8db048079db95e5b8b954eb7228e6047 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 14 Nov 2023 10:08:19 +0100 Subject: [PATCH 2380/2442] Simplify --- crates/hir-def/src/body/pretty.rs | 2 +- crates/hir-def/src/data.rs | 6 +- crates/hir-def/src/generics.rs | 2 +- crates/hir-def/src/item_tree/lower.rs | 13 +--- crates/hir-ty/src/db.rs | 26 ++++---- crates/hir-ty/src/lower.rs | 92 ++++++++++++++------------- crates/hir-ty/src/tests/traits.rs | 56 ++++++++-------- crates/hir-ty/src/traits.rs | 4 +- crates/hir/src/display.rs | 2 +- crates/ide-diagnostics/src/lib.rs | 6 +- crates/test-utils/src/minicore.rs | 11 +++- 11 files changed, 110 insertions(+), 110 deletions(-) diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index fad4d7a4da66..6ecf1c20d6c1 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -54,7 +54,7 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false }; if let DefWithBodyId::FunctionId(it) = owner { p.buf.push('('); - body.params.iter().zip(&db.function_data(it).params).for_each(|(¶m, ty)| { + body.params.iter().zip(db.function_data(it).params.iter()).for_each(|(¶m, ty)| { p.print_pat(param); p.buf.push(':'); p.print_type_ref(ty); diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 718f241cf780..93fd741aff63 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -34,7 +34,7 @@ use crate::{ #[derive(Debug, Clone, PartialEq, Eq)] pub struct FunctionData { pub name: Name, - pub params: Vec>, + pub params: Box<[Interned]>, pub ret_type: Interned, pub attrs: Attrs, pub visibility: RawVisibility, @@ -177,7 +177,7 @@ pub struct TypeAliasData { pub rustc_has_incoherent_inherent_impls: bool, pub rustc_allow_incoherent_impl: bool, /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). - pub bounds: Vec>, + pub bounds: Box<[Interned]>, } impl TypeAliasData { @@ -210,7 +210,7 @@ impl TypeAliasData { is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)), rustc_has_incoherent_inherent_impls, rustc_allow_incoherent_impl, - bounds: typ.bounds.to_vec(), + bounds: typ.bounds.clone(), }) } } diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index 1e2535a8a999..fac90e663045 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -227,7 +227,7 @@ impl GenericParams { let mut expander = Lazy::new(|| { (module.def_map(db), Expander::new(db, loc.source(db).file_id, module)) }); - for param in &func_data.params { + for param in func_data.params.iter() { generic_params.fill_implicit_impl_trait_args(db, &mut expander, param); } diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index c0a880a64bb6..30b649d2f3a0 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -396,14 +396,7 @@ impl<'a> Ctx<'a> { let bounds = self.lower_type_bounds(type_alias); let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); - let res = TypeAlias { - name, - visibility, - bounds: bounds.into_boxed_slice(), - generic_params, - type_ref, - ast_id, - }; + let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id }; Some(id(self.data().type_aliases.alloc(res))) } @@ -637,13 +630,13 @@ impl<'a> Ctx<'a> { Interned::new(generics) } - fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Vec> { + fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned]> { match node.type_bound_list() { Some(bound_list) => bound_list .bounds() .map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it))) .collect(), - None => Vec::new(), + None => Box::default(), } } diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 9c96b5ab8dbb..410bcbf0356f 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -20,8 +20,8 @@ use crate::{ method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, mir::{BorrowckResult, MirBody, MirLowerError}, Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, InferenceResult, - Interner, PolyFnSig, QuantifiedWhereClause, ReturnTypeImplTraits, Substitution, TraitRef, Ty, - TyDefId, ValueTyDefId, + Interner, PolyFnSig, QuantifiedWhereClause, ReturnTypeImplTraits, Substitution, + TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId, }; use hir_expand::name::Name; @@ -47,7 +47,7 @@ pub trait HirDatabase: DefDatabase + Upcast { &self, def: DefWithBodyId, subst: Substitution, - env: Arc, + env: Arc, ) -> Result, MirLowerError>; #[salsa::invoke(crate::mir::monomorphized_mir_body_for_closure_query)] @@ -55,7 +55,7 @@ pub trait HirDatabase: DefDatabase + Upcast { &self, def: ClosureId, subst: Substitution, - env: Arc, + env: Arc, ) -> Result, MirLowerError>; #[salsa::invoke(crate::mir::borrowck_query)] @@ -81,7 +81,7 @@ pub trait HirDatabase: DefDatabase + Upcast { &self, def: GeneralConstId, subst: Substitution, - trait_env: Option>, + trait_env: Option>, ) -> Result; #[salsa::invoke(crate::consteval::const_eval_static_query)] @@ -104,16 +104,12 @@ pub trait HirDatabase: DefDatabase + Upcast { &self, def: AdtId, subst: Substitution, - env: Arc, + env: Arc, ) -> Result, LayoutError>; #[salsa::invoke(crate::layout::layout_of_ty_query)] #[salsa::cycle(crate::layout::layout_of_ty_recover)] - fn layout_of_ty( - &self, - ty: Ty, - env: Arc, - ) -> Result, LayoutError>; + fn layout_of_ty(&self, ty: Ty, env: Arc) -> Result, LayoutError>; #[salsa::invoke(crate::layout::target_data_layout_query)] fn target_data_layout(&self, krate: CrateId) -> Option>; @@ -121,7 +117,7 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)] fn lookup_impl_method( &self, - env: Arc, + env: Arc, func: FunctionId, fn_subst: Substitution, ) -> (FunctionId, Substitution); @@ -149,10 +145,10 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::lower::trait_environment_for_body_query)] #[salsa::transparent] - fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc; + fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc; #[salsa::invoke(crate::lower::trait_environment_query)] - fn trait_environment(&self, def: GenericDefId) -> Arc; + fn trait_environment(&self, def: GenericDefId) -> Arc; #[salsa::invoke(crate::lower::generic_defaults_query)] #[salsa::cycle(crate::lower::generic_defaults_recover)] @@ -249,7 +245,7 @@ pub trait HirDatabase: DefDatabase + Upcast { fn normalize_projection( &self, projection: crate::ProjectionTy, - env: Arc, + env: Arc, ) -> Ty; #[salsa::invoke(trait_solve_wait)] diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 9a61f1535993..c8a85b4a9ff0 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -1383,51 +1383,50 @@ pub(crate) fn generic_predicates_for_param_query( let ctx = TyLoweringContext::new(db, &resolver, def.into()) .with_type_param_mode(ParamLoweringMode::Variable); let generics = generics(db.upcast(), def); + + // we have to filter out all other predicates *first*, before attempting to lower them + let predicate = |pred: &&_| match pred { + WherePredicate::ForLifetime { target, bound, .. } + | WherePredicate::TypeBound { target, bound, .. } => { + let invalid_target = match target { + WherePredicateTypeTarget::TypeRef(type_ref) => { + ctx.lower_ty_only_param(type_ref) != Some(param_id) + } + &WherePredicateTypeTarget::TypeOrConstParam(local_id) => { + let target_id = TypeOrConstParamId { parent: def, local_id }; + target_id != param_id + } + }; + if invalid_target { + return false; + } + + match &**bound { + TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => { + // Only lower the bound if the trait could possibly define the associated + // type we're looking for. + + let Some(assoc_name) = &assoc_name else { return true }; + let Some(TypeNs::TraitId(tr)) = + resolver.resolve_path_in_type_ns_fully(db.upcast(), path) + else { + return false; + }; + + all_super_traits(db.upcast(), tr).iter().any(|tr| { + db.trait_data(*tr).items.iter().any(|(name, item)| { + matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name + }) + }) + } + TypeBound::Lifetime(_) | TypeBound::Error => false, + } + } + WherePredicate::Lifetime { .. } => false, + }; let mut predicates: Vec<_> = resolver .where_predicates_in_scope() - // we have to filter out all other predicates *first*, before attempting to lower them - .filter(|pred| match pred { - WherePredicate::ForLifetime { target, bound, .. } - | WherePredicate::TypeBound { target, bound, .. } => { - match target { - WherePredicateTypeTarget::TypeRef(type_ref) => { - if ctx.lower_ty_only_param(type_ref) != Some(param_id) { - return false; - } - } - &WherePredicateTypeTarget::TypeOrConstParam(local_id) => { - let target_id = TypeOrConstParamId { parent: def, local_id }; - if target_id != param_id { - return false; - } - } - }; - - match &**bound { - TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => { - // Only lower the bound if the trait could possibly define the associated - // type we're looking for. - - let assoc_name = match &assoc_name { - Some(it) => it, - None => return true, - }; - let tr = match resolver.resolve_path_in_type_ns_fully(db.upcast(), path) { - Some(TypeNs::TraitId(tr)) => tr, - _ => return false, - }; - - all_super_traits(db.upcast(), tr).iter().any(|tr| { - db.trait_data(*tr).items.iter().any(|(name, item)| { - matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name - }) - }) - } - TypeBound::Lifetime(_) | TypeBound::Error => false, - } - } - WherePredicate::Lifetime { .. } => false, - }) + .filter(predicate) .flat_map(|pred| { ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p)) }) @@ -1519,7 +1518,12 @@ pub(crate) fn trait_environment_query( let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses); - Arc::new(TraitEnvironment { krate, block: None, traits_from_clauses: traits_in_scope, env }) + Arc::new(TraitEnvironment { + krate, + block: None, + traits_from_clauses: traits_in_scope.into_boxed_slice(), + env, + }) } /// Resolve the where clause(s) of an item with generics. diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index d36b885ec14a..73016d38bb92 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -4439,42 +4439,42 @@ fn test(v: S) { fn associated_type_in_argument() { check( r#" - trait A { - fn m(&self) -> i32; - } +trait A { + fn m(&self) -> i32; +} - fn x(k: &::Ty) { - k.m(); - } +fn x(k: &::Ty) { + k.m(); +} - struct X; - struct Y; +struct X; +struct Y; - impl A for X { - fn m(&self) -> i32 { - 8 - } +impl A for X { + fn m(&self) -> i32 { + 8 } +} - impl A for Y { - fn m(&self) -> i32 { - 32 - } +impl A for Y { + fn m(&self) -> i32 { + 32 } +} - trait B { - type Ty: A; - } +trait B { + type Ty: A; +} - impl B for u16 { - type Ty = X; - } +impl B for u16 { + type Ty = X; +} - fn ttt() { - let inp = Y; - x::(&inp); - //^^^^ expected &X, got &Y - } - "#, +fn ttt() { + let inp = Y; + x::(&inp); + //^^^^ expected &X, got &Y +} +"#, ); } diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index 3c7cfbaed3a4..467b94a2662a 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -48,7 +48,7 @@ pub struct TraitEnvironment { pub krate: CrateId, pub block: Option, // FIXME make this a BTreeMap - pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>, + pub(crate) traits_from_clauses: Box<[(Ty, TraitId)]>, pub env: chalk_ir::Environment, } @@ -57,7 +57,7 @@ impl TraitEnvironment { TraitEnvironment { krate, block: None, - traits_from_clauses: Vec::new(), + traits_from_clauses: Box::default(), env: chalk_ir::Environment::new(Interner), } } diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index cf3ff62fc6c5..5847c8a9fb52 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -616,7 +616,7 @@ impl HirDisplay for TypeAlias { write_where_clause(def_id, f)?; if !data.bounds.is_empty() { f.write_str(": ")?; - f.write_joined(&data.bounds, " + ")?; + f.write_joined(data.bounds.iter(), " + ")?; } if let Some(ty) = &data.type_ref { f.write_str(" = ")?; diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index d8e37a848ac0..68d7e99b7b80 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -301,9 +301,9 @@ pub fn diagnostics( ) })); - let parse = sema.parse(file_id); + let parse = parse.syntax_node(); - for node in parse.syntax().descendants() { + for node in parse.descendants() { handlers::useless_braces::useless_braces(&mut res, file_id, &node); handlers::field_shorthand::field_shorthand(&mut res, file_id, &node); handlers::json_is_not_rust::json_in_items(&sema, &mut res, file_id, &node, config); @@ -386,7 +386,7 @@ pub fn diagnostics( handle_lint_attributes( &ctx.sema, - parse.syntax(), + &parse, &mut rustc_stack, &mut clippy_stack, &mut diagnostics_of_range, diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index cc41d87f5d97..f2ca9d82ed0d 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -44,7 +44,7 @@ //! panic: fmt //! phantom_data: //! pin: -//! pointee: +//! pointee: copy, send, sync, ord, hash, unpin //! range: //! result: //! send: sized @@ -54,6 +54,7 @@ //! sync: sized //! transmute: //! try: infallible +//! unpin: sized //! unsize: sized #![rustc_coherence_is_core] @@ -89,6 +90,11 @@ pub mod marker { pub trait Unsize {} // endregion:unsize + // region:unpin + #[lang = "unpin"] + pub auto trait Unpin {} + // endregion:unpin + // region:copy #[lang = "copy"] pub trait Copy: Clone {} @@ -387,9 +393,10 @@ pub mod ptr { // region:pointee #[lang = "pointee_trait"] + #[rustc_deny_explicit_impl(implement_via_object = false)] pub trait Pointee { #[lang = "metadata_type"] - type Metadata; + type Metadata: Copy + Send + Sync + Ord + Hash + Unpin; } // endregion:pointee // region:non_null From b74015512d06030973641ded964311cfb4e981d0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 14 Nov 2023 13:32:04 +0100 Subject: [PATCH 2381/2442] Remove UserError from LayoutError --- crates/hir-ty/src/layout.rs | 57 ++++++++++++++++++++----------- crates/hir-ty/src/layout/adt.rs | 8 ++--- crates/hir-ty/src/layout/tests.rs | 7 ++-- crates/hir-ty/src/tests/traits.rs | 2 +- 4 files changed, 42 insertions(+), 32 deletions(-) diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index 603e58f9d462..b2591f016d42 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -1,5 +1,7 @@ //! Compute the binary representation of a type +use std::fmt; + use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use hir_def::{ layout::{ @@ -26,12 +28,6 @@ pub use self::{ target::target_data_layout_query, }; -macro_rules! user_error { - ($it: expr) => { - return Err(LayoutError::UserError(format!($it).into())) - }; -} - mod adt; mod target; @@ -73,13 +69,38 @@ pub type Variants = hir_def::layout::Variants), + HasErrorConst, + HasErrorType, + HasPlaceholder, + InvalidSimdType, + NotImplemented, + RecursiveTypeWithoutIndirection, SizeOverflow, TargetLayoutNotAvailable, - HasPlaceholder, - HasErrorType, - NotImplemented, Unknown, + UserReprTooSmall, +} + +impl std::error::Error for LayoutError {} +impl fmt::Display for LayoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + LayoutError::HasErrorConst => write!(f, "type contains an unevaluatable const"), + LayoutError::HasErrorType => write!(f, "type contains an error"), + LayoutError::HasPlaceholder => write!(f, "type contains placeholders"), + LayoutError::InvalidSimdType => write!(f, "invalid simd type definition"), + LayoutError::NotImplemented => write!(f, "not implemented"), + LayoutError::RecursiveTypeWithoutIndirection => { + write!(f, "recursive type without indirection") + } + LayoutError::SizeOverflow => write!(f, "size overflow"), + LayoutError::TargetLayoutNotAvailable => write!(f, "target layout not available"), + LayoutError::Unknown => write!(f, "unknown"), + LayoutError::UserReprTooSmall => { + write!(f, "the `#[repr]` hint is too small to hold the discriminants of the enum") + } + } + } } struct LayoutCx<'a> { @@ -118,9 +139,7 @@ fn layout_of_simd_ty( let f0_ty = match fields.iter().next() { Some(it) => it.1.clone().substitute(Interner, subst), - None => { - user_error!("simd type with zero fields"); - } + None => return Err(LayoutError::InvalidSimdType), }; // The element type and number of elements of the SIMD vector @@ -134,7 +153,7 @@ fn layout_of_simd_ty( // Extract the number of elements from the layout of the array field: let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), env.clone())?.fields else { - user_error!("Array with non array layout"); + return Err(LayoutError::Unknown); }; (e_ty.clone(), count, true) @@ -146,7 +165,7 @@ fn layout_of_simd_ty( // Compute the ABI of the element type: let e_ly = db.layout_of_ty(e_ty, env.clone())?; let Abi::Scalar(e_abi) = e_ly.abi else { - user_error!("simd type with inner non scalar type"); + return Err(LayoutError::Unknown); }; // Compute the size and alignment of the vector: @@ -259,9 +278,7 @@ pub fn layout_of_ty_query( cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)? } TyKind::Array(element, count) => { - let count = try_const_usize(db, &count).ok_or(LayoutError::UserError(Box::from( - "unevaluated or mistyped const generic parameter", - )))? as u64; + let count = try_const_usize(db, &count).ok_or(LayoutError::HasErrorConst)? as u64; let element = db.layout_of_ty(element.clone(), trait_env.clone())?; let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?; @@ -352,7 +369,7 @@ pub fn layout_of_ty_query( let mut unit = layout_of_unit(&cx, dl)?; match unit.abi { Abi::Aggregate { ref mut sized } => *sized = false, - _ => user_error!("bug"), + _ => return Err(LayoutError::Unknown), } unit } @@ -418,7 +435,7 @@ pub fn layout_of_ty_recover( _: &Ty, _: &Arc, ) -> Result, LayoutError> { - user_error!("infinite sized recursive type"); + Err(LayoutError::RecursiveTypeWithoutIndirection) } fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result { diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index 5e713c17cf81..58a06dc64354 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -145,7 +145,7 @@ pub fn layout_of_adt_recover( _: &Substitution, _: &Arc, ) -> Result, LayoutError> { - user_error!("infinite sized recursive type"); + Err(LayoutError::RecursiveTypeWithoutIndirection) } /// Finds the appropriate Integer type and signedness for the given @@ -169,11 +169,7 @@ fn repr_discr( let discr = Integer::from_attr(dl, ity); let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; if discr < fit { - return Err(LayoutError::UserError( - "Integer::repr_discr: `#[repr]` hint too small for \ - discriminant range of enum " - .into(), - )); + return Err(LayoutError::UserReprTooSmall); } return Ok((discr, ity.is_signed())); } diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index ffdbb9de934d..5e3a86c80e3f 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -210,16 +210,13 @@ fn recursive() { struct BoxLike(*mut T); struct Goal(BoxLike); } - check_fail( - r#"struct Goal(Goal);"#, - LayoutError::UserError("infinite sized recursive type".into()), - ); + check_fail(r#"struct Goal(Goal);"#, LayoutError::RecursiveTypeWithoutIndirection); check_fail( r#" struct Foo(Foo); struct Goal(Foo); "#, - LayoutError::UserError("infinite sized recursive type".into()), + LayoutError::RecursiveTypeWithoutIndirection, ); } diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 73016d38bb92..48dd9540329d 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -4473,7 +4473,7 @@ impl B for u16 { fn ttt() { let inp = Y; x::(&inp); - //^^^^ expected &X, got &Y + //^^^^ expected &X, got &Y } "#, ); From 6ddccc9a6e81ebd3350568575051ac795184fa81 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 14 Nov 2023 18:09:28 +0100 Subject: [PATCH 2382/2442] Diagnose some orphan trait impl cases --- crates/hir-ty/src/diagnostics.rs | 6 - crates/hir-ty/src/lib.rs | 1 + crates/hir-ty/src/method_resolution.rs | 56 +++++++++ crates/hir/src/diagnostics.rs | 15 ++- crates/hir/src/lib.rs | 13 ++- .../src/handlers/trait_impl_orphan.rs | 106 ++++++++++++++++++ crates/ide-diagnostics/src/lib.rs | 8 +- crates/ide-diagnostics/src/tests.rs | 15 ++- 8 files changed, 205 insertions(+), 15 deletions(-) create mode 100644 crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs diff --git a/crates/hir-ty/src/diagnostics.rs b/crates/hir-ty/src/diagnostics.rs index ef43ed5c463f..c1b3619009bd 100644 --- a/crates/hir-ty/src/diagnostics.rs +++ b/crates/hir-ty/src/diagnostics.rs @@ -11,9 +11,3 @@ pub use crate::diagnostics::{ }, unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr}, }; - -#[derive(Debug, PartialEq, Eq)] -pub struct IncoherentImpl { - pub file_id: hir_expand::HirFileId, - pub impl_: syntax::AstPtr, -} diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 405bb001b5d1..35a3a1ad8d99 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -80,6 +80,7 @@ pub use mapping::{ lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id, to_placeholder_idx, }; +pub use method_resolution::check_orphan_rules; pub use traits::TraitEnvironment; pub use utils::{all_super_traits, is_fn_unsafe_to_call}; diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index f3a5f69b2a63..87c93283361f 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -862,6 +862,62 @@ fn is_inherent_impl_coherent( } } +/// Checks whether the impl satisfies the orphan rules. +/// +/// Given `impl Trait for T0`, an `impl`` is valid only if at least one of the following is true: +/// - Trait is a local trait +/// - All of +/// - At least one of the types `T0..=Tn`` must be a local type. Let `Ti`` be the first such type. +/// - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`) +pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool { + let substs = TyBuilder::placeholder_subst(db, impl_); + let Some(impl_trait) = db.impl_trait(impl_) else { + // not a trait impl + return true; + }; + + let local_crate = impl_.lookup(db.upcast()).container.krate(); + let is_local = |tgt_crate| tgt_crate == local_crate; + + let trait_ref = impl_trait.substitute(Interner, &substs); + let trait_id = from_chalk_trait_id(trait_ref.trait_id); + if is_local(trait_id.module(db.upcast()).krate()) { + // trait to be implemented is local + return true; + } + + let unwrap_fundamental = |ty: Ty| match ty.kind(Interner) { + TyKind::Ref(_, _, referenced) => referenced.clone(), + &TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), ref subs) => { + let struct_data = db.struct_data(s); + if struct_data.flags.contains(StructFlags::IS_FUNDAMENTAL) { + let next = subs.type_parameters(Interner).next(); + match next { + Some(ty) => ty, + None => ty, + } + } else { + ty + } + } + _ => ty, + }; + // - At least one of the types `T0..=Tn`` must be a local type. Let `Ti`` be the first such type. + let is_not_orphan = trait_ref.substitution.type_parameters(Interner).any(|ty| { + match unwrap_fundamental(ty).kind(Interner) { + &TyKind::Adt(AdtId(id), _) => is_local(id.module(db.upcast()).krate()), + TyKind::Error => true, + TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| { + is_local(from_chalk_trait_id(trait_ref.trait_id).module(db.upcast()).krate()) + }), + _ => false, + } + }); + // FIXME: param coverage + // - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`) + is_not_orphan +} + pub fn iterate_path_candidates( ty: &Canonical, db: &dyn HirDatabase, diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 67d3169243c6..3a4562267554 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -3,7 +3,7 @@ //! //! This probably isn't the best way to do this -- ideally, diagnostics should //! be expressed in terms of hir types themselves. -pub use hir_ty::diagnostics::{CaseType, IncoherentImpl, IncorrectCase}; +pub use hir_ty::diagnostics::{CaseType, IncorrectCase}; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; @@ -38,6 +38,7 @@ diagnostics![ IncorrectCase, InvalidDeriveTarget, IncoherentImpl, + TraitImplOrphan, MacroDefError, MacroError, MacroExpansionParseError, @@ -280,3 +281,15 @@ pub struct MovedOutOfRef { pub ty: Type, pub span: InFile, } + +#[derive(Debug, PartialEq, Eq)] +pub struct IncoherentImpl { + pub file_id: HirFileId, + pub impl_: AstPtr, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct TraitImplOrphan { + pub file_id: HirFileId, + pub impl_: AstPtr, +} diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 6fcc02fb9dac..dfb0779f1029 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -60,7 +60,7 @@ use hir_def::{ }; use hir_expand::{name::name, MacroCallKind}; use hir_ty::{ - all_super_traits, autoderef, + all_super_traits, autoderef, check_orphan_rules, consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt}, diagnostics::BodyValidationDiagnostic, known_const_to_ast, @@ -95,7 +95,7 @@ pub use crate::{ MacroExpansionParseError, MalformedDerive, MismatchedArgCount, MismatchedTupleStructPatArgCount, MissingFields, MissingMatchArms, MissingUnsafe, MovedOutOfRef, NeedMut, NoSuchField, PrivateAssocItem, PrivateField, - ReplaceFilterMapNextWithFindMap, TypeMismatch, TypedHole, UndeclaredLabel, + ReplaceFilterMapNextWithFindMap, TraitImplOrphan, TypeMismatch, TypedHole, UndeclaredLabel, UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField, UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro, UnusedMut, UnusedVariable, @@ -624,6 +624,11 @@ impl Module { acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) } + if !impl_def.check_orphan_rules(db) { + let ast_id_map = db.ast_id_map(file_id); + acc.push(TraitImplOrphan { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) + } + for item in impl_def.items(db) { let def: DefWithBody = match item { AssocItem::Function(it) => it.into(), @@ -3406,6 +3411,10 @@ impl Impl { let src = self.source(db)?; src.file_id.as_builtin_derive_attr_node(db.upcast()) } + + pub fn check_orphan_rules(self, db: &dyn HirDatabase) -> bool { + check_orphan_rules(db, self.id) + } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs b/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs new file mode 100644 index 000000000000..159d87d269de --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs @@ -0,0 +1,106 @@ +use hir::InFile; + +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: trait-impl-orphan +// +// Only traits defined in the current crate can be implemented for arbitrary types +pub(crate) fn trait_impl_orphan( + ctx: &DiagnosticsContext<'_>, + d: &hir::TraitImplOrphan, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0117"), + format!("only traits defined in the current crate can be implemented for arbitrary types"), + InFile::new(d.file_id, d.impl_.clone().into()), + ) + // Not yet checked for false positives + .experimental() +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn simple() { + check_diagnostics( + r#" +//- /foo.rs crate:foo +pub trait Foo {} +//- /bar.rs crate:bar +pub struct Bar; +//- /main.rs crate:main deps:foo,bar +struct LocalType; +trait LocalTrait {} + impl foo::Foo for bar::Bar {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: only traits defined in the current crate can be implemented for arbitrary types +impl foo::Foo for LocalType {} +impl LocalTrait for bar::Bar {} +"#, + ); + } + + #[test] + fn generics() { + check_diagnostics( + r#" +//- /foo.rs crate:foo +pub trait Foo {} +//- /bar.rs crate:bar +pub struct Bar(T); +//- /main.rs crate:main deps:foo,bar +struct LocalType; +trait LocalTrait {} + impl foo::Foo for bar::Bar {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: only traits defined in the current crate can be implemented for arbitrary types + + impl foo::Foo for bar::Bar> {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: only traits defined in the current crate can be implemented for arbitrary types + + impl foo::Foo> for bar::Bar {} + + impl foo::Foo>> for bar::Bar> {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: only traits defined in the current crate can be implemented for arbitrary types +"#, + ); + } + + #[test] + fn fundamental() { + check_diagnostics( + r#" +//- /foo.rs crate:foo +pub trait Foo {} +//- /bar.rs crate:bar +pub struct Bar(T); +#[lang = "owned_box"] +#[fundamental] +pub struct Box(T); +//- /main.rs crate:main deps:foo,bar +struct LocalType; + impl foo::Foo for bar::Box {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: only traits defined in the current crate can be implemented for arbitrary types + impl foo::Foo for &LocalType {} + impl foo::Foo for bar::Box {} +"#, + ); + } + + #[test] + fn dyn_object() { + check_diagnostics( + r#" +//- /foo.rs crate:foo +pub trait Foo {} +//- /bar.rs crate:bar +pub struct Bar; +//- /main.rs crate:main deps:foo,bar +trait LocalTrait {} +impl foo::Foo for dyn LocalTrait {} +impl foo::Foo for Bar {} +"#, + ); + } +} diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 68d7e99b7b80..3226dd29d21d 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -44,6 +44,7 @@ mod handlers { pub(crate) mod private_assoc_item; pub(crate) mod private_field; pub(crate) mod replace_filter_map_next_with_find_map; + pub(crate) mod trait_impl_orphan; pub(crate) mod typed_hole; pub(crate) mod type_mismatch; pub(crate) mod unimplemented_builtin_macro; @@ -301,9 +302,9 @@ pub fn diagnostics( ) })); - let parse = parse.syntax_node(); + let parse = sema.parse(file_id); - for node in parse.descendants() { + for node in parse.syntax().descendants() { handlers::useless_braces::useless_braces(&mut res, file_id, &node); handlers::field_shorthand::field_shorthand(&mut res, file_id, &node); handlers::json_is_not_rust::json_in_items(&sema, &mut res, file_id, &node, config); @@ -358,6 +359,7 @@ pub fn diagnostics( AnyDiagnostic::PrivateAssocItem(d) => handlers::private_assoc_item::private_assoc_item(&ctx, &d), AnyDiagnostic::PrivateField(d) => handlers::private_field::private_field(&ctx, &d), AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d), + AnyDiagnostic::TraitImplOrphan(d) => handlers::trait_impl_orphan::trait_impl_orphan(&ctx, &d), AnyDiagnostic::TypedHole(d) => handlers::typed_hole::typed_hole(&ctx, &d), AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d), AnyDiagnostic::UndeclaredLabel(d) => handlers::undeclared_label::undeclared_label(&ctx, &d), @@ -386,7 +388,7 @@ pub fn diagnostics( handle_lint_attributes( &ctx.sema, - &parse, + parse.syntax(), &mut rustc_stack, &mut clippy_stack, &mut diagnostics_of_range, diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs index ee0e0354906e..ff8f3b268603 100644 --- a/crates/ide-diagnostics/src/tests.rs +++ b/crates/ide-diagnostics/src/tests.rs @@ -5,7 +5,7 @@ use expect_test::Expect; use ide_db::{ assists::AssistResolveStrategy, base_db::{fixture::WithFixture, SourceDatabaseExt}, - RootDatabase, + LineIndexDatabase, RootDatabase, }; use stdx::trim_indent; use test_utils::{assert_eq_text, extract_annotations, MiniCore}; @@ -103,6 +103,7 @@ pub(crate) fn check_diagnostics(ra_fixture: &str) { pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) { let (db, files) = RootDatabase::with_many_files(ra_fixture); for file_id in files { + let line_index = db.line_index(file_id); let diagnostics = super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id); let expected = extract_annotations(&db.file_text(file_id)); @@ -136,8 +137,16 @@ pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixtur } } if expected != actual { - let fneg = expected.iter().filter(|x| !actual.contains(x)).collect::>(); - let fpos = actual.iter().filter(|x| !expected.contains(x)).collect::>(); + let fneg = expected + .iter() + .filter(|x| !actual.contains(x)) + .map(|(range, s)| (line_index.line_col(range.start()), range, s)) + .collect::>(); + let fpos = actual + .iter() + .filter(|x| !expected.contains(x)) + .map(|(range, s)| (line_index.line_col(range.start()), range, s)) + .collect::>(); panic!("Diagnostic test failed.\nFalse negatives: {fneg:?}\nFalse positives: {fpos:?}"); } From d5faad1dae0b5c43b19efbfba7a268f1800b56e4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 14 Nov 2023 18:53:17 +0100 Subject: [PATCH 2383/2442] Fix inlay-hint tests being invalidated by minicore chanes --- crates/hir/src/lib.rs | 4 ++++ crates/ide/src/inlay_hints.rs | 17 +++++++++++++++++ crates/ide/src/inlay_hints/chaining.rs | 20 +++++++++++--------- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index dfb0779f1029..8d82e88da9d7 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -3403,6 +3403,10 @@ impl Impl { db.impl_data(self.id).is_negative } + pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { + db.impl_data(self.id).is_unique() + } + pub fn module(self, db: &dyn HirDatabase) -> Module { self.id.lookup(db.upcast()).container.into() } diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index a5d070fe7673..24f44ca06ffb 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -563,6 +563,7 @@ mod tests { use hir::ClosureStyle; use itertools::Itertools; use test_utils::extract_annotations; + use text_edit::{TextRange, TextSize}; use crate::inlay_hints::{AdjustmentHints, AdjustmentHintsMode}; use crate::DiscriminantHints; @@ -629,6 +630,22 @@ mod tests { expect.assert_debug_eq(&inlay_hints) } + #[track_caller] + pub(super) fn check_expect_clear_loc( + config: InlayHintsConfig, + ra_fixture: &str, + expect: Expect, + ) { + let (analysis, file_id) = fixture::file(ra_fixture); + let mut inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); + inlay_hints.iter_mut().flat_map(|hint| &mut hint.label.parts).for_each(|hint| { + if let Some(loc) = &mut hint.linked_location { + loc.range = TextRange::empty(TextSize::from(0)); + } + }); + expect.assert_debug_eq(&inlay_hints) + } + /// Computes inlay hints for the fixture, applies all the provided text edits and then runs /// expect test. #[track_caller] diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index 4152e6067551..c9e9a2237867 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -78,7 +78,9 @@ mod tests { use expect_test::expect; use crate::{ - inlay_hints::tests::{check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG}, + inlay_hints::tests::{ + check_expect, check_expect_clear_loc, check_with_config, DISABLED_CONFIG, TEST_CONFIG, + }, InlayHintsConfig, }; @@ -444,7 +446,7 @@ fn main() { #[test] fn shorten_iterator_chaining_hints() { - check_expect( + check_expect_clear_loc( InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, r#" //- minicore: iterators @@ -484,7 +486,7 @@ fn main() { file_id: FileId( 1, ), - range: 10752..10760, + range: 0..0, }, ), tooltip: "", @@ -497,7 +499,7 @@ fn main() { file_id: FileId( 1, ), - range: 10784..10788, + range: 0..0, }, ), tooltip: "", @@ -522,7 +524,7 @@ fn main() { file_id: FileId( 1, ), - range: 10752..10760, + range: 0..0, }, ), tooltip: "", @@ -535,7 +537,7 @@ fn main() { file_id: FileId( 1, ), - range: 10784..10788, + range: 0..0, }, ), tooltip: "", @@ -560,7 +562,7 @@ fn main() { file_id: FileId( 1, ), - range: 10752..10760, + range: 0..0, }, ), tooltip: "", @@ -573,7 +575,7 @@ fn main() { file_id: FileId( 1, ), - range: 10784..10788, + range: 0..0, }, ), tooltip: "", @@ -598,7 +600,7 @@ fn main() { file_id: FileId( 0, ), - range: 24..30, + range: 0..0, }, ), tooltip: "", From e21d21a8fb58696b6e0b790d14d13126afecc6b3 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 14 Nov 2023 20:02:23 +0100 Subject: [PATCH 2384/2442] Diagnose incorrect unsafety for trait impls --- crates/hir-def/src/data.rs | 11 +- crates/hir-def/src/item_tree.rs | 1 + crates/hir-def/src/item_tree/lower.rs | 4 +- crates/hir-def/src/item_tree/pretty.rs | 14 ++- crates/hir/src/diagnostics.rs | 11 +- crates/hir/src/lib.rs | 70 ++++++++--- .../handlers/trait_impl_incorrect_safety.rs | 115 ++++++++++++++++++ crates/ide-diagnostics/src/lib.rs | 2 + 8 files changed, 204 insertions(+), 24 deletions(-) create mode 100644 crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 93fd741aff63..72ccc17486f0 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -327,6 +327,7 @@ pub struct ImplData { pub self_ty: Interned, pub items: Vec, pub is_negative: bool, + pub is_unsafe: bool, // box it as the vec is usually empty anyways pub attribute_calls: Option, MacroCallId)>>>, } @@ -348,6 +349,7 @@ impl ImplData { let target_trait = impl_def.target_trait.clone(); let self_ty = impl_def.self_ty.clone(); let is_negative = impl_def.is_negative; + let is_unsafe = impl_def.is_unsafe; let mut collector = AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::ImplId(id)); @@ -357,7 +359,14 @@ impl ImplData { let items = items.into_iter().map(|(_, item)| item).collect(); ( - Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls }), + Arc::new(ImplData { + target_trait, + self_ty, + items, + is_negative, + is_unsafe, + attribute_calls, + }), diagnostics.into(), ) } diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 3c4f21d5c69b..70b96b25739c 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -709,6 +709,7 @@ pub struct Impl { pub target_trait: Option>, pub self_ty: Interned, pub is_negative: bool, + pub is_unsafe: bool, pub items: Box<[AssocItem]>, pub ast_id: FileAstId, } diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 30b649d2f3a0..c898eb5f9211 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -492,6 +492,7 @@ impl<'a> Ctx<'a> { let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr)); let self_ty = self.lower_type_ref(&impl_def.self_ty()?); let is_negative = impl_def.excl_token().is_some(); + let is_unsafe = impl_def.unsafe_token().is_some(); // We cannot use `assoc_items()` here as that does not include macro calls. let items = impl_def @@ -506,7 +507,8 @@ impl<'a> Ctx<'a> { }) .collect(); let ast_id = self.source_ast_id_map.ast_id(impl_def); - let res = Impl { generic_params, target_trait, self_ty, is_negative, items, ast_id }; + let res = + Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id }; Some(id(self.data().impls.alloc(res))) } diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index 5036c2b88297..ca3785bf28df 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -388,8 +388,18 @@ impl Printer<'_> { wln!(self); } ModItem::Impl(it) => { - let Impl { target_trait, self_ty, is_negative, items, generic_params, ast_id: _ } = - &self.tree[it]; + let Impl { + target_trait, + self_ty, + is_negative, + is_unsafe, + items, + generic_params, + ast_id: _, + } = &self.tree[it]; + if *is_unsafe { + w!(self, "unsafe"); + } w!(self, "impl"); self.print_generic_params(generic_params); w!(self, " "); diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 3a4562267554..dd5c9b3535a0 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -38,7 +38,6 @@ diagnostics![ IncorrectCase, InvalidDeriveTarget, IncoherentImpl, - TraitImplOrphan, MacroDefError, MacroError, MacroExpansionParseError, @@ -54,6 +53,8 @@ diagnostics![ PrivateAssocItem, PrivateField, ReplaceFilterMapNextWithFindMap, + TraitImplIncorrectSafety, + TraitImplOrphan, TypedHole, TypeMismatch, UndeclaredLabel, @@ -293,3 +294,11 @@ pub struct TraitImplOrphan { pub file_id: HirFileId, pub impl_: AstPtr, } + +// FIXME: Split this off into the corresponding 4 rustc errors +#[derive(Debug, PartialEq, Eq)] +pub struct TraitImplIncorrectSafety { + pub file_id: HirFileId, + pub impl_: AstPtr, + pub should_be_safe: bool, +} diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8d82e88da9d7..066d7e635a26 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -53,10 +53,10 @@ use hir_def::{ resolver::{HasResolver, Resolver}, src::HasSource as _, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, - EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, HasModule, ImplId, - InTypeConstId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup, - MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, - TypeOrConstParamId, TypeParamId, UnionId, + EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, + ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, + Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, + TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{name::name, MacroCallKind}; use hir_ty::{ @@ -89,17 +89,7 @@ use crate::db::{DefDatabase, HirDatabase}; pub use crate::{ attrs::{resolve_doc_path_on, HasAttrs}, - diagnostics::{ - AnyDiagnostic, BreakOutsideOfLoop, CaseType, ExpectedFunction, InactiveCode, - IncoherentImpl, IncorrectCase, InvalidDeriveTarget, MacroDefError, MacroError, - MacroExpansionParseError, MalformedDerive, MismatchedArgCount, - MismatchedTupleStructPatArgCount, MissingFields, MissingMatchArms, MissingUnsafe, - MovedOutOfRef, NeedMut, NoSuchField, PrivateAssocItem, PrivateField, - ReplaceFilterMapNextWithFindMap, TraitImplOrphan, TypeMismatch, TypedHole, UndeclaredLabel, - UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField, - UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule, - UnresolvedProcMacro, UnusedMut, UnusedVariable, - }, + diagnostics::*, has_source::HasSource, semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits}, }; @@ -613,22 +603,64 @@ impl Module { // FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow continue; } + let ast_id_map = db.ast_id_map(file_id); for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() { emit_def_diagnostic(db, acc, diag); } if inherent_impls.invalid_impls().contains(&impl_def.id) { - let ast_id_map = db.ast_id_map(file_id); - acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) } if !impl_def.check_orphan_rules(db) { - let ast_id_map = db.ast_id_map(file_id); acc.push(TraitImplOrphan { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) } + let trait_ = impl_def.trait_(db); + let trait_is_unsafe = trait_.map_or(false, |t| t.is_unsafe(db)); + let impl_is_negative = impl_def.is_negative(db); + let impl_is_unsafe = impl_def.is_unsafe(db); + + let drop_maybe_dangle = (|| { + // FIXME: This can be simplified a lot by exposing hir-ty's utils.rs::Generics helper + let trait_ = trait_?; + let drop_trait = db.lang_item(self.krate().into(), LangItem::Drop)?.as_trait()?; + if drop_trait != trait_.into() { + return None; + } + let parent = impl_def.id.into(); + let generic_params = db.generic_params(parent); + let lifetime_params = generic_params.lifetimes.iter().map(|(local_id, _)| { + GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id }) + }); + let type_params = generic_params + .iter() + .filter(|(_, it)| it.type_param().is_some()) + .map(|(local_id, _)| { + GenericParamId::TypeParamId(TypeParamId::from_unchecked( + TypeOrConstParamId { parent, local_id }, + )) + }); + let res = type_params + .chain(lifetime_params) + .any(|p| db.attrs(AttrDefId::GenericParamId(p)).by_key("may_dangle").exists()); + Some(res) + })() + .unwrap_or(false); + + match (impl_is_unsafe, trait_is_unsafe, impl_is_negative, drop_maybe_dangle) { + // unsafe negative impl + (true, _, true, _) | + // unsafe impl for safe trait + (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: true }.into()), + // safe impl for unsafe trait + (false, true, false, _) | + // safe impl of dangling drop + (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: false }.into()), + _ => (), + }; + for item in impl_def.items(db) { let def: DefWithBody = match item { AssocItem::Function(it) => it.into(), @@ -3404,7 +3436,7 @@ impl Impl { } pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { - db.impl_data(self.id).is_unique() + db.impl_data(self.id).is_unsafe } pub fn module(self, db: &dyn HirDatabase) -> Module { diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs b/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs new file mode 100644 index 000000000000..f28298de7d83 --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs @@ -0,0 +1,115 @@ +use hir::InFile; + +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity}; + +// Diagnostic: trait-impl-incorrect-safety +// +// Diagnoses incorrect safety annotations of trait impls. +pub(crate) fn trait_impl_incorrect_safety( + ctx: &DiagnosticsContext<'_>, + d: &hir::TraitImplIncorrectSafety, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::Ra("trait-impl-incorrect-safety", Severity::Error), + if d.should_be_safe { + "unsafe impl for safe trait" + } else { + "impl for unsafe trait needs to be unsafe" + }, + InFile::new(d.file_id, d.impl_.clone().into()), + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn simple() { + check_diagnostics( + r#" +trait Safe {} +unsafe trait Unsafe {} + + impl Safe for () {} + + impl Unsafe for () {} +//^^^^^^^^^^^^^^^^^^^^^ error: impl for unsafe trait needs to be unsafe + + unsafe impl Safe for () {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe impl for safe trait + + unsafe impl Unsafe for () {} +"#, + ); + } + + #[test] + fn drop_may_dangle() { + check_diagnostics( + r#" +#[lang = "drop"] +trait Drop {} +struct S; +struct L<'l>; + + impl Drop for S {} + + impl<#[may_dangle] T> Drop for S {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for unsafe trait needs to be unsafe + + unsafe impl Drop for S {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe impl for safe trait + + unsafe impl<#[may_dangle] T> Drop for S {} + + impl<'l> Drop for L<'l> {} + + impl<#[may_dangle] 'l> Drop for L<'l> {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for unsafe trait needs to be unsafe + + unsafe impl<'l> Drop for L<'l> {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe impl for safe trait + + unsafe impl<#[may_dangle] 'l> Drop for L<'l> {} +"#, + ); + } + + #[test] + fn negative() { + check_diagnostics( + r#" +trait Trait {} + + impl !Trait for () {} + + unsafe impl !Trait for () {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe impl for safe trait + +unsafe trait UnsafeTrait {} + + impl !UnsafeTrait for () {} + + unsafe impl !UnsafeTrait for () {} +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe impl for safe trait + +"#, + ); + } + + #[test] + fn inherent() { + check_diagnostics( + r#" +struct S; + + impl S {} + + unsafe impl S {} +//^^^^^^^^^^^^^^^^ error: unsafe impl for safe trait +"#, + ); + } +} diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 3226dd29d21d..99921c1107da 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -45,6 +45,7 @@ mod handlers { pub(crate) mod private_field; pub(crate) mod replace_filter_map_next_with_find_map; pub(crate) mod trait_impl_orphan; + pub(crate) mod trait_impl_incorrect_safety; pub(crate) mod typed_hole; pub(crate) mod type_mismatch; pub(crate) mod unimplemented_builtin_macro; @@ -360,6 +361,7 @@ pub fn diagnostics( AnyDiagnostic::PrivateField(d) => handlers::private_field::private_field(&ctx, &d), AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d), AnyDiagnostic::TraitImplOrphan(d) => handlers::trait_impl_orphan::trait_impl_orphan(&ctx, &d), + AnyDiagnostic::TraitImplIncorrectSafety(d) => handlers::trait_impl_incorrect_safety::trait_impl_incorrect_safety(&ctx, &d), AnyDiagnostic::TypedHole(d) => handlers::typed_hole::typed_hole(&ctx, &d), AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d), AnyDiagnostic::UndeclaredLabel(d) => handlers::undeclared_label::undeclared_label(&ctx, &d), From 723d799ec16dd206b122b371b5802965faa3745f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 14 Nov 2023 21:54:36 +0100 Subject: [PATCH 2385/2442] Diagnose missing assoc items in trait impls --- crates/hir/src/diagnostics.rs | 8 ++ crates/hir/src/lib.rs | 50 ++++++++- .../handlers/trait_impl_incorrect_safety.rs | 40 ++++--- .../handlers/trait_impl_missing_assoc_item.rs | 102 ++++++++++++++++++ .../src/handlers/type_mismatch.rs | 2 + crates/ide-diagnostics/src/lib.rs | 4 +- crates/ide-diagnostics/src/tests.rs | 3 +- 7 files changed, 191 insertions(+), 18 deletions(-) create mode 100644 crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index dd5c9b3535a0..cf9a2b73d9b1 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -54,6 +54,7 @@ diagnostics![ PrivateField, ReplaceFilterMapNextWithFindMap, TraitImplIncorrectSafety, + TraitImplMissingAssocItems, TraitImplOrphan, TypedHole, TypeMismatch, @@ -302,3 +303,10 @@ pub struct TraitImplIncorrectSafety { pub impl_: AstPtr, pub should_be_safe: bool, } + +#[derive(Debug, PartialEq, Eq)] +pub struct TraitImplMissingAssocItems { + pub file_id: HirFileId, + pub impl_: AstPtr, + pub missing: Vec<(Name, AssocItem)>, +} diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 066d7e635a26..e0d27f5262e4 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -33,7 +33,7 @@ pub mod symbols; mod display; -use std::{iter, ops::ControlFlow}; +use std::{iter, mem::discriminant, ops::ControlFlow}; use arrayvec::ArrayVec; use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind}; @@ -593,6 +593,7 @@ impl Module { let inherent_impls = db.inherent_impls_in_crate(self.id.krate()); + let mut impl_assoc_items_scratch = vec![]; for impl_def in self.impl_defs(db) { let loc = impl_def.id.lookup(db.upcast()); let tree = loc.id.item_tree(db.upcast()); @@ -661,8 +662,51 @@ impl Module { _ => (), }; - for item in impl_def.items(db) { - let def: DefWithBody = match item { + if let Some(trait_) = trait_ { + let items = &db.trait_data(trait_.into()).items; + let required_items = items.iter().filter(|&(_, assoc)| match *assoc { + AssocItemId::FunctionId(it) => !db.function_data(it).has_body(), + AssocItemId::ConstId(_) => true, + AssocItemId::TypeAliasId(it) => db.type_alias_data(it).type_ref.is_none(), + }); + impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().map( + |&item| { + ( + item, + match item { + AssocItemId::FunctionId(it) => db.function_data(it).name.clone(), + AssocItemId::ConstId(it) => { + db.const_data(it).name.as_ref().unwrap().clone() + } + AssocItemId::TypeAliasId(it) => db.type_alias_data(it).name.clone(), + }, + ) + }, + )); + + let missing: Vec<_> = required_items + .filter(|(name, id)| { + !impl_assoc_items_scratch.iter().any(|(impl_item, impl_name)| { + discriminant(impl_item) == discriminant(id) && impl_name == name + }) + }) + .map(|(name, item)| (name.clone(), AssocItem::from(*item))) + .collect(); + if !missing.is_empty() { + acc.push( + TraitImplMissingAssocItems { + impl_: ast_id_map.get(node.ast_id()), + file_id, + missing, + } + .into(), + ) + } + impl_assoc_items_scratch.clear(); + } + + for &item in &db.impl_data(impl_def.id).items { + let def: DefWithBody = match AssocItem::from(item) { AssocItem::Function(it) => it.into(), AssocItem::Const(it) => it.into(), AssocItem::TypeAlias(_) => continue, diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs b/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs index f28298de7d83..251a645292ed 100644 --- a/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs +++ b/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs @@ -1,6 +1,7 @@ use hir::InFile; +use syntax::ast; -use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity}; +use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext, Severity}; // Diagnostic: trait-impl-incorrect-safety // @@ -9,15 +10,28 @@ pub(crate) fn trait_impl_incorrect_safety( ctx: &DiagnosticsContext<'_>, d: &hir::TraitImplIncorrectSafety, ) -> Diagnostic { - Diagnostic::new_with_syntax_node_ptr( - ctx, + Diagnostic::new( DiagnosticCode::Ra("trait-impl-incorrect-safety", Severity::Error), if d.should_be_safe { "unsafe impl for safe trait" } else { "impl for unsafe trait needs to be unsafe" }, - InFile::new(d.file_id, d.impl_.clone().into()), + adjusted_display_range::( + ctx, + InFile { file_id: d.file_id, value: d.impl_.syntax_node_ptr() }, + &|impl_| { + if d.should_be_safe { + Some(match (impl_.unsafe_token(), impl_.impl_token()) { + (None, None) => return None, + (None, Some(t)) | (Some(t), None) => t.text_range(), + (Some(t1), Some(t2)) => t1.text_range().cover(t2.text_range()), + }) + } else { + impl_.impl_token().map(|t| t.text_range()) + } + }, + ), ) } @@ -35,10 +49,10 @@ unsafe trait Unsafe {} impl Safe for () {} impl Unsafe for () {} -//^^^^^^^^^^^^^^^^^^^^^ error: impl for unsafe trait needs to be unsafe +//^^^^ error: impl for unsafe trait needs to be unsafe unsafe impl Safe for () {} -//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe impl for safe trait +//^^^^^^^^^^^ error: unsafe impl for safe trait unsafe impl Unsafe for () {} "#, @@ -57,20 +71,20 @@ struct L<'l>; impl Drop for S {} impl<#[may_dangle] T> Drop for S {} -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for unsafe trait needs to be unsafe +//^^^^ error: impl for unsafe trait needs to be unsafe unsafe impl Drop for S {} -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe impl for safe trait +//^^^^^^^^^^^ error: unsafe impl for safe trait unsafe impl<#[may_dangle] T> Drop for S {} impl<'l> Drop for L<'l> {} impl<#[may_dangle] 'l> Drop for L<'l> {} -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for unsafe trait needs to be unsafe +//^^^^ error: impl for unsafe trait needs to be unsafe unsafe impl<'l> Drop for L<'l> {} -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe impl for safe trait +//^^^^^^^^^^^ error: unsafe impl for safe trait unsafe impl<#[may_dangle] 'l> Drop for L<'l> {} "#, @@ -86,14 +100,14 @@ trait Trait {} impl !Trait for () {} unsafe impl !Trait for () {} -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe impl for safe trait +//^^^^^^^^^^^ error: unsafe impl for safe trait unsafe trait UnsafeTrait {} impl !UnsafeTrait for () {} unsafe impl !UnsafeTrait for () {} -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe impl for safe trait +//^^^^^^^^^^^ error: unsafe impl for safe trait "#, ); @@ -108,7 +122,7 @@ struct S; impl S {} unsafe impl S {} -//^^^^^^^^^^^^^^^^ error: unsafe impl for safe trait +//^^^^^^^^^^^ error: unsafe impl for safe trait "#, ); } diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs new file mode 100644 index 000000000000..40d0b6fdd4b0 --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs @@ -0,0 +1,102 @@ +use hir::InFile; +use itertools::Itertools; +use syntax::{ast, AstNode}; + +use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: trait-impl-missing-assoc_item +// +// Diagnoses missing trait items in a trait impl. +pub(crate) fn trait_impl_missing_assoc_item( + ctx: &DiagnosticsContext<'_>, + d: &hir::TraitImplMissingAssocItems, +) -> Diagnostic { + let missing = d.missing.iter().format_with(", ", |(name, item), f| { + f(&match *item { + hir::AssocItem::Function(_) => "`fn ", + hir::AssocItem::Const(_) => "`const ", + hir::AssocItem::TypeAlias(_) => "`type ", + })?; + f(&name.display(ctx.sema.db))?; + f(&"`") + }); + Diagnostic::new( + DiagnosticCode::RustcHardError("E0046"), + format!("not all trait items implemented, missing: {missing}"), + adjusted_display_range::( + ctx, + InFile { file_id: d.file_id, value: d.impl_.syntax_node_ptr() }, + &|impl_| impl_.trait_().map(|t| t.syntax().text_range()), + ), + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn simple() { + check_diagnostics( + r#" +trait Trait { + const C: (); + type T; + fn f(); +} + +impl Trait for () { + const C: () = (); + type T = (); + fn f() {} +} + +impl Trait for () { + //^^^^^ error: not all trait items implemented, missing: `const C` + type T = (); + fn f() {} +} + +impl Trait for () { + //^^^^^ error: not all trait items implemented, missing: `const C`, `type T`, `fn f` +} + +"#, + ); + } + + #[test] + fn default() { + check_diagnostics( + r#" +trait Trait { + const C: (); + type T = (); + fn f() {} +} + +impl Trait for () { + const C: () = (); + type T = (); + fn f() {} +} + +impl Trait for () { + //^^^^^ error: not all trait items implemented, missing: `const C` + type T = (); + fn f() {} +} + +impl Trait for () { + //^^^^^ error: not all trait items implemented, missing: `const C` + type T = (); + } + +impl Trait for () { + //^^^^^ error: not all trait items implemented, missing: `const C` +} + +"#, + ); + } +} diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 14454fe8dc40..16d8ed64ad5a 100644 --- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -278,6 +278,7 @@ struct Foo; struct Bar; impl core::ops::Deref for Foo { type Target = Bar; + fn deref(&self) -> &Self::Target { loop {} } } fn main() { @@ -290,6 +291,7 @@ struct Foo; struct Bar; impl core::ops::Deref for Foo { type Target = Bar; + fn deref(&self) -> &Self::Target { loop {} } } fn main() { diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 99921c1107da..6744895f3cd2 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -46,6 +46,7 @@ mod handlers { pub(crate) mod replace_filter_map_next_with_find_map; pub(crate) mod trait_impl_orphan; pub(crate) mod trait_impl_incorrect_safety; + pub(crate) mod trait_impl_missing_assoc_item; pub(crate) mod typed_hole; pub(crate) mod type_mismatch; pub(crate) mod unimplemented_builtin_macro; @@ -360,8 +361,9 @@ pub fn diagnostics( AnyDiagnostic::PrivateAssocItem(d) => handlers::private_assoc_item::private_assoc_item(&ctx, &d), AnyDiagnostic::PrivateField(d) => handlers::private_field::private_field(&ctx, &d), AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d), - AnyDiagnostic::TraitImplOrphan(d) => handlers::trait_impl_orphan::trait_impl_orphan(&ctx, &d), AnyDiagnostic::TraitImplIncorrectSafety(d) => handlers::trait_impl_incorrect_safety::trait_impl_incorrect_safety(&ctx, &d), + AnyDiagnostic::TraitImplMissingAssocItems(d) => handlers::trait_impl_missing_assoc_item::trait_impl_missing_assoc_item(&ctx, &d), + AnyDiagnostic::TraitImplOrphan(d) => handlers::trait_impl_orphan::trait_impl_orphan(&ctx, &d), AnyDiagnostic::TypedHole(d) => handlers::typed_hole::typed_hole(&ctx, &d), AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d), AnyDiagnostic::UndeclaredLabel(d) => handlers::undeclared_label::undeclared_label(&ctx, &d), diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs index ff8f3b268603..c766a018bfd0 100644 --- a/crates/ide-diagnostics/src/tests.rs +++ b/crates/ide-diagnostics/src/tests.rs @@ -43,7 +43,8 @@ fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id) .pop() .expect("no diagnostics"); - let fix = &diagnostic.fixes.expect("diagnostic misses fixes")[nth]; + let fix = + &diagnostic.fixes.expect(&format!("{:?} diagnostic misses fixes", diagnostic.code))[nth]; let actual = { let source_change = fix.source_change.as_ref().unwrap(); let file_id = *source_change.source_file_edits.keys().next().unwrap(); From df629627c5bd63ea8f44eca1751f2026baf65e5b Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Tue, 14 Nov 2023 17:35:24 -0500 Subject: [PATCH 2386/2442] Add tests for `LetStmt::set_ty` --- crates/syntax/src/ast/edit_in_place.rs | 62 ++++++++++++++++++++------ 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index edb55a2f1360..37d8212042da 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -663,25 +663,28 @@ impl ast::LetStmt { ted::remove(existing_ty.syntax()); } + + // Remove any trailing ws + if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) + { + last.detach(); + } } Some(new_ty) => { if self.colon_token().is_none() { - let mut to_insert: Vec = vec![]; - - let position = match self.pat() { - Some(pat) => Position::after(pat.syntax()), - None => { - to_insert.push(make::tokens::single_space().into()); - Position::after(self.let_token().unwrap()) - } - }; - - to_insert.push(make::token(T![:]).into()); - - ted::insert_all_raw(position, to_insert); + ted::insert_raw( + Position::after( + self.pat().expect("let stmt should have a pattern").syntax(), + ), + make::token(T![:]), + ); } - ted::insert(Position::after(self.colon_token().unwrap()), new_ty.syntax()); + if let Some(old_ty) = self.ty() { + ted::replace(old_ty.syntax(), new_ty.syntax()); + } else { + ted::insert(Position::after(self.colon_token().unwrap()), new_ty.syntax()); + } } } } @@ -1022,6 +1025,37 @@ mod tests { check("let a @ ", "let a", None); } + #[test] + fn test_let_stmt_set_ty() { + #[track_caller] + fn check(before: &str, expected: &str, ty: Option) { + let ty = ty.map(|it| it.clone_for_update()); + + let let_stmt = ast_mut_from_text::(&format!("fn f() {{ {before} }}")); + let_stmt.set_ty(ty); + + let after = ast_mut_from_text::(&format!("fn f() {{ {expected} }}")); + assert_eq!(let_stmt.to_string(), after.to_string(), "{let_stmt:#?}\n!=\n{after:#?}"); + } + + // adding + check("let a;", "let a: ();", Some(make::ty_tuple([]))); + // no semicolon due to it being eaten during error recovery + check("let a:", "let a: ()", Some(make::ty_tuple([]))); + + // replacing + check("let a: u8;", "let a: ();", Some(make::ty_tuple([]))); + check("let a: u8 = 3;", "let a: () = 3;", Some(make::ty_tuple([]))); + check("let a: = 3;", "let a: () = 3;", Some(make::ty_tuple([]))); + + // removing + check("let a: u8;", "let a;", None); + check("let a:;", "let a;", None); + + check("let a: u8 = 3;", "let a = 3;", None); + check("let a: = 3;", "let a = 3;", None); + } + #[test] fn add_variant_to_empty_enum() { let variant = make::variant(make::name("Bar"), None).clone_for_update(); From 3f99a56faef063b236744b5689d0918dd62b6fa0 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Tue, 14 Nov 2023 17:50:33 -0500 Subject: [PATCH 2387/2442] Fix panic in `add_type_ascription` Assist wasn't applicable when the let statement was missing a pattern before, so we should do the same now. --- .../ide-assists/src/handlers/add_turbo_fish.rs | 17 +++++++++-------- crates/ide-assists/src/tests.rs | 5 +++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_turbo_fish.rs b/crates/ide-assists/src/handlers/add_turbo_fish.rs index 6afc1693fab0..88fd0b1b7339 100644 --- a/crates/ide-assists/src/handlers/add_turbo_fish.rs +++ b/crates/ide-assists/src/handlers/add_turbo_fish.rs @@ -85,6 +85,10 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti if let Some(let_stmt) = ctx.find_node_at_offset::() { if let_stmt.colon_token().is_none() { + if let_stmt.pat().is_none() { + return None; + } + acc.add( AssistId("add_type_ascription", AssistKind::RefactorRewrite), "Add `: _` before assignment operator", @@ -157,7 +161,10 @@ fn get_fish_head(number_of_arguments: usize) -> ast::GenericArgList { #[cfg(test)] mod tests { - use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable}; + use crate::tests::{ + check_assist, check_assist_by_label, check_assist_not_applicable, + check_assist_not_applicable_by_label, + }; use super::*; @@ -400,19 +407,13 @@ fn main() { #[test] fn add_type_ascription_missing_pattern() { - check_assist_by_label( + check_assist_not_applicable_by_label( add_turbo_fish, r#" fn make() -> T {} fn main() { let = make$0() } -"#, - r#" -fn make() -> T {} -fn main() { - let : ${0:_} = make(); -} "#, "Add `: _` before assignment operator", ); diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs index cc3e251a8f2a..1f72e4f03e08 100644 --- a/crates/ide-assists/src/tests.rs +++ b/crates/ide-assists/src/tests.rs @@ -98,6 +98,11 @@ pub(crate) fn check_assist_not_applicable(assist: Handler, ra_fixture: &str) { check(assist, ra_fixture, ExpectedResult::NotApplicable, None); } +#[track_caller] +pub(crate) fn check_assist_not_applicable_by_label(assist: Handler, ra_fixture: &str, label: &str) { + check(assist, ra_fixture, ExpectedResult::NotApplicable, Some(label)); +} + /// Check assist in unresolved state. Useful to check assists for lazy computation. #[track_caller] pub(crate) fn check_assist_unresolved(assist: Handler, ra_fixture: &str) { From fb70fe27d4853ca8e1bbf266b9d500c956ac5130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 10:26:22 +0200 Subject: [PATCH 2388/2442] Disable win32-ia32 VSIX builds --- .github/workflows/release.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index b5dbe30c3221..6a3cdfe3a3c7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -30,7 +30,6 @@ jobs: code-target: win32-x64 - os: windows-latest target: i686-pc-windows-msvc - code-target: win32-ia32 - os: windows-latest target: aarch64-pc-windows-msvc code-target: win32-arm64 @@ -102,12 +101,12 @@ jobs: working-directory: editors/code - name: Package Extension (release) - if: github.ref == 'refs/heads/release' + if: github.ref == 'refs/heads/release' && matrix.code-target run: npx vsce package -o "../../dist/rust-analyzer-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} working-directory: editors/code - name: Package Extension (nightly) - if: github.ref != 'refs/heads/release' + if: github.ref != 'refs/heads/release' && matrix.code-target run: npx vsce package -o "../../dist/rust-analyzer-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release working-directory: editors/code From 498f39eae2d23a0b0626d64051a34c42f4dc6131 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 15 Nov 2023 09:46:07 +0100 Subject: [PATCH 2389/2442] fix: Diagnose everything in nested items, not just def diagnostics --- crates/hir-ty/src/diagnostics/decl_check.rs | 28 ++----------------- crates/hir/src/lib.rs | 4 +-- .../src/handlers/incorrect_case.rs | 8 +++--- .../src/handlers/type_mismatch.rs | 15 ++++++++++ 4 files changed, 22 insertions(+), 33 deletions(-) diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs index b432588b2308..f4c079b48c58 100644 --- a/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/crates/hir-ty/src/diagnostics/decl_check.rs @@ -19,8 +19,8 @@ use hir_def::{ data::adt::VariantData, hir::{Pat, PatId}, src::HasSource, - AdtId, AttrDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, ItemContainerId, - Lookup, ModuleDefId, ModuleId, StaticId, StructId, + AdtId, AttrDefId, ConstId, EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, ModuleId, + StaticId, StructId, }; use hir_expand::{ name::{AsName, Name}, @@ -290,8 +290,6 @@ impl<'a> DeclValidator<'a> { return; } - self.validate_body_inner_items(func.into()); - // Check whether non-snake case identifiers are allowed for this function. if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) { return; @@ -568,11 +566,6 @@ impl<'a> DeclValidator<'a> { fn validate_enum(&mut self, enum_id: EnumId) { let data = self.db.enum_data(enum_id); - for (local_id, _) in data.variants.iter() { - let variant_id = EnumVariantId { parent: enum_id, local_id }; - self.validate_body_inner_items(variant_id.into()); - } - // Check whether non-camel case names are allowed for this enum. if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) { return; @@ -697,8 +690,6 @@ impl<'a> DeclValidator<'a> { fn validate_const(&mut self, const_id: ConstId) { let data = self.db.const_data(const_id); - self.validate_body_inner_items(const_id.into()); - if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) { return; } @@ -747,8 +738,6 @@ impl<'a> DeclValidator<'a> { return; } - self.validate_body_inner_items(static_id.into()); - if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) { return; } @@ -786,17 +775,4 @@ impl<'a> DeclValidator<'a> { self.sink.push(diagnostic); } - - // FIXME: We don't currently validate names within `DefWithBodyId::InTypeConstId`. - /// Recursively validates inner scope items, such as static variables and constants. - fn validate_body_inner_items(&mut self, body_id: DefWithBodyId) { - let body = self.db.body(body_id); - for (_, block_def_map) in body.blocks(self.db.upcast()) { - for (_, module) in block_def_map.modules() { - for def_id in module.scope.declarations() { - self.validate_item(def_id); - } - } - } - } } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index e0d27f5262e4..bd2f8e4a93eb 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1536,9 +1536,7 @@ impl DefWithBody { let (body, source_map) = db.body_with_source_map(self.into()); for (_, def_map) in body.blocks(db.upcast()) { - for diag in def_map.diagnostics() { - emit_def_diagnostic(db, acc, diag); - } + Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc); } for diag in source_map.diagnostics() { diff --git a/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/crates/ide-diagnostics/src/handlers/incorrect_case.rs index 85dbb7e6f263..0f12e814ba39 100644 --- a/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -599,12 +599,12 @@ fn main() { //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR` fn BAZ() { //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz` - let INNER_INNER = 42; - //^^^^^^^^^^^ 💡 warn: Variable `INNER_INNER` should have snake_case name, e.g. `inner_inner` + let _INNER_INNER = 42; + //^^^^^^^^^^^^ 💡 warn: Variable `_INNER_INNER` should have snake_case name, e.g. `_inner_inner` } - let INNER_LOCAL = 42; - //^^^^^^^^^^^ 💡 warn: Variable `INNER_LOCAL` should have snake_case name, e.g. `inner_local` + let _INNER_LOCAL = 42; + //^^^^^^^^^^^^ 💡 warn: Variable `_INNER_LOCAL` should have snake_case name, e.g. `_inner_local` } } "#, diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 16d8ed64ad5a..c92d92ceae8c 100644 --- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -739,6 +739,21 @@ fn f() -> i32 { 0 } fn g() { return; } +"#, + ); + } + + #[test] + fn smoke_test_inner_items() { + check_diagnostics( + r#" +fn f() { + fn inner() -> i32 { + return; + // ^^^^^^ error: expected i32, found () + 0 + } +} "#, ); } From dfc885e0fdd1550720ddb1ed9a799311eb8a9df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 12:49:32 +0200 Subject: [PATCH 2390/2442] Bump anyhow --- Cargo.lock | 4 ++-- Cargo.toml | 1 + crates/load-cargo/Cargo.toml | 4 ++-- crates/project-model/Cargo.toml | 2 +- crates/rust-analyzer/Cargo.toml | 2 +- xtask/Cargo.toml | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fcb188c0dfab..f2e99e777185 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,9 +28,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arbitrary" diff --git a/Cargo.toml b/Cargo.toml index c382a5a37d23..789d423ac20e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,6 +90,7 @@ la-arena = { version = "0.3.1" } lsp-server = { version = "0.7.4" } # non-local crates +anyhow = "1.0.75" smallvec = { version = "1.10.0", features = [ "const_new", "union", diff --git a/crates/load-cargo/Cargo.toml b/crates/load-cargo/Cargo.toml index f041ca88ac08..26cfe8ead4b3 100644 --- a/crates/load-cargo/Cargo.toml +++ b/crates/load-cargo/Cargo.toml @@ -11,13 +11,13 @@ authors.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0.62" +anyhow.workspace = true crossbeam-channel = "0.5.5" itertools = "0.10.5" tracing = "0.1.35" ide.workspace = true -ide-db.workspace =true +ide-db.workspace = true proc-macro-api.workspace = true project-model.workspace = true tt.workspace = true diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml index 75977fc5b04f..99314ec889bc 100644 --- a/crates/project-model/Cargo.toml +++ b/crates/project-model/Cargo.toml @@ -16,10 +16,10 @@ tracing = "0.1.35" rustc-hash = "1.1.0" cargo_metadata = "0.15.0" semver = "1.0.14" +anyhow.workspace = true serde_json.workspace = true serde.workspace = true triomphe.workspace = true -anyhow = "1.0.62" la-arena.workspace = true itertools = "0.10.5" diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index c85b3e53cda2..0af48b0c9a9e 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -19,7 +19,7 @@ name = "rust-analyzer" path = "src/bin/main.rs" [dependencies] -anyhow = "1.0.62" +anyhow.workspace = true crossbeam-channel = "0.5.5" dissimilar = "1.0.4" itertools = "0.10.5" diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 7a34617e2558..d32bfe856d3f 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" rust-version.workspace = true [dependencies] -anyhow = "1.0.62" +anyhow.workspace = true flate2 = "1.0.24" write-json = "0.1.2" xshell = "0.2.2" From f66df10f87f0c74a8e8e4c9d4d153a2b903c4038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 12:53:56 +0200 Subject: [PATCH 2391/2442] Bump itertools --- Cargo.lock | 41 ++++++++++++++++++------------ Cargo.toml | 1 + crates/hir-def/Cargo.toml | 2 +- crates/hir-expand/Cargo.toml | 2 +- crates/hir-ty/Cargo.toml | 2 +- crates/hir/Cargo.toml | 2 +- crates/ide-assists/Cargo.toml | 2 +- crates/ide-completion/Cargo.toml | 2 +- crates/ide-db/Cargo.toml | 2 +- crates/ide-db/src/source_change.rs | 6 ++--- crates/ide-diagnostics/Cargo.toml | 2 +- crates/ide-ssr/Cargo.toml | 2 +- crates/ide/Cargo.toml | 2 +- crates/load-cargo/Cargo.toml | 2 +- crates/project-model/Cargo.toml | 2 +- crates/rust-analyzer/Cargo.toml | 2 +- crates/syntax/Cargo.toml | 2 +- crates/text-edit/Cargo.toml | 2 +- 18 files changed, 44 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2e99e777185..7ac2311c92b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,7 +215,7 @@ dependencies = [ "chalk-ir", "ena", "indexmap 1.9.3", - "itertools", + "itertools 0.10.5", "petgraph", "rustc-hash", "tracing", @@ -497,7 +497,7 @@ dependencies = [ "hir-def", "hir-expand", "hir-ty", - "itertools", + "itertools 0.12.0", "once_cell", "profile", "rustc-hash", @@ -526,7 +526,7 @@ dependencies = [ "hir-expand", "indexmap 2.0.0", "intern", - "itertools", + "itertools 0.12.0", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "mbe", @@ -554,7 +554,7 @@ dependencies = [ "expect-test", "hashbrown 0.12.3", "intern", - "itertools", + "itertools 0.12.0", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "mbe", @@ -586,7 +586,7 @@ dependencies = [ "hir-def", "hir-expand", "intern", - "itertools", + "itertools 0.12.0", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "nohash-hasher", @@ -633,7 +633,7 @@ dependencies = [ "ide-db", "ide-diagnostics", "ide-ssr", - "itertools", + "itertools 0.12.0", "nohash-hasher", "oorandom", "profile", @@ -659,7 +659,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools", + "itertools 0.12.0", "profile", "smallvec", "sourcegen", @@ -678,7 +678,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools", + "itertools 0.12.0", "once_cell", "profile", "smallvec", @@ -700,7 +700,7 @@ dependencies = [ "fst", "hir", "indexmap 2.0.0", - "itertools", + "itertools 0.12.0", "limit", "line-index 0.1.0-pre.1", "memchr", @@ -731,7 +731,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools", + "itertools 0.12.0", "once_cell", "profile", "serde_json", @@ -750,7 +750,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools", + "itertools 0.12.0", "nohash-hasher", "parser", "stdx", @@ -838,6 +838,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.6" @@ -942,7 +951,7 @@ dependencies = [ "crossbeam-channel", "ide", "ide-db", - "itertools", + "itertools 0.12.0", "proc-macro-api", "project-model", "tracing", @@ -1389,7 +1398,7 @@ dependencies = [ "cargo_metadata", "cfg", "expect-test", - "itertools", + "itertools 0.12.0", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "paths", "profile", @@ -1583,7 +1592,7 @@ dependencies = [ "ide", "ide-db", "ide-ssr", - "itertools", + "itertools 0.12.0", "load-cargo", "lsp-server 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "lsp-types", @@ -1860,7 +1869,7 @@ dependencies = [ "either", "expect-test", "indexmap 2.0.0", - "itertools", + "itertools 0.12.0", "once_cell", "parser", "proc-macro2", @@ -1894,7 +1903,7 @@ dependencies = [ name = "text-edit" version = "0.0.0" dependencies = [ - "itertools", + "itertools 0.12.0", "text-size", ] diff --git a/Cargo.toml b/Cargo.toml index 789d423ac20e..3dda3582be1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ lsp-server = { version = "0.7.4" } # non-local crates anyhow = "1.0.75" +itertools = "0.12.0" smallvec = { version = "1.10.0", features = [ "const_new", "union", diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index 99b8e9bf0e14..cd0fe6247171 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -21,7 +21,7 @@ drop_bomb = "0.1.5" either = "1.7.0" fst = { version = "0.4.7", default-features = false } indexmap = "2.0.0" -itertools = "0.10.5" +itertools.workspace = true la-arena.workspace = true once_cell = "1.17.0" rustc-hash = "1.1.0" diff --git a/crates/hir-expand/Cargo.toml b/crates/hir-expand/Cargo.toml index 1f27204c1917..97d99a69ab00 100644 --- a/crates/hir-expand/Cargo.toml +++ b/crates/hir-expand/Cargo.toml @@ -17,7 +17,7 @@ tracing = "0.1.35" either = "1.7.0" rustc-hash = "1.1.0" la-arena.workspace = true -itertools = "0.10.5" +itertools.workspace = true hashbrown.workspace = true smallvec.workspace = true triomphe.workspace = true diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index c30807ad8849..3699df98ec56 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" -itertools = "0.10.5" +itertools.workspace = true arrayvec = "0.7.2" bitflags = "2.1.0" smallvec.workspace = true diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index 09ab60dd549f..2df9be88f030 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml @@ -15,7 +15,7 @@ doctest = false rustc-hash = "1.1.0" either = "1.7.0" arrayvec = "0.7.2" -itertools = "0.10.5" +itertools.workspace = true smallvec.workspace = true triomphe.workspace = true once_cell = "1.17.1" diff --git a/crates/ide-assists/Cargo.toml b/crates/ide-assists/Cargo.toml index 447e38f91f43..2496169a6b22 100644 --- a/crates/ide-assists/Cargo.toml +++ b/crates/ide-assists/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" -itertools = "0.10.5" +itertools.workspace = true either = "1.7.0" smallvec.workspace = true diff --git a/crates/ide-completion/Cargo.toml b/crates/ide-completion/Cargo.toml index 092fb303668f..60f90a41b962 100644 --- a/crates/ide-completion/Cargo.toml +++ b/crates/ide-completion/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" -itertools = "0.10.5" +itertools.workspace = true once_cell = "1.17.0" smallvec.workspace = true diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index faec74206811..409748fa73ef 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -19,7 +19,7 @@ fst = { version = "0.4.7", default-features = false } rustc-hash = "1.1.0" once_cell = "1.17.0" either = "1.7.0" -itertools = "0.10.5" +itertools.workspace = true arrayvec = "0.7.2" indexmap = "2.0.0" memchr = "2.5.0" diff --git a/crates/ide-db/src/source_change.rs b/crates/ide-db/src/source_change.rs index 39763479c65a..c7188f1f7943 100644 --- a/crates/ide-db/src/source_change.rs +++ b/crates/ide-db/src/source_change.rs @@ -140,10 +140,10 @@ impl SnippetEdit { .with_position() .map(|pos| { let (snippet, index) = match pos { - itertools::Position::First(it) | itertools::Position::Middle(it) => it, + (itertools::Position::First, it) | (itertools::Position::Middle, it) => it, // last/only snippet gets index 0 - itertools::Position::Last((snippet, _)) - | itertools::Position::Only((snippet, _)) => (snippet, 0), + (itertools::Position::Last, (snippet, _)) + | (itertools::Position::Only, (snippet, _)) => (snippet, 0), }; let range = match snippet { diff --git a/crates/ide-diagnostics/Cargo.toml b/crates/ide-diagnostics/Cargo.toml index 14aa3940199a..1e455dcfd654 100644 --- a/crates/ide-diagnostics/Cargo.toml +++ b/crates/ide-diagnostics/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" either = "1.7.0" -itertools = "0.10.5" +itertools.workspace = true serde_json = "1.0.86" once_cell = "1.17.0" diff --git a/crates/ide-ssr/Cargo.toml b/crates/ide-ssr/Cargo.toml index 70ed6dea5bf2..56b29f92b829 100644 --- a/crates/ide-ssr/Cargo.toml +++ b/crates/ide-ssr/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" -itertools = "0.10.5" +itertools.workspace = true triomphe.workspace = true nohash-hasher.workspace = true diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index 2aee203c4ea5..90e7847bc86a 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -15,7 +15,7 @@ doctest = false cov-mark = "2.0.0-pre.1" crossbeam-channel = "0.5.5" either = "1.7.0" -itertools = "0.10.5" +itertools.workspace = true tracing = "0.1.35" oorandom = "11.1.3" pulldown-cmark-to-cmark = "10.0.4" diff --git a/crates/load-cargo/Cargo.toml b/crates/load-cargo/Cargo.toml index 26cfe8ead4b3..e31b0c2c814f 100644 --- a/crates/load-cargo/Cargo.toml +++ b/crates/load-cargo/Cargo.toml @@ -13,7 +13,7 @@ authors.workspace = true [dependencies] anyhow.workspace = true crossbeam-channel = "0.5.5" -itertools = "0.10.5" +itertools.workspace = true tracing = "0.1.35" ide.workspace = true diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml index 99314ec889bc..11dba4494f3d 100644 --- a/crates/project-model/Cargo.toml +++ b/crates/project-model/Cargo.toml @@ -21,7 +21,7 @@ serde_json.workspace = true serde.workspace = true triomphe.workspace = true la-arena.workspace = true -itertools = "0.10.5" +itertools.workspace = true # local deps base-db.workspace = true diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 0af48b0c9a9e..90f8577996c8 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -22,7 +22,7 @@ path = "src/bin/main.rs" anyhow.workspace = true crossbeam-channel = "0.5.5" dissimilar = "1.0.4" -itertools = "0.10.5" +itertools.workspace = true scip = "0.3.1" lsp-types = { version = "=0.94.0", features = ["proposed"] } parking_lot = "0.12.1" diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index dc92366d1c7a..671da08737b1 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -15,7 +15,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" either = "1.7.0" -itertools = "0.10.5" +itertools.workspace = true rowan = "0.15.11" rustc-hash = "1.1.0" once_cell = "1.17.0" diff --git a/crates/text-edit/Cargo.toml b/crates/text-edit/Cargo.toml index 76d0ca5ccb60..4620cc72d0a2 100644 --- a/crates/text-edit/Cargo.toml +++ b/crates/text-edit/Cargo.toml @@ -12,5 +12,5 @@ rust-version.workspace = true doctest = false [dependencies] -itertools = "0.10.5" +itertools.workspace = true text-size.workspace = true From f53368dd3f175edbaa8c709ce62a81f9efd5d52a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:00:32 +0200 Subject: [PATCH 2392/2442] Bump tracing --- Cargo.lock | 13 ++++++------- Cargo.toml | 1 + crates/flycheck/Cargo.toml | 2 +- crates/hir-def/Cargo.toml | 2 +- crates/hir-expand/Cargo.toml | 2 +- crates/hir-ty/Cargo.toml | 4 ++-- crates/ide-db/Cargo.toml | 2 +- crates/ide/Cargo.toml | 2 +- crates/load-cargo/Cargo.toml | 2 +- crates/mbe/Cargo.toml | 2 +- crates/proc-macro-api/Cargo.toml | 2 +- crates/project-model/Cargo.toml | 2 +- crates/rust-analyzer/Cargo.toml | 2 +- crates/vfs-notify/Cargo.toml | 2 +- 14 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ac2311c92b8..f991f4fc8260 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2014,11 +2014,10 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2026,9 +2025,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", @@ -2037,9 +2036,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", diff --git a/Cargo.toml b/Cargo.toml index 3dda3582be1b..984459c8289e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,6 +97,7 @@ smallvec = { version = "1.10.0", features = [ "union", "const_generics", ] } +tracing = "0.1.40" smol_str = "0.2.0" nohash-hasher = "0.2.0" text-size = "1.1.0" diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index e7f7adc78471..12e0b14cc5a0 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] crossbeam-channel = "0.5.8" -tracing = "0.1.37" +tracing.workspace = true cargo_metadata = "0.15.4" rustc-hash = "1.1.0" serde_json.workspace = true diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index cd0fe6247171..daed5d635d94 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -25,7 +25,7 @@ itertools.workspace = true la-arena.workspace = true once_cell = "1.17.0" rustc-hash = "1.1.0" -tracing = "0.1.35" +tracing.workspace = true smallvec.workspace = true hashbrown.workspace = true triomphe.workspace = true diff --git a/crates/hir-expand/Cargo.toml b/crates/hir-expand/Cargo.toml index 97d99a69ab00..12cb6503c660 100644 --- a/crates/hir-expand/Cargo.toml +++ b/crates/hir-expand/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" -tracing = "0.1.35" +tracing.workspace = true either = "1.7.0" rustc-hash = "1.1.0" la-arena.workspace = true diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index 3699df98ec56..ea2bf2cdc5cd 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -20,7 +20,7 @@ smallvec.workspace = true ena = "0.14.0" either = "1.7.0" oorandom = "11.1.3" -tracing = "0.1.35" +tracing.workspace = true rustc-hash = "1.1.0" scoped-tls = "1.0.0" chalk-solve = { version = "0.93.0", default-features = false } @@ -47,7 +47,7 @@ limit.workspace = true [dev-dependencies] expect-test = "1.4.0" -tracing = "0.1.35" +tracing.workspace = true tracing-subscriber = { version = "0.3.16", default-features = false, features = [ "registry", ] } diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index 409748fa73ef..f4057b33e65b 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" -tracing = "0.1.35" +tracing.workspace = true rayon = "1.6.1" fst = { version = "0.4.7", default-features = false } rustc-hash = "1.1.0" diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index 90e7847bc86a..f4d834d2ccd3 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -16,7 +16,7 @@ cov-mark = "2.0.0-pre.1" crossbeam-channel = "0.5.5" either = "1.7.0" itertools.workspace = true -tracing = "0.1.35" +tracing.workspace = true oorandom = "11.1.3" pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.1", default-features = false } diff --git a/crates/load-cargo/Cargo.toml b/crates/load-cargo/Cargo.toml index e31b0c2c814f..31b9f6c76d06 100644 --- a/crates/load-cargo/Cargo.toml +++ b/crates/load-cargo/Cargo.toml @@ -14,7 +14,7 @@ authors.workspace = true anyhow.workspace = true crossbeam-channel = "0.5.5" itertools.workspace = true -tracing = "0.1.35" +tracing.workspace = true ide.workspace = true ide-db.workspace = true diff --git a/crates/mbe/Cargo.toml b/crates/mbe/Cargo.toml index 82105522ebdd..adab1003d103 100644 --- a/crates/mbe/Cargo.toml +++ b/crates/mbe/Cargo.toml @@ -15,7 +15,7 @@ doctest = false cov-mark = "2.0.0-pre.1" rustc-hash = "1.1.0" smallvec.workspace = true -tracing = "0.1.35" +tracing.workspace = true # local deps syntax.workspace = true diff --git a/crates/proc-macro-api/Cargo.toml b/crates/proc-macro-api/Cargo.toml index 4229f289130f..2c2d2e8a9452 100644 --- a/crates/proc-macro-api/Cargo.toml +++ b/crates/proc-macro-api/Cargo.toml @@ -21,7 +21,7 @@ object = { version = "0.32.0", default-features = false, features = [ ] } serde.workspace = true serde_json = { workspace = true, features = ["unbounded_depth"] } -tracing = "0.1.37" +tracing.workspace = true triomphe.workspace = true memmap2 = "0.5.4" snap = "1.1.0" diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml index 11dba4494f3d..d35e5f599262 100644 --- a/crates/project-model/Cargo.toml +++ b/crates/project-model/Cargo.toml @@ -12,7 +12,7 @@ rust-version.workspace = true doctest = false [dependencies] -tracing = "0.1.35" +tracing.workspace = true rustc-hash = "1.1.0" cargo_metadata = "0.15.0" semver = "1.0.14" diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 90f8577996c8..75019ea69913 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -35,7 +35,7 @@ rayon = "1.6.1" num_cpus = "1.15.0" mimalloc = { version = "0.1.30", default-features = false, optional = true } lsp-server.workspace = true -tracing = "0.1.35" +tracing.workspace = true tracing-subscriber = { version = "0.3.16", default-features = false, features = [ "registry", "fmt", diff --git a/crates/vfs-notify/Cargo.toml b/crates/vfs-notify/Cargo.toml index 11055f0280ac..0273df8e4abd 100644 --- a/crates/vfs-notify/Cargo.toml +++ b/crates/vfs-notify/Cargo.toml @@ -12,7 +12,7 @@ rust-version.workspace = true doctest = false [dependencies] -tracing = "0.1.35" +tracing.workspace = true walkdir = "2.3.2" crossbeam-channel = "0.5.5" # We demand 5.1.0 as any higher version pulls in a new windows-sys dupe From d83620a5bae0db141bd0fdac9fbe3a773d11856f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:01:54 +0200 Subject: [PATCH 2393/2442] Bump tracing-tree --- Cargo.lock | 27 +++------------------------ Cargo.toml | 1 + crates/hir-ty/Cargo.toml | 2 +- crates/rust-analyzer/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f991f4fc8260..c5ae82b57eea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,17 +44,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -468,15 +457,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.2.6" @@ -1161,7 +1141,7 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] @@ -2069,11 +2049,10 @@ dependencies = [ [[package]] name = "tracing-tree" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9742d8df709837409dbb22aa25dd7769c260406f20ff48a2320b80a4a6aed0" +checksum = "2ec6adcab41b1391b08a308cc6302b79f8095d1673f6947c2dc65ffb028b0b2d" dependencies = [ - "atty", "nu-ansi-term", "tracing-core", "tracing-log", diff --git a/Cargo.toml b/Cargo.toml index 984459c8289e..973385667ab5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,6 +98,7 @@ smallvec = { version = "1.10.0", features = [ "const_generics", ] } tracing = "0.1.40" +tracing-tree = "0.2.5" smol_str = "0.2.0" nohash-hasher = "0.2.0" text-size = "1.1.0" diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index ea2bf2cdc5cd..de07e184e3dc 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -51,7 +51,7 @@ tracing.workspace = true tracing-subscriber = { version = "0.3.16", default-features = false, features = [ "registry", ] } -tracing-tree = "0.2.1" +tracing-tree.workspace = true project-model = { path = "../project-model" } # local deps diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 75019ea69913..e9af760618fa 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -42,7 +42,7 @@ tracing-subscriber = { version = "0.3.16", default-features = false, features = "tracing-log", ] } tracing-log = "0.1.3" -tracing-tree = "0.2.1" +tracing-tree.workspace = true triomphe.workspace = true nohash-hasher.workspace = true always-assert = "0.1.2" From 2dbdaa247b0aae3db0f987af9b1252529a8903f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:04:39 +0200 Subject: [PATCH 2394/2442] Bump tracing-subscriber --- Cargo.lock | 23 +++++++++++++++++------ Cargo.toml | 5 +++++ crates/hir-ty/Cargo.toml | 4 +--- crates/rust-analyzer/Cargo.toml | 6 +----- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5ae82b57eea..df83c9948d84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1601,7 +1601,7 @@ dependencies = [ "tikv-jemallocator", "toolchain", "tracing", - "tracing-log", + "tracing-log 0.1.3", "tracing-subscriber", "tracing-tree", "triomphe", @@ -2036,15 +2036,26 @@ dependencies = [ ] [[package]] -name = "tracing-subscriber" -version = "0.3.17" +name = "tracing-log" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "sharded-slab", "thread_local", "tracing-core", - "tracing-log", + "tracing-log 0.2.0", ] [[package]] @@ -2055,7 +2066,7 @@ checksum = "2ec6adcab41b1391b08a308cc6302b79f8095d1673f6947c2dc65ffb028b0b2d" dependencies = [ "nu-ansi-term", "tracing-core", - "tracing-log", + "tracing-log 0.1.3", "tracing-subscriber", ] diff --git a/Cargo.toml b/Cargo.toml index 973385667ab5..3ebeb8102694 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,6 +99,11 @@ smallvec = { version = "1.10.0", features = [ ] } tracing = "0.1.40" tracing-tree = "0.2.5" +tracing-subscriber = { version = "0.3.18", default-features = false, features = [ + "registry", + "fmt", + "tracing-log", +] } smol_str = "0.2.0" nohash-hasher = "0.2.0" text-size = "1.1.0" diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index de07e184e3dc..2b65563add41 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -48,9 +48,7 @@ limit.workspace = true [dev-dependencies] expect-test = "1.4.0" tracing.workspace = true -tracing-subscriber = { version = "0.3.16", default-features = false, features = [ - "registry", -] } +tracing-subscriber.workspace = true tracing-tree.workspace = true project-model = { path = "../project-model" } diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index e9af760618fa..6c4a2ea177c2 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -36,11 +36,7 @@ num_cpus = "1.15.0" mimalloc = { version = "0.1.30", default-features = false, optional = true } lsp-server.workspace = true tracing.workspace = true -tracing-subscriber = { version = "0.3.16", default-features = false, features = [ - "registry", - "fmt", - "tracing-log", -] } +tracing-subscriber.workspace = true tracing-log = "0.1.3" tracing-tree.workspace = true triomphe.workspace = true From cb8434e594903279b236f5c2025fa199ac6c2fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:07:36 +0200 Subject: [PATCH 2395/2442] Bump either --- Cargo.lock | 4 ++-- Cargo.toml | 1 + crates/hir-def/Cargo.toml | 2 +- crates/hir-expand/Cargo.toml | 2 +- crates/hir-ty/Cargo.toml | 2 +- crates/hir/Cargo.toml | 2 +- crates/ide-assists/Cargo.toml | 2 +- crates/ide-db/Cargo.toml | 2 +- crates/ide-diagnostics/Cargo.toml | 2 +- crates/ide/Cargo.toml | 2 +- crates/syntax/Cargo.toml | 2 +- 11 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df83c9948d84..387825531163 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -333,9 +333,9 @@ checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "ena" diff --git a/Cargo.toml b/Cargo.toml index 3ebeb8102694..dd678a76b847 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ lsp-server = { version = "0.7.4" } # non-local crates anyhow = "1.0.75" +either = "1.9.0" itertools = "0.12.0" smallvec = { version = "1.10.0", features = [ "const_new", diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index daed5d635d94..f01db7bf8338 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -18,7 +18,7 @@ cov-mark = "2.0.0-pre.1" # We need to freeze the version of the crate, as the raw-api feature is considered unstable dashmap = { version = "=5.4.0", features = ["raw-api"] } drop_bomb = "0.1.5" -either = "1.7.0" +either.workspace = true fst = { version = "0.4.7", default-features = false } indexmap = "2.0.0" itertools.workspace = true diff --git a/crates/hir-expand/Cargo.toml b/crates/hir-expand/Cargo.toml index 12cb6503c660..361bbec4318f 100644 --- a/crates/hir-expand/Cargo.toml +++ b/crates/hir-expand/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" tracing.workspace = true -either = "1.7.0" +either.workspace = true rustc-hash = "1.1.0" la-arena.workspace = true itertools.workspace = true diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index 2b65563add41..ca626e671aba 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -18,7 +18,7 @@ arrayvec = "0.7.2" bitflags = "2.1.0" smallvec.workspace = true ena = "0.14.0" -either = "1.7.0" +either.workspace = true oorandom = "11.1.3" tracing.workspace = true rustc-hash = "1.1.0" diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index 2df9be88f030..4c1dfbc294e5 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] rustc-hash = "1.1.0" -either = "1.7.0" +either.workspace = true arrayvec = "0.7.2" itertools.workspace = true smallvec.workspace = true diff --git a/crates/ide-assists/Cargo.toml b/crates/ide-assists/Cargo.toml index 2496169a6b22..a622ec1a9532 100644 --- a/crates/ide-assists/Cargo.toml +++ b/crates/ide-assists/Cargo.toml @@ -15,7 +15,7 @@ doctest = false cov-mark = "2.0.0-pre.1" itertools.workspace = true -either = "1.7.0" +either.workspace = true smallvec.workspace = true # local deps diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index f4057b33e65b..a9873004a1d1 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -18,7 +18,7 @@ rayon = "1.6.1" fst = { version = "0.4.7", default-features = false } rustc-hash = "1.1.0" once_cell = "1.17.0" -either = "1.7.0" +either.workspace = true itertools.workspace = true arrayvec = "0.7.2" indexmap = "2.0.0" diff --git a/crates/ide-diagnostics/Cargo.toml b/crates/ide-diagnostics/Cargo.toml index 1e455dcfd654..ac7a41fcfe21 100644 --- a/crates/ide-diagnostics/Cargo.toml +++ b/crates/ide-diagnostics/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" -either = "1.7.0" +either.workspace = true itertools.workspace = true serde_json = "1.0.86" once_cell = "1.17.0" diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index f4d834d2ccd3..d5c3439f9563 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" crossbeam-channel = "0.5.5" -either = "1.7.0" +either.workspace = true itertools.workspace = true tracing.workspace = true oorandom = "11.1.3" diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 671da08737b1..e0df0f2c9999 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" -either = "1.7.0" +either.workspace = true itertools.workspace = true rowan = "0.15.11" rustc-hash = "1.1.0" From 970a7963684f2e247c5ed3c74f8bacc9572e1f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:16:07 +0200 Subject: [PATCH 2396/2442] Bump serde --- Cargo.lock | 30 +++++++++++++++--------------- Cargo.toml | 2 +- lib/lsp-server/Cargo.toml | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 387825531163..6def1347f4a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,7 +166,7 @@ checksum = "264726159011fc7f22c23eb51f49021ece6e71bc358b96e7f2e842db0b14162b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.39", "synstructure", ] @@ -310,7 +310,7 @@ checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.39", ] [[package]] @@ -1348,9 +1348,9 @@ version = "0.0.0" [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -1710,22 +1710,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.156" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.156" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] @@ -1748,7 +1748,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.39", ] [[package]] @@ -1820,9 +1820,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -1837,7 +1837,7 @@ checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.39", "unicode-xid", ] @@ -1910,7 +1910,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.39", ] [[package]] @@ -2011,7 +2011,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.39", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index dd678a76b847..08e02d5b106d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,7 +108,7 @@ tracing-subscriber = { version = "0.3.18", default-features = false, features = smol_str = "0.2.0" nohash-hasher = "0.2.0" text-size = "1.1.0" -serde = { version = "1.0.156", features = ["derive"] } +serde = { version = "1.0.192", features = ["derive"] } serde_json = "1.0.96" triomphe = { version = "0.1.8", default-features = false, features = ["std"] } # can't upgrade due to dashmap depending on 0.12.3 currently diff --git a/lib/lsp-server/Cargo.toml b/lib/lsp-server/Cargo.toml index 7ec3247e943a..5290794c5282 100644 --- a/lib/lsp-server/Cargo.toml +++ b/lib/lsp-server/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" [dependencies] log = "0.4.17" serde_json = "1.0.96" -serde = { version = "1.0.156", features = ["derive"] } +serde = { version = "1.0.192", features = ["derive"] } crossbeam-channel = "0.5.6" [dev-dependencies] From 2bfd6b659d1aa51292efff59dbb97cae30e2764b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:17:36 +0200 Subject: [PATCH 2397/2442] Bump serde_json --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- crates/ide-diagnostics/Cargo.toml | 2 +- lib/lsp-server/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6def1347f4a9..95c6991b4199 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1730,11 +1730,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.97" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "indexmap 1.9.3", + "indexmap 2.0.0", "itoa", "ryu", "serde", diff --git a/Cargo.toml b/Cargo.toml index 08e02d5b106d..7f76b30598e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,7 +109,7 @@ smol_str = "0.2.0" nohash-hasher = "0.2.0" text-size = "1.1.0" serde = { version = "1.0.192", features = ["derive"] } -serde_json = "1.0.96" +serde_json = "1.0.108" triomphe = { version = "0.1.8", default-features = false, features = ["std"] } # can't upgrade due to dashmap depending on 0.12.3 currently hashbrown = { version = "0.12.3", features = [ diff --git a/crates/ide-diagnostics/Cargo.toml b/crates/ide-diagnostics/Cargo.toml index ac7a41fcfe21..f4055024cc32 100644 --- a/crates/ide-diagnostics/Cargo.toml +++ b/crates/ide-diagnostics/Cargo.toml @@ -15,7 +15,7 @@ doctest = false cov-mark = "2.0.0-pre.1" either.workspace = true itertools.workspace = true -serde_json = "1.0.86" +serde_json.workspace = true once_cell = "1.17.0" # local deps diff --git a/lib/lsp-server/Cargo.toml b/lib/lsp-server/Cargo.toml index 5290794c5282..8d00813b0d7a 100644 --- a/lib/lsp-server/Cargo.toml +++ b/lib/lsp-server/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] log = "0.4.17" -serde_json = "1.0.96" +serde_json = "1.0.108" serde = { version = "1.0.192", features = ["derive"] } crossbeam-channel = "0.5.6" From 1fc056ec93d01af61fc3c7aaf1787ec01e255da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:21:34 +0200 Subject: [PATCH 2398/2442] Bump indexmap --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 1 + crates/hir-def/Cargo.toml | 2 +- crates/ide-db/Cargo.toml | 2 +- crates/syntax/Cargo.toml | 2 +- crates/vfs/Cargo.toml | 2 +- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 95c6991b4199..0d06e80bf532 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -444,9 +444,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "heck" @@ -504,7 +504,7 @@ dependencies = [ "fst", "hashbrown 0.12.3", "hir-expand", - "indexmap 2.0.0", + "indexmap 2.1.0", "intern", "itertools 0.12.0", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -679,7 +679,7 @@ dependencies = [ "expect-test", "fst", "hir", - "indexmap 2.0.0", + "indexmap 2.1.0", "itertools 0.12.0", "limit", "line-index 0.1.0-pre.1", @@ -762,12 +762,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.2", ] [[package]] @@ -1734,7 +1734,7 @@ version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.1.0", "itoa", "ryu", "serde", @@ -1848,7 +1848,7 @@ dependencies = [ "cov-mark", "either", "expect-test", - "indexmap 2.0.0", + "indexmap 2.1.0", "itertools 0.12.0", "once_cell", "parser", @@ -2173,7 +2173,7 @@ name = "vfs" version = "0.0.0" dependencies = [ "fst", - "indexmap 2.0.0", + "indexmap 2.1.0", "nohash-hasher", "paths", "rustc-hash", diff --git a/Cargo.toml b/Cargo.toml index 7f76b30598e2..135391694656 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,6 +92,7 @@ lsp-server = { version = "0.7.4" } # non-local crates anyhow = "1.0.75" either = "1.9.0" +indexmap = "2.1.0" itertools = "0.12.0" smallvec = { version = "1.10.0", features = [ "const_new", diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index f01db7bf8338..cbadfe715004 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -20,7 +20,7 @@ dashmap = { version = "=5.4.0", features = ["raw-api"] } drop_bomb = "0.1.5" either.workspace = true fst = { version = "0.4.7", default-features = false } -indexmap = "2.0.0" +indexmap.workspace = true itertools.workspace = true la-arena.workspace = true once_cell = "1.17.0" diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index a9873004a1d1..954541aab2a3 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -21,7 +21,7 @@ once_cell = "1.17.0" either.workspace = true itertools.workspace = true arrayvec = "0.7.2" -indexmap = "2.0.0" +indexmap.workspace = true memchr = "2.5.0" triomphe.workspace = true nohash-hasher.workspace = true diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index e0df0f2c9999..0b6c2360f465 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -19,7 +19,7 @@ itertools.workspace = true rowan = "0.15.11" rustc-hash = "1.1.0" once_cell = "1.17.0" -indexmap = "2.0.0" +indexmap.workspace = true smol_str.workspace = true triomphe.workspace = true diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml index c35785cf98c4..11409f2eb819 100644 --- a/crates/vfs/Cargo.toml +++ b/crates/vfs/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [dependencies] rustc-hash = "1.1.0" fst = "0.4.7" -indexmap = "2.0.0" +indexmap.workspace = true nohash-hasher.workspace = true paths.workspace = true From c4dfa06b9d51904c6fe267a902596cbe5d93753a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:25:19 +0200 Subject: [PATCH 2399/2442] Bump tracing-log --- Cargo.lock | 2 +- crates/rust-analyzer/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d06e80bf532..166ac3c78c48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1601,7 +1601,7 @@ dependencies = [ "tikv-jemallocator", "toolchain", "tracing", - "tracing-log 0.1.3", + "tracing-log 0.2.0", "tracing-subscriber", "tracing-tree", "triomphe", diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 6c4a2ea177c2..210f75cddd6d 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -37,7 +37,7 @@ mimalloc = { version = "0.1.30", default-features = false, optional = true } lsp-server.workspace = true tracing.workspace = true tracing-subscriber.workspace = true -tracing-log = "0.1.3" +tracing-log = "0.2.0" tracing-tree.workspace = true triomphe.workspace = true nohash-hasher.workspace = true From 441e8c71f1ecdcd22a34c43b25a44cc385ab1c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:27:48 +0200 Subject: [PATCH 2400/2442] Remove outdated comment --- crates/vfs-notify/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/vfs-notify/Cargo.toml b/crates/vfs-notify/Cargo.toml index 0273df8e4abd..fe6cb0a2c3fd 100644 --- a/crates/vfs-notify/Cargo.toml +++ b/crates/vfs-notify/Cargo.toml @@ -15,7 +15,6 @@ doctest = false tracing.workspace = true walkdir = "2.3.2" crossbeam-channel = "0.5.5" -# We demand 5.1.0 as any higher version pulls in a new windows-sys dupe notify = "6.1.1" stdx.workspace = true From a1f81a7e75e136889f960d49635c94d67b8ef43d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:31:45 +0200 Subject: [PATCH 2401/2442] Bump chalk --- Cargo.lock | 28 ++++++++++++++-------------- crates/hir-ty/Cargo.toml | 8 ++++---- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 166ac3c78c48..4e35f72635f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -160,9 +160,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chalk-derive" -version = "0.93.0" +version = "0.94.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "264726159011fc7f22c23eb51f49021ece6e71bc358b96e7f2e842db0b14162b" +checksum = "c0322d5289ceba3217a03c9af72aa403d87542822b753daa1da32e4b992a4e80" dependencies = [ "proc-macro2", "quote", @@ -172,9 +172,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.93.0" +version = "0.94.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65c17407d4c756b8f7f84344acb0fb96364d0298822743219bb25769b6d00df" +checksum = "0946cbc6d9136980a24a2dddf1888b5f0aa978dda300a3aa470b55b777b6bf3c" dependencies = [ "bitflags 1.3.2", "chalk-derive", @@ -183,9 +183,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.93.0" +version = "0.94.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e2cf7b70bedaaf3a8cf3c93b6120c2bb65be89389124028e724d19e209686e" +checksum = "4cd93fedbeeadc0cd4d0eb73bd061b621af99f5324a6a518264c8ef5e526e0ec" dependencies = [ "chalk-derive", "chalk-ir", @@ -196,14 +196,14 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.93.0" +version = "0.94.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc67c548d3854f64e97e67dc5b7c88513425c5bfa347cff96b7992ae6379288" +checksum = "a254cff72303c58c82df421cfe9465606372b81588923fcf179922b7eaad9a53" dependencies = [ "chalk-derive", "chalk-ir", "ena", - "indexmap 1.9.3", + "indexmap 2.1.0", "itertools 0.10.5", "petgraph", "rustc-hash", @@ -376,9 +376,9 @@ dependencies = [ [[package]] name = "fixedbitset" -version = "0.2.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" @@ -1278,12 +1278,12 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.5.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 1.9.3", + "indexmap 2.1.0", ] [[package]] diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index ca626e671aba..4f421171a0c1 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -23,10 +23,10 @@ oorandom = "11.1.3" tracing.workspace = true rustc-hash = "1.1.0" scoped-tls = "1.0.0" -chalk-solve = { version = "0.93.0", default-features = false } -chalk-ir = "0.93.0" -chalk-recursive = { version = "0.93.0", default-features = false } -chalk-derive = "0.93.0" +chalk-solve = { version = "0.94.0", default-features = false } +chalk-ir = "0.94.0" +chalk-recursive = { version = "0.94.0", default-features = false } +chalk-derive = "0.94.0" la-arena.workspace = true once_cell = "1.17.0" triomphe.workspace = true From 572583262cea1b57b2c988c4289dfb012923baee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:33:03 +0200 Subject: [PATCH 2402/2442] Bump text-size --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- lib/line-index/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e35f72635f9..305d7f8a84d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1889,9 +1889,9 @@ dependencies = [ [[package]] name = "text-size" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a" +checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" [[package]] name = "thiserror" diff --git a/Cargo.toml b/Cargo.toml index 135391694656..aea88ee87917 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,7 +108,7 @@ tracing-subscriber = { version = "0.3.18", default-features = false, features = ] } smol_str = "0.2.0" nohash-hasher = "0.2.0" -text-size = "1.1.0" +text-size = "1.1.1" serde = { version = "1.0.192", features = ["derive"] } serde_json = "1.0.108" triomphe = { version = "0.1.8", default-features = false, features = ["std"] } diff --git a/lib/line-index/Cargo.toml b/lib/line-index/Cargo.toml index 6c0d06f47178..b7b4a01818ea 100644 --- a/lib/line-index/Cargo.toml +++ b/lib/line-index/Cargo.toml @@ -7,5 +7,5 @@ repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/line-in edition = "2021" [dependencies] -text-size = "1.1.0" +text-size = "1.1.1" nohash-hasher = "0.2.0" From 829cf8db4cadd69ee7f4991881c5edf0714a04db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:34:56 +0200 Subject: [PATCH 2403/2442] Bump dissimilar --- Cargo.lock | 4 ++-- Cargo.toml | 1 + crates/rust-analyzer/Cargo.toml | 2 +- crates/test-utils/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 305d7f8a84d5..9b99ffc23bbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -315,9 +315,9 @@ dependencies = [ [[package]] name = "dissimilar" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "210ec60ae7d710bed8683e333e9d2855a8a56a3e9892b38bad3bb0d4d29b0d5e" +checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" [[package]] name = "dot" diff --git a/Cargo.toml b/Cargo.toml index aea88ee87917..87203f41c335 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ lsp-server = { version = "0.7.4" } # non-local crates anyhow = "1.0.75" +dissimilar = "1.0.7" either = "1.9.0" indexmap = "2.1.0" itertools = "0.12.0" diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 210f75cddd6d..30c90bde6508 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -21,7 +21,7 @@ path = "src/bin/main.rs" [dependencies] anyhow.workspace = true crossbeam-channel = "0.5.5" -dissimilar = "1.0.4" +dissimilar.workspace = true itertools.workspace = true scip = "0.3.1" lsp-types = { version = "=0.94.0", features = ["proposed"] } diff --git a/crates/test-utils/Cargo.toml b/crates/test-utils/Cargo.toml index 2b5b6f495616..438b599ffaae 100644 --- a/crates/test-utils/Cargo.toml +++ b/crates/test-utils/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] # Avoid adding deps here, this crate is widely used in tests it should compile fast! -dissimilar = "1.0.4" +dissimilar = "1.0.7" text-size.workspace = true rustc-hash = "1.1.0" From 0d147b382f46d9f19145d03295519ca4558858af Mon Sep 17 00:00:00 2001 From: jprochazk <1665677+jprochazk@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:36:08 +0100 Subject: [PATCH 2404/2442] detect internal error via `error.code` instead of error message --- editors/code/src/lang_client.ts | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/editors/code/src/lang_client.ts b/editors/code/src/lang_client.ts index e28330e6dba6..09d64efc048a 100644 --- a/editors/code/src/lang_client.ts +++ b/editors/code/src/lang_client.ts @@ -2,15 +2,25 @@ import * as lc from "vscode-languageclient/node"; import * as vscode from "vscode"; export class RaLanguageClient extends lc.LanguageClient { - override error(message: string, data?: any, showNotification?: boolean | "force"): void { - // ignore `Request TYPE failed.` errors + override handleFailedRequest( + type: lc.MessageSignature, + token: vscode.CancellationToken | undefined, + error: any, + defaultValue: T, + showNotification?: boolean | undefined, + ): T { const showError = vscode.workspace .getConfiguration("rust-analyzer") .get("showRequestFailedErrorNotification"); - if (!showError && message.startsWith("Request") && message.endsWith("failed.")) { - return; + if ( + !showError && + error instanceof lc.ResponseError && + error.code === lc.ErrorCodes.InternalError + ) { + // Don't show notification for internal errors, these are emitted by r-a when a request fails. + showNotification = false; } - super.error(message, data, showNotification); + return super.handleFailedRequest(type, token, error, defaultValue, showNotification); } } From b267f6b07131691b0d2db3f4e29118851b323f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:40:43 +0200 Subject: [PATCH 2405/2442] Bump ra-ap-rustc_lexer --- Cargo.lock | 6 +++--- crates/rustc-dependencies/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9b99ffc23bbd..cf4230eaad84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1484,9 +1484,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1762abb25eb1e37c1823f62b5da0821bbcd870812318db084c9516c2f78d2dcd" +checksum = "90e573bf707e01fe2841dbdedeed42012004274db0edc0314e6e3e58a40598fc" dependencies = [ "unicode-properties", "unicode-xid", @@ -1624,7 +1624,7 @@ version = "0.0.0" dependencies = [ "ra-ap-rustc_abi", "ra-ap-rustc_index 0.18.0", - "ra-ap-rustc_lexer 0.18.0", + "ra-ap-rustc_lexer 0.19.0", "ra-ap-rustc_parse_format", ] diff --git a/crates/rustc-dependencies/Cargo.toml b/crates/rustc-dependencies/Cargo.toml index a313507bff31..3c23896538a8 100644 --- a/crates/rustc-dependencies/Cargo.toml +++ b/crates/rustc-dependencies/Cargo.toml @@ -11,7 +11,7 @@ authors.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ra-ap-rustc_lexer = { version = "0.18.0" } +ra-ap-rustc_lexer = { version = "0.19.0" } ra-ap-rustc_parse_format = { version = "0.14.0", default-features = false } ra-ap-rustc_index = { version = "0.18.0", default-features = false } ra-ap-rustc_abi = { version = "0.18.0", default-features = false } From 9c8727eea5ba01c87cf384b1864e7ce86f31111d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= <1665677+jprochazk@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:41:54 +0100 Subject: [PATCH 2406/2442] Update editors/code/package.json Co-authored-by: Lukas Wirth --- editors/code/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/code/package.json b/editors/code/package.json index 59f89cebdeaa..850c0772f381 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -503,7 +503,7 @@ "type": "boolean" }, "rust-analyzer.showRequestFailedErrorNotification": { - "markdownDescription": "Whether to show panic error notifications.", + "markdownDescription": "Whether to show error notifications for failing requests.", "default": true, "type": "boolean" }, From c66084b9c6a617c230f82bf748711c71f091e8d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 13:42:13 +0200 Subject: [PATCH 2407/2442] Bump ra-ap-rustc_index and ra-ap-rustc_abi --- Cargo.lock | 12 ++++++------ crates/rustc-dependencies/Cargo.toml | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cf4230eaad84..990933365a66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1443,12 +1443,12 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7082716cb2bbcd8b5f062fe950cbbc87f3aba022d6da4168db35af6732a7f15d" +checksum = "9a2ea80a299f04a896000ce17b76f3aa1d2fe59f347fbc99c4b8970316ef5a0d" dependencies = [ "bitflags 1.3.2", - "ra-ap-rustc_index 0.18.0", + "ra-ap-rustc_index 0.19.0", "tracing", ] @@ -1464,9 +1464,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e14b1fc835d6992b128a03a3f3a8365ba9f03e1c656a1670305f63f30d786d" +checksum = "4556489ef652e5eb6cdad6078fff08507badac80bfc1f79085c85a6d8b77ab5c" dependencies = [ "arrayvec", "smallvec", @@ -1623,7 +1623,7 @@ name = "rustc-dependencies" version = "0.0.0" dependencies = [ "ra-ap-rustc_abi", - "ra-ap-rustc_index 0.18.0", + "ra-ap-rustc_index 0.19.0", "ra-ap-rustc_lexer 0.19.0", "ra-ap-rustc_parse_format", ] diff --git a/crates/rustc-dependencies/Cargo.toml b/crates/rustc-dependencies/Cargo.toml index 3c23896538a8..ba36fb0b0446 100644 --- a/crates/rustc-dependencies/Cargo.toml +++ b/crates/rustc-dependencies/Cargo.toml @@ -13,8 +13,8 @@ authors.workspace = true [dependencies] ra-ap-rustc_lexer = { version = "0.19.0" } ra-ap-rustc_parse_format = { version = "0.14.0", default-features = false } -ra-ap-rustc_index = { version = "0.18.0", default-features = false } -ra-ap-rustc_abi = { version = "0.18.0", default-features = false } +ra-ap-rustc_index = { version = "0.19.0", default-features = false } +ra-ap-rustc_abi = { version = "0.19.0", default-features = false } [features] in-rust-tree = [] From e8c4007cfcbb606e167ee90bc4eca2753284f7fc Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 15 Nov 2023 12:41:14 +0100 Subject: [PATCH 2408/2442] Fix builtin line! expansion --- .../macro_expansion_tests/builtin_fn_macro.rs | 4 +-- .../macro_expansion_tests/mbe/regression.rs | 34 +++++++++++++++++++ crates/hir-expand/src/builtin_fn_macro.rs | 27 +++++---------- crates/hir-ty/src/tests/macros.rs | 6 ++-- crates/rust-analyzer/src/reload.rs | 1 - 5 files changed, 46 insertions(+), 26 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 4aedb22c6bc9..106ead83fad7 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -17,7 +17,7 @@ fn main() { column!(); } #[rustc_builtin_macro] macro_rules! column {() => {}} -fn main() { 0 as u32; } +fn main() { 0u32; } "#]], ); } @@ -74,7 +74,7 @@ fn main() { line!() } #[rustc_builtin_macro] macro_rules! line {() => {}} -fn main() { 0 as u32 } +fn main() { 0u32 } "#]], ); } diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs index b416f45ff208..2886b2a366c0 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs @@ -970,3 +970,37 @@ builtin #format_args ("{}", &[0 2]); "##]], ); } + +#[test] +fn eager_concat_line() { + check( + r#" +#[rustc_builtin_macro] +#[macro_export] +macro_rules! concat {} + +#[rustc_builtin_macro] +#[macro_export] +macro_rules! line {} + +fn main() { + concat!("event ", line!()); +} + +"#, + expect![[r##" +#[rustc_builtin_macro] +#[macro_export] +macro_rules! concat {} + +#[rustc_builtin_macro] +#[macro_export] +macro_rules! line {} + +fn main() { + "event 0u32"; +} + +"##]], + ); +} diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index 30b19b6e51b8..a04de10b899c 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -78,7 +78,7 @@ pub fn find_builtin_macro( register_builtin! { LAZY: - (column, Column) => column_expand, + (column, Column) => line_expand, (file, File) => file_expand, (line, Line) => line_expand, (module_path, ModulePath) => module_path_expand, @@ -127,11 +127,13 @@ fn line_expand( _tt: &tt::Subtree, ) -> ExpandResult { // dummy implementation for type-checking purposes - let expanded = quote! { - 0 as u32 - }; - - ExpandResult::ok(expanded) + ExpandResult::ok(tt::Subtree { + delimiter: tt::Delimiter::unspecified(), + token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { + text: "0u32".into(), + span: tt::Span::UNSPECIFIED, + }))], + }) } fn log_syntax_expand( @@ -164,19 +166,6 @@ fn stringify_expand( ExpandResult::ok(expanded) } -fn column_expand( - _db: &dyn ExpandDatabase, - _id: MacroCallId, - _tt: &tt::Subtree, -) -> ExpandResult { - // dummy implementation for type-checking purposes - let expanded = quote! { - 0 as u32 - }; - - ExpandResult::ok(expanded) -} - fn assert_expand( _db: &dyn ExpandDatabase, _id: MacroCallId, diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ty/src/tests/macros.rs index 1e6e946a13f8..d16e0eb0137b 100644 --- a/crates/hir-ty/src/tests/macros.rs +++ b/crates/hir-ty/src/tests/macros.rs @@ -684,8 +684,7 @@ fn infer_builtin_macros_line() { } "#, expect![[r#" - !0..1 '0': i32 - !0..6 '0asu32': u32 + !0..4 '0u32': u32 63..87 '{ ...!(); }': () 73..74 'x': u32 "#]], @@ -723,8 +722,7 @@ fn infer_builtin_macros_column() { } "#, expect![[r#" - !0..1 '0': i32 - !0..6 '0asu32': u32 + !0..4 '0u32': u32 65..91 '{ ...!(); }': () 75..76 'x': u32 "#]], diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 3fae08b82e27..8dba83ed5edd 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -380,7 +380,6 @@ impl GlobalState { ws }) .collect::>(); - // Workspaces are the same, but we've updated build data. self.workspaces = Arc::new(workspaces); } else { From 8e8e7de93bf8297633e1723ba639f4ec4c38fc1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 17:08:39 +0200 Subject: [PATCH 2409/2442] Tweak tsconfig.json --- editors/code/tsconfig.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json index ee353c28dd67..c74284a00d96 100644 --- a/editors/code/tsconfig.json +++ b/editors/code/tsconfig.json @@ -2,14 +2,14 @@ "extends": "@tsconfig/strictest/tsconfig.json", "compilerOptions": { "esModuleInterop": false, - "module": "commonjs", - "moduleResolution": "node16", - "target": "es2021", + "module": "CommonJS", + "moduleResolution": "Node16", + "target": "ES2021", "outDir": "out", - "lib": ["es2021"], + "lib": ["ES2021"], "sourceMap": true, "rootDir": ".", - "newLine": "LF", + "newLine": "lf", // FIXME: https://github.com/rust-lang/rust-analyzer/issues/15253 "exactOptionalPropertyTypes": false From df7fa7f6807fe10e1207e4405b9cdb42b8d5a24a Mon Sep 17 00:00:00 2001 From: David Barsky Date: Wed, 15 Nov 2023 09:21:48 -0500 Subject: [PATCH 2410/2442] editor/code: bump minimum version of VS Code to 1.78 --- editors/code/package-lock.json | 10 +++++----- editors/code/package.json | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 20fe781ae9e4..1c94f13d7451 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -18,7 +18,7 @@ "devDependencies": { "@tsconfig/strictest": "^2.0.1", "@types/node": "~16.11.7", - "@types/vscode": "~1.75", + "@types/vscode": "~1.78.1", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vscode/test-electron": "^2.3.3", @@ -32,7 +32,7 @@ "typescript": "^5.1.6" }, "engines": { - "vscode": "^1.75.0" + "vscode": "^1.78.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -565,9 +565,9 @@ "dev": true }, "node_modules/@types/vscode": { - "version": "1.75.1", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.75.1.tgz", - "integrity": "sha512-emg7wdsTFzdi+elvoyoA+Q8keEautdQHyY5LNmHVM4PTpY8JgOTVADrGVyXGepJ6dVW2OS5/xnLUWh+nZxvdiA==", + "version": "1.78.1", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.78.1.tgz", + "integrity": "sha512-wEA+54axejHu7DhcUfnFBan1IqFD1gBDxAFz8LoX06NbNDMRJv/T6OGthOs52yZccasKfN588EyffHWABkR0fg==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { diff --git a/editors/code/package.json b/editors/code/package.json index a4ce7314dd49..c2d8954beefe 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -27,7 +27,7 @@ } }, "engines": { - "vscode": "^1.75.0" + "vscode": "^1.78.0" }, "enabledApiProposals": [], "scripts": { @@ -54,7 +54,7 @@ "devDependencies": { "@tsconfig/strictest": "^2.0.1", "@types/node": "~16.11.7", - "@types/vscode": "~1.75", + "@types/vscode": "~1.78.1", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vscode/test-electron": "^2.3.3", From 83e6d7938c54f8d6d294098c3706bb6ceb15f371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 21:07:31 +0200 Subject: [PATCH 2411/2442] Bump tracing-tree again --- Cargo.lock | 34 ++++++++-------------------------- Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 990933365a66..4b9cbc823ae1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1127,12 +1127,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68" dependencies = [ - "overload", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -1175,12 +1174,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "parking_lot" version = "0.11.2" @@ -1601,7 +1594,7 @@ dependencies = [ "tikv-jemallocator", "toolchain", "tracing", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", "tracing-tree", "triomphe", @@ -2024,17 +2017,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-log" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -2055,18 +2037,18 @@ dependencies = [ "sharded-slab", "thread_local", "tracing-core", - "tracing-log 0.2.0", + "tracing-log", ] [[package]] name = "tracing-tree" -version = "0.2.5" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ec6adcab41b1391b08a308cc6302b79f8095d1673f6947c2dc65ffb028b0b2d" +checksum = "65139ecd2c3f6484c3b99bc01c77afe21e95473630747c7aca525e78b0666675" dependencies = [ "nu-ansi-term", "tracing-core", - "tracing-log 0.1.3", + "tracing-log", "tracing-subscriber", ] diff --git a/Cargo.toml b/Cargo.toml index 87203f41c335..859a1cc579fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,7 +101,7 @@ smallvec = { version = "1.10.0", features = [ "const_generics", ] } tracing = "0.1.40" -tracing-tree = "0.2.5" +tracing-tree = "0.3.0" tracing-subscriber = { version = "0.3.18", default-features = false, features = [ "registry", "fmt", From b18ce4f8ea650556432c4399707a847265deb811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 21:12:18 +0200 Subject: [PATCH 2412/2442] Bump xshell --- Cargo.lock | 8 ++++---- Cargo.toml | 1 + crates/ide-db/Cargo.toml | 2 +- crates/rust-analyzer/Cargo.toml | 2 +- crates/sourcegen/Cargo.toml | 2 +- xtask/Cargo.toml | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b9cbc823ae1..84e839d99e63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2368,18 +2368,18 @@ checksum = "f58e7b3ca8977093aae6b87b6a7730216fc4c53a6530bab5c43a783cd810c1a8" [[package]] name = "xshell" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "962c039b3a7b16cf4e9a4248397c6585c07547412e7d6a6e035389a802dcfe90" +checksum = "ce2107fe03e558353b4c71ad7626d58ed82efaf56c54134228608893c77023ad" dependencies = [ "xshell-macros", ] [[package]] name = "xshell-macros" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbabb1cbd15a1d6d12d9ed6b35cc6777d4af87ab3ba155ea37215f20beab80c" +checksum = "7e2c411759b501fb9501aac2b1b2d287a6e93e5bdcf13c25306b23e1b716dd0e" [[package]] name = "xtask" diff --git a/Cargo.toml b/Cargo.toml index 859a1cc579fa..020d449921da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -117,3 +117,4 @@ triomphe = { version = "0.1.8", default-features = false, features = ["std"] } hashbrown = { version = "0.12.3", features = [ "inline-more", ], default-features = false } +xshell = "0.2.5" diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index 954541aab2a3..cf4daf4d2ac2 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -43,7 +43,7 @@ line-index.workspace = true [dev-dependencies] expect-test = "1.4.0" oorandom = "11.1.3" -xshell = "0.2.2" +xshell.workspace = true # local deps test-utils.workspace = true diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 30c90bde6508..59f4162d58e0 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -77,7 +77,7 @@ jemallocator = { version = "0.5.0", package = "tikv-jemallocator", optional = tr [dev-dependencies] expect-test = "1.4.0" -xshell = "0.2.2" +xshell.workspace = true test-utils.workspace = true sourcegen.workspace = true diff --git a/crates/sourcegen/Cargo.toml b/crates/sourcegen/Cargo.toml index fb2b9ebef506..0514af8e7839 100644 --- a/crates/sourcegen/Cargo.toml +++ b/crates/sourcegen/Cargo.toml @@ -12,4 +12,4 @@ rust-version.workspace = true doctest = false [dependencies] -xshell = "0.2.2" +xshell.workspace = true diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index d32bfe856d3f..1c785b60a3d8 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -10,7 +10,7 @@ rust-version.workspace = true anyhow.workspace = true flate2 = "1.0.24" write-json = "0.1.2" -xshell = "0.2.2" +xshell.workspace = true xflags = "0.3.0" time = { version = "0.3", default-features = false } zip = { version = "0.6", default-features = false, features = ["deflate", "time"] } From 2814d646cb93956706e28f259cf55b15881486db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 21:14:56 +0200 Subject: [PATCH 2413/2442] Bump rayon --- Cargo.lock | 10 ++++------ Cargo.toml | 1 + crates/ide-db/Cargo.toml | 2 +- crates/rust-analyzer/Cargo.toml | 2 +- crates/syntax/Cargo.toml | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84e839d99e63..79bef79be233 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1497,9 +1497,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -1507,14 +1507,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 020d449921da..d47ec7468948 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,6 +110,7 @@ tracing-subscriber = { version = "0.3.18", default-features = false, features = smol_str = "0.2.0" nohash-hasher = "0.2.0" text-size = "1.1.1" +rayon = "1.8.0" serde = { version = "1.0.192", features = ["derive"] } serde_json = "1.0.108" triomphe = { version = "0.1.8", default-features = false, features = ["std"] } diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index cf4daf4d2ac2..0f723950f8dd 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [dependencies] cov-mark = "2.0.0-pre.1" tracing.workspace = true -rayon = "1.6.1" +rayon.workspace = true fst = { version = "0.4.7", default-features = false } rustc-hash = "1.1.0" once_cell = "1.17.0" diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 59f4162d58e0..76f764460329 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -28,10 +28,10 @@ lsp-types = { version = "=0.94.0", features = ["proposed"] } parking_lot = "0.12.1" xflags = "0.3.0" oorandom = "11.1.3" +rayon.workspace = true rustc-hash = "1.1.0" serde_json = { workspace = true, features = ["preserve_order"] } serde.workspace = true -rayon = "1.6.1" num_cpus = "1.15.0" mimalloc = { version = "0.1.30", default-features = false, optional = true } lsp-server.workspace = true diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 0b6c2360f465..3b55921dc759 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -31,7 +31,7 @@ stdx.workspace = true text-edit.workspace = true [dev-dependencies] -rayon = "1.6.1" +rayon.workspace = true expect-test = "1.4.0" proc-macro2 = "1.0.47" quote = "1.0.20" From 3ed27d21f262f2a817eab85fce71c08962046914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 21:18:49 +0200 Subject: [PATCH 2414/2442] Bump cargo_metadata --- Cargo.lock | 4 ++-- Cargo.toml | 1 + crates/flycheck/Cargo.toml | 2 +- crates/proc-macro-test/Cargo.toml | 2 +- crates/project-model/Cargo.toml | 8 ++++---- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 79bef79be233..0febbc599602 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.4" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", diff --git a/Cargo.toml b/Cargo.toml index d47ec7468948..2c9740af68f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ lsp-server = { version = "0.7.4" } # non-local crates anyhow = "1.0.75" +cargo_metadata = "0.18.1" dissimilar = "1.0.7" either = "1.9.0" indexmap = "2.1.0" diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index 12e0b14cc5a0..4322d2d966a1 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml @@ -12,9 +12,9 @@ rust-version.workspace = true doctest = false [dependencies] +cargo_metadata.workspace = true crossbeam-channel = "0.5.8" tracing.workspace = true -cargo_metadata = "0.15.4" rustc-hash = "1.1.0" serde_json.workspace = true serde.workspace = true diff --git a/crates/proc-macro-test/Cargo.toml b/crates/proc-macro-test/Cargo.toml index 77b4afd7d7e1..12d7c07d3ed9 100644 --- a/crates/proc-macro-test/Cargo.toml +++ b/crates/proc-macro-test/Cargo.toml @@ -12,7 +12,7 @@ rust-version.workspace = true doctest = false [build-dependencies] -cargo_metadata = "0.15.0" +cargo_metadata.workspace = true proc-macro-test-impl = { path = "imp", version = "0.0.0" } diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml index d35e5f599262..3e48de6456b0 100644 --- a/crates/project-model/Cargo.toml +++ b/crates/project-model/Cargo.toml @@ -12,13 +12,13 @@ rust-version.workspace = true doctest = false [dependencies] -tracing.workspace = true -rustc-hash = "1.1.0" -cargo_metadata = "0.15.0" -semver = "1.0.14" anyhow.workspace = true +cargo_metadata.workspace = true +rustc-hash = "1.1.0" +semver = "1.0.14" serde_json.workspace = true serde.workspace = true +tracing.workspace = true triomphe.workspace = true la-arena.workspace = true itertools.workspace = true From c6fad55c98bac7f4c94dc1152537f6743d97e642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 21:20:47 +0200 Subject: [PATCH 2415/2442] Bump bitflags --- Cargo.lock | 10 +++++----- Cargo.toml | 1 + crates/hir-def/Cargo.toml | 2 +- crates/hir-ty/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0febbc599602..121dbcbfd9ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,9 +90,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.2" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "byteorder" @@ -494,7 +494,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.3.2", + "bitflags 2.4.1", "cfg", "cov-mark", "dashmap", @@ -554,7 +554,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.3.2", + "bitflags 2.4.1", "chalk-derive", "chalk-ir", "chalk-recursive", @@ -1112,7 +1112,7 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.3.2", + "bitflags 2.4.1", "crossbeam-channel", "filetime", "fsevent-sys", diff --git a/Cargo.toml b/Cargo.toml index 2c9740af68f9..68f4cef587b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ lsp-server = { version = "0.7.4" } # non-local crates anyhow = "1.0.75" +bitflags = "2.4.1" cargo_metadata = "0.18.1" dissimilar = "1.0.7" either = "1.9.0" diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index cbadfe715004..e4f2e14c51c7 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -13,7 +13,7 @@ doctest = false [dependencies] arrayvec = "0.7.2" -bitflags = "2.1.0" +bitflags.workspace = true cov-mark = "2.0.0-pre.1" # We need to freeze the version of the crate, as the raw-api feature is considered unstable dashmap = { version = "=5.4.0", features = ["raw-api"] } diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index 4f421171a0c1..f2d2451511f7 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -15,7 +15,7 @@ doctest = false cov-mark = "2.0.0-pre.1" itertools.workspace = true arrayvec = "0.7.2" -bitflags = "2.1.0" +bitflags.workspace = true smallvec.workspace = true ena = "0.14.0" either.workspace = true From 8ea06c8ec8137fff67d9a98847f60127d3cc2039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 21:22:34 +0200 Subject: [PATCH 2416/2442] Bump arbitrary and derive-arbitrary --- Cargo.lock | 8 ++++---- crates/cfg/Cargo.toml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 121dbcbfd9ed..705d55c91f25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,9 +34,9 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arbitrary" -version = "1.3.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" [[package]] name = "arrayvec" @@ -304,9 +304,9 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml index ed380897278b..4324584df39d 100644 --- a/crates/cfg/Cargo.toml +++ b/crates/cfg/Cargo.toml @@ -23,8 +23,8 @@ oorandom = "11.1.3" # We depend on both individually instead of using `features = ["derive"]` to microoptimize the # build graph: if the feature was enabled, syn would be built early on in the graph if `smolstr` # supports `arbitrary`. This way, we avoid feature unification. -arbitrary = "1.3.0" -derive_arbitrary = "1.3.1" +arbitrary = "1.3.2" +derive_arbitrary = "1.3.2" # local deps mbe.workspace = true From da24b6fb125d66fb9e846c45a88c342e96a1e624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 15 Nov 2023 21:24:20 +0200 Subject: [PATCH 2417/2442] Bump memchr --- Cargo.lock | 4 ++-- crates/ide-db/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 705d55c91f25..050df49f2f40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1009,9 +1009,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memmap2" diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index 0f723950f8dd..4a2e770f193a 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -22,7 +22,7 @@ either.workspace = true itertools.workspace = true arrayvec = "0.7.2" indexmap.workspace = true -memchr = "2.5.0" +memchr = "2.6.4" triomphe.workspace = true nohash-hasher.workspace = true From cfc881ae137af972a2240df9c92492abd314bbb8 Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Thu, 16 Nov 2023 22:27:21 +0800 Subject: [PATCH 2418/2442] fix missing assoc item --- crates/hir/src/lib.rs | 10 +++++----- .../src/handlers/trait_impl_missing_assoc_item.rs | 13 +++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index bdc11aa3561b..1bfbf7212bf0 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -667,21 +667,21 @@ impl Module { let items = &db.trait_data(trait_.into()).items; let required_items = items.iter().filter(|&(_, assoc)| match *assoc { AssocItemId::FunctionId(it) => !db.function_data(it).has_body(), - AssocItemId::ConstId(_) => true, + AssocItemId::ConstId(id) => Const::from(id).value(db).is_none(), AssocItemId::TypeAliasId(it) => db.type_alias_data(it).type_ref.is_none(), }); - impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().map( + impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().filter_map( |&item| { - ( + Some(( item, match item { AssocItemId::FunctionId(it) => db.function_data(it).name.clone(), AssocItemId::ConstId(it) => { - db.const_data(it).name.as_ref().unwrap().clone() + db.const_data(it).name.as_ref()?.clone() } AssocItemId::TypeAliasId(it) => db.type_alias_data(it).name.clone(), }, - ) + )) }, )); diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs index 40d0b6fdd4b0..51923797ac91 100644 --- a/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs +++ b/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs @@ -35,6 +35,19 @@ pub(crate) fn trait_impl_missing_assoc_item( mod tests { use crate::tests::check_diagnostics; + #[test] + fn trait_with_default_value() { + check_diagnostics( + r#" +trait Marker { + const FLAG: bool = false; +} +struct Foo; +impl Marker for Foo {} + "#, + ) + } + #[test] fn simple() { check_diagnostics( From e95ec552731be34a0820ded3c001a91398b6a2e1 Mon Sep 17 00:00:00 2001 From: austaras Date: Thu, 2 Nov 2023 22:37:50 +0800 Subject: [PATCH 2419/2442] fix: better resolve assoc item with type bound --- crates/hir-ty/src/infer/unify.rs | 29 ++++++++ crates/hir-ty/src/lower.rs | 23 +++++- crates/hir-ty/src/method_resolution.rs | 50 ++++++++----- crates/ide-completion/src/completions/dot.rs | 77 ++++++++++++++++++++ 4 files changed, 156 insertions(+), 23 deletions(-) diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 0a68a9f3b583..78bdd62a2769 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -495,6 +495,35 @@ impl<'a> InferenceTable<'a> { solution } + pub(crate) fn try_resolve_alias(&mut self, goal: Goal) -> bool { + let in_env = InEnvironment::new(&self.trait_env.env, goal); + let canonicalized = self.canonicalize(in_env); + let solution = self.db.trait_solve( + self.trait_env.krate, + self.trait_env.block, + canonicalized.value.clone(), + ); + + match solution { + Some(Solution::Unique(canonical_subst)) => { + canonicalized.apply_solution( + self, + Canonical { + binders: canonical_subst.binders, + value: canonical_subst.value.subst, + }, + ); + true + } + Some(Solution::Ambig(Guidance::Definite(substs))) => { + canonicalized.apply_solution(self, substs); + true + } + Some(_) => true, + None => false, + } + } + pub(crate) fn register_obligation(&mut self, goal: Goal) { let in_env = InEnvironment::new(&self.trait_env.env, goal); self.register_obligation_in_env(in_env) diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index c8a85b4a9ff0..04005311b673 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -1097,10 +1097,25 @@ impl<'a> TyLoweringContext<'a> { binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), ); if let Some(type_ref) = &binding.type_ref { - let ty = self.lower_ty(type_ref); - let alias_eq = - AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; - predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); + if let (TypeRef::ImplTrait(bounds), ImplTraitLoweringState::Disallowed) = + (type_ref, &self.impl_trait_mode) + { + for bound in bounds { + predicates.extend( + self.lower_type_bound( + bound, + TyKind::Alias(AliasTy::Projection(projection_ty.clone())) + .intern(Interner), + false, + ), + ); + } + } else { + let ty = self.lower_ty(type_ref); + let alias_eq = + AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; + predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); + } } for bound in binding.bounds.iter() { predicates.extend(self.lower_type_bound( diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 87c93283361f..04a55c3536df 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -1478,26 +1478,38 @@ fn is_valid_fn_candidate( // We need to consider the bounds on the impl to distinguish functions of the same name // for a type. let predicates = db.generic_predicates(impl_id.into()); - let valid = predicates - .iter() - .map(|predicate| { - let (p, b) = predicate - .clone() - .substitute(Interner, &impl_subst) - // Skipping the inner binders is ok, as we don't handle quantified where - // clauses yet. - .into_value_and_skipped_binders(); - stdx::always!(b.len(Interner) == 0); - p - }) - // It's ok to get ambiguity here, as we may not have enough information to prove - // obligations. We'll check if the user is calling the selected method properly - // later anyway. - .all(|p| table.try_obligation(p.cast(Interner)).is_some()); - match valid { - true => IsValidCandidate::Yes, - false => IsValidCandidate::No, + let mut alias = Vec::new(); + let mut other_predicate = Vec::new(); + + for predicate in predicates.iter() { + let (p, b) = predicate + .clone() + .substitute(Interner, &impl_subst) + // Skipping the inner binders is ok, as we don't handle quantified where + // clauses yet. + .into_value_and_skipped_binders(); + stdx::always!(b.len(Interner) == 0); + + if let WhereClause::AliasEq(_) = p { + alias.push(p); + } else { + other_predicate.push(p); + } } + + for p in alias { + if !table.try_resolve_alias(p.cast(Interner)) { + return IsValidCandidate::No; + } + } + + for p in other_predicate { + if table.try_obligation(p.cast(Interner)).is_none() { + return IsValidCandidate::No; + } + } + + IsValidCandidate::Yes } else { // For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in // `iterate_trait_method_candidates()`. diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs index c5bbb7f8d755..5bcc867fe181 100644 --- a/crates/ide-completion/src/completions/dot.rs +++ b/crates/ide-completion/src/completions/dot.rs @@ -1095,4 +1095,81 @@ fn test(s: S) { "#]], ); } + + #[test] + fn assoc_impl_1() { + check( + r#" +//- minicore: deref +fn main() { + let foo: Foo<&u8> = Foo::new(&42_u8); + foo.$0 +} + +trait Bar { + fn bar(&self); +} + +impl Bar for u8 { + fn bar(&self) {} +} + +struct Foo { + foo: F, +} + +impl Foo { + fn new(foo: F) -> Foo { + Foo { foo } + } +} + +impl> Foo { + fn foobar(&self) { + self.foo.deref().bar() + } +} +"#, + expect![[r#" + fd foo &u8 + me foobar() fn(&self) + "#]], + ); + } + + #[test] + fn assoc_impl_2() { + check( + r#" +//- minicore: deref +fn main() { + let foo: Foo<&u8> = Foo::new(&42_u8); + foo.$0 +} + +trait Bar { + fn bar(&self); +} + +struct Foo { + foo: F, +} + +impl Foo { + fn new(foo: F) -> Foo { + Foo { foo } + } +} + +impl> Foo { + fn foobar(&self) { + self.foo.deref().bar() + } +} +"#, + expect![[r#" + fd foo &u8 + "#]], + ); + } } From 0cd68bfed3e31c034a5ead664ac8ad84d8bc06fd Mon Sep 17 00:00:00 2001 From: David Barsky Date: Tue, 17 Oct 2023 11:29:11 -0400 Subject: [PATCH 2420/2442] code: expose workspaces to other extensions; remove `addProject` command --- editors/code/package.json | 5 ----- editors/code/src/commands.ts | 22 ---------------------- editors/code/src/ctx.ts | 32 +++++++++++++++++++------------- editors/code/src/main.ts | 5 ++++- 4 files changed, 23 insertions(+), 41 deletions(-) diff --git a/editors/code/package.json b/editors/code/package.json index c2d8954beefe..265c63f3e2dc 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -209,11 +209,6 @@ "title": "Rebuild proc macros and build scripts", "category": "rust-analyzer" }, - { - "command": "rust-analyzer.addProject", - "title": "Add current file's crate to workspace", - "category": "rust-analyzer" - }, { "command": "rust-analyzer.restartServer", "title": "Restart server", diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 7e24de664e9e..3d33d255ad49 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -870,28 +870,6 @@ export function rebuildProcMacros(ctx: CtxInit): Cmd { return async () => ctx.client.sendRequest(ra.rebuildProcMacros); } -export function addProject(ctx: CtxInit): Cmd { - return async () => { - const extensionName = ctx.config.discoverProjectRunner; - // this command shouldn't be enabled in the first place if this isn't set. - if (!extensionName) { - return; - } - - const command = `${extensionName}.discoverWorkspaceCommand`; - const project: JsonProject = await vscode.commands.executeCommand(command); - - ctx.addToDiscoveredWorkspaces([project]); - - // this is a workaround to avoid needing writing the `rust-project.json` into - // a workspace-level VS Code-specific settings folder. We'd like to keep the - // `rust-project.json` entirely in-memory. - await ctx.client?.sendNotification(lc.DidChangeConfigurationNotification.type, { - settings: "", - }); - }; -} - async function showReferencesImpl( client: LanguageClient | undefined, uri: string, diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 84d1ad98bd98..63ae386c8ad1 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -1,5 +1,5 @@ import * as vscode from "vscode"; -import type * as lc from "vscode-languageclient/node"; +import * as lc from "vscode-languageclient/node"; import * as ra from "./lsp_ext"; import { Config, prepareVSCodeConfig } from "./config"; @@ -22,6 +22,7 @@ import { import { execRevealDependency } from "./commands"; import { PersistentState } from "./persistent_state"; import { bootstrap } from "./bootstrap"; +import type { RustAnalyzerExtensionApi } from "./main"; // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if // only those are in use. We use "Empty" to represent these scenarios @@ -64,7 +65,7 @@ export type CtxInit = Ctx & { readonly client: lc.LanguageClient; }; -export class Ctx { +export class Ctx implements RustAnalyzerExtensionApi { readonly statusBar: vscode.StatusBarItem; config: Config; readonly workspace: Workspace; @@ -189,8 +190,11 @@ export class Ctx { if (this.config.discoverProjectRunner) { const command = `${this.config.discoverProjectRunner}.discoverWorkspaceCommand`; log.info(`running command: ${command}`); - const project: JsonProject = await vscode.commands.executeCommand(command); - this.addToDiscoveredWorkspaces([project]); + const uris = vscode.workspace.textDocuments + .filter(isRustDocument) + .map((document) => document.uri); + const projects: JsonProject[] = await vscode.commands.executeCommand(command, uris); + this.setWorkspaces(projects); } if (this.workspace.kind === "Detached Files") { @@ -342,15 +346,17 @@ export class Ctx { return this._serverPath; } - addToDiscoveredWorkspaces(workspaces: JsonProject[]) { - for (const workspace of workspaces) { - const index = this.config.discoveredWorkspaces.indexOf(workspace); - if (~index) { - this.config.discoveredWorkspaces[index] = workspace; - } else { - this.config.discoveredWorkspaces.push(workspace); - } - } + setWorkspaces(workspaces: JsonProject[]) { + this.config.discoveredWorkspaces = workspaces; + } + + async notifyRustAnalyzer(): Promise { + // this is a workaround to avoid needing writing the `rust-project.json` into + // a workspace-level VS Code-specific settings folder. We'd like to keep the + // `rust-project.json` entirely in-memory. + await this.client?.sendNotification(lc.DidChangeConfigurationNotification.type, { + settings: "", + }); } private updateCommands(forceDisable?: "disable") { diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 5de5aabc39f7..3073353674ce 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -9,8 +9,12 @@ import { setContextValue } from "./util"; const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; +// This API is not stable and may break in between minor releases. export interface RustAnalyzerExtensionApi { readonly client?: lc.LanguageClient; + + setWorkspaces(workspaces: JsonProject[]): void; + notifyRustAnalyzer(): Promise; } export async function deactivate() { @@ -152,7 +156,6 @@ function createCommands(): Record { shuffleCrateGraph: { enabled: commands.shuffleCrateGraph }, reloadWorkspace: { enabled: commands.reloadWorkspace }, rebuildProcMacros: { enabled: commands.rebuildProcMacros }, - addProject: { enabled: commands.addProject }, matchingBrace: { enabled: commands.matchingBrace }, joinLines: { enabled: commands.joinLines }, parentModule: { enabled: commands.parentModule }, From 480cb60be3159c26b27a3b6d033a135b42bbbf27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 16 Nov 2023 21:48:49 +0200 Subject: [PATCH 2421/2442] Bump libc --- Cargo.lock | 4 ++-- Cargo.toml | 1 + crates/profile/Cargo.toml | 2 +- crates/stdx/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 050df49f2f40..701e36d74a65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -877,9 +877,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libloading" diff --git a/Cargo.toml b/Cargo.toml index 68f4cef587b2..73bb9c84d2c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,6 +97,7 @@ dissimilar = "1.0.7" either = "1.9.0" indexmap = "2.1.0" itertools = "0.12.0" +libc = "0.2.150" smallvec = { version = "1.10.0", features = [ "const_new", "union", diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index 937834a82aef..56ce9d11c085 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml @@ -14,8 +14,8 @@ doctest = false [dependencies] once_cell = "1.17.0" cfg-if = "1.0.0" -libc = "0.2.135" la-arena.workspace = true +libc.workspace = true countme = { version = "3.0.1", features = ["enable"] } jemalloc-ctl = { version = "0.5.0", package = "tikv-jemalloc-ctl", optional = true } diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml index 536f000a44b7..35986799fdd4 100644 --- a/crates/stdx/Cargo.toml +++ b/crates/stdx/Cargo.toml @@ -12,10 +12,10 @@ rust-version.workspace = true doctest = false [dependencies] -libc = "0.2.135" backtrace = { version = "0.3.67", optional = true } always-assert = { version = "0.1.2", features = ["log"] } jod-thread = "0.1.2" +libc.workspace = true crossbeam-channel = "0.5.5" # Think twice before adding anything here From 808f6687f7b796dd2c171e3be3829f1dedb6d537 Mon Sep 17 00:00:00 2001 From: austaras Date: Fri, 17 Nov 2023 16:47:46 +0800 Subject: [PATCH 2422/2442] address comment --- crates/hir-ty/src/infer/unify.rs | 31 +-------------- crates/hir-ty/src/method_resolution.rs | 53 +++++++++++++++++--------- crates/hir-ty/src/tests/traits.rs | 28 ++++++++++++++ 3 files changed, 63 insertions(+), 49 deletions(-) diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 78bdd62a2769..ac39bdf5bf53 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -43,7 +43,7 @@ where } impl> Canonicalized { - pub(super) fn apply_solution( + pub(crate) fn apply_solution( &self, ctx: &mut InferenceTable<'_>, solution: Canonical, @@ -495,35 +495,6 @@ impl<'a> InferenceTable<'a> { solution } - pub(crate) fn try_resolve_alias(&mut self, goal: Goal) -> bool { - let in_env = InEnvironment::new(&self.trait_env.env, goal); - let canonicalized = self.canonicalize(in_env); - let solution = self.db.trait_solve( - self.trait_env.krate, - self.trait_env.block, - canonicalized.value.clone(), - ); - - match solution { - Some(Solution::Unique(canonical_subst)) => { - canonicalized.apply_solution( - self, - Canonical { - binders: canonical_subst.binders, - value: canonical_subst.value.subst, - }, - ); - true - } - Some(Solution::Ambig(Guidance::Definite(substs))) => { - canonicalized.apply_solution(self, substs); - true - } - Some(_) => true, - None => false, - } - } - pub(crate) fn register_obligation(&mut self, goal: Goal) { let in_env = InEnvironment::new(&self.trait_env.env, goal); self.register_obligation_in_env(in_env) diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 04a55c3536df..732643566a2d 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -27,8 +27,9 @@ use crate::{ primitive::{FloatTy, IntTy, UintTy}, static_lifetime, to_chalk_trait_id, utils::all_super_traits, - AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, InEnvironment, - Interner, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, + AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, Goal, Guidance, + InEnvironment, Interner, Scalar, Solution, Substitution, TraitEnvironment, TraitRef, + TraitRefExt, Ty, TyBuilder, TyExt, }; /// This is used as a key for indexing impls. @@ -1478,11 +1479,8 @@ fn is_valid_fn_candidate( // We need to consider the bounds on the impl to distinguish functions of the same name // for a type. let predicates = db.generic_predicates(impl_id.into()); - let mut alias = Vec::new(); - let mut other_predicate = Vec::new(); - - for predicate in predicates.iter() { - let (p, b) = predicate + let goals = predicates.iter().map(|p| { + let (p, b) = p .clone() .substitute(Interner, &impl_subst) // Skipping the inner binders is ok, as we don't handle quantified where @@ -1490,21 +1488,38 @@ fn is_valid_fn_candidate( .into_value_and_skipped_binders(); stdx::always!(b.len(Interner) == 0); - if let WhereClause::AliasEq(_) = p { - alias.push(p); - } else { - other_predicate.push(p); + p.cast::(Interner) + }); + + for goal in goals.clone() { + let in_env = InEnvironment::new(&table.trait_env.env, goal); + let canonicalized = table.canonicalize(in_env); + let solution = table.db.trait_solve( + table.trait_env.krate, + table.trait_env.block, + canonicalized.value.clone(), + ); + + match solution { + Some(Solution::Unique(canonical_subst)) => { + canonicalized.apply_solution( + table, + Canonical { + binders: canonical_subst.binders, + value: canonical_subst.value.subst, + }, + ); + } + Some(Solution::Ambig(Guidance::Definite(substs))) => { + canonicalized.apply_solution(table, substs); + } + Some(_) => (), + None => return IsValidCandidate::No, } } - for p in alias { - if !table.try_resolve_alias(p.cast(Interner)) { - return IsValidCandidate::No; - } - } - - for p in other_predicate { - if table.try_obligation(p.cast(Interner)).is_none() { + for goal in goals { + if table.try_obligation(goal).is_none() { return IsValidCandidate::No; } } diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 48dd9540329d..003ae60e8e51 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -2597,6 +2597,34 @@ fn test() { ); } +#[test] +fn associated_type_in_type_bound() { + check_types( + r#" +//- minicore: deref +fn fb(f: Foo<&u8>) { + f.foobar(); + //^^^^^^^^^^ u8 +} +trait Bar { + fn bar(&self) -> u8; +} +impl Bar for u8 { + fn bar(&self) -> u8 { *self } +} + +struct Foo { + foo: F, +} +impl> Foo { + fn foobar(&self) -> u8 { + self.foo.deref().bar() + } +} +"#, + ) +} + #[test] fn dyn_trait_through_chalk() { check_types( From 1cbda612bc2d95c14bb0b511c9d8024316dffc8b Mon Sep 17 00:00:00 2001 From: Young-Flash <871946895@qq.com> Date: Fri, 17 Nov 2023 21:31:33 +0800 Subject: [PATCH 2423/2442] chore: add use case for `PathSegment::qualifying_trait` --- crates/ide-assists/src/handlers/unqualify_method_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/unqualify_method_call.rs b/crates/ide-assists/src/handlers/unqualify_method_call.rs index 0bf1782a489d..0876246e90b1 100644 --- a/crates/ide-assists/src/handlers/unqualify_method_call.rs +++ b/crates/ide-assists/src/handlers/unqualify_method_call.rs @@ -91,7 +91,7 @@ fn add_import( ) { if let Some(path_segment) = qualifier.segment() { // for `` - let path_type = path_segment.syntax().children().filter_map(ast::PathType::cast).last(); + let path_type = path_segment.qualifying_trait(); let import = match path_type { Some(it) => { if let Some(path) = it.path() { From a54c0dafc8b670802b8ba8dc8ba1a65766cdd08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Fri, 17 Nov 2023 20:58:43 +0200 Subject: [PATCH 2424/2442] Remove debugging code in path resolution --- crates/hir-def/src/nameres/path_resolution.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 460a908b6db2..4c1b8f306c50 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -183,15 +183,6 @@ impl DefMap { shadow: BuiltinShadowMode, expected_macro_subns: Option, ) -> ResolvePathResult { - let graph = db.crate_graph(); - let _cx = stdx::panic_context::enter(format!( - "DefMap {:?} crate_name={:?} block={:?} path={}", - self.krate, - graph[self.krate].display_name, - self.block, - path.display(db.upcast()) - )); - let mut segments = path.segments().iter().enumerate(); let mut curr_per_ns = match path.kind { PathKind::DollarCrate(krate) => { From 9f8191b62d0a5c830e605e090d2dbc476101f05b Mon Sep 17 00:00:00 2001 From: Dash Lu Date: Tue, 21 Nov 2023 22:41:49 +0800 Subject: [PATCH 2425/2442] Update Arch Linux package URL in manual.adoc --- docs/user/manual.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 18d5ddd4d0af..9fc19a7d0745 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -174,7 +174,7 @@ $ rustup component add rust-analyzer The `rust-analyzer` binary can be installed from the repos or AUR (Arch User Repository): -- https://www.archlinux.org/packages/community/x86_64/rust-analyzer/[`rust-analyzer`] (built from latest tagged source) +- https://www.archlinux.org/packages/extra/x86_64/rust-analyzer/[`rust-analyzer`] (built from latest tagged source) - https://aur.archlinux.org/packages/rust-analyzer-git[`rust-analyzer-git`] (latest Git version) Install it with pacman, for example: From 81c2d3552e6d377bf0332523c1278b7e5723c27c Mon Sep 17 00:00:00 2001 From: Marc Schreiber Date: Tue, 14 Nov 2023 21:37:40 +0100 Subject: [PATCH 2426/2442] Cancelable Initialization This commit provides additional initialization methods to Connection in order to support CTRL + C sigterm handling. --- Cargo.lock | 32 ++++++-- lib/lsp-server/Cargo.toml | 1 + lib/lsp-server/src/lib.rs | 169 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 188 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 701e36d74a65..11283034ea2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -216,7 +216,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5080df6b0f0ecb76cab30808f00d937ba725cebe266a3da8cd89dff92f2a9916" dependencies = [ - "nix", + "nix 0.26.2", "winapi", ] @@ -289,6 +289,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ctrlc" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" +dependencies = [ + "nix 0.27.1", + "windows-sys 0.48.0", +] + [[package]] name = "dashmap" version = "5.4.0" @@ -961,6 +971,7 @@ name = "lsp-server" version = "0.7.4" dependencies = [ "crossbeam-channel", + "ctrlc", "log", "lsp-types", "serde", @@ -1100,6 +1111,17 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "libc", +] + [[package]] name = "nohash-hasher" version = "0.2.0" @@ -1701,18 +1723,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", diff --git a/lib/lsp-server/Cargo.toml b/lib/lsp-server/Cargo.toml index 8d00813b0d7a..be1573913ff2 100644 --- a/lib/lsp-server/Cargo.toml +++ b/lib/lsp-server/Cargo.toml @@ -14,3 +14,4 @@ crossbeam-channel = "0.5.6" [dev-dependencies] lsp-types = "=0.94" +ctrlc = "3.4.1" diff --git a/lib/lsp-server/src/lib.rs b/lib/lsp-server/src/lib.rs index affab60a2278..b190c0af73d7 100644 --- a/lib/lsp-server/src/lib.rs +++ b/lib/lsp-server/src/lib.rs @@ -17,7 +17,7 @@ use std::{ net::{TcpListener, TcpStream, ToSocketAddrs}, }; -use crossbeam_channel::{Receiver, Sender}; +use crossbeam_channel::{Receiver, RecvTimeoutError, Sender}; pub use crate::{ error::{ExtractError, ProtocolError}, @@ -113,11 +113,62 @@ impl Connection { /// } /// ``` pub fn initialize_start(&self) -> Result<(RequestId, serde_json::Value), ProtocolError> { - loop { - break match self.receiver.recv() { - Ok(Message::Request(req)) if req.is_initialize() => Ok((req.id, req.params)), + self.initialize_start_while(|| true) + } + + /// Starts the initialization process by waiting for an initialize as described in + /// [`Self::initialize_start`] as long as `running` returns + /// `true` while the return value can be changed through a sig handler such as `CTRL + C`. + /// + /// # Example + /// + /// ```rust + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// use std::sync::Arc; + /// # use std::error::Error; + /// # use lsp_types::{ClientCapabilities, InitializeParams, ServerCapabilities}; + /// # use lsp_server::{Connection, Message, Request, RequestId, Response}; + /// # fn main() -> Result<(), Box> { + /// let running = Arc::new(AtomicBool::new(true)); + /// # running.store(true, Ordering::SeqCst); + /// let r = running.clone(); + /// + /// ctrlc::set_handler(move || { + /// r.store(false, Ordering::SeqCst); + /// }).expect("Error setting Ctrl-C handler"); + /// + /// let (connection, io_threads) = Connection::stdio(); + /// + /// let res = connection.initialize_start_while(|| running.load(Ordering::SeqCst)); + /// # assert!(res.is_err()); + /// + /// # Ok(()) + /// # } + /// ``` + pub fn initialize_start_while( + &self, + running: C, + ) -> Result<(RequestId, serde_json::Value), ProtocolError> + where + C: Fn() -> bool, + { + while running() { + let msg = match self.receiver.recv_timeout(std::time::Duration::from_secs(1)) { + Ok(msg) => msg, + Err(RecvTimeoutError::Timeout) => { + continue; + } + Err(e) => { + return Err(ProtocolError(format!( + "expected initialize request, got error: {e}" + ))) + } + }; + + match msg { + Message::Request(req) if req.is_initialize() => return Ok((req.id, req.params)), // Respond to non-initialize requests with ServerNotInitialized - Ok(Message::Request(req)) => { + Message::Request(req) => { let resp = Response::new_err( req.id.clone(), ErrorCode::ServerNotInitialized as i32, @@ -126,15 +177,18 @@ impl Connection { self.sender.send(resp.into()).unwrap(); continue; } - Ok(Message::Notification(n)) if !n.is_exit() => { + Message::Notification(n) if !n.is_exit() => { continue; } - Ok(msg) => Err(ProtocolError(format!("expected initialize request, got {msg:?}"))), - Err(e) => { - Err(ProtocolError(format!("expected initialize request, got error: {e}"))) + msg => { + return Err(ProtocolError(format!("expected initialize request, got {msg:?}"))); } }; } + + return Err(ProtocolError(String::from( + "Initialization has been aborted during initialization", + ))); } /// Finishes the initialization process by sending an `InitializeResult` to the client @@ -156,6 +210,51 @@ impl Connection { } } + /// Finishes the initialization process as described in [`Self::initialize_finish`] as + /// long as `running` returns `true` while the return value can be changed through a sig + /// handler such as `CTRL + C`. + pub fn initialize_finish_while( + &self, + initialize_id: RequestId, + initialize_result: serde_json::Value, + running: C, + ) -> Result<(), ProtocolError> + where + C: Fn() -> bool, + { + let resp = Response::new_ok(initialize_id, initialize_result); + self.sender.send(resp.into()).unwrap(); + + while running() { + let msg = match self.receiver.recv_timeout(std::time::Duration::from_secs(1)) { + Ok(msg) => msg, + Err(RecvTimeoutError::Timeout) => { + continue; + } + Err(e) => { + return Err(ProtocolError(format!( + "expected initialized notification, got error: {e}", + ))); + } + }; + + match msg { + Message::Notification(n) if n.is_initialized() => { + return Ok(()); + } + msg => { + return Err(ProtocolError(format!( + r#"expected initialized notification, got: {msg:?}"# + ))); + } + } + } + + return Err(ProtocolError(String::from( + "Initialization has been aborted during initialization", + ))); + } + /// Initialize the connection. Sends the server capabilities /// to the client and returns the serialized client capabilities /// on success. If more fine-grained initialization is required use @@ -198,6 +297,58 @@ impl Connection { Ok(params) } + /// Initialize the connection as described in [`Self::initialize`] as long as `running` returns + /// `true` while the return value can be changed through a sig handler such as `CTRL + C`. + /// + /// # Example + /// + /// ```rust + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// use std::sync::Arc; + /// # use std::error::Error; + /// # use lsp_types::ServerCapabilities; + /// # use lsp_server::{Connection, Message, Request, RequestId, Response}; + /// + /// # fn main() -> Result<(), Box> { + /// let running = Arc::new(AtomicBool::new(true)); + /// # running.store(true, Ordering::SeqCst); + /// let r = running.clone(); + /// + /// ctrlc::set_handler(move || { + /// r.store(false, Ordering::SeqCst); + /// }).expect("Error setting Ctrl-C handler"); + /// + /// let (connection, io_threads) = Connection::stdio(); + /// + /// let server_capabilities = serde_json::to_value(&ServerCapabilities::default()).unwrap(); + /// let initialization_params = connection.initialize_while( + /// server_capabilities, + /// || running.load(Ordering::SeqCst) + /// ); + /// + /// # assert!(initialization_params.is_err()); + /// # Ok(()) + /// # } + /// ``` + pub fn initialize_while( + &self, + server_capabilities: serde_json::Value, + running: C, + ) -> Result + where + C: Fn() -> bool, + { + let (id, params) = self.initialize_start_while(&running)?; + + let initialize_data = serde_json::json!({ + "capabilities": server_capabilities, + }); + + self.initialize_finish_while(id, initialize_data, running)?; + + Ok(params) + } + /// If `req` is `Shutdown`, respond to it and return `true`, otherwise return `false` pub fn handle_shutdown(&self, req: &Request) -> Result { if !req.is_shutdown() { From 886eaa0a7d2b1d7098fd49ec56e3b6f65a457449 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Sun, 24 Sep 2023 18:27:15 +0200 Subject: [PATCH 2427/2442] Relaxation for crate graph mergin Partially fixes #15656 . When a crate graph is extended which is the case when new workspaces are added to the project the rules for deduplication were too strict. One problem that arises from this is that in certain conditions when we see the same crate having different `CrateOrigin`s the first form would be maintained. This approach however results in some unwanted results such as making renaming forbidden as this has been recently only made available for local crates. The given example in #15656 can still not be resolved with this PR as that involves taking inconsistencies between dependencies into consideration. This will be addressed in a future PR. --- crates/base-db/src/fixture.rs | 28 ++- crates/base-db/src/input.rs | 221 +++++++++++++++--- crates/base-db/src/lib.rs | 1 + crates/cfg/src/lib.rs | 4 +- crates/project-model/src/project_json.rs | 3 +- crates/project-model/src/workspace.rs | 67 ++++-- .../cargo_hello_world_project_model.txt | 7 + ...project_model_with_selective_overrides.txt | 7 + ..._project_model_with_wildcard_overrides.txt | 7 + ...rust_project_hello_world_project_model.txt | 16 ++ crates/rust-analyzer/tests/slow-tests/main.rs | 208 ++++++++++++++++- 11 files changed, 515 insertions(+), 54 deletions(-) diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs index 3f5ccb621c76..3da555a47acb 100644 --- a/crates/base-db/src/fixture.rs +++ b/crates/base-db/src/fixture.rs @@ -13,9 +13,9 @@ use vfs::{file_set::FileSet, VfsPath}; use crate::{ input::{CrateName, CrateOrigin, LangCrateOrigin}, - Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition, - FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacros, ReleaseChannel, - SourceDatabaseExt, SourceRoot, SourceRootId, + Change, CrateDisplayName, CrateGraph, CrateId, Dependency, DependencyKind, Edition, Env, + FileId, FilePosition, FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, + ProcMacros, ReleaseChannel, SourceDatabaseExt, SourceRoot, SourceRootId, }; pub const WORKSPACE: SourceRootId = SourceRootId(0); @@ -237,7 +237,12 @@ impl ChangeFixture { crate_graph .add_dep( from_id, - Dependency::with_prelude(CrateName::new(&to).unwrap(), to_id, prelude), + Dependency::with_prelude( + CrateName::new(&to).unwrap(), + to_id, + prelude, + DependencyKind::Normal, + ), ) .unwrap(); } @@ -275,7 +280,14 @@ impl ChangeFixture { for krate in all_crates { crate_graph - .add_dep(krate, Dependency::new(CrateName::new("core").unwrap(), core_crate)) + .add_dep( + krate, + Dependency::new( + CrateName::new("core").unwrap(), + core_crate, + DependencyKind::Normal, + ), + ) .unwrap(); } } @@ -317,7 +329,11 @@ impl ChangeFixture { crate_graph .add_dep( krate, - Dependency::new(CrateName::new("proc_macros").unwrap(), proc_macros_crate), + Dependency::new( + CrateName::new("proc_macros").unwrap(), + proc_macros_crate, + DependencyKind::Normal, + ), ) .unwrap(); } diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 65db5c0fc7d3..fb69e667ad95 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -8,7 +8,7 @@ use std::{fmt, mem, ops, panic::RefUnwindSafe, str::FromStr, sync}; -use cfg::CfgOptions; +use cfg::{CfgDiff, CfgOptions}; use la_arena::{Arena, Idx}; use rustc_hash::{FxHashMap, FxHashSet}; use syntax::SmolStr; @@ -155,6 +155,10 @@ impl CrateOrigin { pub fn is_local(&self) -> bool { matches!(self, CrateOrigin::Local { .. }) } + + pub fn is_lib(&self) -> bool { + matches!(self, CrateOrigin::Library { .. }) + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -324,6 +328,99 @@ pub struct CrateData { pub channel: Option, } +impl CrateData { + /** + Check if [`other`] is almost equal to [`self`]. + This method has some obscure bits. These are mostly there to be compliant with + some patches. References to the patches are given. + */ + pub fn almost_eq(&self, other: &CrateData) -> bool { + if self.root_file_id != other.root_file_id { + return false; + } + + if self.display_name != other.display_name { + return false; + } + + if self.is_proc_macro != other.is_proc_macro { + return false; + } + + if self.edition != other.edition { + return false; + } + + if self.version != other.version { + return false; + } + + let mut opts = self.cfg_options.clone(); + opts.apply_diff(CfgDiff { + disable: other.cfg_options.clone().into_iter().collect(), + enable: vec![], + }); + + let mut cfgs = opts.into_iter(); + if let Some(cfg) = cfgs.next() { + // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs. + // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894 + if !cfgs.next().is_none() || cfg.to_string() != "rust_analyzer" { + return false; + } + } + + let mut itself = self.dependencies.iter(); + let mut otself = other.dependencies.iter(); + let (mut anx, mut bnx) = (itself.next(), otself.next()); + loop { + match (anx, bnx) { + (None, None) => { + break; + } + (None, Some(b)) => { + if b.kind != DependencyKind::Normal { + bnx = otself.next(); + } else { + break; + } + } + (Some(a), None) => { + if a.kind != DependencyKind::Normal { + anx = itself.next(); + } else { + break; + } + } + (Some(a), Some(b)) => { + if a.kind != DependencyKind::Normal { + anx = itself.next(); + continue; + } + + if b.kind != DependencyKind::Normal { + bnx = otself.next(); + continue; + } + + if a != b { + return false; + } + + anx = itself.next(); + bnx = otself.next(); + } + } + } + + if self.env != other.env { + return false; + } + + true + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Edition { Edition2015, @@ -351,26 +448,43 @@ impl Env { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum DependencyKind { + Normal, + Dev, + Build, +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Dependency { pub crate_id: CrateId, pub name: CrateName, + kind: DependencyKind, prelude: bool, } impl Dependency { - pub fn new(name: CrateName, crate_id: CrateId) -> Self { - Self { name, crate_id, prelude: true } + pub fn new(name: CrateName, crate_id: CrateId, kind: DependencyKind) -> Self { + Self { name, crate_id, prelude: true, kind } } - pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool) -> Self { - Self { name, crate_id, prelude } + pub fn with_prelude( + name: CrateName, + crate_id: CrateId, + prelude: bool, + kind: DependencyKind, + ) -> Self { + Self { name, crate_id, prelude, kind } } /// Whether this dependency is to be added to the depending crate's extern prelude. pub fn is_prelude(&self) -> bool { self.prelude } + + pub fn kind(&self) -> &DependencyKind { + &self.kind + } } impl CrateGraph { @@ -572,25 +686,41 @@ impl CrateGraph { /// Note that for deduplication to fully work, `self`'s crate dependencies must be sorted by crate id. /// If the crate dependencies were sorted, the resulting graph from this `extend` call will also have the crate dependencies sorted. pub fn extend(&mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths) { + enum ExtendStrategy { + Dedup(CrateId), + Replace(CrateId), + } + let topo = other.crates_in_topological_order(); let mut id_map: FxHashMap = FxHashMap::default(); - for topo in topo { let crate_data = &mut other.arena[topo]; - crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]); - crate_data.dependencies.sort_by_key(|dep| dep.crate_id); - let res = self.arena.iter().find_map( - |(id, data)| { - if data == crate_data { - Some(id) - } else { - None + crate_data.dependencies.iter_mut().for_each(|dep| { + dep.crate_id = id_map[&dep.crate_id]; + }); + crate_data.dependencies.sort_by_key(|dep| dep.crate_id); + let res = self.arena.iter().find_map(|(id, data)| { + if data.almost_eq(crate_data) { + if data.origin.is_lib() && crate_data.origin.is_local() { + // See #15656 for a relevant example. + return Some(ExtendStrategy::Replace(id)); } - }, - ); + + return Some(ExtendStrategy::Dedup(id)); + } + None + }); + if let Some(res) = res { - id_map.insert(topo, res); + match res { + ExtendStrategy::Dedup(res) => id_map.insert(topo, res), + ExtendStrategy::Replace(res) => { + let id = self.arena.alloc(crate_data.clone()); + let _ = self.remove_and_replace(res, id); + id_map.insert(topo, id) + } + }; } else { let id = self.arena.alloc(crate_data.clone()); id_map.insert(topo, id); @@ -636,9 +766,11 @@ impl CrateGraph { match (cfg_if, std) { (Some(cfg_if), Some(std)) => { self.arena[cfg_if].dependencies.clear(); - self.arena[std] - .dependencies - .push(Dependency::new(CrateName::new("cfg_if").unwrap(), cfg_if)); + self.arena[std].dependencies.push(Dependency::new( + CrateName::new("cfg_if").unwrap(), + cfg_if, + DependencyKind::Normal, + )); true } _ => false, @@ -759,7 +891,7 @@ impl fmt::Display for CyclicDependenciesError { #[cfg(test)] mod tests { - use crate::CrateOrigin; + use crate::{CrateOrigin, DependencyKind}; use super::{CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; @@ -806,13 +938,22 @@ mod tests { None, ); assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) + .add_dep( + crate1, + Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal) + ) .is_ok()); assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3)) + .add_dep( + crate2, + Dependency::new(CrateName::new("crate3").unwrap(), crate3, DependencyKind::Normal) + ) .is_ok()); assert!(graph - .add_dep(crate3, Dependency::new(CrateName::new("crate1").unwrap(), crate1)) + .add_dep( + crate3, + Dependency::new(CrateName::new("crate1").unwrap(), crate1, DependencyKind::Normal) + ) .is_err()); } @@ -846,10 +987,16 @@ mod tests { None, ); assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) + .add_dep( + crate1, + Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal) + ) .is_ok()); assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) + .add_dep( + crate2, + Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal) + ) .is_err()); } @@ -896,10 +1043,16 @@ mod tests { None, ); assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) + .add_dep( + crate1, + Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal) + ) .is_ok()); assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3)) + .add_dep( + crate2, + Dependency::new(CrateName::new("crate3").unwrap(), crate3, DependencyKind::Normal) + ) .is_ok()); } @@ -935,12 +1088,20 @@ mod tests { assert!(graph .add_dep( crate1, - Dependency::new(CrateName::normalize_dashes("crate-name-with-dashes"), crate2) + Dependency::new( + CrateName::normalize_dashes("crate-name-with-dashes"), + crate2, + DependencyKind::Normal + ) ) .is_ok()); assert_eq!( graph[crate1].dependencies, - vec![Dependency::new(CrateName::new("crate_name_with_dashes").unwrap(), crate2)] + vec![Dependency::new( + CrateName::new("crate_name_with_dashes").unwrap(), + crate2, + DependencyKind::Normal + )] ); } } diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index c5c4afa30f79..40cfab88afdb 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -12,6 +12,7 @@ use rustc_hash::FxHashSet; use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; use triomphe::Arc; +pub use crate::input::DependencyKind; pub use crate::{ change::Change, input::{ diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index 0aeb0b050524..90dba008ad70 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs @@ -115,8 +115,8 @@ impl<'a> IntoIterator for &'a CfgOptions { #[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct CfgDiff { // Invariants: No duplicates, no atom that's both in `enable` and `disable`. - enable: Vec, - disable: Vec, + pub enable: Vec, + pub disable: Vec, } impl CfgDiff { diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs index 80897f7478cf..931eba115766 100644 --- a/crates/project-model/src/project_json.rs +++ b/crates/project-model/src/project_json.rs @@ -49,7 +49,7 @@ //! user explores them belongs to that extension (it's totally valid to change //! rust-project.json over time via configuration request!) -use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition}; +use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, DependencyKind, Edition}; use la_arena::RawIdx; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; @@ -135,6 +135,7 @@ impl ProjectJson { Dependency::new( dep_data.name, CrateId::from_raw(RawIdx::from(dep_data.krate as u32)), + DependencyKind::Normal, ) }) .collect::>(), diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index e0209ca15a53..9333570354a0 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -6,8 +6,8 @@ use std::{collections::VecDeque, fmt, fs, iter, process::Command, str::FromStr, use anyhow::{format_err, Context}; use base_db::{ - CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, - FileId, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, TargetLayoutLoadResult, + CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, DependencyKind, + Edition, Env, FileId, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, TargetLayoutLoadResult, }; use cfg::{CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; @@ -834,7 +834,7 @@ fn project_json_to_crate_graph( for dep in &krate.deps { if let Some(&to) = crates.get(&dep.crate_id) { - add_dep(crate_graph, from, dep.name.clone(), to) + add_dep(crate_graph, from, dep.name.clone(), to, dep.kind().to_owned()) } } } @@ -979,7 +979,7 @@ fn cargo_to_crate_graph( // cargo metadata does not do any normalization, // so we do it ourselves currently let name = CrateName::normalize_dashes(&name); - add_dep(crate_graph, from, name, to); + add_dep(crate_graph, from, name, to, DependencyKind::Normal); } } } @@ -999,7 +999,17 @@ fn cargo_to_crate_graph( continue; } - add_dep(crate_graph, from, name.clone(), to) + add_dep( + crate_graph, + from, + name.clone(), + to, + match dep.kind { + DepKind::Normal => DependencyKind::Normal, + DepKind::Dev => DependencyKind::Dev, + DepKind::Build => DependencyKind::Build, + }, + ) } } } @@ -1187,7 +1197,17 @@ fn handle_rustc_crates( let name = CrateName::new(&dep.name).unwrap(); if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { - add_dep(crate_graph, from, name.clone(), to); + add_dep( + crate_graph, + from, + name.clone(), + to, + match dep.kind { + DepKind::Normal => DependencyKind::Normal, + DepKind::Dev => DependencyKind::Dev, + DepKind::Build => DependencyKind::Build, + }, + ); } } } @@ -1209,7 +1229,7 @@ fn handle_rustc_crates( // `rust_analyzer` thinks that it should use the one from the `rustc_source` // instead of the one from `crates.io` if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) { - add_dep(crate_graph, *from, name.clone(), to); + add_dep(crate_graph, *from, name.clone(), to, DependencyKind::Normal); } } } @@ -1308,7 +1328,14 @@ impl SysrootPublicDeps { /// Makes `from` depend on the public sysroot crates. fn add_to_crate_graph(&self, crate_graph: &mut CrateGraph, from: CrateId) { for (name, krate, prelude) in &self.deps { - add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude); + add_dep_with_prelude( + crate_graph, + from, + name.clone(), + *krate, + *prelude, + DependencyKind::Normal, + ); } } } @@ -1363,7 +1390,7 @@ fn sysroot_to_crate_graph( for &to in sysroot[from].deps.iter() { let name = CrateName::new(&sysroot[to].name).unwrap(); if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) { - add_dep(crate_graph, from, name, to); + add_dep(crate_graph, from, name, to, DependencyKind::Normal); } } } @@ -1442,8 +1469,14 @@ fn handle_hack_cargo_workspace( .collect() } -fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { - add_dep_inner(graph, from, Dependency::new(name, to)) +fn add_dep( + graph: &mut CrateGraph, + from: CrateId, + name: CrateName, + to: CrateId, + kind: DependencyKind, +) { + add_dep_inner(graph, from, Dependency::new(name, to, kind)) } fn add_dep_with_prelude( @@ -1452,12 +1485,20 @@ fn add_dep_with_prelude( name: CrateName, to: CrateId, prelude: bool, + kind: DependencyKind, ) { - add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude)) + add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude, kind)) } fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, prelude: bool) { - add_dep_with_prelude(crate_graph, from, CrateName::new("proc_macro").unwrap(), to, prelude); + add_dep_with_prelude( + crate_graph, + from, + CrateName::new("proc_macro").unwrap(), + to, + prelude, + DependencyKind::Normal, + ); } fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) { diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model.txt index 727d39a3077c..e98f016ca7df 100644 --- a/crates/project-model/test_data/output/cargo_hello_world_project_model.txt +++ b/crates/project-model/test_data/output/cargo_hello_world_project_model.txt @@ -48,6 +48,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -112,6 +113,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -119,6 +121,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -183,6 +186,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -190,6 +194,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -254,6 +259,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -261,6 +267,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt index 727d39a3077c..e98f016ca7df 100644 --- a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt +++ b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt @@ -48,6 +48,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -112,6 +113,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -119,6 +121,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -183,6 +186,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -190,6 +194,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -254,6 +259,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -261,6 +267,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt index 89728babd82e..7ecd53572e2f 100644 --- a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt +++ b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt @@ -47,6 +47,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -110,6 +111,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -117,6 +119,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -180,6 +183,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -187,6 +191,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -250,6 +255,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -257,6 +263,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], diff --git a/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt index b7bf6cb2774e..581a6afc148f 100644 --- a/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt +++ b/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt @@ -28,6 +28,7 @@ name: CrateName( "core", ), + kind: Normal, prelude: true, }, ], @@ -168,6 +169,7 @@ name: CrateName( "std", ), + kind: Normal, prelude: true, }, Dependency { @@ -175,6 +177,7 @@ name: CrateName( "core", ), + kind: Normal, prelude: true, }, ], @@ -249,6 +252,7 @@ name: CrateName( "alloc", ), + kind: Normal, prelude: true, }, Dependency { @@ -256,6 +260,7 @@ name: CrateName( "panic_unwind", ), + kind: Normal, prelude: true, }, Dependency { @@ -263,6 +268,7 @@ name: CrateName( "panic_abort", ), + kind: Normal, prelude: true, }, Dependency { @@ -270,6 +276,7 @@ name: CrateName( "core", ), + kind: Normal, prelude: true, }, Dependency { @@ -277,6 +284,7 @@ name: CrateName( "profiler_builtins", ), + kind: Normal, prelude: true, }, Dependency { @@ -284,6 +292,7 @@ name: CrateName( "unwind", ), + kind: Normal, prelude: true, }, Dependency { @@ -291,6 +300,7 @@ name: CrateName( "std_detect", ), + kind: Normal, prelude: true, }, Dependency { @@ -298,6 +308,7 @@ name: CrateName( "test", ), + kind: Normal, prelude: true, }, ], @@ -438,6 +449,7 @@ name: CrateName( "core", ), + kind: Normal, prelude: true, }, Dependency { @@ -445,6 +457,7 @@ name: CrateName( "alloc", ), + kind: Normal, prelude: true, }, Dependency { @@ -452,6 +465,7 @@ name: CrateName( "std", ), + kind: Normal, prelude: true, }, Dependency { @@ -459,6 +473,7 @@ name: CrateName( "test", ), + kind: Normal, prelude: false, }, Dependency { @@ -466,6 +481,7 @@ name: CrateName( "proc_macro", ), + kind: Normal, prelude: false, }, ], diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs index d59914298991..423c07183e25 100644 --- a/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/crates/rust-analyzer/tests/slow-tests/main.rs @@ -21,12 +21,12 @@ use std::{collections::HashMap, path::PathBuf, time::Instant}; use lsp_types::{ notification::DidOpenTextDocument, request::{ - CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest, + CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest, Rename, WillRenameFiles, WorkspaceSymbolRequest, }, CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams, DocumentFormattingParams, FileRename, FormattingOptions, GotoDefinitionParams, HoverParams, - PartialResultParams, Position, Range, RenameFilesParams, TextDocumentItem, + PartialResultParams, Position, Range, RenameFilesParams, RenameParams, TextDocumentItem, TextDocumentPositionParams, WorkDoneProgressParams, }; use rust_analyzer::lsp::ext::{OnEnter, Runnables, RunnablesParams}; @@ -1131,3 +1131,207 @@ version = "0.0.0" server.request::(Default::default(), json!([])); } + +#[test] +fn test_deduplicate_crate_differing_in_origin() { + let fixture = r#" +//- /projects/p1/Cargo.toml +[package] +name = "p1" +version = "0.0.0" + +//- /projects/p1/src/lib.rs +pub fn add2(left: usize, right: usize) -> usize { + left + right +} + +//- /projects/p2/Cargo.toml +[package] +name = "p2" +version = "0.0.0" + +[dependencies] +p1 = { path = "../p1" } + +//- /projects/p2/src/lib.rs +use p1::add2; + +pub fn bar() {} + "#; + + let server = Project::with_fixture(fixture) + .with_config(serde_json::json!({ + "linkedProjects" : [ + "./projects/p1/Cargo.toml", + "./projects/p2/Cargo.toml" + ], + } + )) + .with_config(serde_json::json!({ + "cargo": { "sysroot": null }, + })) + .server() + .wait_until_workspace_is_loaded(); + + let doc_id = server.doc_id("./projects/p2/src/lib.rs"); + let doc2_id = server.doc_id("./projects/p1/src/lib.rs"); + + server.request::( + RenameParams { + text_document_position: TextDocumentPositionParams { + text_document: doc_id.clone(), + position: Position { line: 0, character: 8 }, + }, + new_name: "ABC".to_owned(), + work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, + }, + json!({ + "documentChanges": [ + { + "textDocument": { + "uri": doc2_id.uri, + "version": null + }, + "edits": [ + { + "range": { + "start": { + "line": 0, + "character": 7 + }, + "end": { + "line": 0, + "character": 11 + } + }, + "newText": "ABC" + } + ] + }, + { + "textDocument": { + "uri": doc_id.uri, + "version": null + }, + "edits": [ + { + "range": { + "start": { + "line": 0, + "character": 8 + }, + "end": { + "line": 0, + "character": 12 + } + }, + "newText": "ABC" + } + ] + }, + ] + }), + ); +} + +#[test] +fn test_deduplicate_crate_differing_in_origin_in_rev_resolution_order() { + let fixture = r#" +//- /projects/p1/Cargo.toml +[package] +name = "p1" +version = "0.0.0" + +//- /projects/p1/src/lib.rs +pub fn add2(left: usize, right: usize) -> usize { + left + right +} + +//- /projects/p2/Cargo.toml +[package] +name = "p2" +version = "0.0.0" + +[dependencies] +p1 = { path = "../p1" } + +//- /projects/p2/src/lib.rs +use p1::add2; + +pub fn bar() {} + "#; + + let server = Project::with_fixture(fixture) + .with_config(serde_json::json!({ + "linkedProjects" : [ + "./projects/p2/Cargo.toml", + "./projects/p1/Cargo.toml", + ], + } + )) + .with_config(serde_json::json!({ + "cargo": { "sysroot": null }, + })) + .server() + .wait_until_workspace_is_loaded(); + + let doc_id = server.doc_id("./projects/p2/src/lib.rs"); + let doc2_id = server.doc_id("./projects/p1/src/lib.rs"); + + server.request::( + RenameParams { + text_document_position: TextDocumentPositionParams { + text_document: doc_id.clone(), + position: Position { line: 0, character: 8 }, + }, + new_name: "ABC".to_owned(), + work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, + }, + json!({ + "documentChanges": [ + { + "textDocument": { + "uri": doc2_id.uri, + "version": null + }, + "edits": [ + { + "range": { + "start": { + "line": 0, + "character": 7 + }, + "end": { + "line": 0, + "character": 11 + } + }, + "newText": "ABC" + } + ] + }, + { + "textDocument": { + "uri": doc_id.uri, + "version": null + }, + "edits": [ + { + "range": { + "start": { + "line": 0, + "character": 8 + }, + "end": { + "line": 0, + "character": 12 + } + }, + "newText": "ABC" + } + ] + }, + ] + }), + ); +} From 7e4aad5ba570745ef8924f1fa6ad90aedf6aa51e Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Sun, 15 Oct 2023 17:32:12 +0200 Subject: [PATCH 2428/2442] v2 --- crates/base-db/src/input.rs | 52 ++--- crates/cfg/src/lib.rs | 4 +- crates/project-model/src/tests.rs | 50 +++++ .../deduplication_crate_graph_A.json | 66 ++++++ .../deduplication_crate_graph_B.json | 140 ++++++++++++ crates/rust-analyzer/tests/slow-tests/main.rs | 208 +----------------- 6 files changed, 282 insertions(+), 238 deletions(-) create mode 100644 crates/project-model/test_data/deduplication_crate_graph_A.json create mode 100644 crates/project-model/test_data/deduplication_crate_graph_B.json diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index fb69e667ad95..61a17da9aa6e 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -329,12 +329,10 @@ pub struct CrateData { } impl CrateData { - /** - Check if [`other`] is almost equal to [`self`]. - This method has some obscure bits. These are mostly there to be compliant with - some patches. References to the patches are given. - */ - pub fn almost_eq(&self, other: &CrateData) -> bool { + /// Check if [`other`] is almost equal to [`self`] ignoring `CrateOrigin` value. + pub fn eq_ignoring_origin(&self, other: &CrateData) -> bool { + // This method has some obscure bits. These are mostly there to be compliant with + // some patches. References to the patches are given. if self.root_file_id != other.root_file_id { return false; } @@ -356,16 +354,16 @@ impl CrateData { } let mut opts = self.cfg_options.clone(); - opts.apply_diff(CfgDiff { - disable: other.cfg_options.clone().into_iter().collect(), - enable: vec![], - }); + opts.apply_diff( + CfgDiff::new(vec![], other.cfg_options.clone().into_iter().collect()) + .expect("CfgOptions were expected to contain no duplicates."), + ); let mut cfgs = opts.into_iter(); if let Some(cfg) = cfgs.next() { // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs. // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894 - if !cfgs.next().is_none() || cfg.to_string() != "rust_analyzer" { + if cfgs.next().is_some() || cfg.to_string() != "rust_analyzer" { return false; } } @@ -686,41 +684,35 @@ impl CrateGraph { /// Note that for deduplication to fully work, `self`'s crate dependencies must be sorted by crate id. /// If the crate dependencies were sorted, the resulting graph from this `extend` call will also have the crate dependencies sorted. pub fn extend(&mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths) { - enum ExtendStrategy { - Dedup(CrateId), - Replace(CrateId), - } - let topo = other.crates_in_topological_order(); let mut id_map: FxHashMap = FxHashMap::default(); for topo in topo { let crate_data = &mut other.arena[topo]; - crate_data.dependencies.iter_mut().for_each(|dep| { - dep.crate_id = id_map[&dep.crate_id]; - }); + crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]); crate_data.dependencies.sort_by_key(|dep| dep.crate_id); let res = self.arena.iter().find_map(|(id, data)| { - if data.almost_eq(crate_data) { + if data.eq_ignoring_origin(crate_data) { if data.origin.is_lib() && crate_data.origin.is_local() { // See #15656 for a relevant example. - return Some(ExtendStrategy::Replace(id)); + return Some((id, true)); } - return Some(ExtendStrategy::Dedup(id)); + return Some((id, false)); } None }); - if let Some(res) = res { - match res { - ExtendStrategy::Dedup(res) => id_map.insert(topo, res), - ExtendStrategy::Replace(res) => { - let id = self.arena.alloc(crate_data.clone()); - let _ = self.remove_and_replace(res, id); - id_map.insert(topo, id) + if let Some((res, should_update_lib_to_local)) = res { + id_map.insert(topo, res); + if should_update_lib_to_local { + let origin_old = self.arena[res].origin.clone(); + assert!(origin_old.is_lib()); + + if let CrateOrigin::Library { repo, name } = origin_old { + self.arena[res].origin = CrateOrigin::Local { repo, name: Some(name) }; } - }; + } } else { let id = self.arena.alloc(crate_data.clone()); id_map.insert(topo, id); diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index 90dba008ad70..0aeb0b050524 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs @@ -115,8 +115,8 @@ impl<'a> IntoIterator for &'a CfgOptions { #[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct CfgDiff { // Invariants: No duplicates, no atom that's both in `enable` and `disable`. - pub enable: Vec, - pub disable: Vec, + enable: Vec, + disable: Vec, } impl CfgDiff { diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index 7815b9dda77f..65c6f0b25624 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -249,3 +249,53 @@ fn crate_graph_dedup() { crate_graph.extend(regex_crate_graph, &mut regex_proc_macros); assert_eq!(crate_graph.iter().count(), 118); } + +#[test] +fn test_deduplicate_crate_differing_in_origin() { + let path_map = &mut Default::default(); + let (mut crate_graph, _proc_macros) = + load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json"); + crate_graph.sort_deps(); + let (crate_graph_1, mut _proc_macros_2) = + load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json"); + + crate_graph.extend(crate_graph_1, &mut _proc_macros_2); + + let mut crates_named_p1 = vec![]; + for id in crate_graph.iter() { + let krate = &crate_graph[id]; + if let Some(name) = krate.display_name.as_ref() { + if name.to_string() == "p1" { + crates_named_p1.push(krate); + } + } + } + + assert!(crates_named_p1.len() == 1); + assert!(crates_named_p1[0].origin.is_local()); +} + +#[test] +fn test_deduplicate_crate_differing_in_origin_in_rev_resolution_order() { + let path_map = &mut Default::default(); + let (mut crate_graph, _proc_macros) = + load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json"); + crate_graph.sort_deps(); + let (crate_graph_1, mut _proc_macros_2) = + load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json"); + + crate_graph.extend(crate_graph_1, &mut _proc_macros_2); + + let mut crates_named_p1 = vec![]; + for id in crate_graph.iter() { + let krate = &crate_graph[id]; + if let Some(name) = krate.display_name.as_ref() { + if name.to_string() == "p1" { + crates_named_p1.push(krate); + } + } + } + + assert!(crates_named_p1.len() == 1); + assert!(crates_named_p1[0].origin.is_local()); +} diff --git a/crates/project-model/test_data/deduplication_crate_graph_A.json b/crates/project-model/test_data/deduplication_crate_graph_A.json new file mode 100644 index 000000000000..3f627082f9f9 --- /dev/null +++ b/crates/project-model/test_data/deduplication_crate_graph_A.json @@ -0,0 +1,66 @@ +{ + "packages": [ + { + "name": "p1", + "version": "0.1.0", + "id": "p1 0.1.0 (path+file:///path/to/project/projects/p1)", + "license": null, + "license_file": null, + "description": null, + "source": null, + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "p1", + "src_path": "/path/to/project/projects/p1/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "/path/to/project/projects/p1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "homepage": null, + "documentation": null, + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": null + } + ], + "workspace_members": [ + "p1 0.1.0 (path+file:///path/to/project/projects/p1)" + ], + "workspace_default_members": [ + "p1 0.1.0 (path+file:///path/to/project/projects/p1)" + ], + "resolve": { + "nodes": [ + { + "id": "p1 0.1.0 (path+file:///path/to/project/projects/p1)", + "dependencies": [], + "deps": [], + "features": [] + } + ], + "root": "p1 0.1.0 (path+file:///path/to/project/projects/p1)" + }, + "target_directory": "/path/to/project/projects/p1/target", + "version": 1, + "workspace_root": "/path/to/project/projects/p1", + "metadata": null +} \ No newline at end of file diff --git a/crates/project-model/test_data/deduplication_crate_graph_B.json b/crates/project-model/test_data/deduplication_crate_graph_B.json new file mode 100644 index 000000000000..a2bf1af04407 --- /dev/null +++ b/crates/project-model/test_data/deduplication_crate_graph_B.json @@ -0,0 +1,140 @@ +{ + "packages": [ + { + "name": "p1", + "version": "0.1.0", + "id": "p1 0.1.0 (path+file:///path/to/project/projects/p1)", + "license": null, + "license_file": null, + "description": null, + "source": null, + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "p1", + "src_path": "/path/to/project/projects/p1/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "/path/to/project/projects/p1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "homepage": null, + "documentation": null, + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "p2", + "version": "0.1.0", + "id": "p2 0.1.0 (path+file:///path/to/project/projects/p2)", + "license": null, + "license_file": null, + "description": null, + "source": null, + "dependencies": [ + { + "name": "p1", + "source": null, + "req": "*", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "/path/to/project/projects/p1" + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "p2", + "src_path": "/path/to/project/projects/p2/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "/path/to/project/projects/p2/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "homepage": null, + "documentation": null, + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": null + } + ], + "workspace_members": [ + "p2 0.1.0 (path+file:///path/to/project/projects/p2)" + ], + "workspace_default_members": [ + "p2 0.1.0 (path+file:///path/to/project/projects/p2)" + ], + "resolve": { + "nodes": [ + { + "id": "p1 0.1.0 (path+file:///path/to/project/projects/p1)", + "dependencies": [], + "deps": [], + "features": [] + }, + { + "id": "p2 0.1.0 (path+file:///path/to/project/projects/p2)", + "dependencies": [ + "p1 0.1.0 (path+file:///path/to/project/projects/p1)" + ], + "deps": [ + { + "name": "p1", + "pkg": "p1 0.1.0 (path+file:///path/to/project/projects/p1)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + } + ], + "root": "p2 0.1.0 (path+file:///path/to/project/projects/p2)" + }, + "target_directory": "/path/to/project/projects/p2/target", + "version": 1, + "workspace_root": "/path/to/project/projects/p2", + "metadata": null +} \ No newline at end of file diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs index 423c07183e25..d59914298991 100644 --- a/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/crates/rust-analyzer/tests/slow-tests/main.rs @@ -21,12 +21,12 @@ use std::{collections::HashMap, path::PathBuf, time::Instant}; use lsp_types::{ notification::DidOpenTextDocument, request::{ - CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest, Rename, + CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest, WillRenameFiles, WorkspaceSymbolRequest, }, CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams, DocumentFormattingParams, FileRename, FormattingOptions, GotoDefinitionParams, HoverParams, - PartialResultParams, Position, Range, RenameFilesParams, RenameParams, TextDocumentItem, + PartialResultParams, Position, Range, RenameFilesParams, TextDocumentItem, TextDocumentPositionParams, WorkDoneProgressParams, }; use rust_analyzer::lsp::ext::{OnEnter, Runnables, RunnablesParams}; @@ -1131,207 +1131,3 @@ version = "0.0.0" server.request::(Default::default(), json!([])); } - -#[test] -fn test_deduplicate_crate_differing_in_origin() { - let fixture = r#" -//- /projects/p1/Cargo.toml -[package] -name = "p1" -version = "0.0.0" - -//- /projects/p1/src/lib.rs -pub fn add2(left: usize, right: usize) -> usize { - left + right -} - -//- /projects/p2/Cargo.toml -[package] -name = "p2" -version = "0.0.0" - -[dependencies] -p1 = { path = "../p1" } - -//- /projects/p2/src/lib.rs -use p1::add2; - -pub fn bar() {} - "#; - - let server = Project::with_fixture(fixture) - .with_config(serde_json::json!({ - "linkedProjects" : [ - "./projects/p1/Cargo.toml", - "./projects/p2/Cargo.toml" - ], - } - )) - .with_config(serde_json::json!({ - "cargo": { "sysroot": null }, - })) - .server() - .wait_until_workspace_is_loaded(); - - let doc_id = server.doc_id("./projects/p2/src/lib.rs"); - let doc2_id = server.doc_id("./projects/p1/src/lib.rs"); - - server.request::( - RenameParams { - text_document_position: TextDocumentPositionParams { - text_document: doc_id.clone(), - position: Position { line: 0, character: 8 }, - }, - new_name: "ABC".to_owned(), - work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, - }, - json!({ - "documentChanges": [ - { - "textDocument": { - "uri": doc2_id.uri, - "version": null - }, - "edits": [ - { - "range": { - "start": { - "line": 0, - "character": 7 - }, - "end": { - "line": 0, - "character": 11 - } - }, - "newText": "ABC" - } - ] - }, - { - "textDocument": { - "uri": doc_id.uri, - "version": null - }, - "edits": [ - { - "range": { - "start": { - "line": 0, - "character": 8 - }, - "end": { - "line": 0, - "character": 12 - } - }, - "newText": "ABC" - } - ] - }, - ] - }), - ); -} - -#[test] -fn test_deduplicate_crate_differing_in_origin_in_rev_resolution_order() { - let fixture = r#" -//- /projects/p1/Cargo.toml -[package] -name = "p1" -version = "0.0.0" - -//- /projects/p1/src/lib.rs -pub fn add2(left: usize, right: usize) -> usize { - left + right -} - -//- /projects/p2/Cargo.toml -[package] -name = "p2" -version = "0.0.0" - -[dependencies] -p1 = { path = "../p1" } - -//- /projects/p2/src/lib.rs -use p1::add2; - -pub fn bar() {} - "#; - - let server = Project::with_fixture(fixture) - .with_config(serde_json::json!({ - "linkedProjects" : [ - "./projects/p2/Cargo.toml", - "./projects/p1/Cargo.toml", - ], - } - )) - .with_config(serde_json::json!({ - "cargo": { "sysroot": null }, - })) - .server() - .wait_until_workspace_is_loaded(); - - let doc_id = server.doc_id("./projects/p2/src/lib.rs"); - let doc2_id = server.doc_id("./projects/p1/src/lib.rs"); - - server.request::( - RenameParams { - text_document_position: TextDocumentPositionParams { - text_document: doc_id.clone(), - position: Position { line: 0, character: 8 }, - }, - new_name: "ABC".to_owned(), - work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, - }, - json!({ - "documentChanges": [ - { - "textDocument": { - "uri": doc2_id.uri, - "version": null - }, - "edits": [ - { - "range": { - "start": { - "line": 0, - "character": 7 - }, - "end": { - "line": 0, - "character": 11 - } - }, - "newText": "ABC" - } - ] - }, - { - "textDocument": { - "uri": doc_id.uri, - "version": null - }, - "edits": [ - { - "range": { - "start": { - "line": 0, - "character": 8 - }, - "end": { - "line": 0, - "character": 12 - } - }, - "newText": "ABC" - } - ] - }, - ] - }), - ); -} From 25e990d753982682c71ae09888383f2c862411c3 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Wed, 8 Nov 2023 16:51:20 +0100 Subject: [PATCH 2429/2442] v3 --- crates/base-db/src/input.rs | 110 +++++++++++++++--------------------- crates/cfg/src/lib.rs | 6 +- 2 files changed, 50 insertions(+), 66 deletions(-) diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 61a17da9aa6e..7dec01ff4dee 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -8,7 +8,7 @@ use std::{fmt, mem, ops, panic::RefUnwindSafe, str::FromStr, sync}; -use cfg::{CfgDiff, CfgOptions}; +use cfg::CfgOptions; use la_arena::{Arena, Idx}; use rustc_hash::{FxHashMap, FxHashSet}; use syntax::SmolStr; @@ -330,7 +330,7 @@ pub struct CrateData { impl CrateData { /// Check if [`other`] is almost equal to [`self`] ignoring `CrateOrigin` value. - pub fn eq_ignoring_origin(&self, other: &CrateData) -> bool { + pub fn eq_ignoring_origin_and_deps(&self, other: &CrateData, ignore_dev_deps: bool) -> bool { // This method has some obscure bits. These are mostly there to be compliant with // some patches. References to the patches are given. if self.root_file_id != other.root_file_id { @@ -353,69 +353,36 @@ impl CrateData { return false; } - let mut opts = self.cfg_options.clone(); - opts.apply_diff( - CfgDiff::new(vec![], other.cfg_options.clone().into_iter().collect()) - .expect("CfgOptions were expected to contain no duplicates."), - ); - - let mut cfgs = opts.into_iter(); - if let Some(cfg) = cfgs.next() { - // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs. - // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894 - if cfgs.next().is_some() || cfg.to_string() != "rust_analyzer" { - return false; - } - } - - let mut itself = self.dependencies.iter(); - let mut otself = other.dependencies.iter(); - let (mut anx, mut bnx) = (itself.next(), otself.next()); - loop { - match (anx, bnx) { - (None, None) => { - break; - } - (None, Some(b)) => { - if b.kind != DependencyKind::Normal { - bnx = otself.next(); - } else { - break; - } - } - (Some(a), None) => { - if a.kind != DependencyKind::Normal { - anx = itself.next(); - } else { - break; - } - } - (Some(a), Some(b)) => { - if a.kind != DependencyKind::Normal { - anx = itself.next(); - continue; - } - - if b.kind != DependencyKind::Normal { - bnx = otself.next(); - continue; - } - - if a != b { + let mut opts = self.cfg_options.diff(&other.cfg_options).into_iter(); + match opts.len() { + 0 => (), + 1 => { + // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs. + // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894 + if let Some(cfg) = opts.next() { + if cfg.to_string() != "rust_analyzer" { return false; } - - anx = itself.next(); - bnx = otself.next(); } } - } + _ => return false, + }; if self.env != other.env { return false; } - true + let slf_deps = self.dependencies.iter(); + let other_deps = other.dependencies.iter(); + + if ignore_dev_deps { + slf_deps + .clone() + .filter(|it| it.kind == DependencyKind::Normal) + .eq(other_deps.clone().filter(|it| it.kind == DependencyKind::Normal)); + } + + slf_deps.eq(other_deps) } } @@ -446,7 +413,7 @@ impl Env { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum DependencyKind { Normal, Dev, @@ -480,8 +447,8 @@ impl Dependency { self.prelude } - pub fn kind(&self) -> &DependencyKind { - &self.kind + pub fn kind(&self) -> DependencyKind { + self.kind } } @@ -692,14 +659,27 @@ impl CrateGraph { crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]); crate_data.dependencies.sort_by_key(|dep| dep.crate_id); let res = self.arena.iter().find_map(|(id, data)| { - if data.eq_ignoring_origin(crate_data) { - if data.origin.is_lib() && crate_data.origin.is_local() { - // See #15656 for a relevant example. - return Some((id, true)); + match (&data.origin, &crate_data.origin) { + (a, b) if a == b => { + if data.eq_ignoring_origin_and_deps(&crate_data, false) { + return Some((id, false)); + } } - - return Some((id, false)); + (CrateOrigin::Local { .. }, CrateOrigin::Library { .. }) => { + // See #15656 for a relevant example. + if data.eq_ignoring_origin_and_deps(&crate_data, true) { + return Some((id, false)); + } + } + (CrateOrigin::Library { .. }, CrateOrigin::Local { .. }) => { + // See #15656 for a relevant example. + if data.eq_ignoring_origin_and_deps(&crate_data, true) { + return Some((id, true)); + } + } + (_, _) => return None, } + None }); diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index 0aeb0b050524..f197dad2b25e 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs @@ -7,7 +7,7 @@ mod dnf; #[cfg(test)] mod tests; -use std::fmt; +use std::{collections::HashSet, fmt}; use rustc_hash::FxHashSet; use tt::SmolStr; @@ -58,6 +58,10 @@ impl CfgOptions { self.enabled.insert(CfgAtom::KeyValue { key, value }); } + pub fn diff<'a>(&'a self, other: &'a CfgOptions) -> HashSet<&CfgAtom> { + self.enabled.difference(&other.enabled).collect() + } + pub fn apply_diff(&mut self, diff: CfgDiff) { for atom in diff.enable { self.enabled.insert(atom); From 74d8fdc8fef42fe47b12d533bb0d58ae024c4c66 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Sat, 11 Nov 2023 13:45:50 +0100 Subject: [PATCH 2430/2442] Update test data for crate deduping Make data reflect a case where dev deps are existent. base-db::CrateGraph::extend now adds dev dependencies for a crate in case of its upgrading from a CrateOrigin::Lib kind of a crate to a CrateOrigin::Local one. --- crates/base-db/src/input.rs | 51 +++++++--- crates/project-model/src/tests.rs | 10 +- .../deduplication_crate_graph_A.json | 94 +++++++++++++++++-- .../deduplication_crate_graph_B.json | 48 ++++++---- 4 files changed, 162 insertions(+), 41 deletions(-) diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 7dec01ff4dee..cec3e91eee47 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -376,7 +376,7 @@ impl CrateData { let other_deps = other.dependencies.iter(); if ignore_dev_deps { - slf_deps + return slf_deps .clone() .filter(|it| it.kind == DependencyKind::Normal) .eq(other_deps.clone().filter(|it| it.kind == DependencyKind::Normal)); @@ -524,7 +524,7 @@ impl CrateGraph { self.check_cycle_after_dependency(from, dep.crate_id)?; - self.arena[from].add_dep(dep); + self.arena[from].add_dep_unchecked(dep); Ok(()) } @@ -665,16 +665,11 @@ impl CrateGraph { return Some((id, false)); } } - (CrateOrigin::Local { .. }, CrateOrigin::Library { .. }) => { + (a @ CrateOrigin::Local { .. }, CrateOrigin::Library { .. }) + | (a @ CrateOrigin::Library { .. }, CrateOrigin::Local { .. }) => { // See #15656 for a relevant example. if data.eq_ignoring_origin_and_deps(&crate_data, true) { - return Some((id, false)); - } - } - (CrateOrigin::Library { .. }, CrateOrigin::Local { .. }) => { - // See #15656 for a relevant example. - if data.eq_ignoring_origin_and_deps(&crate_data, true) { - return Some((id, true)); + return Some((id, if a.is_local() { false } else { true })); } } (_, _) => return None, @@ -692,6 +687,16 @@ impl CrateGraph { if let CrateOrigin::Library { repo, name } = origin_old { self.arena[res].origin = CrateOrigin::Local { repo, name: Some(name) }; } + + // Move local's dev dependencies into the newly-local-formerly-lib crate. + let dev_deps = crate_data + .dependencies + .clone() + .into_iter() + .filter(|dep| dep.kind() == DependencyKind::Dev) + .collect::>(); + + self.arena[res].add_dep(dev_deps).unwrap_or_default(); } } else { let id = self.arena.alloc(crate_data.clone()); @@ -761,10 +766,34 @@ impl ops::Index for CrateGraph { } } +struct ExistingDepsError(Vec); + impl CrateData { - fn add_dep(&mut self, dep: Dependency) { + /// Add a dependency to `self` without checking if the dependency + // is existent among `self.dependencies`. + fn add_dep_unchecked(&mut self, dep: Dependency) { self.dependencies.push(dep) } + + /// Add `deps` to `self` if the dependency is not already listed. + /// Finally returning an `Err` propagating the dependencies it couldn't add. + fn add_dep(&mut self, deps: Vec) -> Result<(), ExistingDepsError> { + let mut existing_deps: Vec = vec![]; + + deps.into_iter().for_each(|dep| { + if !self.dependencies.contains(&dep) { + self.dependencies.push(dep); + } else { + existing_deps.push(dep); + } + }); + + if !existing_deps.is_empty() { + return Err(ExistingDepsError(existing_deps)); + } + + Ok(()) + } } impl FromStr for Edition { diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index 65c6f0b25624..35ac80eee328 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -3,7 +3,7 @@ use std::{ path::{Path, PathBuf}, }; -use base_db::{CrateGraph, FileId, ProcMacroPaths}; +use base_db::{CrateGraph, DependencyKind, FileId, ProcMacroPaths}; use cfg::{CfgAtom, CfgDiff}; use expect_test::{expect_file, ExpectFile}; use paths::{AbsPath, AbsPathBuf}; @@ -272,7 +272,9 @@ fn test_deduplicate_crate_differing_in_origin() { } assert!(crates_named_p1.len() == 1); - assert!(crates_named_p1[0].origin.is_local()); + let p1 = crates_named_p1[0]; + assert!(p1.dependencies.iter().filter(|dep| dep.kind() == DependencyKind::Dev).count() == 1); + assert!(p1.origin.is_local()); } #[test] @@ -297,5 +299,7 @@ fn test_deduplicate_crate_differing_in_origin_in_rev_resolution_order() { } assert!(crates_named_p1.len() == 1); - assert!(crates_named_p1[0].origin.is_local()); + let p1 = crates_named_p1[0]; + assert!(p1.dependencies.iter().filter(|dep| dep.kind() == DependencyKind::Dev).count() == 1); + assert!(p1.origin.is_local()); } diff --git a/crates/project-model/test_data/deduplication_crate_graph_A.json b/crates/project-model/test_data/deduplication_crate_graph_A.json index 3f627082f9f9..edaf185fc61a 100644 --- a/crates/project-model/test_data/deduplication_crate_graph_A.json +++ b/crates/project-model/test_data/deduplication_crate_graph_A.json @@ -3,7 +3,62 @@ { "name": "p1", "version": "0.1.0", - "id": "p1 0.1.0 (path+file:///path/to/project/projects/p1)", + "id": "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)", + "license": null, + "license_file": null, + "description": null, + "source": null, + "dependencies": [ + { + "name": "p3", + "source": null, + "req": "*", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "/path/to/project/example_project/projects/p3" + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "p1", + "src_path": "/path/to/project/example_project/projects/p1/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "/path/to/project/example_project/projects/p1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "homepage": null, + "documentation": null, + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "p3", + "version": "0.1.0", + "id": "p3 0.1.0 (path+file:///path/to/project/example_project/projects/p3)", "license": null, "license_file": null, "description": null, @@ -17,8 +72,8 @@ "crate_types": [ "lib" ], - "name": "p1", - "src_path": "/path/to/project/projects/p1/src/lib.rs", + "name": "p3", + "src_path": "/path/to/project/example_project/projects/p3/src/lib.rs", "edition": "2021", "doc": true, "doctest": true, @@ -26,7 +81,7 @@ } ], "features": {}, - "manifest_path": "/path/to/project/projects/p1/Cargo.toml", + "manifest_path": "/path/to/project/example_project/projects/p3/Cargo.toml", "metadata": null, "publish": null, "authors": [], @@ -43,24 +98,43 @@ } ], "workspace_members": [ - "p1 0.1.0 (path+file:///path/to/project/projects/p1)" + "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)" ], "workspace_default_members": [ - "p1 0.1.0 (path+file:///path/to/project/projects/p1)" + "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)" ], "resolve": { "nodes": [ { - "id": "p1 0.1.0 (path+file:///path/to/project/projects/p1)", + "id": "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)", + "dependencies": [ + "p3 0.1.0 (path+file:///path/to/project/example_project/projects/p3)" + ], + "deps": [ + { + "name": "p3", + "pkg": "p3 0.1.0 (path+file:///path/to/project/example_project/projects/p3)", + "dep_kinds": [ + { + "kind": "dev", + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "p3 0.1.0 (path+file:///path/to/project/example_project/projects/p3)", "dependencies": [], "deps": [], "features": [] } ], - "root": "p1 0.1.0 (path+file:///path/to/project/projects/p1)" + "root": "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)" }, - "target_directory": "/path/to/project/projects/p1/target", + "target_directory": "/path/to/project/example_project/projects/p1/target", "version": 1, - "workspace_root": "/path/to/project/projects/p1", + "workspace_root": "/path/to/project/example_project/projects/p1", "metadata": null } \ No newline at end of file diff --git a/crates/project-model/test_data/deduplication_crate_graph_B.json b/crates/project-model/test_data/deduplication_crate_graph_B.json index a2bf1af04407..4f753db71bf0 100644 --- a/crates/project-model/test_data/deduplication_crate_graph_B.json +++ b/crates/project-model/test_data/deduplication_crate_graph_B.json @@ -3,12 +3,26 @@ { "name": "p1", "version": "0.1.0", - "id": "p1 0.1.0 (path+file:///path/to/project/projects/p1)", + "id": "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)", "license": null, "license_file": null, "description": null, "source": null, - "dependencies": [], + "dependencies": [ + { + "name": "p3", + "source": null, + "req": "*", + "kind": "dev", + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "/path/to/project/example_project/projects/p3" + } + ], "targets": [ { "kind": [ @@ -18,7 +32,7 @@ "lib" ], "name": "p1", - "src_path": "/path/to/project/projects/p1/src/lib.rs", + "src_path": "/path/to/project/example_project/projects/p1/src/lib.rs", "edition": "2021", "doc": true, "doctest": true, @@ -26,7 +40,7 @@ } ], "features": {}, - "manifest_path": "/path/to/project/projects/p1/Cargo.toml", + "manifest_path": "/path/to/project/example_project/projects/p1/Cargo.toml", "metadata": null, "publish": null, "authors": [], @@ -44,7 +58,7 @@ { "name": "p2", "version": "0.1.0", - "id": "p2 0.1.0 (path+file:///path/to/project/projects/p2)", + "id": "p2 0.1.0 (path+file:///path/to/project/example_project/projects/p2)", "license": null, "license_file": null, "description": null, @@ -61,7 +75,7 @@ "features": [], "target": null, "registry": null, - "path": "/path/to/project/projects/p1" + "path": "/path/to/project/example_project/projects/p1" } ], "targets": [ @@ -73,7 +87,7 @@ "lib" ], "name": "p2", - "src_path": "/path/to/project/projects/p2/src/lib.rs", + "src_path": "/path/to/project/example_project/projects/p2/src/lib.rs", "edition": "2021", "doc": true, "doctest": true, @@ -81,7 +95,7 @@ } ], "features": {}, - "manifest_path": "/path/to/project/projects/p2/Cargo.toml", + "manifest_path": "/path/to/project/example_project/projects/p2/Cargo.toml", "metadata": null, "publish": null, "authors": [], @@ -98,28 +112,28 @@ } ], "workspace_members": [ - "p2 0.1.0 (path+file:///path/to/project/projects/p2)" + "p2 0.1.0 (path+file:///path/to/project/example_project/projects/p2)" ], "workspace_default_members": [ - "p2 0.1.0 (path+file:///path/to/project/projects/p2)" + "p2 0.1.0 (path+file:///path/to/project/example_project/projects/p2)" ], "resolve": { "nodes": [ { - "id": "p1 0.1.0 (path+file:///path/to/project/projects/p1)", + "id": "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)", "dependencies": [], "deps": [], "features": [] }, { - "id": "p2 0.1.0 (path+file:///path/to/project/projects/p2)", + "id": "p2 0.1.0 (path+file:///path/to/project/example_project/projects/p2)", "dependencies": [ - "p1 0.1.0 (path+file:///path/to/project/projects/p1)" + "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)" ], "deps": [ { "name": "p1", - "pkg": "p1 0.1.0 (path+file:///path/to/project/projects/p1)", + "pkg": "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)", "dep_kinds": [ { "kind": null, @@ -131,10 +145,10 @@ "features": [] } ], - "root": "p2 0.1.0 (path+file:///path/to/project/projects/p2)" + "root": "p2 0.1.0 (path+file:///path/to/project/example_project/projects/p2)" }, - "target_directory": "/path/to/project/projects/p2/target", + "target_directory": "/path/to/project/example_project/projects/p2/target", "version": 1, - "workspace_root": "/path/to/project/projects/p2", + "workspace_root": "/path/to/project/example_project/projects/p2", "metadata": null } \ No newline at end of file From f79e8182c1e611b385fd91c924e347ea5f6c71d3 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Tue, 21 Nov 2023 14:05:31 +0100 Subject: [PATCH 2431/2442] v3 --- crates/base-db/src/input.rs | 79 ++++++++++++------------------------- crates/cfg/src/lib.rs | 9 +++-- 2 files changed, 31 insertions(+), 57 deletions(-) diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index cec3e91eee47..82149892bd68 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -353,20 +353,18 @@ impl CrateData { return false; } - let mut opts = self.cfg_options.diff(&other.cfg_options).into_iter(); - match opts.len() { - 0 => (), - 1 => { - // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs. - // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894 - if let Some(cfg) = opts.next() { - if cfg.to_string() != "rust_analyzer" { - return false; - } - } + let mut opts = self.cfg_options.difference(&other.cfg_options); + if let Some(it) = opts.next() { + // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs. + // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894 + if it.to_string() != "rust_analyzer" { + return false; } - _ => return false, - }; + + if let Some(_) = opts.next() { + return false; + } + } if self.env != other.env { return false; @@ -378,8 +376,8 @@ impl CrateData { if ignore_dev_deps { return slf_deps .clone() - .filter(|it| it.kind == DependencyKind::Normal) - .eq(other_deps.clone().filter(|it| it.kind == DependencyKind::Normal)); + .filter(|it| it.kind != DependencyKind::Dev) + .eq(other_deps.clone().filter(|it| it.kind != DependencyKind::Dev)); } slf_deps.eq(other_deps) @@ -524,7 +522,7 @@ impl CrateGraph { self.check_cycle_after_dependency(from, dep.crate_id)?; - self.arena[from].add_dep_unchecked(dep); + self.arena[from].add_dep(dep); Ok(()) } @@ -667,7 +665,12 @@ impl CrateGraph { } (a @ CrateOrigin::Local { .. }, CrateOrigin::Library { .. }) | (a @ CrateOrigin::Library { .. }, CrateOrigin::Local { .. }) => { - // See #15656 for a relevant example. + // If the origins differ, check if the two crates are equal without + // considering the dev dependencies, if they are, they most likely are in + // different loaded workspaces which may cause issues. We keep the local + // version and discard the library one as the local version may have + // dev-dependencies that we want to keep resolving. See #15656 for more + // information. if data.eq_ignoring_origin_and_deps(&crate_data, true) { return Some((id, if a.is_local() { false } else { true })); } @@ -681,22 +684,12 @@ impl CrateGraph { if let Some((res, should_update_lib_to_local)) = res { id_map.insert(topo, res); if should_update_lib_to_local { - let origin_old = self.arena[res].origin.clone(); - assert!(origin_old.is_lib()); - - if let CrateOrigin::Library { repo, name } = origin_old { - self.arena[res].origin = CrateOrigin::Local { repo, name: Some(name) }; - } + assert!(self.arena[res].origin.is_lib()); + assert!(crate_data.origin.is_local()); + self.arena[res].origin = crate_data.origin.clone(); // Move local's dev dependencies into the newly-local-formerly-lib crate. - let dev_deps = crate_data - .dependencies - .clone() - .into_iter() - .filter(|dep| dep.kind() == DependencyKind::Dev) - .collect::>(); - - self.arena[res].add_dep(dev_deps).unwrap_or_default(); + self.arena[res].dependencies = crate_data.dependencies.clone(); } } else { let id = self.arena.alloc(crate_data.clone()); @@ -766,34 +759,12 @@ impl ops::Index for CrateGraph { } } -struct ExistingDepsError(Vec); - impl CrateData { /// Add a dependency to `self` without checking if the dependency // is existent among `self.dependencies`. - fn add_dep_unchecked(&mut self, dep: Dependency) { + fn add_dep(&mut self, dep: Dependency) { self.dependencies.push(dep) } - - /// Add `deps` to `self` if the dependency is not already listed. - /// Finally returning an `Err` propagating the dependencies it couldn't add. - fn add_dep(&mut self, deps: Vec) -> Result<(), ExistingDepsError> { - let mut existing_deps: Vec = vec![]; - - deps.into_iter().for_each(|dep| { - if !self.dependencies.contains(&dep) { - self.dependencies.push(dep); - } else { - existing_deps.push(dep); - } - }); - - if !existing_deps.is_empty() { - return Err(ExistingDepsError(existing_deps)); - } - - Ok(()) - } } impl FromStr for Edition { diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index f197dad2b25e..8bbe5e2a8c29 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs @@ -7,7 +7,7 @@ mod dnf; #[cfg(test)] mod tests; -use std::{collections::HashSet, fmt}; +use std::fmt; use rustc_hash::FxHashSet; use tt::SmolStr; @@ -58,8 +58,11 @@ impl CfgOptions { self.enabled.insert(CfgAtom::KeyValue { key, value }); } - pub fn diff<'a>(&'a self, other: &'a CfgOptions) -> HashSet<&CfgAtom> { - self.enabled.difference(&other.enabled).collect() + pub fn difference<'a>( + &'a self, + other: &'a CfgOptions, + ) -> impl Iterator + 'a { + self.enabled.difference(&other.enabled) } pub fn apply_diff(&mut self, diff: CfgDiff) { From 736994f02664aa4cd84f55be481aae33bcf48ca3 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Thu, 23 Nov 2023 02:08:30 +0100 Subject: [PATCH 2432/2442] Make test cases simpler --- crates/base-db/src/input.rs | 2 +- crates/project-model/src/tests.rs | 32 +++--- .../deduplication_crate_graph_A.json | 44 +++---- .../deduplication_crate_graph_B.json | 108 ++---------------- 4 files changed, 48 insertions(+), 138 deletions(-) diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 82149892bd68..e4f78321e215 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -668,7 +668,7 @@ impl CrateGraph { // If the origins differ, check if the two crates are equal without // considering the dev dependencies, if they are, they most likely are in // different loaded workspaces which may cause issues. We keep the local - // version and discard the library one as the local version may have + // version and discard the library one as the local version may have // dev-dependencies that we want to keep resolving. See #15656 for more // information. if data.eq_ignoring_origin_and_deps(&crate_data, true) { diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index 35ac80eee328..98f3063bb982 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -3,7 +3,7 @@ use std::{ path::{Path, PathBuf}, }; -use base_db::{CrateGraph, DependencyKind, FileId, ProcMacroPaths}; +use base_db::{CrateGraph, FileId, ProcMacroPaths}; use cfg::{CfgAtom, CfgDiff}; use expect_test::{expect_file, ExpectFile}; use paths::{AbsPath, AbsPathBuf}; @@ -251,7 +251,7 @@ fn crate_graph_dedup() { } #[test] -fn test_deduplicate_crate_differing_in_origin() { +fn test_deduplicate_origin_dev() { let path_map = &mut Default::default(); let (mut crate_graph, _proc_macros) = load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json"); @@ -261,24 +261,23 @@ fn test_deduplicate_crate_differing_in_origin() { crate_graph.extend(crate_graph_1, &mut _proc_macros_2); - let mut crates_named_p1 = vec![]; + let mut crates_named_p2 = vec![]; for id in crate_graph.iter() { let krate = &crate_graph[id]; if let Some(name) = krate.display_name.as_ref() { - if name.to_string() == "p1" { - crates_named_p1.push(krate); + if name.to_string() == "p2" { + crates_named_p2.push(krate); } } } - assert!(crates_named_p1.len() == 1); - let p1 = crates_named_p1[0]; - assert!(p1.dependencies.iter().filter(|dep| dep.kind() == DependencyKind::Dev).count() == 1); - assert!(p1.origin.is_local()); + assert!(crates_named_p2.len() == 1); + let p2 = crates_named_p2[0]; + assert!(p2.origin.is_local()); } #[test] -fn test_deduplicate_crate_differing_in_origin_in_rev_resolution_order() { +fn test_deduplicate_origin_dev_rev() { let path_map = &mut Default::default(); let (mut crate_graph, _proc_macros) = load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json"); @@ -288,18 +287,17 @@ fn test_deduplicate_crate_differing_in_origin_in_rev_resolution_order() { crate_graph.extend(crate_graph_1, &mut _proc_macros_2); - let mut crates_named_p1 = vec![]; + let mut crates_named_p2 = vec![]; for id in crate_graph.iter() { let krate = &crate_graph[id]; if let Some(name) = krate.display_name.as_ref() { - if name.to_string() == "p1" { - crates_named_p1.push(krate); + if name.to_string() == "p2" { + crates_named_p2.push(krate); } } } - assert!(crates_named_p1.len() == 1); - let p1 = crates_named_p1[0]; - assert!(p1.dependencies.iter().filter(|dep| dep.kind() == DependencyKind::Dev).count() == 1); - assert!(p1.origin.is_local()); + assert!(crates_named_p2.len() == 1); + let p2 = crates_named_p2[0]; + assert!(p2.origin.is_local()); } diff --git a/crates/project-model/test_data/deduplication_crate_graph_A.json b/crates/project-model/test_data/deduplication_crate_graph_A.json index edaf185fc61a..66bfcb2bf6ef 100644 --- a/crates/project-model/test_data/deduplication_crate_graph_A.json +++ b/crates/project-model/test_data/deduplication_crate_graph_A.json @@ -3,24 +3,24 @@ { "name": "p1", "version": "0.1.0", - "id": "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)", + "id": "p1 0.1.0 (path+file:///example_project/p1)", "license": null, "license_file": null, "description": null, "source": null, "dependencies": [ { - "name": "p3", + "name": "p2", "source": null, "req": "*", - "kind": "dev", + "kind": null, "rename": null, "optional": false, "uses_default_features": true, "features": [], "target": null, "registry": null, - "path": "/path/to/project/example_project/projects/p3" + "path": "/example_project/p2" } ], "targets": [ @@ -32,7 +32,7 @@ "lib" ], "name": "p1", - "src_path": "/path/to/project/example_project/projects/p1/src/lib.rs", + "src_path": "/example_project/p1/src/lib.rs", "edition": "2021", "doc": true, "doctest": true, @@ -40,7 +40,7 @@ } ], "features": {}, - "manifest_path": "/path/to/project/example_project/projects/p1/Cargo.toml", + "manifest_path": "/example_project/p1/Cargo.toml", "metadata": null, "publish": null, "authors": [], @@ -56,9 +56,9 @@ "rust_version": null }, { - "name": "p3", + "name": "p2", "version": "0.1.0", - "id": "p3 0.1.0 (path+file:///path/to/project/example_project/projects/p3)", + "id": "p2 0.1.0 (path+file:///example_project/p2)", "license": null, "license_file": null, "description": null, @@ -72,8 +72,8 @@ "crate_types": [ "lib" ], - "name": "p3", - "src_path": "/path/to/project/example_project/projects/p3/src/lib.rs", + "name": "p2", + "src_path": "/example_project/p2/src/lib.rs", "edition": "2021", "doc": true, "doctest": true, @@ -81,7 +81,7 @@ } ], "features": {}, - "manifest_path": "/path/to/project/example_project/projects/p3/Cargo.toml", + "manifest_path": "/example_project/p2/Cargo.toml", "metadata": null, "publish": null, "authors": [], @@ -98,25 +98,25 @@ } ], "workspace_members": [ - "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)" + "p1 0.1.0 (path+file:///example_project/p1)" ], "workspace_default_members": [ - "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)" + "p1 0.1.0 (path+file:///example_project/p1)" ], "resolve": { "nodes": [ { - "id": "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)", + "id": "p1 0.1.0 (path+file:///example_project/p1)", "dependencies": [ - "p3 0.1.0 (path+file:///path/to/project/example_project/projects/p3)" + "p2 0.1.0 (path+file:///example_project/p2)" ], "deps": [ { - "name": "p3", - "pkg": "p3 0.1.0 (path+file:///path/to/project/example_project/projects/p3)", + "name": "p2", + "pkg": "p2 0.1.0 (path+file:///example_project/p2)", "dep_kinds": [ { - "kind": "dev", + "kind": null, "target": null } ] @@ -125,16 +125,16 @@ "features": [] }, { - "id": "p3 0.1.0 (path+file:///path/to/project/example_project/projects/p3)", + "id": "p2 0.1.0 (path+file:///example_project/p2)", "dependencies": [], "deps": [], "features": [] } ], - "root": "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)" + "root": "p1 0.1.0 (path+file:///example_project/p1)" }, - "target_directory": "/path/to/project/example_project/projects/p1/target", + "target_directory": "/example_project/p1/target", "version": 1, - "workspace_root": "/path/to/project/example_project/projects/p1", + "workspace_root": "/example_project/p1", "metadata": null } \ No newline at end of file diff --git a/crates/project-model/test_data/deduplication_crate_graph_B.json b/crates/project-model/test_data/deduplication_crate_graph_B.json index 4f753db71bf0..6e67da7eae13 100644 --- a/crates/project-model/test_data/deduplication_crate_graph_B.json +++ b/crates/project-model/test_data/deduplication_crate_graph_B.json @@ -1,83 +1,14 @@ { "packages": [ - { - "name": "p1", - "version": "0.1.0", - "id": "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)", - "license": null, - "license_file": null, - "description": null, - "source": null, - "dependencies": [ - { - "name": "p3", - "source": null, - "req": "*", - "kind": "dev", - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "/path/to/project/example_project/projects/p3" - } - ], - "targets": [ - { - "kind": [ - "lib" - ], - "crate_types": [ - "lib" - ], - "name": "p1", - "src_path": "/path/to/project/example_project/projects/p1/src/lib.rs", - "edition": "2021", - "doc": true, - "doctest": true, - "test": true - } - ], - "features": {}, - "manifest_path": "/path/to/project/example_project/projects/p1/Cargo.toml", - "metadata": null, - "publish": null, - "authors": [], - "categories": [], - "keywords": [], - "readme": null, - "repository": null, - "homepage": null, - "documentation": null, - "edition": "2021", - "links": null, - "default_run": null, - "rust_version": null - }, { "name": "p2", "version": "0.1.0", - "id": "p2 0.1.0 (path+file:///path/to/project/example_project/projects/p2)", + "id": "p2 0.1.0 (path+file:///example_project/p2)", "license": null, "license_file": null, "description": null, "source": null, - "dependencies": [ - { - "name": "p1", - "source": null, - "req": "*", - "kind": null, - "rename": null, - "optional": false, - "uses_default_features": true, - "features": [], - "target": null, - "registry": null, - "path": "/path/to/project/example_project/projects/p1" - } - ], + "dependencies": [], "targets": [ { "kind": [ @@ -87,7 +18,7 @@ "lib" ], "name": "p2", - "src_path": "/path/to/project/example_project/projects/p2/src/lib.rs", + "src_path": "/example_project/p2/src/lib.rs", "edition": "2021", "doc": true, "doctest": true, @@ -95,7 +26,7 @@ } ], "features": {}, - "manifest_path": "/path/to/project/example_project/projects/p2/Cargo.toml", + "manifest_path": "/example_project/p2/Cargo.toml", "metadata": null, "publish": null, "authors": [], @@ -112,43 +43,24 @@ } ], "workspace_members": [ - "p2 0.1.0 (path+file:///path/to/project/example_project/projects/p2)" + "p2 0.1.0 (path+file:///example_project/p2)" ], "workspace_default_members": [ - "p2 0.1.0 (path+file:///path/to/project/example_project/projects/p2)" + "p2 0.1.0 (path+file:///example_project/p2)" ], "resolve": { "nodes": [ { - "id": "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)", + "id": "p2 0.1.0 (path+file:///example_project/p2)", "dependencies": [], "deps": [], "features": [] - }, - { - "id": "p2 0.1.0 (path+file:///path/to/project/example_project/projects/p2)", - "dependencies": [ - "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)" - ], - "deps": [ - { - "name": "p1", - "pkg": "p1 0.1.0 (path+file:///path/to/project/example_project/projects/p1)", - "dep_kinds": [ - { - "kind": null, - "target": null - } - ] - } - ], - "features": [] } ], - "root": "p2 0.1.0 (path+file:///path/to/project/example_project/projects/p2)" + "root": "p2 0.1.0 (path+file:///example_project/p2)" }, - "target_directory": "/path/to/project/example_project/projects/p2/target", + "target_directory": "/example_project/p2/target", "version": 1, - "workspace_root": "/path/to/project/example_project/projects/p2", + "workspace_root": "/example_project/p2", "metadata": null } \ No newline at end of file From ba1b08080559fdaa714d9e58ce21f7f2030adc56 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Thu, 23 Nov 2023 12:34:38 +0100 Subject: [PATCH 2433/2442] Precede paths with $ROOT$ --- .../test_data/deduplication_crate_graph_A.json | 14 +++++++------- .../test_data/deduplication_crate_graph_B.json | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/project-model/test_data/deduplication_crate_graph_A.json b/crates/project-model/test_data/deduplication_crate_graph_A.json index 66bfcb2bf6ef..b0fb5845cef7 100644 --- a/crates/project-model/test_data/deduplication_crate_graph_A.json +++ b/crates/project-model/test_data/deduplication_crate_graph_A.json @@ -20,7 +20,7 @@ "features": [], "target": null, "registry": null, - "path": "/example_project/p2" + "path": "$ROOT$example_project/p2" } ], "targets": [ @@ -32,7 +32,7 @@ "lib" ], "name": "p1", - "src_path": "/example_project/p1/src/lib.rs", + "src_path": "$ROOT$example_project/p1/src/lib.rs", "edition": "2021", "doc": true, "doctest": true, @@ -40,7 +40,7 @@ } ], "features": {}, - "manifest_path": "/example_project/p1/Cargo.toml", + "manifest_path": "$ROOT$example_project/p1/Cargo.toml", "metadata": null, "publish": null, "authors": [], @@ -73,7 +73,7 @@ "lib" ], "name": "p2", - "src_path": "/example_project/p2/src/lib.rs", + "src_path": "$ROOT$example_project/p2/src/lib.rs", "edition": "2021", "doc": true, "doctest": true, @@ -81,7 +81,7 @@ } ], "features": {}, - "manifest_path": "/example_project/p2/Cargo.toml", + "manifest_path": "$ROOT$example_project/p2/Cargo.toml", "metadata": null, "publish": null, "authors": [], @@ -133,8 +133,8 @@ ], "root": "p1 0.1.0 (path+file:///example_project/p1)" }, - "target_directory": "/example_project/p1/target", + "target_directory": "$ROOT$example_project/p1/target", "version": 1, - "workspace_root": "/example_project/p1", + "workspace_root": "$ROOT$example_project/p1", "metadata": null } \ No newline at end of file diff --git a/crates/project-model/test_data/deduplication_crate_graph_B.json b/crates/project-model/test_data/deduplication_crate_graph_B.json index 6e67da7eae13..b5d1e16e62e0 100644 --- a/crates/project-model/test_data/deduplication_crate_graph_B.json +++ b/crates/project-model/test_data/deduplication_crate_graph_B.json @@ -18,7 +18,7 @@ "lib" ], "name": "p2", - "src_path": "/example_project/p2/src/lib.rs", + "src_path": "$ROOT$example_project/p2/src/lib.rs", "edition": "2021", "doc": true, "doctest": true, @@ -26,7 +26,7 @@ } ], "features": {}, - "manifest_path": "/example_project/p2/Cargo.toml", + "manifest_path": "$ROOT$example_project/p2/Cargo.toml", "metadata": null, "publish": null, "authors": [], @@ -59,8 +59,8 @@ ], "root": "p2 0.1.0 (path+file:///example_project/p2)" }, - "target_directory": "/example_project/p2/target", + "target_directory": "$ROOT$example_project/p2/target", "version": 1, - "workspace_root": "/example_project/p2", + "workspace_root": "$ROOT$example_project/p2", "metadata": null } \ No newline at end of file From 615abb3c92430e85a9b197022e008ef129bdb45f Mon Sep 17 00:00:00 2001 From: Andrew Hlynskyi Date: Fri, 24 Nov 2023 12:57:16 +0200 Subject: [PATCH 2434/2442] Improve completion label details display --- crates/ide-completion/src/item.rs | 21 +++++++++++++++++---- crates/rust-analyzer/src/lsp/to_proto.rs | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index ed74ef7b667b..5397a9fc90b9 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -26,6 +26,10 @@ use crate::{ pub struct CompletionItem { /// Label in the completion pop up which identifies completion. pub label: SmolStr, + /// Addition label details in the completion pop up that are + /// displayed and aligned on the right side after the label. + pub label_detail: Option, + /// Range of identifier that is being completed. /// /// It should be used primarily for UI, but we also use this to convert @@ -425,13 +429,14 @@ impl Builder { pub(crate) fn build(self, db: &RootDatabase) -> CompletionItem { let _p = profile::span("item::Builder::build"); - let mut label = self.label; + let label = self.label; + let mut label_detail = None; let mut lookup = self.lookup.unwrap_or_else(|| label.clone()); let insert_text = self.insert_text.unwrap_or_else(|| label.to_string()); if !self.doc_aliases.is_empty() { let doc_aliases = self.doc_aliases.iter().join(", "); - label = SmolStr::from(format!("{label} (alias {doc_aliases})")); + label_detail.replace(SmolStr::from(format!(" (alias {doc_aliases})"))); let lookup_doc_aliases = self .doc_aliases .iter() @@ -454,10 +459,17 @@ impl Builder { if let [import_edit] = &*self.imports_to_add { // snippets can have multiple imports, but normal completions only have up to one if let Some(original_path) = import_edit.original_path.as_ref() { - label = SmolStr::from(format!("{label} (use {})", original_path.display(db))); + label_detail.replace(SmolStr::from(format!( + "{} (use {})", + label_detail.as_deref().unwrap_or_default(), + original_path.display(db) + ))); } } else if let Some(trait_name) = self.trait_name { - label = SmolStr::from(format!("{label} (as {trait_name})")); + label_detail.replace(SmolStr::from(format!( + "{} (as {trait_name})", + label_detail.as_deref().unwrap_or_default(), + ))); } let text_edit = match self.text_edit { @@ -479,6 +491,7 @@ impl Builder { CompletionItem { source_range: self.source_range, label, + label_detail, text_edit, is_snippet: self.is_snippet, detail: self.detail, diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs index 4e3dce35ec39..b4ba5bf4f91a 100644 --- a/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/crates/rust-analyzer/src/lsp/to_proto.rs @@ -301,7 +301,7 @@ fn completion_item( if config.completion_label_details_support() { lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails { - detail: None, + detail: item.label_detail.as_ref().map(ToString::to_string), description: lsp_item.detail.clone(), }); } From f0adf8c4ecedae38796769bd9ef3d4daa5ec2260 Mon Sep 17 00:00:00 2001 From: Andrew Hlynskyi Date: Fri, 24 Nov 2023 13:28:30 +0200 Subject: [PATCH 2435/2442] Update tests --- crates/ide-completion/src/render.rs | 6 +++++- crates/ide-completion/src/tests.rs | 19 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index dfe8fe7e2f7f..00a9081985b8 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -557,7 +557,11 @@ mod tests { let tag = it.kind.tag(); let relevance = display_relevance(it.relevance); - items.push(format!("{tag} {} {relevance}\n", it.label)); + items.push(format!( + "{tag} {}{} {relevance}\n", + it.label, + it.label_detail.clone().unwrap_or_default(), + )); if let Some((label, _indel, relevance)) = it.ref_match() { let relevance = display_relevance(relevance); diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs index 9db8e972dd4b..f28afacc586f 100644 --- a/crates/ide-completion/src/tests.rs +++ b/crates/ide-completion/src/tests.rs @@ -150,16 +150,29 @@ fn render_completion_list(completions: Vec) -> String { fn monospace_width(s: &str) -> usize { s.chars().count() } - let label_width = - completions.iter().map(|it| monospace_width(&it.label)).max().unwrap_or_default().min(22); + let label_width = completions + .iter() + .map(|it| { + monospace_width(&it.label) + + monospace_width(it.label_detail.as_deref().unwrap_or_default()) + }) + .max() + .unwrap_or_default() + .min(22); completions .into_iter() .map(|it| { let tag = it.kind.tag(); let var_name = format!("{tag} {}", it.label); let mut buf = var_name; + if let Some(ref label_detail) = it.label_detail { + format_to!(buf, "{label_detail}"); + } if let Some(detail) = it.detail { - let width = label_width.saturating_sub(monospace_width(&it.label)); + let width = label_width.saturating_sub( + monospace_width(&it.label) + + monospace_width(&it.label_detail.unwrap_or_default()), + ); format_to!(buf, "{:width$} {}", "", detail, width = width); } if it.deprecated { From b68f5311b52d109cf813dff1268264d17af766ba Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 24 Nov 2023 09:06:43 -0800 Subject: [PATCH 2436/2442] Replace `option.map(cond) == Some(true)` with `option.is_some_and(cond)` --- crates/ide-assists/src/handlers/toggle_ignore.rs | 2 +- crates/ide/src/extend_selection.rs | 2 +- crates/rust-analyzer/tests/slow-tests/tidy.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ide-assists/src/handlers/toggle_ignore.rs b/crates/ide-assists/src/handlers/toggle_ignore.rs index b7d57f02be56..f864ee50c81d 100644 --- a/crates/ide-assists/src/handlers/toggle_ignore.rs +++ b/crates/ide-assists/src/handlers/toggle_ignore.rs @@ -55,7 +55,7 @@ pub(crate) fn toggle_ignore(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio } fn has_ignore_attribute(fn_def: &ast::Fn) -> Option { - fn_def.attrs().find(|attr| attr.path().map(|it| it.syntax().text() == "ignore") == Some(true)) + fn_def.attrs().find(|attr| attr.path().is_some_and(|it| it.syntax().text() == "ignore")) } #[cfg(test)] diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs index 3d89599c5832..9b2ff070c74b 100644 --- a/crates/ide/src/extend_selection.rs +++ b/crates/ide/src/extend_selection.rs @@ -108,7 +108,7 @@ fn try_extend_selection( let node = shallowest_node(&node); - if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) { + if node.parent().is_some_and(|n| list_kinds.contains(&n.kind())) { if let Some(range) = extend_list_item(&node) { return Some(range); } diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs index 56b5fcef3c2f..45adbf5c573b 100644 --- a/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs @@ -316,7 +316,7 @@ fn check_trailing_ws(path: &Path, text: &str) { return; } for (line_number, line) in text.lines().enumerate() { - if line.chars().last().map(char::is_whitespace) == Some(true) { + if line.chars().last().is_some_and(char::is_whitespace) { panic!("Trailing whitespace in {} at line {}", path.display(), line_number + 1) } } From 94cea4663a3a826beccfeb291187df4849fe990e Mon Sep 17 00:00:00 2001 From: Andrew Hlynskyi Date: Fri, 24 Nov 2023 15:24:57 +0200 Subject: [PATCH 2437/2442] fix: add fallback for completion label details --- crates/ide-completion/src/item.rs | 2 +- crates/rust-analyzer/src/lsp/to_proto.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index 5397a9fc90b9..99b895eed4d2 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -26,7 +26,7 @@ use crate::{ pub struct CompletionItem { /// Label in the completion pop up which identifies completion. pub label: SmolStr, - /// Addition label details in the completion pop up that are + /// Additional label details in the completion pop up that are /// displayed and aligned on the right side after the label. pub label_detail: Option, diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs index b4ba5bf4f91a..fb366fd5cc41 100644 --- a/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/crates/rust-analyzer/src/lsp/to_proto.rs @@ -304,6 +304,8 @@ fn completion_item( detail: item.label_detail.as_ref().map(ToString::to_string), description: lsp_item.detail.clone(), }); + } else if let Some(label_detail) = item.label_detail { + lsp_item.label.push_str(label_detail.as_str()); } set_score(&mut lsp_item, max_relevance, item.relevance); From fa74ac845710c9ca233a0a89ca5e0786a11d08e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sat, 25 Nov 2023 20:35:26 +0200 Subject: [PATCH 2438/2442] Bump ra-ap-rustc_parse_format --- Cargo.lock | 53 +++++++++++++++++----------- crates/rustc-dependencies/Cargo.toml | 2 +- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 11283034ea2f..a1cb09bafaad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1467,16 +1467,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "ra-ap-rustc_index" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643ca3609870b1778d9cd1f2a8e4ccb4af0f48f3637cc257a09494d087bd93dc" -dependencies = [ - "arrayvec", - "smallvec", -] - [[package]] name = "ra-ap-rustc_index" version = "0.19.0" @@ -1488,13 +1478,26 @@ dependencies = [ ] [[package]] -name = "ra-ap-rustc_lexer" -version = "0.14.0" +name = "ra-ap-rustc_index" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ffd24f9ba4f1d25ff27ca1469b8d22a3bdfb12cf644fc8bfcb63121fa5da6b" +checksum = "69fb5da07e1a39222d9c311203123c3b6a86420fa06dc695aa1661b0aecf8d16" dependencies = [ - "unicode-properties", - "unicode-xid", + "arrayvec", + "ra-ap-rustc_index_macros", + "smallvec", +] + +[[package]] +name = "ra-ap-rustc_index_macros" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d69f9f6af58124f2da0cb8b0c3d8494e0d883a5fe0c6732258bde81ac5a87cc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", + "synstructure", ] [[package]] @@ -1508,13 +1511,23 @@ dependencies = [ ] [[package]] -name = "ra-ap-rustc_parse_format" -version = "0.14.0" +name = "ra-ap-rustc_lexer" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "207b5ac1a21d4926695e03b605ffb9f63d4968e0488e9197c04c512c37303aa7" +checksum = "9d5e8650195795c4023d8321846466994a975bc457cb8a91c0b3b17a5fc8ba40" dependencies = [ - "ra-ap-rustc_index 0.14.0", - "ra-ap-rustc_lexer 0.14.0", + "unicode-properties", + "unicode-xid", +] + +[[package]] +name = "ra-ap-rustc_parse_format" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6b325ee1ec90e4dbd4394913adf4ef32e4fcf2b311ec9563a0fa50cd549af6" +dependencies = [ + "ra-ap-rustc_index 0.20.0", + "ra-ap-rustc_lexer 0.20.0", ] [[package]] diff --git a/crates/rustc-dependencies/Cargo.toml b/crates/rustc-dependencies/Cargo.toml index ba36fb0b0446..893ed76e3f1e 100644 --- a/crates/rustc-dependencies/Cargo.toml +++ b/crates/rustc-dependencies/Cargo.toml @@ -12,7 +12,7 @@ authors.workspace = true [dependencies] ra-ap-rustc_lexer = { version = "0.19.0" } -ra-ap-rustc_parse_format = { version = "0.14.0", default-features = false } +ra-ap-rustc_parse_format = { version = "0.20.0", default-features = false } ra-ap-rustc_index = { version = "0.19.0", default-features = false } ra-ap-rustc_abi = { version = "0.19.0", default-features = false } From c01679eb7b2d2fb9c2c0899a5fe5898581f39fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sat, 25 Nov 2023 20:36:06 +0200 Subject: [PATCH 2439/2442] Bump ra-ap-rustc_lexer --- Cargo.lock | 14 ++------------ crates/rustc-dependencies/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1cb09bafaad..5189811f4953 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1500,16 +1500,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "ra-ap-rustc_lexer" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e573bf707e01fe2841dbdedeed42012004274db0edc0314e6e3e58a40598fc" -dependencies = [ - "unicode-properties", - "unicode-xid", -] - [[package]] name = "ra-ap-rustc_lexer" version = "0.20.0" @@ -1527,7 +1517,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6b325ee1ec90e4dbd4394913adf4ef32e4fcf2b311ec9563a0fa50cd549af6" dependencies = [ "ra-ap-rustc_index 0.20.0", - "ra-ap-rustc_lexer 0.20.0", + "ra-ap-rustc_lexer", ] [[package]] @@ -1650,7 +1640,7 @@ version = "0.0.0" dependencies = [ "ra-ap-rustc_abi", "ra-ap-rustc_index 0.19.0", - "ra-ap-rustc_lexer 0.19.0", + "ra-ap-rustc_lexer", "ra-ap-rustc_parse_format", ] diff --git a/crates/rustc-dependencies/Cargo.toml b/crates/rustc-dependencies/Cargo.toml index 893ed76e3f1e..41bcfd11722c 100644 --- a/crates/rustc-dependencies/Cargo.toml +++ b/crates/rustc-dependencies/Cargo.toml @@ -11,7 +11,7 @@ authors.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ra-ap-rustc_lexer = { version = "0.19.0" } +ra-ap-rustc_lexer = { version = "0.20.0" } ra-ap-rustc_parse_format = { version = "0.20.0", default-features = false } ra-ap-rustc_index = { version = "0.19.0", default-features = false } ra-ap-rustc_abi = { version = "0.19.0", default-features = false } From aadeb66d036d4a3d786f3ee3eac5cd5aab73e180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sat, 25 Nov 2023 20:36:45 +0200 Subject: [PATCH 2440/2442] Bump ra-ap-rustc_index and ra-ap-rustc_abi --- Cargo.lock | 20 +++++--------------- crates/rustc-dependencies/Cargo.toml | 4 ++-- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5189811f4953..29644efb07c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1458,25 +1458,15 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2ea80a299f04a896000ce17b76f3aa1d2fe59f347fbc99c4b8970316ef5a0d" +checksum = "b5f38444d48da534b3bb612713fce9b0aeeffb2e0dfa242764f55482acc5b52d" dependencies = [ "bitflags 1.3.2", - "ra-ap-rustc_index 0.19.0", + "ra-ap-rustc_index", "tracing", ] -[[package]] -name = "ra-ap-rustc_index" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4556489ef652e5eb6cdad6078fff08507badac80bfc1f79085c85a6d8b77ab5c" -dependencies = [ - "arrayvec", - "smallvec", -] - [[package]] name = "ra-ap-rustc_index" version = "0.20.0" @@ -1516,7 +1506,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6b325ee1ec90e4dbd4394913adf4ef32e4fcf2b311ec9563a0fa50cd549af6" dependencies = [ - "ra-ap-rustc_index 0.20.0", + "ra-ap-rustc_index", "ra-ap-rustc_lexer", ] @@ -1639,7 +1629,7 @@ name = "rustc-dependencies" version = "0.0.0" dependencies = [ "ra-ap-rustc_abi", - "ra-ap-rustc_index 0.19.0", + "ra-ap-rustc_index", "ra-ap-rustc_lexer", "ra-ap-rustc_parse_format", ] diff --git a/crates/rustc-dependencies/Cargo.toml b/crates/rustc-dependencies/Cargo.toml index 41bcfd11722c..cd7ec3059365 100644 --- a/crates/rustc-dependencies/Cargo.toml +++ b/crates/rustc-dependencies/Cargo.toml @@ -13,8 +13,8 @@ authors.workspace = true [dependencies] ra-ap-rustc_lexer = { version = "0.20.0" } ra-ap-rustc_parse_format = { version = "0.20.0", default-features = false } -ra-ap-rustc_index = { version = "0.19.0", default-features = false } -ra-ap-rustc_abi = { version = "0.19.0", default-features = false } +ra-ap-rustc_index = { version = "0.20.0", default-features = false } +ra-ap-rustc_abi = { version = "0.20.0", default-features = false } [features] in-rust-tree = [] From fc880be491a372ac71de4e6a1f79290fd5e6a967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sat, 25 Nov 2023 20:38:11 +0200 Subject: [PATCH 2441/2442] Bump chalk --- Cargo.lock | 59 +++++++++++++++++----------------------- crates/hir-ty/Cargo.toml | 8 +++--- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29644efb07c6..b4346972f2a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -160,9 +160,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chalk-derive" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0322d5289ceba3217a03c9af72aa403d87542822b753daa1da32e4b992a4e80" +checksum = "329427f28cd2bddaacd47c4dcd3d7082d315c61fb164394c690fe98c1b6ee9d3" dependencies = [ "proc-macro2", "quote", @@ -172,20 +172,20 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0946cbc6d9136980a24a2dddf1888b5f0aa978dda300a3aa470b55b777b6bf3c" +checksum = "9e1e1659238bd598d0f7dbc5034cf1ff46010a3d6827704c9ed443c8359cb484" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "chalk-derive", "lazy_static", ] [[package]] name = "chalk-recursive" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd93fedbeeadc0cd4d0eb73bd061b621af99f5324a6a518264c8ef5e526e0ec" +checksum = "b3e0bff0ba1bed11407384fcec0353aeb6888901e63cb47d04505ec47adad847" dependencies = [ "chalk-derive", "chalk-ir", @@ -196,15 +196,15 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a254cff72303c58c82df421cfe9465606372b81588923fcf179922b7eaad9a53" +checksum = "eb9c46d501cf83732a91056c0c846ae7a16d6b3c67a6a6bb5e9cc0a2e91563b6" dependencies = [ "chalk-derive", "chalk-ir", "ena", "indexmap 2.1.0", - "itertools 0.10.5", + "itertools", "petgraph", "rustc-hash", "tracing", @@ -487,7 +487,7 @@ dependencies = [ "hir-def", "hir-expand", "hir-ty", - "itertools 0.12.0", + "itertools", "once_cell", "profile", "rustc-hash", @@ -516,7 +516,7 @@ dependencies = [ "hir-expand", "indexmap 2.1.0", "intern", - "itertools 0.12.0", + "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "mbe", @@ -544,7 +544,7 @@ dependencies = [ "expect-test", "hashbrown 0.12.3", "intern", - "itertools 0.12.0", + "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "mbe", @@ -576,7 +576,7 @@ dependencies = [ "hir-def", "hir-expand", "intern", - "itertools 0.12.0", + "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "nohash-hasher", @@ -623,7 +623,7 @@ dependencies = [ "ide-db", "ide-diagnostics", "ide-ssr", - "itertools 0.12.0", + "itertools", "nohash-hasher", "oorandom", "profile", @@ -649,7 +649,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools 0.12.0", + "itertools", "profile", "smallvec", "sourcegen", @@ -668,7 +668,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools 0.12.0", + "itertools", "once_cell", "profile", "smallvec", @@ -690,7 +690,7 @@ dependencies = [ "fst", "hir", "indexmap 2.1.0", - "itertools 0.12.0", + "itertools", "limit", "line-index 0.1.0-pre.1", "memchr", @@ -721,7 +721,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools 0.12.0", + "itertools", "once_cell", "profile", "serde_json", @@ -740,7 +740,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools 0.12.0", + "itertools", "nohash-hasher", "parser", "stdx", @@ -819,15 +819,6 @@ dependencies = [ "triomphe", ] -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.0" @@ -941,7 +932,7 @@ dependencies = [ "crossbeam-channel", "ide", "ide-db", - "itertools 0.12.0", + "itertools", "proc-macro-api", "project-model", "tracing", @@ -1393,7 +1384,7 @@ dependencies = [ "cargo_metadata", "cfg", "expect-test", - "itertools 0.12.0", + "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "paths", "profile", @@ -1578,7 +1569,7 @@ dependencies = [ "ide", "ide-db", "ide-ssr", - "itertools 0.12.0", + "itertools", "load-cargo", "lsp-server 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "lsp-types", @@ -1855,7 +1846,7 @@ dependencies = [ "either", "expect-test", "indexmap 2.1.0", - "itertools 0.12.0", + "itertools", "once_cell", "parser", "proc-macro2", @@ -1889,7 +1880,7 @@ dependencies = [ name = "text-edit" version = "0.0.0" dependencies = [ - "itertools 0.12.0", + "itertools", "text-size", ] diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index f2d2451511f7..bbcb76a43ffe 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -23,10 +23,10 @@ oorandom = "11.1.3" tracing.workspace = true rustc-hash = "1.1.0" scoped-tls = "1.0.0" -chalk-solve = { version = "0.94.0", default-features = false } -chalk-ir = "0.94.0" -chalk-recursive = { version = "0.94.0", default-features = false } -chalk-derive = "0.94.0" +chalk-solve = { version = "0.95.0", default-features = false } +chalk-ir = "0.95.0" +chalk-recursive = { version = "0.95.0", default-features = false } +chalk-derive = "0.95.0" la-arena.workspace = true once_cell = "1.17.0" triomphe.workspace = true From 3ccde009cbef1cc3153bb0542b86320b34f974a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sun, 26 Nov 2023 13:06:36 +0200 Subject: [PATCH 2442/2442] Switch to our own salsa fork --- Cargo.lock | 166 ++++++++++++-------------------------- crates/base-db/Cargo.toml | 2 +- 2 files changed, 52 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b4346972f2a5..5a8d971c3d4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,8 +72,8 @@ dependencies = [ "cfg", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "profile", + "rust-analyzer-salsa", "rustc-hash", - "salsa", "stdx", "syntax", "test-utils", @@ -166,7 +166,7 @@ checksum = "329427f28cd2bddaacd47c4dcd3d7082d315c61fb164394c690fe98c1b6ee9d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", "synstructure", ] @@ -203,7 +203,7 @@ dependencies = [ "chalk-derive", "chalk-ir", "ena", - "indexmap 2.1.0", + "indexmap", "itertools", "petgraph", "rustc-hash", @@ -309,7 +309,7 @@ dependencies = [ "hashbrown 0.12.3", "lock_api", "once_cell", - "parking_lot_core 0.9.6", + "parking_lot_core", ] [[package]] @@ -320,7 +320,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -460,12 +460,9 @@ checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "heck" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -514,7 +511,7 @@ dependencies = [ "fst", "hashbrown 0.12.3", "hir-expand", - "indexmap 2.1.0", + "indexmap", "intern", "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -689,7 +686,7 @@ dependencies = [ "expect-test", "fst", "hir", - "indexmap 2.1.0", + "indexmap", "itertools", "limit", "line-index 0.1.0-pre.1", @@ -760,16 +757,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.1.0" @@ -800,15 +787,6 @@ dependencies = [ "libc", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "intern" version = "0.0.0" @@ -1187,17 +1165,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -1205,21 +1172,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.6", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -1289,7 +1242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap", ] [[package]] @@ -1477,7 +1430,7 @@ checksum = "3d69f9f6af58124f2da0cb8b0c3d8494e0d883a5fe0c6732258bde81ac5a87cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", "synstructure", ] @@ -1579,8 +1532,8 @@ dependencies = [ "nohash-hasher", "num_cpus", "oorandom", - "parking_lot 0.12.1", - "parking_lot_core 0.9.6", + "parking_lot", + "parking_lot_core", "parser", "proc-macro-api", "profile", @@ -1609,6 +1562,35 @@ dependencies = [ "xshell", ] +[[package]] +name = "rust-analyzer-salsa" +version = "0.17.0-pre.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca92b657d614d076800aa7bf5d5ba33564e71fa7f16cd79eacdfe301a50ab1c" +dependencies = [ + "crossbeam-utils", + "indexmap", + "lock_api", + "log", + "oorandom", + "parking_lot", + "rust-analyzer-salsa-macros", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "rust-analyzer-salsa-macros" +version = "0.17.0-pre.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b190359266d293f2ee13eaa502a766dc8b77b63fbaa5d460d24fd0210675ceef" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1637,35 +1619,6 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" -[[package]] -name = "salsa" -version = "0.17.0-pre.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b223dccb46c32753144d0b51290da7230bb4aedcd8379d6b4c9a474c18bf17a" -dependencies = [ - "crossbeam-utils", - "indexmap 1.9.3", - "lock_api", - "log", - "oorandom", - "parking_lot 0.11.2", - "rustc-hash", - "salsa-macros", - "smallvec", -] - -[[package]] -name = "salsa-macros" -version = "0.17.0-pre.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6c2e352df550bf019da7b16164ed2f7fa107c39653d1311d1bba42d1582ff7" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "same-file" version = "1.0.6" @@ -1722,7 +1675,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -1731,7 +1684,7 @@ version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "indexmap 2.1.0", + "indexmap", "itoa", "ryu", "serde", @@ -1745,7 +1698,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -1804,17 +1757,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.39" @@ -1834,7 +1776,7 @@ checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", "unicode-xid", ] @@ -1845,7 +1787,7 @@ dependencies = [ "cov-mark", "either", "expect-test", - "indexmap 2.1.0", + "indexmap", "itertools", "once_cell", "parser", @@ -1907,7 +1849,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -2008,7 +1950,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -2118,12 +2060,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f91c8b21fbbaa18853c3d0801c78f4fc94cdb976699bb03e832e75f7fd22f0" -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - [[package]] name = "unicode-xid" version = "0.2.4" @@ -2159,7 +2095,7 @@ name = "vfs" version = "0.0.0" dependencies = [ "fst", - "indexmap 2.1.0", + "indexmap", "nohash-hasher", "paths", "rustc-hash", diff --git a/crates/base-db/Cargo.toml b/crates/base-db/Cargo.toml index 171c113a950d..5ad88f65188e 100644 --- a/crates/base-db/Cargo.toml +++ b/crates/base-db/Cargo.toml @@ -12,7 +12,7 @@ rust-version.workspace = true doctest = false [dependencies] -salsa = "0.17.0-pre.2" +rust-analyzer-salsa = "0.17.0-pre.3" rustc-hash = "1.1.0" triomphe.workspace = true