From 1883d1f14146959cfa9cdf1ed43e5d1ad013e07e Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sun, 7 Aug 2022 20:39:11 +0530 Subject: [PATCH 01/53] 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 97ea5c456a635..6715823f1ffb2 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 196f389a708d5e0002a1d3b4e1059d43dc4542fb Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Mon, 8 Aug 2022 16:40:29 +0530 Subject: [PATCH 02/53] 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 35c8708955a77..1b4f4ed04ac1d 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 03/53] 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 45f631936d2ab..a2181a6bf41c0 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 0d01f6d0aba34..ed7e920fd2b83 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 ad7a1ed8cc9ba44c6a294317a2289a0b6fd75219 Mon Sep 17 00:00:00 2001 From: Dominik Gschwind Date: Tue, 16 Aug 2022 17:30:17 +0200 Subject: [PATCH 04/53] 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 239f66bcb7e79..3ec321ad3714f 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 93a88ab58ef82..9b64fccccd249 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 83319755da73a..bdb9ade9c8569 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 87b779756cb52ed27d4e5b1cdec28544b07f43d7 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sat, 20 Aug 2022 13:28:43 +0530 Subject: [PATCH 05/53] make impl and trait inactive diagnostics work --- crates/hir-def/src/data.rs | 49 ++++++++++++------- crates/hir-def/src/db.rs | 8 ++- crates/hir/src/lib.rs | 11 +++++ .../src/handlers/inactive_code.rs | 1 - 4 files changed, 49 insertions(+), 20 deletions(-) diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 1b4f4ed04ac1d..891104cbb37f0 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -210,6 +210,10 @@ pub struct TraitData { impl TraitData { pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc { + db.trait_data_with_diagnostics(tr).0 + } + + pub(crate) fn trait_data_with_diagnostics_query(db: &dyn DefDatabase, tr: TraitId) -> (Arc, Arc>) { let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db); let item_tree = tree_id.item_tree(db); let tr_def = &item_tree[tree_id.value]; @@ -229,17 +233,20 @@ impl TraitData { 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) = collector.finish(); - - Arc::new(TraitData { - name, - attribute_calls, - items, - is_auto, - is_unsafe, - visibility, - skip_array_during_method_dispatch, - }) + let (items, attribute_calls, diagnostics) = collector.finish(); + + ( + Arc::new(TraitData { + name, + attribute_calls, + items, + is_auto, + is_unsafe, + visibility, + skip_array_during_method_dispatch, + }), + Arc::new(diagnostics) + ) } pub fn associated_types(&self) -> impl Iterator + '_ { @@ -280,7 +287,11 @@ pub struct ImplData { impl ImplData { pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc { - let _p = profile::span("impl_data_query"); + db.impl_data_with_diagnostics(id).0 + } + + pub(crate) fn impl_data_with_diagnostics_query(db: &dyn DefDatabase, id: ImplId) -> (Arc, Arc>) { + let _p = profile::span("impl_data_with_diagnostics_query"); let ItemLoc { container: module_id, id: tree_id } = id.lookup(db); let item_tree = tree_id.item_tree(db); @@ -293,10 +304,10 @@ impl ImplData { AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::ImplId(id)); collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items); - let (items, attribute_calls) = collector.finish(); + let (items, attribute_calls, diagnostics) = collector.finish(); 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, attribute_calls }), Arc::new(diagnostics)) } pub fn attribute_calls(&self) -> impl Iterator, MacroCallId)> + '_ { @@ -437,6 +448,7 @@ struct AssocItemCollector<'a> { db: &'a dyn DefDatabase, module_id: ModuleId, def_map: Arc, + inactive_diagnostics: Vec, container: ItemContainerId, expander: Expander, @@ -459,15 +471,17 @@ impl<'a> AssocItemCollector<'a> { expander: Expander::new(db, file_id, module_id), items: Vec::new(), attr_calls: Vec::new(), + inactive_diagnostics: Vec::new(), } } fn finish( self, - ) -> (Vec<(Name, AssocItemId)>, Option, MacroCallId)>>>) { + ) -> (Vec<(Name, AssocItemId)>, Option, MacroCallId)>>>, Vec) { ( self.items, if self.attr_calls.is_empty() { None } else { Some(Box::new(self.attr_calls)) }, + self.inactive_diagnostics ) } @@ -479,13 +493,12 @@ 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.inactive_diagnostics.push(DefDiagnostic::unconfigured_code( self.module_id.local_id, - InFile::new(tree_id.file_id(), item.ast_id(&item_tree).upcast()), + InFile::new(self.expander.current_file_id(), item.ast_id(&item_tree).upcast()), attrs.cfg().unwrap(), self.expander.cfg_options().clone() )); - dbg!("Ignoring assoc item!"); continue; } diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index df6dcb024b5ea..2f5ee80cd8584 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -20,7 +20,7 @@ use crate::{ intern::Interned, item_tree::{AttrOwner, ItemTree}, lang_item::{LangItemTarget, LangItems}, - nameres::DefMap, + nameres::{DefMap, diagnostics::DefDiagnostic}, visibility::{self, Visibility}, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, @@ -106,9 +106,15 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast { #[salsa::invoke(ImplData::impl_data_query)] fn impl_data(&self, e: ImplId) -> Arc; + #[salsa::invoke(ImplData::impl_data_with_diagnostics_query)] + fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc, Arc>); + #[salsa::invoke(TraitData::trait_data_query)] fn trait_data(&self, e: TraitId) -> Arc; + #[salsa::invoke(TraitData::trait_data_with_diagnostics_query)] + fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc, Arc>); + #[salsa::invoke(TypeAliasData::type_alias_data_query)] fn type_alias_data(&self, e: TypeAliasId) -> Arc; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8f984210e1176..45bb057d31a69 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -511,6 +511,7 @@ impl Module { .collect() } + /// Fills `acc` with the module's diagnostics. pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { let _p = profile::span("Module::diagnostics").detail(|| { format!("{:?}", self.name(db).map_or("".into(), |name| name.to_string())) @@ -530,12 +531,22 @@ impl Module { if def_map[m.id.local_id].origin.is_inline() { m.diagnostics(db, acc) } + }, + ModuleDef::Trait(t) => { + for diag in db.trait_data_with_diagnostics(t.id).1.iter() { + emit_def_diagnostic(db, acc, diag); + } + acc.extend(decl.diagnostics(db)) } _ => acc.extend(decl.diagnostics(db)), } } for impl_def in self.impl_defs(db) { + for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() { + emit_def_diagnostic(db, acc, diag); + } + for item in impl_def.items(db) { let def: DefWithBody = match item { AssocItem::Function(it) => it.into(), diff --git a/crates/ide-diagnostics/src/handlers/inactive_code.rs b/crates/ide-diagnostics/src/handlers/inactive_code.rs index 6715823f1ffb2..18fd1c644a168 100644 --- a/crates/ide-diagnostics/src/handlers/inactive_code.rs +++ b/crates/ide-diagnostics/src/handlers/inactive_code.rs @@ -106,7 +106,6 @@ fn f() { #[test] fn inactive_assoc_item() { - // FIXME these currently don't work, hence the * check( r#" struct Foo; From 8f87fcb179421369eee4fdbaae8f25de8a6e9ed7 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sat, 20 Aug 2022 13:30:25 +0530 Subject: [PATCH 06/53] remove push_diagnostic methods weren't used in the end --- crates/hir-def/src/nameres.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index a2181a6bf41c0..45f631936d2ab 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -511,14 +511,6 @@ 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 } From 23c00ed50d327918b0f9fb59345ed87cfe7584a9 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sat, 20 Aug 2022 13:44:01 +0530 Subject: [PATCH 07/53] fix: formatting --- crates/hir-def/src/data.rs | 34 +++++++++++++++++++++++++--------- crates/hir-def/src/db.rs | 5 +++-- crates/hir/src/lib.rs | 2 +- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 891104cbb37f0..631ae3cf11fa7 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, InFile}; +use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroDefKind}; use smallvec::SmallVec; use syntax::ast; @@ -12,7 +12,10 @@ use crate::{ db::DefDatabase, intern::Interned, item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId}, - nameres::{attr_resolution::ResolvedAttr, proc_macro::ProcMacroKind, DefMap, diagnostics::DefDiagnostic}, + nameres::{ + attr_resolution::ResolvedAttr, diagnostics::DefDiagnostic, proc_macro::ProcMacroKind, + DefMap, + }, type_ref::{TraitRef, TypeBound, TypeRef}, visibility::RawVisibility, AssocItemId, AstIdWithPath, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, @@ -213,7 +216,10 @@ impl TraitData { db.trait_data_with_diagnostics(tr).0 } - pub(crate) fn trait_data_with_diagnostics_query(db: &dyn DefDatabase, tr: TraitId) -> (Arc, Arc>) { + pub(crate) fn trait_data_with_diagnostics_query( + db: &dyn DefDatabase, + tr: TraitId, + ) -> (Arc, Arc>) { let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db); let item_tree = tree_id.item_tree(db); let tr_def = &item_tree[tree_id.value]; @@ -245,7 +251,7 @@ impl TraitData { visibility, skip_array_during_method_dispatch, }), - Arc::new(diagnostics) + Arc::new(diagnostics), ) } @@ -290,7 +296,10 @@ impl ImplData { db.impl_data_with_diagnostics(id).0 } - pub(crate) fn impl_data_with_diagnostics_query(db: &dyn DefDatabase, id: ImplId) -> (Arc, Arc>) { + pub(crate) fn impl_data_with_diagnostics_query( + db: &dyn DefDatabase, + id: ImplId, + ) -> (Arc, Arc>) { let _p = profile::span("impl_data_with_diagnostics_query"); let ItemLoc { container: module_id, id: tree_id } = id.lookup(db); @@ -307,7 +316,10 @@ impl ImplData { let (items, attribute_calls, diagnostics) = collector.finish(); let items = items.into_iter().map(|(_, item)| item).collect(); - (Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls }), Arc::new(diagnostics)) + ( + Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls }), + Arc::new(diagnostics), + ) } pub fn attribute_calls(&self) -> impl Iterator, MacroCallId)> + '_ { @@ -477,11 +489,15 @@ impl<'a> AssocItemCollector<'a> { fn finish( self, - ) -> (Vec<(Name, AssocItemId)>, Option, MacroCallId)>>>, Vec) { + ) -> ( + Vec<(Name, AssocItemId)>, + Option, MacroCallId)>>>, + Vec, + ) { ( self.items, if self.attr_calls.is_empty() { None } else { Some(Box::new(self.attr_calls)) }, - self.inactive_diagnostics + self.inactive_diagnostics, ) } @@ -497,7 +513,7 @@ impl<'a> AssocItemCollector<'a> { self.module_id.local_id, InFile::new(self.expander.current_file_id(), item.ast_id(&item_tree).upcast()), attrs.cfg().unwrap(), - self.expander.cfg_options().clone() + self.expander.cfg_options().clone(), )); continue; } diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 2f5ee80cd8584..40b2f734b7117 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -20,7 +20,7 @@ use crate::{ intern::Interned, item_tree::{AttrOwner, ItemTree}, lang_item::{LangItemTarget, LangItems}, - nameres::{DefMap, diagnostics::DefDiagnostic}, + nameres::{diagnostics::DefDiagnostic, DefMap}, visibility::{self, Visibility}, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, @@ -113,7 +113,8 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast { fn trait_data(&self, e: TraitId) -> Arc; #[salsa::invoke(TraitData::trait_data_with_diagnostics_query)] - fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc, Arc>); + fn trait_data_with_diagnostics(&self, tr: TraitId) + -> (Arc, Arc>); #[salsa::invoke(TypeAliasData::type_alias_data_query)] fn type_alias_data(&self, e: TypeAliasId) -> Arc; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 45bb057d31a69..cc9f3180a98a7 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -531,7 +531,7 @@ impl Module { if def_map[m.id.local_id].origin.is_inline() { m.diagnostics(db, acc) } - }, + } ModuleDef::Trait(t) => { for diag in db.trait_data_with_diagnostics(t.id).1.iter() { emit_def_diagnostic(db, acc, diag); From 76e5d8835cf72c55e0d91b2da08f367cde62ccf7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 20 Aug 2022 15:13:34 +0200 Subject: [PATCH 08/53] Fix hover and focus display for search results on ayu theme --- src/librustdoc/html/static/css/themes/ayu.css | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 4dfb64abbebe8..b88a2a7eee483 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -89,12 +89,13 @@ pre, .rustdoc.source .example-wrap { } .search-results a:hover { - background-color: #777; + color: #fff !important; + background-color: #3c3c3c; } .search-results a:focus { - color: #000 !important; - background-color: #c6afb3; + color: #fff !important; + background-color: #3c3c3c; } .search-results a { color: #0096cf; From f7cce2f959303c23e12019f673b7cf2a8f6a4486 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 20 Aug 2022 15:13:53 +0200 Subject: [PATCH 09/53] Extend GUI test for search results colors --- src/test/rustdoc-gui/search-result-color.goml | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/test/rustdoc-gui/search-result-color.goml b/src/test/rustdoc-gui/search-result-color.goml index 9a49ae2c6b853..5e328133e62a1 100644 --- a/src/test/rustdoc-gui/search-result-color.goml +++ b/src/test/rustdoc-gui/search-result-color.goml @@ -29,6 +29,23 @@ assert-css: ( {"color": "rgb(120, 135, 151)"}, ) +// Checking the `` container. +assert-css: ( + "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", + {"color": "rgb(0, 150, 207)", "background-color": "rgba(0, 0, 0, 0)"}, +) + +// Checking color and background on hover. +move-cursor-to: "//*[@class='desc']//*[text()='Just a normal struct.']" +assert-css: ( + "//*[@class='result-name']/*[text()='test_docs::']", + {"color": "rgb(255, 255, 255)"}, +) +assert-css: ( + "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", + {"color": "rgb(255, 255, 255)", "background-color": "rgb(60, 60, 60)"}, +) + // Dark theme local-storage: { "rustdoc-theme": "dark", @@ -54,6 +71,23 @@ assert-css: ( {"color": "rgb(221, 221, 221)"}, ) +// Checking the `` container. +assert-css: ( + "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", + {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"}, +) + +// Checking color and background on hover. +move-cursor-to: "//*[@class='desc']//*[text()='Just a normal struct.']" +assert-css: ( + "//*[@class='result-name']/*[text()='test_docs::']", + {"color": "rgb(221, 221, 221)"}, +) +assert-css: ( + "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(119, 119, 119)"}, +) + // Light theme local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} reload: @@ -75,6 +109,23 @@ assert-css: ( {"color": "rgb(0, 0, 0)"}, ) +// Checking the `` container. +assert-css: ( + "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", + {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"}, +) + +// Checking color and background on hover. +move-cursor-to: "//*[@class='desc']//*[text()='Just a normal struct.']" +assert-css: ( + "//*[@class='result-name']/*[text()='test_docs::']", + {"color": "rgb(0, 0, 0)"}, +) +assert-css: ( + "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(221, 221, 221)"}, +) + // Check the alias more specifically in the dark theme. goto: file://|DOC_PATH|/test_docs/index.html // We set the theme so we're sure that the correct values will be used, whatever the computer From ac8cb8ce3b81b4f4559809a3aec50cb0799c126f Mon Sep 17 00:00:00 2001 From: Dominik Gschwind Date: Sun, 21 Aug 2022 22:48:53 +0200 Subject: [PATCH 10/53] Expect the test to panic by catching the unwind --- crates/hir-ty/src/tests/regression.rs | 13 ++++++++++--- crates/hir-ty/src/utils.rs | 7 +++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 9b64fccccd249..582e2338efedb 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -1528,9 +1528,14 @@ unsafe impl Storage for InlineStorage { #[test] fn gat_crash_3() { + // FIXME: This test currently crashes rust analyzer in a debug build but not in a + // release build (i.e. for the user). With the assumption that tests will always be run + // in debug mode, we catch the unwind and expect that it panicked. See the + // [`crate::utils::generics`] function for more information. cov_mark::check!(ignore_gats); - check_no_mismatches( - r#" + std::panic::catch_unwind(|| { + check_no_mismatches( + r#" trait Collection { type Item; type Member: Collection; @@ -1544,7 +1549,9 @@ impl Collection for ConstGen { type Member = ConstGen; } "#, - ); + ); + }) + .expect_err("must panic"); } #[test] diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index bdb9ade9c8569..d6638db028511 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -183,9 +183,12 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { 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 + // (#11769) + // + // 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. + // Avoids that by disabling GATs when the parent (i.e. `impl` block) has + // const generics (#12193). // // Chalk expects the inner associated type's parameters to come // *before*, not after the trait's generics as we've always done it. From 2c0d2e719dcc9e714d11129f3609091e897a8116 Mon Sep 17 00:00:00 2001 From: wuaoxiang Date: Mon, 22 Aug 2022 11:25:21 +0800 Subject: [PATCH 11/53] internal: remove unnecessary stream writer try_clone in lsp-server --- lib/lsp-server/src/socket.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lsp-server/src/socket.rs b/lib/lsp-server/src/socket.rs index 4a59c4c0fad05..36d728456f77c 100644 --- a/lib/lsp-server/src/socket.rs +++ b/lib/lsp-server/src/socket.rs @@ -15,7 +15,7 @@ pub(crate) fn socket_transport( stream: TcpStream, ) -> (Sender, Receiver, IoThreads) { let (reader_receiver, reader) = make_reader(stream.try_clone().unwrap()); - let (writer_sender, writer) = make_write(stream.try_clone().unwrap()); + let (writer_sender, writer) = make_write(stream); let io_threads = make_io_threads(reader, writer); (writer_sender, reader_receiver, io_threads) } From f9d1b26a96144fecd14c1bf61d9fce1060956e4c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 11 Aug 2022 17:12:25 +0200 Subject: [PATCH 12/53] Replace crossbeam with std's scoped threads --- Cargo.lock | 25 ------------------------- crates/proc-macro-srv/Cargo.toml | 1 - crates/proc-macro-srv/src/lib.rs | 17 ++++++----------- 3 files changed, 6 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a61ea1c92414..ff9948d03cb9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -247,20 +247,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - [[package]] name = "crossbeam-channel" version = "0.5.6" @@ -296,16 +282,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "crossbeam-queue" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.11" @@ -1178,7 +1154,6 @@ dependencies = [ name = "proc-macro-srv" version = "0.0.0" dependencies = [ - "crossbeam", "expect-test", "libloading", "mbe", diff --git a/crates/proc-macro-srv/Cargo.toml b/crates/proc-macro-srv/Cargo.toml index 5746eac0b3790..e39026ac70bfd 100644 --- a/crates/proc-macro-srv/Cargo.toml +++ b/crates/proc-macro-srv/Cargo.toml @@ -24,7 +24,6 @@ tt = { path = "../tt", version = "0.0.0" } mbe = { path = "../mbe", version = "0.0.0" } paths = { path = "../paths", version = "0.0.0" } proc-macro-api = { path = "../proc-macro-api", version = "0.0.0" } -crossbeam = "0.8.1" [dev-dependencies] expect-test = "1.4.0" diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index 4c205b9cadac3..3679bfc43c980 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -26,6 +26,7 @@ use std::{ ffi::OsString, fs, path::{Path, PathBuf}, + thread, time::SystemTime, }; @@ -65,18 +66,16 @@ impl ProcMacroSrv { let macro_body = task.macro_body.to_subtree(); let attributes = task.attributes.map(|it| it.to_subtree()); - // FIXME: replace this with std's scoped threads once they stabilize - // (then remove dependency on crossbeam) - let result = crossbeam::scope(|s| { - let res = match s - .builder() + let result = thread::scope(|s| { + let thread = thread::Builder::new() .stack_size(EXPANDER_STACK_SIZE) .name(task.macro_name.clone()) - .spawn(|_| { + .spawn_scoped(s, || { expander .expand(&task.macro_name, ¯o_body, attributes.as_ref()) .map(|it| FlatTree::new(&it)) - }) { + }); + let res = match thread { Ok(handle) => handle.join(), Err(e) => std::panic::resume_unwind(Box::new(e)), }; @@ -86,10 +85,6 @@ impl ProcMacroSrv { Err(e) => std::panic::resume_unwind(e), } }); - let result = match result { - Ok(result) => result, - Err(e) => std::panic::resume_unwind(e), - }; prev_env.rollback(); From b19f78b022dfbbc5699ba4de9fd967fe8da628a0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 22 Aug 2022 17:13:49 +0200 Subject: [PATCH 13/53] Remove auto-config patching from the VSCode client --- editors/code/src/client.ts | 6 --- editors/code/src/config.ts | 94 -------------------------------------- 2 files changed, 100 deletions(-) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 27ab31db8db4f..719d2734643f4 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -5,7 +5,6 @@ import * as Is from "vscode-languageclient/lib/common/utils/is"; import { assert } from "./util"; import { WorkspaceEdit } from "vscode"; import { Workspace } from "./ctx"; -import { updateConfig } from "./config"; import { substituteVariablesInEnv } from "./config"; import { outputChannel, traceOutputChannel } from "./main"; import { randomUUID } from "crypto"; @@ -86,11 +85,6 @@ export async function createClient( let initializationOptions = vscode.workspace.getConfiguration("rust-analyzer"); - // Update outdated user configs - await updateConfig(initializationOptions).catch((err) => { - void vscode.window.showErrorMessage(`Failed updating old config keys: ${err.message}`); - }); - if (workspace.kind === "Detached Files") { initializationOptions = { detachedFiles: workspace.files.map((file) => file.uri.fsPath), diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index b83582a344a98..7e6d4ac297040 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -175,100 +175,6 @@ export class Config { } } -export async function updateConfig(config: vscode.WorkspaceConfiguration) { - const renames = [ - ["assist.allowMergingIntoGlobImports", "imports.merge.glob"], - ["assist.exprFillDefault", "assist.expressionFillDefault"], - ["assist.importEnforceGranularity", "imports.granularity.enforce"], - ["assist.importGranularity", "imports.granularity.group"], - ["assist.importMergeBehavior", "imports.granularity.group"], - ["assist.importMergeBehaviour", "imports.granularity.group"], - ["assist.importGroup", "imports.group.enable"], - ["assist.importPrefix", "imports.prefix"], - ["primeCaches.enable", "cachePriming.enable"], - ["cache.warmup", "cachePriming.enable"], - ["cargo.loadOutDirsFromCheck", "cargo.buildScripts.enable"], - ["cargo.runBuildScripts", "cargo.buildScripts.enable"], - ["cargo.runBuildScriptsCommand", "cargo.buildScripts.overrideCommand"], - ["cargo.useRustcWrapperForBuildScripts", "cargo.buildScripts.useRustcWrapper"], - ["completion.snippets", "completion.snippets.custom"], - ["diagnostics.enableExperimental", "diagnostics.experimental.enable"], - ["experimental.procAttrMacros", "procMacro.attributes.enable"], - ["highlighting.strings", "semanticHighlighting.strings.enable"], - ["highlightRelated.breakPoints", "highlightRelated.breakPoints.enable"], - ["highlightRelated.exitPoints", "highlightRelated.exitPoints.enable"], - ["highlightRelated.yieldPoints", "highlightRelated.yieldPoints.enable"], - ["highlightRelated.references", "highlightRelated.references.enable"], - ["hover.documentation", "hover.documentation.enable"], - ["hover.linksInHover", "hover.links.enable"], - ["hoverActions.linksInHover", "hover.links.enable"], - ["hoverActions.debug", "hover.actions.debug.enable"], - ["hoverActions.enable", "hover.actions.enable.enable"], - ["hoverActions.gotoTypeDef", "hover.actions.gotoTypeDef.enable"], - ["hoverActions.implementations", "hover.actions.implementations.enable"], - ["hoverActions.references", "hover.actions.references.enable"], - ["hoverActions.run", "hover.actions.run.enable"], - ["inlayHints.chainingHints", "inlayHints.chainingHints.enable"], - ["inlayHints.closureReturnTypeHints", "inlayHints.closureReturnTypeHints.enable"], - ["inlayHints.hideNamedConstructorHints", "inlayHints.typeHints.hideNamedConstructor"], - ["inlayHints.parameterHints", "inlayHints.parameterHints.enable"], - ["inlayHints.reborrowHints", "inlayHints.reborrowHints.enable"], - ["inlayHints.typeHints", "inlayHints.typeHints.enable"], - ["lruCapacity", "lru.capacity"], - ["runnables.cargoExtraArgs", "runnables.extraArgs"], - ["runnables.overrideCargo", "runnables.command"], - ["rustcSource", "rustc.source"], - ["rustfmt.enableRangeFormatting", "rustfmt.rangeFormatting.enable"], - ]; - - for (const [oldKey, newKey] of renames) { - const inspect = config.inspect(oldKey); - if (inspect !== undefined) { - const valMatrix = [ - { - val: inspect.globalValue, - langVal: inspect.globalLanguageValue, - target: vscode.ConfigurationTarget.Global, - }, - { - val: inspect.workspaceFolderValue, - langVal: inspect.workspaceFolderLanguageValue, - target: vscode.ConfigurationTarget.WorkspaceFolder, - }, - { - val: inspect.workspaceValue, - langVal: inspect.workspaceLanguageValue, - target: vscode.ConfigurationTarget.Workspace, - }, - ]; - for (const { val, langVal, target } of valMatrix) { - const patch = (val: unknown) => { - // some of the updates we do only append "enable" or "custom" - // that means on the next run we would find these again, but as objects with - // these properties causing us to destroy the config - // so filter those already updated ones out - return ( - val !== undefined && - !( - typeof val === "object" && - val !== null && - (oldKey === "completion.snippets" || !val.hasOwnProperty("custom")) - ) - ); - }; - if (patch(val)) { - await config.update(newKey, val, target, false); - await config.update(oldKey, undefined, target, false); - } - if (patch(langVal)) { - await config.update(newKey, langVal, target, true); - await config.update(oldKey, undefined, target, true); - } - } - } - } -} - export function substituteVariablesInEnv(env: Env): Env { const missingDeps = new Set(); // vscode uses `env:ENV_NAME` for env vars resolution, and it's easier From 2abb78d06d958ec9ce6c63e11bbeb9d5e273513b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 22 Aug 2022 17:42:33 +0200 Subject: [PATCH 14/53] Pop an error notification when flycheck can't be restarted --- crates/flycheck/src/lib.rs | 10 ++++++---- crates/rust-analyzer/src/main_loop.rs | 7 +++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index c22945c81fcb9..d9f4ef5b7ff57 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -125,6 +125,7 @@ pub enum Progress { DidCheckCrate(String), DidFinish(io::Result<()>), DidCancel, + DidFailToRestart(String), } enum Restart { @@ -193,10 +194,11 @@ impl FlycheckActor { self.progress(Progress::DidStart); } Err(error) => { - tracing::error!( - command = ?self.check_command(), - %error, "failed to restart flycheck" - ); + self.progress(Progress::DidFailToRestart(format!( + "Failed to run the following command: {:?} error={}", + self.check_command(), + error + ))); } } } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index f187547019a13..122aba2f7d926 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -529,6 +529,13 @@ impl GlobalState { } flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)), flycheck::Progress::DidCancel => (Progress::End, None), + flycheck::Progress::DidFailToRestart(err) => { + self.show_and_log_error( + "cargo check failed".to_string(), + Some(err.to_string()), + ); + return; + } flycheck::Progress::DidFinish(result) => { if let Err(err) = result { self.show_and_log_error( From 50ecb09da460b58d1f62a2e0b8f7b4b52aa76139 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Fri, 10 Jun 2022 21:29:04 -0400 Subject: [PATCH 15/53] feat: emit SCIP via rust-analyzer --- Cargo.lock | 50 +++ crates/ide/src/lib.rs | 2 +- crates/ide/src/moniker.rs | 131 +++++++- crates/rust-analyzer/Cargo.toml | 1 + crates/rust-analyzer/src/bin/main.rs | 1 + crates/rust-analyzer/src/cli.rs | 1 + crates/rust-analyzer/src/cli/flags.rs | 10 + crates/rust-analyzer/src/cli/scip.rs | 448 ++++++++++++++++++++++++++ 8 files changed, 630 insertions(+), 14 deletions(-) create mode 100644 crates/rust-analyzer/src/cli/scip.rs diff --git a/Cargo.lock b/Cargo.lock index ff9948d03cb9f..783345ce7a458 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1229,6 +1229,26 @@ dependencies = [ "tracing", ] +[[package]] +name = "protobuf" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee4a7d8b91800c8f167a6268d1a1026607368e1adc84e98fe044aeb905302f7" +dependencies = [ + "once_cell", + "protobuf-support", + "thiserror", +] + +[[package]] +name = "protobuf-support" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca157fe12fc7ee2e315f2f735e27df41b3d97cdd70ea112824dac1ffb08ee1c" +dependencies = [ + "thiserror", +] + [[package]] name = "pulldown-cmark" version = "0.9.2" @@ -1360,6 +1380,7 @@ dependencies = [ "project-model", "rayon", "rustc-hash", + "scip", "serde", "serde_json", "sourcegen", @@ -1446,6 +1467,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scip" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bfbb10286f69fad7c78db71004b7839bf957788359fe0c479f029f9849136b" +dependencies = [ + "protobuf", +] + [[package]] name = "scoped-tls" version = "1.0.0" @@ -1631,6 +1661,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a" +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.4" diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index dd108fa799970..2b2d3f86a2921 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -87,7 +87,7 @@ pub use crate::{ }, join_lines::JoinLinesConfig, markup::Markup, - moniker::{MonikerKind, MonikerResult, PackageInformation}, + moniker::{MonikerDescriptorKind, MonikerKind, MonikerResult, PackageInformation}, move_item::Direction, navigation_target::NavigationTarget, prime_caches::ParallelPrimeCachesProgress, diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 4f758967b4619..600a526300c76 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -13,17 +13,39 @@ use syntax::{AstNode, SyntaxKind::*, T}; use crate::{doc_links::token_as_doc_comment, RangeInfo}; +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum MonikerDescriptorKind { + Namespace, + Type, + Term, + Method, + TypeParameter, + Parameter, + Macro, + Meta, +} + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct MonikerDescriptor { + pub name: Name, + pub desc: MonikerDescriptorKind, +} + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MonikerIdentifier { - crate_name: String, - path: Vec, + pub crate_name: String, + pub description: Vec, } impl ToString for MonikerIdentifier { fn to_string(&self) -> String { match self { - MonikerIdentifier { path, crate_name } => { - format!("{}::{}", crate_name, path.iter().map(|x| x.to_string()).join("::")) + MonikerIdentifier { description, crate_name } => { + format!( + "{}::{}", + crate_name, + description.iter().map(|x| x.name.to_string()).join("::") + ) } } } @@ -42,6 +64,12 @@ pub struct MonikerResult { pub package_information: PackageInformation, } +impl MonikerResult { + pub fn from_def(db: &RootDatabase, def: Definition, from_crate: Crate) -> Option { + def_to_moniker(db, def, from_crate) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct PackageInformation { pub name: String, @@ -105,13 +133,23 @@ pub(crate) fn def_to_moniker( def: Definition, from_crate: Crate, ) -> Option { - if matches!(def, Definition::GenericParam(_) | Definition::SelfType(_) | Definition::Local(_)) { + if matches!( + def, + Definition::GenericParam(_) + | Definition::Label(_) + | Definition::DeriveHelper(_) + | Definition::BuiltinAttr(_) + | Definition::ToolModule(_) + ) { return None; } + let module = def.module(db)?; let krate = module.krate(); - let mut path = vec![]; - path.extend(module.path_to_root(db).into_iter().filter_map(|x| x.name(db))); + let mut description = vec![]; + description.extend(module.path_to_root(db).into_iter().filter_map(|x| { + Some(MonikerDescriptor { name: x.name(db)?, desc: MonikerDescriptorKind::Namespace }) + })); // Handle associated items within a trait if let Some(assoc) = def.as_assoc_item(db) { @@ -120,31 +158,98 @@ pub(crate) fn def_to_moniker( AssocItemContainer::Trait(trait_) => { // Because different traits can have functions with the same name, // we have to include the trait name as part of the moniker for uniqueness. - path.push(trait_.name(db)); + description.push(MonikerDescriptor { + name: trait_.name(db), + desc: MonikerDescriptorKind::Type, + }); } AssocItemContainer::Impl(impl_) => { // Because a struct can implement multiple traits, for implementations // we add both the struct name and the trait name to the path if let Some(adt) = impl_.self_ty(db).as_adt() { - path.push(adt.name(db)); + description.push(MonikerDescriptor { + name: adt.name(db), + desc: MonikerDescriptorKind::Type, + }); } if let Some(trait_) = impl_.trait_(db) { - path.push(trait_.name(db)); + description.push(MonikerDescriptor { + name: trait_.name(db), + desc: MonikerDescriptorKind::Type, + }); } } } } if let Definition::Field(it) = def { - path.push(it.parent_def(db).name(db)); + description.push(MonikerDescriptor { + name: it.parent_def(db).name(db), + desc: MonikerDescriptorKind::Type, + }); } - path.push(def.name(db)?); + let name_desc = match def { + // These are handled by top-level guard (for performance). + Definition::GenericParam(_) + | Definition::Label(_) + | Definition::DeriveHelper(_) + | Definition::BuiltinAttr(_) + | Definition::ToolModule(_) => return None, + + Definition::Local(local) => { + if !local.is_param(db) { + return None; + } + + MonikerDescriptor { name: local.name(db), desc: MonikerDescriptorKind::Parameter } + } + Definition::Macro(m) => { + MonikerDescriptor { name: m.name(db), desc: MonikerDescriptorKind::Macro } + } + Definition::Function(f) => { + MonikerDescriptor { name: f.name(db), desc: MonikerDescriptorKind::Method } + } + Definition::Variant(v) => { + MonikerDescriptor { name: v.name(db), desc: MonikerDescriptorKind::Type } + } + Definition::Const(c) => { + MonikerDescriptor { name: c.name(db)?, desc: MonikerDescriptorKind::Term } + } + Definition::Trait(trait_) => { + MonikerDescriptor { name: trait_.name(db), desc: MonikerDescriptorKind::Type } + } + Definition::TypeAlias(ta) => { + MonikerDescriptor { name: ta.name(db), desc: MonikerDescriptorKind::TypeParameter } + } + Definition::Module(m) => { + MonikerDescriptor { name: m.name(db)?, desc: MonikerDescriptorKind::Namespace } + } + Definition::BuiltinType(b) => { + MonikerDescriptor { name: b.name(), desc: MonikerDescriptorKind::Type } + } + Definition::SelfType(imp) => MonikerDescriptor { + name: imp.self_ty(db).as_adt()?.name(db), + desc: MonikerDescriptorKind::Type, + }, + Definition::Field(it) => { + MonikerDescriptor { name: it.name(db), desc: MonikerDescriptorKind::Term } + } + Definition::Adt(adt) => { + MonikerDescriptor { name: adt.name(db), desc: MonikerDescriptorKind::Type } + } + Definition::Static(s) => { + MonikerDescriptor { name: s.name(db), desc: MonikerDescriptorKind::Meta } + } + }; + + description.push(name_desc); + Some(MonikerResult { identifier: MonikerIdentifier { crate_name: krate.display_name(db)?.crate_name().to_string(), - path, + description, }, kind: if krate == from_crate { MonikerKind::Export } else { MonikerKind::Import }, package_information: { diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 07771d1b392ce..b36732c834d85 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -23,6 +23,7 @@ crossbeam-channel = "0.5.5" dissimilar = "1.0.4" itertools = "0.10.3" lsp-types = { version = "0.93.0", features = ["proposed"] } +scip = "0.1.1" parking_lot = "0.12.1" xflags = "0.2.4" oorandom = "11.1.3" diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index e9de23cb395d1..f6a6802972525 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -93,6 +93,7 @@ fn try_main() -> Result<()> { flags::RustAnalyzerCmd::Ssr(cmd) => cmd.run()?, flags::RustAnalyzerCmd::Search(cmd) => cmd.run()?, flags::RustAnalyzerCmd::Lsif(cmd) => cmd.run()?, + flags::RustAnalyzerCmd::Scip(cmd) => cmd.run()?, } Ok(()) } diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs index 6ccdaa86dd628..60ba67e25f93b 100644 --- a/crates/rust-analyzer/src/cli.rs +++ b/crates/rust-analyzer/src/cli.rs @@ -9,6 +9,7 @@ mod analysis_stats; mod diagnostics; mod ssr; mod lsif; +mod scip; mod progress_report; diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs index 080e2fb443881..aa32654fbdca1 100644 --- a/crates/rust-analyzer/src/cli/flags.rs +++ b/crates/rust-analyzer/src/cli/flags.rs @@ -112,6 +112,10 @@ xflags::xflags! { cmd lsif required path: PathBuf {} + + cmd scip + required path: PathBuf + {} } } @@ -140,6 +144,7 @@ pub enum RustAnalyzerCmd { Search(Search), ProcMacro(ProcMacro), Lsif(Lsif), + Scip(Scip), } #[derive(Debug)] @@ -207,6 +212,11 @@ pub struct Lsif { pub path: PathBuf, } +#[derive(Debug)] +pub struct Scip { + pub path: PathBuf, +} + impl RustAnalyzer { pub const HELP: &'static str = Self::HELP_; diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs new file mode 100644 index 0000000000000..65cc993c45e71 --- /dev/null +++ b/crates/rust-analyzer/src/cli/scip.rs @@ -0,0 +1,448 @@ +//! SCIP generator + +use std::{ + collections::{HashMap, HashSet}, + time::Instant, +}; + +use crate::line_index::{LineEndings, LineIndex, OffsetEncoding}; +use hir::Name; +use ide::{ + LineCol, MonikerDescriptorKind, MonikerResult, StaticIndex, StaticIndexedFile, TextRange, + TokenId, +}; +use ide_db::LineIndexDatabase; +use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace}; +use scip::types as scip_types; +use std::env; + +use crate::cli::{ + flags, + load_cargo::{load_workspace, LoadCargoConfig}, + Result, +}; + +impl flags::Scip { + pub fn run(self) -> Result<()> { + eprintln!("Generating SCIP start..."); + let now = Instant::now(); + let cargo_config = CargoConfig::default(); + + let no_progress = &|s| (eprintln!("rust-analyzer: Loading {}", s)); + let load_cargo_config = LoadCargoConfig { + load_out_dirs_from_check: true, + with_proc_macro: true, + prefill_caches: true, + }; + let path = vfs::AbsPathBuf::assert(env::current_dir()?.join(&self.path)); + let rootpath = path.normalize(); + let manifest = ProjectManifest::discover_single(&path)?; + + let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?; + + let (host, vfs, _) = load_workspace(workspace, &load_cargo_config)?; + let db = host.raw_database(); + let analysis = host.analysis(); + + 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() + }) + .into(), + ..Default::default() + }; + + let mut symbols_emitted: HashSet = HashSet::default(); + let mut tokens_to_symbol: HashMap = HashMap::new(); + + for file in si.files { + let mut local_count = 0; + let mut new_local_symbol = || { + let new_symbol = scip::types::Symbol::new_local(local_count); + local_count += 1; + + new_symbol + }; + + let StaticIndexedFile { file_id, tokens, .. } = file; + let relative_path = match get_relative_filepath(&vfs, &rootpath, file_id) { + Some(relative_path) => relative_path, + None => continue, + }; + + let line_index = LineIndex { + index: db.line_index(file_id), + encoding: OffsetEncoding::Utf8, + endings: LineEndings::Unix, + }; + + let mut doc = scip_types::Document { + relative_path, + language: "rust".to_string(), + ..Default::default() + }; + + tokens.into_iter().for_each(|(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 = match tokens_to_symbol.get(&id) { + Some(symbol) => symbol.clone(), + None => { + let symbol = match &token.moniker { + Some(moniker) => moniker_to_symbol(&moniker), + None => new_local_symbol(), + }; + + let symbol = scip::symbol::format_symbol(symbol); + tokens_to_symbol.insert(id, symbol.clone()); + symbol + } + }; + + if let Some(def) = token.definition { + if def.range == range { + occurrence.symbol_roles |= scip_types::SymbolRole::Definition as i32; + } + + if !symbols_emitted.contains(&id) { + 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()]; + } + } + + doc.symbols.push(symbol_info) + } + } + + doc.occurrences.push(occurrence); + }); + + if doc.occurrences.is_empty() { + continue; + } + + index.documents.push(doc); + } + + scip::write_message_to_file("index.scip", index) + .map_err(|err| anyhow::anyhow!("Failed to write scip to file: {}", err))?; + + eprintln!("Generating SCIP finished {:?}", now.elapsed()); + Ok(()) + } +} + +fn get_relative_filepath( + vfs: &vfs::Vfs, + rootpath: &vfs::AbsPathBuf, + file_id: ide::FileId, +) -> Option { + Some(vfs.file_path(file_id).as_path()?.strip_prefix(&rootpath)?.as_ref().to_str()?.to_string()) +} + +// SCIP Ranges have a (very large) optimization that ranges if they are on the same line +// only encode as a vector of [start_line, start_col, end_col]. +// +// This transforms a line index into the optimized SCIP Range. +fn text_range_to_scip_range(line_index: &LineIndex, range: TextRange) -> Vec { + let LineCol { line: start_line, col: start_col } = line_index.index.line_col(range.start()); + let LineCol { line: end_line, col: end_col } = line_index.index.line_col(range.end()); + + if start_line == end_line { + vec![start_line as i32, start_col as i32, end_col as i32] + } else { + vec![start_line as i32, start_col as i32, end_line as i32, end_col as i32] + } +} + +fn new_descriptor_str( + name: &str, + suffix: scip_types::descriptor::Suffix, +) -> scip_types::Descriptor { + scip_types::Descriptor { + name: name.to_string(), + disambiguator: "".to_string(), + suffix: suffix.into(), + ..Default::default() + } +} + +fn new_descriptor(name: Name, suffix: scip_types::descriptor::Suffix) -> scip_types::Descriptor { + let mut name = name.to_string(); + if name.contains("'") { + name = format!("`{}`", name); + } + + new_descriptor_str(name.as_str(), suffix) +} + +/// Loosely based on `def_to_moniker` +/// +/// Only returns a Symbol when it's a non-local symbol. +/// So if the visibility isn't outside of a document, then it will return None +fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol { + use scip_types::descriptor::Suffix::*; + + let package_name = moniker.package_information.name.clone(); + let version = moniker.package_information.version.clone(); + let descriptors = moniker + .identifier + .description + .iter() + .map(|desc| { + new_descriptor( + desc.name.clone(), + match desc.desc { + MonikerDescriptorKind::Namespace => Namespace, + MonikerDescriptorKind::Type => Type, + MonikerDescriptorKind::Term => Term, + MonikerDescriptorKind::Method => Method, + MonikerDescriptorKind::TypeParameter => TypeParameter, + MonikerDescriptorKind::Parameter => Parameter, + MonikerDescriptorKind::Macro => Macro, + MonikerDescriptorKind::Meta => Meta, + }, + ) + }) + .collect(); + + scip_types::Symbol { + scheme: "rust-analyzer".into(), + package: Some(scip_types::Package { + manager: "cargo".to_string(), + name: package_name, + version, + ..Default::default() + }) + .into(), + descriptors, + ..Default::default() + } +} + +#[cfg(test)] +mod test { + use super::*; + use hir::Semantics; + use ide::{AnalysisHost, FilePosition}; + use ide_db::defs::IdentClass; + use ide_db::{base_db::fixture::ChangeFixture, helpers::pick_best_token}; + use scip::symbol::format_symbol; + use syntax::SyntaxKind::*; + use syntax::{AstNode, T}; + + fn position(ra_fixture: &str) -> (AnalysisHost, FilePosition) { + let mut host = AnalysisHost::default(); + let change_fixture = ChangeFixture::parse(ra_fixture); + host.raw_database_mut().apply_change(change_fixture.change); + let (file_id, range_or_offset) = + change_fixture.file_position.expect("expected a marker ($0)"); + let offset = range_or_offset.expect_offset(); + (host, FilePosition { file_id, offset }) + } + + /// If expected == "", then assert that there are no symbols (this is basically local symbol) + #[track_caller] + fn check_symbol(ra_fixture: &str, expected: &str) { + let (host, position) = position(ra_fixture); + + let FilePosition { file_id, offset } = position; + + let db = host.raw_database(); + let sema = &Semantics::new(db); + let file = sema.parse(file_id).syntax().clone(); + 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] + | COMMENT => 2, + kind if kind.is_trivia() => 0, + _ => 1, + }) + .expect("OK OK"); + + let navs = sema + .descend_into_macros(original_token.clone()) + .into_iter() + .filter_map(|token| { + IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| { + it.into_iter().flat_map(|def| { + let module = def.module(db).unwrap(); + let current_crate = module.krate(); + + match MonikerResult::from_def(sema.db, def, current_crate) { + Some(moniker_result) => Some(moniker_to_symbol(&moniker_result)), + None => None, + } + }) + }) + }) + .flatten() + .collect::>(); + + if expected == "" { + assert_eq!(0, navs.len(), "must have no symbols {:?}", navs); + return; + } + + assert_eq!(1, navs.len(), "must have one symbol {:?}", navs); + + let res = navs.get(0).unwrap(); + let formatted = format_symbol(res.clone()); + assert_eq!(formatted, expected); + } + + #[test] + fn basic() { + check_symbol( + r#" +//- /lib.rs crate:main deps:foo +use foo::example_mod::func; +fn main() { + func$0(); +} +//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git +pub mod example_mod { + pub fn func() {} +} +"#, + "rust-analyzer cargo foo 0.1.0 example_mod/func().", + ); + } + + #[test] + fn symbol_for_trait() { + check_symbol( + r#" +//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git +pub mod module { + pub trait MyTrait { + pub fn func$0() {} + } +} +"#, + "rust-analyzer cargo foo 0.1.0 module/MyTrait#func().", + ); + } + + #[test] + fn symbol_for_trait_constant() { + check_symbol( + r#" + //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git + pub mod module { + pub trait MyTrait { + const MY_CONST$0: u8; + } + } + "#, + "rust-analyzer cargo foo 0.1.0 module/MyTrait#MY_CONST.", + ); + } + + #[test] + fn symbol_for_trait_type() { + check_symbol( + r#" + //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git + pub mod module { + pub trait MyTrait { + type MyType$0; + } + } + "#, + // "foo::module::MyTrait::MyType", + "rust-analyzer cargo foo 0.1.0 module/MyTrait#[MyType]", + ); + } + + #[test] + fn symbol_for_trait_impl_function() { + check_symbol( + r#" + //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git + pub mod module { + pub trait MyTrait { + pub fn func() {} + } + + struct MyStruct {} + + impl MyTrait for MyStruct { + pub fn func$0() {} + } + } + "#, + // "foo::module::MyStruct::MyTrait::func", + "rust-analyzer cargo foo 0.1.0 module/MyStruct#MyTrait#func().", + ); + } + + #[test] + fn symbol_for_field() { + check_symbol( + r#" + //- /lib.rs crate:main deps:foo + use foo::St; + fn main() { + let x = St { a$0: 2 }; + } + //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git + pub struct St { + pub a: i32, + } + "#, + "rust-analyzer cargo foo 0.1.0 St#a.", + ); + } + + #[test] + fn local_symbol_for_local() { + check_symbol( + r#" + //- /lib.rs crate:main deps:foo + use foo::module::func; + fn main() { + func(); + } + //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git + pub mod module { + pub fn func() { + let x$0 = 2; + } + } + "#, + "", + ); + } +} From 2efe6b0d3d1cca5b0b360ff760f08cb7d647878a Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 22 Aug 2022 12:14:35 -0700 Subject: [PATCH 16/53] Add `AsFd` implementations for stdio types on WASI. This mirrors the implementations on Unix platforms, and also mirrors the existing `AsRawFd` impls. --- library/std/src/sys/wasi/stdio.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs index 4cc0e4ed5a45a..d2081771b6ec7 100644 --- a/library/std/src/sys/wasi/stdio.rs +++ b/library/std/src/sys/wasi/stdio.rs @@ -4,7 +4,7 @@ use super::fd::WasiFd; use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; use crate::os::raw; -use crate::os::wasi::io::{AsRawFd, FromRawFd}; +use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd}; pub struct Stdin; pub struct Stdout; @@ -23,6 +23,13 @@ impl AsRawFd for Stdin { } } +impl AsFd for Stdin { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw(0) } + } +} + impl io::Read for Stdin { fn read(&mut self, data: &mut [u8]) -> io::Result { self.read_vectored(&mut [IoSliceMut::new(data)]) @@ -51,6 +58,13 @@ impl AsRawFd for Stdout { } } +impl AsFd for Stdout { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw(1) } + } +} + impl io::Write for Stdout { fn write(&mut self, data: &[u8]) -> io::Result { self.write_vectored(&[IoSlice::new(data)]) @@ -82,6 +96,13 @@ impl AsRawFd for Stderr { } } +impl AsFd for Stderr { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw(2) } + } +} + impl io::Write for Stderr { fn write(&mut self, data: &[u8]) -> io::Result { self.write_vectored(&[IoSlice::new(data)]) From 148bdf85f24099498918087d89103cbd808ea89d Mon Sep 17 00:00:00 2001 From: ice1000 Date: Tue, 23 Aug 2022 04:55:05 +0000 Subject: [PATCH 17/53] Do not substitute `Self` when in same impl block --- .../ide-assists/src/handlers/inline_call.rs | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs index b5d092e39b029..96890ad51a6f9 100644 --- a/crates/ide-assists/src/handlers/inline_call.rs +++ b/crates/ide-assists/src/handlers/inline_call.rs @@ -311,12 +311,16 @@ fn inline( } else { fn_body.clone_for_update() }; - 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())); + if let Some(imp) = body.syntax().ancestors().find_map(ast::Impl::cast) { + if !node.syntax().ancestors().any(|anc| &anc == imp.syntax()) { + if let Some(t) = imp.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) @@ -1221,6 +1225,31 @@ impl A { fn main() { A(114514); } +"#, + ) + } + + #[test] + fn inline_call_with_self_type_but_within_same_impl() { + check_assist( + inline_call, + r#" +struct A(u32); +impl A { + fn f() -> Self { Self(1919810) } + fn main() { + Self::f$0(); + } +} +"#, + r#" +struct A(u32); +impl A { + fn f() -> Self { Self(1919810) } + fn main() { + Self(1919810); + } +} "#, ) } From 16315edaee9078e6bd67cf09b5c2c76e13e584ff Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 22 Aug 2022 13:15:42 +0200 Subject: [PATCH 18/53] Make punctuation highlighting configurable, disable it by default --- crates/ide/src/syntax_highlighting/tags.rs | 6 ++++- crates/rust-analyzer/src/config.rs | 25 ++++++++++++++++-- crates/rust-analyzer/src/handlers.rs | 8 +++--- crates/rust-analyzer/src/to_proto.rs | 30 +++++++++++++++++----- 4 files changed, 56 insertions(+), 13 deletions(-) diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 5262770f30317..9db35b17c060a 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs @@ -296,7 +296,7 @@ impl Highlight { Highlight { tag, mods: HlMods::default() } } pub fn is_empty(&self) -> bool { - self.tag == HlTag::None && self.mods == HlMods::default() + self.tag == HlTag::None && self.mods.is_empty() } } @@ -330,6 +330,10 @@ impl ops::BitOr for Highlight { } impl HlMods { + pub fn is_empty(&self) -> bool { + self.0 == 0 + } + pub fn contains(self, m: HlMod) -> bool { self.0 & m.mask() == m.mask() } diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 6649f42b4ef9e..732d01595e13c 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -391,6 +391,16 @@ config_data! { /// By disabling semantic tokens for strings, other grammars can be used to highlight /// their contents. semanticHighlighting_strings_enable: bool = "true", + /// Use semantic tokens for punctuations. + /// + /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when + /// they are tagged with modifiers. + semanticHighlighting_punctuation_enable: bool = "false", + /// Use specialized semantic tokens for punctuations. + /// + /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead + /// of the generic `punctuation` token type. + semanticHighlighting_punctuation_specialize: bool = "false", /// Show full signature of the callable. Only shows parameters if disabled. signatureInfo_detail: SignatureDetail = "\"full\"", @@ -523,6 +533,13 @@ impl HoverActionsConfig { } } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct HighlightingConfig { + pub strings: bool, + pub punctuation: bool, + pub specialize_punctuation: bool, +} + #[derive(Debug, Clone)] pub struct FilesConfig { pub watcher: FilesWatcher, @@ -1171,8 +1188,12 @@ impl Config { } } - pub fn highlighting_strings(&self) -> bool { - self.data.semanticHighlighting_strings_enable + pub fn highlighting_config(&self) -> HighlightingConfig { + HighlightingConfig { + strings: self.data.semanticHighlighting_strings_enable, + punctuation: self.data.semanticHighlighting_punctuation_enable, + specialize_punctuation: self.data.semanticHighlighting_punctuation_specialize, + } } pub fn hover(&self) -> HoverConfig { diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index e0bcc80b31cb9..beec3433b7255 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -1505,9 +1505,9 @@ pub(crate) fn handle_semantic_tokens_full( let line_index = snap.file_line_index(file_id)?; let highlights = snap.analysis.highlight(file_id)?; - let highlight_strings = snap.config.highlighting_strings(); + let highlighting_config = snap.config.highlighting_config(); let semantic_tokens = - to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings); + to_proto::semantic_tokens(&text, &line_index, highlights, highlighting_config); // Unconditionally cache the tokens snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens.clone()); @@ -1526,7 +1526,7 @@ pub(crate) fn handle_semantic_tokens_full_delta( let line_index = snap.file_line_index(file_id)?; let highlights = snap.analysis.highlight(file_id)?; - let highlight_strings = snap.config.highlighting_strings(); + let highlight_strings = snap.config.highlighting_config(); let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings); @@ -1557,7 +1557,7 @@ pub(crate) fn handle_semantic_tokens_range( let line_index = snap.file_line_index(frange.file_id)?; let highlights = snap.analysis.highlight_range(frange)?; - let highlight_strings = snap.config.highlighting_strings(); + let highlight_strings = snap.config.highlighting_config(); let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings); Ok(Some(semantic_tokens.into())) diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index e7115b0732e20..21fd6c72552c8 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -18,7 +18,7 @@ use vfs::AbsPath; use crate::{ cargo_target_spec::CargoTargetSpec, - config::{CallInfoConfig, Config}, + config::{CallInfoConfig, Config, HighlightingConfig}, global_state::GlobalStateSnapshot, line_index::{LineEndings, LineIndex, OffsetEncoding}, lsp_ext, @@ -517,19 +517,37 @@ pub(crate) fn semantic_tokens( text: &str, line_index: &LineIndex, highlights: Vec, - highlight_strings: bool, + config: HighlightingConfig, ) -> lsp_types::SemanticTokens { let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string(); let mut builder = semantic_tokens::SemanticTokensBuilder::new(id); - for highlight_range in highlights { + for mut highlight_range in highlights { if highlight_range.highlight.is_empty() { continue; } - let (ty, mods) = semantic_token_type_and_modifiers(highlight_range.highlight); - if !highlight_strings && ty == lsp_types::SemanticTokenType::STRING { - continue; + + // apply config filtering + match &mut highlight_range.highlight.tag { + HlTag::StringLiteral if !config.strings => continue, + // If punctuation is disabled, make the macro bang part of the macro call again. + tag @ HlTag::Punctuation(HlPunct::MacroBang) + if !config.punctuation || !config.specialize_punctuation => + { + *tag = HlTag::Symbol(SymbolKind::Macro); + } + HlTag::Punctuation(_) + if !config.punctuation && highlight_range.highlight.mods.is_empty() => + { + continue + } + tag @ HlTag::Punctuation(_) if !config.specialize_punctuation => { + *tag = HlTag::Punctuation(HlPunct::Other); + } + _ => (), } + + let (ty, mods) = semantic_token_type_and_modifiers(highlight_range.highlight); let token_index = semantic_tokens::type_index(ty); let modifier_bitset = mods.0; From afc8cfb4d1a565f844fa805aa658fb80b23c1314 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 22 Aug 2022 13:21:30 +0200 Subject: [PATCH 19/53] Make operator highlighting configurable, disable it by default --- crates/rust-analyzer/src/config.rs | 20 ++++++++++++++++++-- crates/rust-analyzer/src/to_proto.rs | 6 ++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 732d01595e13c..13f533c0ec286 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -400,7 +400,17 @@ config_data! { /// /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead /// of the generic `punctuation` token type. - semanticHighlighting_punctuation_specialize: bool = "false", + semanticHighlighting_punctuation_specialization_enable: bool = "false", + /// Use semantic tokens for operators. + /// + /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when + /// they are tagged with modifiers. + semanticHighlighting_operator_enable: bool = "true", + /// Use specialized semantic tokens for operators. + /// + /// When enabled, rust-analyzer will emit special token types for operator tokens instead + /// of the generic `operator` token type. + semanticHighlighting_operator_specialization_enable: bool = "false", /// Show full signature of the callable. Only shows parameters if disabled. signatureInfo_detail: SignatureDetail = "\"full\"", @@ -538,6 +548,8 @@ pub struct HighlightingConfig { pub strings: bool, pub punctuation: bool, pub specialize_punctuation: bool, + pub specialize_operator: bool, + pub operator: bool, } #[derive(Debug, Clone)] @@ -1192,7 +1204,11 @@ impl Config { HighlightingConfig { strings: self.data.semanticHighlighting_strings_enable, punctuation: self.data.semanticHighlighting_punctuation_enable, - specialize_punctuation: self.data.semanticHighlighting_punctuation_specialize, + specialize_punctuation: self + .data + .semanticHighlighting_punctuation_specialization_enable, + operator: self.data.semanticHighlighting_operator_enable, + specialize_operator: self.data.semanticHighlighting_operator_specialization_enable, } } diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 21fd6c72552c8..f05b81c35d0d5 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -544,6 +544,12 @@ pub(crate) fn semantic_tokens( tag @ HlTag::Punctuation(_) if !config.specialize_punctuation => { *tag = HlTag::Punctuation(HlPunct::Other); } + HlTag::Operator(_) if !config.operator && highlight_range.highlight.mods.is_empty() => { + continue + } + tag @ HlTag::Operator(_) if !config.specialize_operator => { + *tag = HlTag::Operator(HlOperator::Other); + } _ => (), } From 9a201873b828b64dd276df42b3dbd263682392b7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 22 Aug 2022 13:38:35 +0200 Subject: [PATCH 20/53] Move highlight configuration from protocol into the feature --- crates/ide/src/lib.rs | 18 +++++-- crates/ide/src/syntax_highlighting.rs | 56 ++++++++++++++------ crates/ide/src/syntax_highlighting/html.rs | 19 ++++++- crates/ide/src/syntax_highlighting/inject.rs | 21 ++++++-- crates/ide/src/syntax_highlighting/tests.rs | 24 ++++++--- crates/rust-analyzer/src/config.rs | 18 ++----- crates/rust-analyzer/src/handlers.rs | 18 +++---- crates/rust-analyzer/src/to_proto.rs | 31 +---------- 8 files changed, 119 insertions(+), 86 deletions(-) diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 2b2d3f86a2921..d61d69a090b33 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -98,7 +98,7 @@ pub use crate::{ static_index::{StaticIndex, StaticIndexedFile, TokenId, TokenStaticData}, syntax_highlighting::{ tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag}, - HlRange, + HighlightConfig, HlRange, }, }; pub use hir::{Documentation, Semantics}; @@ -517,8 +517,12 @@ impl Analysis { } /// Computes syntax highlighting for the given file - pub fn highlight(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false)) + pub fn highlight( + &self, + highlight_config: HighlightConfig, + file_id: FileId, + ) -> Cancellable> { + self.with_db(|db| syntax_highlighting::highlight(db, highlight_config, file_id, None)) } /// Computes all ranges to highlight for a given item in a file. @@ -533,9 +537,13 @@ impl Analysis { } /// Computes syntax highlighting for the given file range. - pub fn highlight_range(&self, frange: FileRange) -> Cancellable> { + pub fn highlight_range( + &self, + highlight_config: HighlightConfig, + frange: FileRange, + ) -> Cancellable> { self.with_db(|db| { - syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false) + syntax_highlighting::highlight(db, highlight_config, frange.file_id, Some(frange.range)) }) } diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 3fb49b45d9888..21beeb44a9d90 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -14,7 +14,7 @@ mod html; mod tests; use hir::{Name, Semantics}; -use ide_db::{FxHashMap, RootDatabase}; +use ide_db::{FxHashMap, RootDatabase, SymbolKind}; use syntax::{ ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T, }; @@ -24,7 +24,7 @@ use crate::{ escape::highlight_escape_string, format::highlight_format_string, highlights::Highlights, macro_::MacroHighlighter, tags::Highlight, }, - FileId, HlMod, HlTag, + FileId, HlMod, HlOperator, HlPunct, HlTag, }; pub(crate) use html::highlight_as_html; @@ -36,6 +36,16 @@ pub struct HlRange { pub binding_hash: Option, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct HighlightConfig { + pub strings: bool, + pub punctuation: bool, + pub specialize_punctuation: bool, + pub specialize_operator: bool, + pub operator: bool, + pub syntactic_name_ref_highlighting: bool, +} + // Feature: Semantic Syntax Highlighting // // rust-analyzer highlights the code semantically. @@ -155,9 +165,9 @@ pub struct HlRange { // image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[] pub(crate) fn highlight( db: &RootDatabase, + config: HighlightConfig, file_id: FileId, range_to_highlight: Option, - syntactic_name_ref_highlighting: bool, ) -> Vec { let _p = profile::span("highlight"); let sema = Semantics::new(db); @@ -183,26 +193,18 @@ pub(crate) fn highlight( Some(it) => it.krate(), None => return hl.to_vec(), }; - traverse( - &mut hl, - &sema, - file_id, - &root, - krate, - range_to_highlight, - syntactic_name_ref_highlighting, - ); + traverse(&mut hl, &sema, config, file_id, &root, krate, range_to_highlight); hl.to_vec() } fn traverse( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, + config: HighlightConfig, file_id: FileId, root: &SyntaxNode, krate: hir::Crate, range_to_highlight: TextRange, - syntactic_name_ref_highlighting: bool, ) { let is_unlinked = sema.to_module_def(file_id).is_none(); let mut bindings_shadow_count: FxHashMap = FxHashMap::default(); @@ -325,7 +327,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, file_id, &node); + inject::doc_comment(hl, sema, config, file_id, &node); continue; } }; @@ -400,7 +402,8 @@ fn traverse( 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, &string, &expanded_string).is_some() { + if inject::ra_fixture(hl, sema, config, &string, &expanded_string).is_some() + { continue; } } @@ -421,7 +424,7 @@ fn traverse( sema, krate, &mut bindings_shadow_count, - syntactic_name_ref_highlighting, + config.syntactic_name_ref_highlighting, name_like, ), NodeOrToken::Token(token) => highlight::token(sema, token).zip(Some(None)), @@ -439,6 +442,27 @@ fn traverse( // something unresolvable. FIXME: There should be a way to prevent that continue; } + + // apply config filtering + match &mut highlight.tag { + HlTag::StringLiteral if !config.strings => continue, + // If punctuation is disabled, make the macro bang part of the macro call again. + tag @ HlTag::Punctuation(HlPunct::MacroBang) + if !config.punctuation || !config.specialize_punctuation => + { + *tag = HlTag::Symbol(SymbolKind::Macro); + } + HlTag::Punctuation(_) if !config.punctuation => continue, + tag @ HlTag::Punctuation(_) if !config.specialize_punctuation => { + *tag = HlTag::Punctuation(HlPunct::Other); + } + HlTag::Operator(_) if !config.operator && highlight.mods.is_empty() => continue, + tag @ HlTag::Operator(_) if !config.specialize_operator => { + *tag = HlTag::Operator(HlOperator::Other); + } + _ => (), + } + if inside_attribute { highlight |= HlMod::Attribute } diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs index 9777c014c7a16..c841456aef3c4 100644 --- a/crates/ide/src/syntax_highlighting/html.rs +++ b/crates/ide/src/syntax_highlighting/html.rs @@ -5,7 +5,10 @@ use oorandom::Rand32; use stdx::format_to; use syntax::AstNode; -use crate::{syntax_highlighting::highlight, FileId, RootDatabase}; +use crate::{ + syntax_highlighting::{highlight, HighlightConfig}, + FileId, RootDatabase, +}; pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String { let parse = db.parse(file_id); @@ -20,7 +23,19 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo ) } - let hl_ranges = highlight(db, file_id, None, false); + let hl_ranges = highlight( + db, + HighlightConfig { + strings: true, + punctuation: true, + specialize_punctuation: true, + specialize_operator: true, + operator: true, + syntactic_name_ref_highlighting: false, + }, + file_id, + None, + ); let text = parse.tree().syntax().to_string(); let mut buf = String::new(); buf.push_str(STYLE); diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index f376f9fda7a57..9139528c7ed96 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs @@ -15,13 +15,14 @@ use syntax::{ use crate::{ doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def}, - syntax_highlighting::{highlights::Highlights, injector::Injector}, + syntax_highlighting::{highlights::Highlights, injector::Injector, HighlightConfig}, Analysis, HlMod, HlRange, HlTag, RootDatabase, }; pub(super) fn ra_fixture( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, + config: HighlightConfig, literal: &ast::String, expanded: &ast::String, ) -> Option<()> { @@ -63,7 +64,13 @@ pub(super) fn ra_fixture( let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text()); - for mut hl_range in analysis.highlight(tmp_file_id).unwrap() { + for mut hl_range in analysis + .highlight( + HighlightConfig { syntactic_name_ref_highlighting: false, ..config }, + tmp_file_id, + ) + .unwrap() + { for range in inj.map_range_up(hl_range.range) { if let Some(range) = literal.map_range_up(range) { hl_range.range = range; @@ -86,6 +93,7 @@ const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"]; pub(super) fn doc_comment( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, + config: HighlightConfig, src_file_id: FileId, node: &SyntaxNode, ) { @@ -206,7 +214,14 @@ pub(super) fn doc_comment( let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text()); - if let Ok(ranges) = analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)) { + if let Ok(ranges) = analysis.with_db(|db| { + super::highlight( + db, + HighlightConfig { syntactic_name_ref_highlighting: true, ..config }, + tmp_file_id, + None, + ) + }) { for HlRange { range, highlight, binding_hash } in ranges { for range in inj.map_range_up(range) { hl.add(HlRange { range, highlight: highlight | HlMod::Injected, binding_hash }); diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 382735cb368df..246c6e3722559 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -4,7 +4,16 @@ use expect_test::{expect_file, ExpectFile}; use ide_db::SymbolKind; use test_utils::{bench, bench_fixture, skip_slow_tests, AssertLinear}; -use crate::{fixture, FileRange, HlTag, TextRange}; +use crate::{fixture, FileRange, HighlightConfig, HlTag, TextRange}; + +const HL_CONFIG: HighlightConfig = HighlightConfig { + strings: true, + punctuation: true, + specialize_punctuation: true, + specialize_operator: true, + operator: true, + syntactic_name_ref_highlighting: false, +}; #[test] fn attributes() { @@ -996,7 +1005,10 @@ struct Foo { // The "x" let highlights = &analysis - .highlight_range(FileRange { file_id, range: TextRange::at(45.into(), 1.into()) }) + .highlight_range( + HL_CONFIG, + FileRange { file_id, range: TextRange::at(45.into(), 1.into()) }, + ) .unwrap(); assert_eq!(&highlights[0].highlight.to_string(), "field.declaration.public"); @@ -1011,7 +1023,7 @@ macro_rules! test {} }"# .trim(), ); - let _ = analysis.highlight(file_id).unwrap(); + let _ = analysis.highlight(HL_CONFIG, file_id).unwrap(); } /// Highlights the code given by the `ra_fixture` argument, renders the @@ -1035,7 +1047,7 @@ fn benchmark_syntax_highlighting_long_struct() { let hash = { let _pt = bench("syntax highlighting long struct"); analysis - .highlight(file_id) + .highlight(HL_CONFIG, file_id) .unwrap() .iter() .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct)) @@ -1061,7 +1073,7 @@ fn syntax_highlighting_not_quadratic() { let time = Instant::now(); let hash = analysis - .highlight(file_id) + .highlight(HL_CONFIG, file_id) .unwrap() .iter() .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct)) @@ -1086,7 +1098,7 @@ fn benchmark_syntax_highlighting_parser() { let hash = { let _pt = bench("syntax highlighting parser"); analysis - .highlight(file_id) + .highlight(HL_CONFIG, file_id) .unwrap() .iter() .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function)) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 13f533c0ec286..3badc890958ae 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -12,8 +12,8 @@ use std::{ffi::OsString, fmt, iter, path::PathBuf}; use flycheck::FlycheckConfig; use ide::{ AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, - HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig, JoinLinesConfig, - Snippet, SnippetScope, + HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig, + JoinLinesConfig, Snippet, SnippetScope, }; use ide_db::{ imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, @@ -543,15 +543,6 @@ impl HoverActionsConfig { } } -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct HighlightingConfig { - pub strings: bool, - pub punctuation: bool, - pub specialize_punctuation: bool, - pub specialize_operator: bool, - pub operator: bool, -} - #[derive(Debug, Clone)] pub struct FilesConfig { pub watcher: FilesWatcher, @@ -1200,8 +1191,8 @@ impl Config { } } - pub fn highlighting_config(&self) -> HighlightingConfig { - HighlightingConfig { + pub fn highlighting_config(&self) -> HighlightConfig { + HighlightConfig { strings: self.data.semanticHighlighting_strings_enable, punctuation: self.data.semanticHighlighting_punctuation_enable, specialize_punctuation: self @@ -1209,6 +1200,7 @@ impl Config { .semanticHighlighting_punctuation_specialization_enable, operator: self.data.semanticHighlighting_operator_enable, specialize_operator: self.data.semanticHighlighting_operator_specialization_enable, + syntactic_name_ref_highlighting: false, } } diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index beec3433b7255..d89f0f5a3cf45 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -1504,10 +1504,8 @@ pub(crate) fn handle_semantic_tokens_full( let text = snap.analysis.file_text(file_id)?; let line_index = snap.file_line_index(file_id)?; - let highlights = snap.analysis.highlight(file_id)?; - let highlighting_config = snap.config.highlighting_config(); - let semantic_tokens = - to_proto::semantic_tokens(&text, &line_index, highlights, highlighting_config); + let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?; + let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); // Unconditionally cache the tokens snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens.clone()); @@ -1525,10 +1523,8 @@ pub(crate) fn handle_semantic_tokens_full_delta( let text = snap.analysis.file_text(file_id)?; let line_index = snap.file_line_index(file_id)?; - let highlights = snap.analysis.highlight(file_id)?; - let highlight_strings = snap.config.highlighting_config(); - let semantic_tokens = - to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings); + let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?; + let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); let mut cache = snap.semantic_tokens_cache.lock(); let cached_tokens = cache.entry(params.text_document.uri).or_default(); @@ -1556,10 +1552,8 @@ pub(crate) fn handle_semantic_tokens_range( let text = snap.analysis.file_text(frange.file_id)?; let line_index = snap.file_line_index(frange.file_id)?; - let highlights = snap.analysis.highlight_range(frange)?; - let highlight_strings = snap.config.highlighting_config(); - let semantic_tokens = - to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings); + let highlights = snap.analysis.highlight_range(snap.config.highlighting_config(), frange)?; + let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); Ok(Some(semantic_tokens.into())) } diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index f05b81c35d0d5..7a89d6e3e1233 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -18,7 +18,7 @@ use vfs::AbsPath; use crate::{ cargo_target_spec::CargoTargetSpec, - config::{CallInfoConfig, Config, HighlightingConfig}, + config::{CallInfoConfig, Config}, global_state::GlobalStateSnapshot, line_index::{LineEndings, LineIndex, OffsetEncoding}, lsp_ext, @@ -517,42 +517,15 @@ pub(crate) fn semantic_tokens( text: &str, line_index: &LineIndex, highlights: Vec, - config: HighlightingConfig, ) -> lsp_types::SemanticTokens { let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string(); let mut builder = semantic_tokens::SemanticTokensBuilder::new(id); - for mut highlight_range in highlights { + for highlight_range in highlights { if highlight_range.highlight.is_empty() { continue; } - // apply config filtering - match &mut highlight_range.highlight.tag { - HlTag::StringLiteral if !config.strings => continue, - // If punctuation is disabled, make the macro bang part of the macro call again. - tag @ HlTag::Punctuation(HlPunct::MacroBang) - if !config.punctuation || !config.specialize_punctuation => - { - *tag = HlTag::Symbol(SymbolKind::Macro); - } - HlTag::Punctuation(_) - if !config.punctuation && highlight_range.highlight.mods.is_empty() => - { - continue - } - tag @ HlTag::Punctuation(_) if !config.specialize_punctuation => { - *tag = HlTag::Punctuation(HlPunct::Other); - } - HlTag::Operator(_) if !config.operator && highlight_range.highlight.mods.is_empty() => { - continue - } - tag @ HlTag::Operator(_) if !config.specialize_operator => { - *tag = HlTag::Operator(HlOperator::Other); - } - _ => (), - } - let (ty, mods) = semantic_token_type_and_modifiers(highlight_range.highlight); let token_index = semantic_tokens::type_index(ty); let modifier_bitset = mods.0; From 9700c95ced0abb3047ace17afe9aba0086679a76 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 22 Aug 2022 13:44:07 +0200 Subject: [PATCH 21/53] Make doc comment highlight injection configurable --- crates/ide/src/syntax_highlighting.rs | 18 ++++++++++++++---- crates/ide/src/syntax_highlighting/html.rs | 1 + crates/ide/src/syntax_highlighting/tests.rs | 1 + crates/rust-analyzer/src/config.rs | 6 ++++++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 21beeb44a9d90..1804dc722897e 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -38,11 +38,19 @@ pub struct HlRange { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct HighlightConfig { + /// Whether to highlight strings pub strings: bool, + /// Whether to highlight punctuation pub punctuation: bool, + /// Whether to specialize punctuation highlights pub specialize_punctuation: bool, - pub specialize_operator: bool, + /// Whether to highlight operator pub operator: bool, + /// Whether to specialize operator highlights + pub specialize_operator: bool, + /// Whether to inject highlights into doc comments + pub inject_doc_comment: bool, + /// Whether to highlight unresolved things be their syntax pub syntactic_name_ref_highlighting: bool, } @@ -325,9 +333,11 @@ fn traverse( Enter(it) => it, Leave(NodeOrToken::Token(_)) => continue, 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, config, file_id, &node); + if config.inject_doc_comment { + // 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, config, file_id, &node); + } continue; } }; diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs index c841456aef3c4..832f19b1c8ac0 100644 --- a/crates/ide/src/syntax_highlighting/html.rs +++ b/crates/ide/src/syntax_highlighting/html.rs @@ -31,6 +31,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo specialize_punctuation: true, specialize_operator: true, operator: true, + inject_doc_comment: true, syntactic_name_ref_highlighting: false, }, file_id, diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 246c6e3722559..3d086935f07ce 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -12,6 +12,7 @@ const HL_CONFIG: HighlightConfig = HighlightConfig { specialize_punctuation: true, specialize_operator: true, operator: true, + inject_doc_comment: true, syntactic_name_ref_highlighting: false, }; diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 3badc890958ae..a3a4f9f3f139e 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -411,6 +411,11 @@ config_data! { /// When enabled, rust-analyzer will emit special token types for operator tokens instead /// of the generic `operator` token type. semanticHighlighting_operator_specialization_enable: bool = "false", + /// Inject additional highlighting into doc comments. + /// + /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra + /// doc links. + semanticHighlighting_doc_comment_inject_enable: bool = "true", /// Show full signature of the callable. Only shows parameters if disabled. signatureInfo_detail: SignatureDetail = "\"full\"", @@ -1200,6 +1205,7 @@ impl Config { .semanticHighlighting_punctuation_specialization_enable, operator: self.data.semanticHighlighting_operator_enable, specialize_operator: self.data.semanticHighlighting_operator_specialization_enable, + inject_doc_comment: self.data.semanticHighlighting_doc_comment_inject_enable, syntactic_name_ref_highlighting: false, } } From b26733f8a0b46355e385fceb2baa30aa9b4d420c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 22 Aug 2022 13:55:44 +0200 Subject: [PATCH 22/53] Change attribute semantic token type to decorator --- crates/rust-analyzer/src/semantic_tokens.rs | 4 ++-- crates/rust-analyzer/src/to_proto.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index 6c78b5df1a705..ecbbeed93b6e9 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs @@ -40,7 +40,6 @@ macro_rules! define_semantic_token_types { define_semantic_token_types![ (ANGLE, "angle"), (ARITHMETIC, "arithmetic"), - (ATTRIBUTE, "attribute"), (ATTRIBUTE_BRACKET, "attributeBracket"), (BITWISE, "bitwise"), (BOOLEAN, "boolean"), @@ -53,6 +52,8 @@ define_semantic_token_types![ (COMMA, "comma"), (COMPARISON, "comparison"), (CONST_PARAMETER, "constParameter"), + // FIXME: to be replaced once lsp-types has the upstream version + (DECORATOR, "decorator"), (DERIVE, "derive"), (DERIVE_HELPER, "deriveHelper"), (DOT, "dot"), @@ -63,7 +64,6 @@ define_semantic_token_types![ (LIFETIME, "lifetime"), (LOGICAL, "logical"), (MACRO_BANG, "macroBang"), - (OPERATOR, "operator"), (PARENTHESIS, "parenthesis"), (PUNCTUATION, "punctuation"), (SELF_KEYWORD, "selfKeyword"), diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 7a89d6e3e1233..6d83adbc5bf8e 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -558,7 +558,7 @@ fn semantic_token_type_and_modifiers( let mut mods = semantic_tokens::ModifierSet::default(); let type_ = match highlight.tag { HlTag::Symbol(symbol) => match symbol { - SymbolKind::Attribute => semantic_tokens::ATTRIBUTE, + SymbolKind::Attribute => semantic_tokens::DECORATOR, SymbolKind::Derive => semantic_tokens::DERIVE, SymbolKind::DeriveHelper => semantic_tokens::DERIVE_HELPER, SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE, @@ -613,7 +613,7 @@ fn semantic_token_type_and_modifiers( HlOperator::Arithmetic => semantic_tokens::ARITHMETIC, HlOperator::Logical => semantic_tokens::LOGICAL, HlOperator::Comparison => semantic_tokens::COMPARISON, - HlOperator::Other => semantic_tokens::OPERATOR, + HlOperator::Other => lsp_types::SemanticTokenType::OPERATOR, }, HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING, HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE, From f6f0516603b50d2b4c77fc0bcabd0ee3fe1b09e9 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 22 Aug 2022 14:09:38 +0200 Subject: [PATCH 23/53] Add config for macro bang token highlighting, disable by default --- crates/ide/src/syntax_highlighting.rs | 12 ++++++++---- crates/ide/src/syntax_highlighting/html.rs | 1 + crates/ide/src/syntax_highlighting/tags.rs | 2 +- crates/ide/src/syntax_highlighting/tests.rs | 1 + crates/rust-analyzer/src/config.rs | 6 +++++- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 1804dc722897e..50371d620eb2a 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -50,6 +50,8 @@ pub struct HighlightConfig { pub specialize_operator: bool, /// Whether to inject highlights into doc comments pub inject_doc_comment: bool, + /// Whether to highlight the macro call bang + pub macro_bang: bool, /// Whether to highlight unresolved things be their syntax pub syntactic_name_ref_highlighting: bool, } @@ -457,10 +459,12 @@ fn traverse( match &mut highlight.tag { HlTag::StringLiteral if !config.strings => continue, // If punctuation is disabled, make the macro bang part of the macro call again. - tag @ HlTag::Punctuation(HlPunct::MacroBang) - if !config.punctuation || !config.specialize_punctuation => - { - *tag = HlTag::Symbol(SymbolKind::Macro); + tag @ HlTag::Punctuation(HlPunct::MacroBang) => { + if !config.macro_bang { + *tag = HlTag::Symbol(SymbolKind::Macro); + } else if !config.specialize_punctuation { + *tag = HlTag::Punctuation(HlPunct::Other); + } } HlTag::Punctuation(_) if !config.punctuation => continue, tag @ HlTag::Punctuation(_) if !config.specialize_punctuation => { diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs index 832f19b1c8ac0..e91fd7f125716 100644 --- a/crates/ide/src/syntax_highlighting/html.rs +++ b/crates/ide/src/syntax_highlighting/html.rs @@ -32,6 +32,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo specialize_operator: true, operator: true, inject_doc_comment: true, + macro_bang: true, syntactic_name_ref_highlighting: false, }, file_id, diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 9db35b17c060a..3949f1189bd5e 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs @@ -199,7 +199,7 @@ impl fmt::Display for HlTag { } impl HlMod { - const ALL: &'static [HlMod; HlMod::Unsafe as u8 as usize + 1] = &[ + const ALL: &'static [HlMod; 19] = &[ HlMod::Associated, HlMod::Async, HlMod::Attribute, diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 3d086935f07ce..51ddea63ac136 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -13,6 +13,7 @@ const HL_CONFIG: HighlightConfig = HighlightConfig { specialize_operator: true, operator: true, inject_doc_comment: true, + macro_bang: true, syntactic_name_ref_highlighting: false, }; diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index a3a4f9f3f139e..0538aeb65e161 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -394,13 +394,16 @@ config_data! { /// Use semantic tokens for punctuations. /// /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when - /// they are tagged with modifiers. + /// they are tagged with modifiers or have a special role. semanticHighlighting_punctuation_enable: bool = "false", /// Use specialized semantic tokens for punctuations. /// /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead /// of the generic `punctuation` token type. semanticHighlighting_punctuation_specialization_enable: bool = "false", + /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro + /// calls. + semanticHighlighting_punctuation_separate_macro_bang: bool = "false", /// Use semantic tokens for operators. /// /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when @@ -1203,6 +1206,7 @@ impl Config { specialize_punctuation: self .data .semanticHighlighting_punctuation_specialization_enable, + macro_bang: self.data.semanticHighlighting_punctuation_separate_macro_bang, operator: self.data.semanticHighlighting_operator_enable, specialize_operator: self.data.semanticHighlighting_operator_specialization_enable, inject_doc_comment: self.data.semanticHighlighting_doc_comment_inject_enable, From eadc2673c0738e84963384315d953abc4118a4d7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 22 Aug 2022 14:15:09 +0200 Subject: [PATCH 24/53] Regen docs --- crates/rust-analyzer/src/config.rs | 44 ++++++++++++++-------------- docs/user/generated_config.adoc | 46 ++++++++++++++++++++++++++++++ editors/code/package.json | 30 +++++++++++++++++++ 3 files changed, 98 insertions(+), 22 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 0538aeb65e161..54dcb42d99c78 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -385,25 +385,11 @@ config_data! { /// available on a nightly build. rustfmt_rangeFormatting_enable: bool = "false", - /// Use semantic tokens for strings. - /// - /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars. - /// By disabling semantic tokens for strings, other grammars can be used to highlight - /// their contents. - semanticHighlighting_strings_enable: bool = "true", - /// Use semantic tokens for punctuations. - /// - /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when - /// they are tagged with modifiers or have a special role. - semanticHighlighting_punctuation_enable: bool = "false", - /// Use specialized semantic tokens for punctuations. + /// Inject additional highlighting into doc comments. /// - /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead - /// of the generic `punctuation` token type. - semanticHighlighting_punctuation_specialization_enable: bool = "false", - /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro - /// calls. - semanticHighlighting_punctuation_separate_macro_bang: bool = "false", + /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra + /// doc links. + semanticHighlighting_doc_comment_inject_enable: bool = "true", /// Use semantic tokens for operators. /// /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when @@ -414,11 +400,25 @@ config_data! { /// When enabled, rust-analyzer will emit special token types for operator tokens instead /// of the generic `operator` token type. semanticHighlighting_operator_specialization_enable: bool = "false", - /// Inject additional highlighting into doc comments. + /// Use semantic tokens for punctuations. /// - /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra - /// doc links. - semanticHighlighting_doc_comment_inject_enable: bool = "true", + /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when + /// they are tagged with modifiers or have a special role. + semanticHighlighting_punctuation_enable: bool = "false", + /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro + /// calls. + semanticHighlighting_punctuation_separate_macro_bang: bool = "false", + /// Use specialized semantic tokens for punctuations. + /// + /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead + /// of the generic `punctuation` token type. + semanticHighlighting_punctuation_specialization_enable: bool = "false", + /// Use semantic tokens for strings. + /// + /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars. + /// By disabling semantic tokens for strings, other grammars can be used to highlight + /// their contents. + semanticHighlighting_strings_enable: bool = "true", /// Show full signature of the callable. Only shows parameters if disabled. signatureInfo_detail: SignatureDetail = "\"full\"", diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 751ec79af0fd4..72b925726479e 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -587,6 +587,52 @@ Enables the use of rustfmt's unstable range formatting command for the `textDocument/rangeFormatting` request. The rustfmt option is unstable and only available on a nightly build. -- +[[rust-analyzer.semanticHighlighting.doc.comment.inject.enable]]rust-analyzer.semanticHighlighting.doc.comment.inject.enable (default: `true`):: ++ +-- +Inject additional highlighting into doc comments. + +When enabled, rust-analyzer will highlight rust source in doc comments as well as intra +doc links. +-- +[[rust-analyzer.semanticHighlighting.operator.enable]]rust-analyzer.semanticHighlighting.operator.enable (default: `true`):: ++ +-- +Use semantic tokens for operators. + +When disabled, rust-analyzer will emit semantic tokens only for operator tokens when +they are tagged with modifiers. +-- +[[rust-analyzer.semanticHighlighting.operator.specialization.enable]]rust-analyzer.semanticHighlighting.operator.specialization.enable (default: `false`):: ++ +-- +Use specialized semantic tokens for operators. + +When enabled, rust-analyzer will emit special token types for operator tokens instead +of the generic `operator` token type. +-- +[[rust-analyzer.semanticHighlighting.punctuation.enable]]rust-analyzer.semanticHighlighting.punctuation.enable (default: `false`):: ++ +-- +Use semantic tokens for punctuations. + +When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when +they are tagged with modifiers or have a special role. +-- +[[rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang]]rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang (default: `false`):: ++ +-- +When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro +calls. +-- +[[rust-analyzer.semanticHighlighting.punctuation.specialization.enable]]rust-analyzer.semanticHighlighting.punctuation.specialization.enable (default: `false`):: ++ +-- +Use specialized semantic tokens for punctuations. + +When enabled, rust-analyzer will emit special token types for punctuation tokens instead +of the generic `punctuation` token type. +-- [[rust-analyzer.semanticHighlighting.strings.enable]]rust-analyzer.semanticHighlighting.strings.enable (default: `true`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index 67eabc313c832..767c5875bf7e7 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1084,6 +1084,36 @@ "default": false, "type": "boolean" }, + "rust-analyzer.semanticHighlighting.doc.comment.inject.enable": { + "markdownDescription": "Inject additional highlighting into doc comments.\n\nWhen enabled, rust-analyzer will highlight rust source in doc comments as well as intra\ndoc links.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.semanticHighlighting.operator.enable": { + "markdownDescription": "Use semantic tokens for operators.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for operator tokens when\nthey are tagged with modifiers.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.semanticHighlighting.operator.specialization.enable": { + "markdownDescription": "Use specialized semantic tokens for operators.\n\nWhen enabled, rust-analyzer will emit special token types for operator tokens instead\nof the generic `operator` token type.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.semanticHighlighting.punctuation.enable": { + "markdownDescription": "Use semantic tokens for punctuations.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when\nthey are tagged with modifiers or have a special role.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang": { + "markdownDescription": "When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro\ncalls.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.semanticHighlighting.punctuation.specialization.enable": { + "markdownDescription": "Use specialized semantic tokens for punctuations.\n\nWhen enabled, rust-analyzer will emit special token types for punctuation tokens instead\nof the generic `punctuation` token type.", + "default": false, + "type": "boolean" + }, "rust-analyzer.semanticHighlighting.strings.enable": { "markdownDescription": "Use semantic tokens for strings.\n\nIn some editors (e.g. vscode) semantic tokens override other highlighting grammars.\nBy disabling semantic tokens for strings, other grammars can be used to highlight\ntheir contents.", "default": true, From 31fb917d8dc6c5f179069d717d110824a92b1a12 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 22 Aug 2022 14:53:05 +0200 Subject: [PATCH 25/53] Remove unused default semantic modifiers --- crates/rust-analyzer/src/semantic_tokens.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index ecbbeed93b6e9..bb3b5c86bd2f7 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs @@ -82,11 +82,7 @@ macro_rules! define_semantic_token_modifiers { pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[ SemanticTokenModifier::DOCUMENTATION, SemanticTokenModifier::DECLARATION, - SemanticTokenModifier::DEFINITION, SemanticTokenModifier::STATIC, - SemanticTokenModifier::ABSTRACT, - SemanticTokenModifier::DEPRECATED, - SemanticTokenModifier::READONLY, SemanticTokenModifier::DEFAULT_LIBRARY, $($ident),* ]; From 2a26b054b722f0d7bdb973d1cfa193b88fbdeae6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 23 Aug 2022 14:00:29 +0200 Subject: [PATCH 26/53] Use lsp-types DECORATOR token type --- Cargo.lock | 4 +-- crates/rust-analyzer/Cargo.toml | 4 +-- crates/rust-analyzer/src/semantic_tokens.rs | 28 ++++++++++----------- crates/rust-analyzer/src/to_proto.rs | 2 +- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 783345ce7a458..8f4a17dc5cac6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -871,9 +871,9 @@ dependencies = [ [[package]] name = "lsp-types" -version = "0.93.0" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70c74e2173b2b31f8655d33724b4b45ac13f439386f66290f539c22b144c2212" +checksum = "a3bcfee315dde785ba887edb540b08765fd7df75a7d948844be6bf5712246734" dependencies = [ "bitflags", "serde", diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index b36732c834d85..5392589186d1d 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -22,8 +22,8 @@ anyhow = "1.0.57" crossbeam-channel = "0.5.5" dissimilar = "1.0.4" itertools = "0.10.3" -lsp-types = { version = "0.93.0", features = ["proposed"] } scip = "0.1.1" +lsp-types = { version = "0.93.1", features = ["proposed"] } parking_lot = "0.12.1" xflags = "0.2.4" oorandom = "11.1.3" @@ -89,5 +89,5 @@ in-rust-tree = [ "proc-macro-srv/sysroot-abi", "sourcegen/in-rust-tree", "ide/in-rust-tree", - "syntax/in-rust-tree" + "syntax/in-rust-tree", ] diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index bb3b5c86bd2f7..b3f5493bf2078 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs @@ -12,26 +12,26 @@ macro_rules! define_semantic_token_types { $(pub(crate) const $ident: SemanticTokenType = SemanticTokenType::new($string);)* pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[ + SemanticTokenType::CLASS, SemanticTokenType::COMMENT, + SemanticTokenType::ENUM_MEMBER, + SemanticTokenType::ENUM, + SemanticTokenType::FUNCTION, + SemanticTokenType::INTERFACE, SemanticTokenType::KEYWORD, - SemanticTokenType::STRING, + SemanticTokenType::MACRO, + SemanticTokenType::METHOD, + SemanticTokenType::NAMESPACE, SemanticTokenType::NUMBER, - SemanticTokenType::REGEXP, SemanticTokenType::OPERATOR, - SemanticTokenType::NAMESPACE, - SemanticTokenType::TYPE, + SemanticTokenType::PARAMETER, + SemanticTokenType::PROPERTY, + SemanticTokenType::REGEXP, + SemanticTokenType::STRING, SemanticTokenType::STRUCT, - SemanticTokenType::CLASS, - SemanticTokenType::INTERFACE, - SemanticTokenType::ENUM, - SemanticTokenType::ENUM_MEMBER, SemanticTokenType::TYPE_PARAMETER, - SemanticTokenType::FUNCTION, - SemanticTokenType::METHOD, - SemanticTokenType::PROPERTY, - SemanticTokenType::MACRO, + SemanticTokenType::TYPE, SemanticTokenType::VARIABLE, - SemanticTokenType::PARAMETER, $($ident),* ]; }; @@ -52,8 +52,6 @@ define_semantic_token_types![ (COMMA, "comma"), (COMPARISON, "comparison"), (CONST_PARAMETER, "constParameter"), - // FIXME: to be replaced once lsp-types has the upstream version - (DECORATOR, "decorator"), (DERIVE, "derive"), (DERIVE_HELPER, "deriveHelper"), (DOT, "dot"), diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 6d83adbc5bf8e..99f7b573999e5 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -558,7 +558,7 @@ fn semantic_token_type_and_modifiers( let mut mods = semantic_tokens::ModifierSet::default(); let type_ = match highlight.tag { HlTag::Symbol(symbol) => match symbol { - SymbolKind::Attribute => semantic_tokens::DECORATOR, + SymbolKind::Attribute => lsp_types::SemanticTokenType::DECORATOR, SymbolKind::Derive => semantic_tokens::DERIVE, SymbolKind::DeriveHelper => semantic_tokens::DERIVE_HELPER, SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE, From 6c5d15800ea3b8297bf42221c449e633ef3926d6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 23 Aug 2022 14:29:59 +0200 Subject: [PATCH 27/53] fix: Fix reference autocompletions using incorrect offsets in macro inputs Fixes https://github.com/rust-lang/rust-analyzer/issues/13035 --- crates/ide-completion/src/context.rs | 3 +++ crates/ide-completion/src/context/analysis.rs | 3 +++ crates/ide-completion/src/render.rs | 27 ++++++++++++++++--- crates/ide-completion/src/render/function.rs | 16 +++++------ crates/ide-completion/src/render/literal.rs | 8 +++--- 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 759742d347237..a5e854b74df9d 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -64,8 +64,11 @@ pub(crate) struct PathCompletionCtx { pub(super) qualified: Qualified, /// The parent of the path we are completing. pub(super) parent: Option, + #[allow(dead_code)] /// The path of which we are completing the segment pub(super) path: ast::Path, + /// The path of which we are completing the segment in the original file + pub(crate) original_path: Option, pub(super) kind: PathKind, /// Whether the path segment has type args or not. pub(super) has_type_args: bool, diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 22ec7cead4988..01dd9a234f553 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -588,12 +588,15 @@ impl<'a> CompletionContext<'a> { }; let path = segment.parent_path(); + let original_path = find_node_in_file_compensated(sema, original_file, &path); + let mut path_ctx = PathCompletionCtx { has_call_parens: false, has_macro_bang: false, qualified: Qualified::No, parent: None, path: path.clone(), + original_path, kind: PathKind::Item { kind: ItemListKind::SourceFile }, has_type_args: false, use_tree_parent: false, diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index a2cf6d68e5b3a..86302cb0678f1 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -323,9 +323,7 @@ fn render_resolution_path( ..CompletionRelevance::default() }); - if let Some(ref_match) = compute_ref_match(completion, &ty) { - item.ref_match(ref_match, path_ctx.path.syntax().text_range().start()); - } + path_ref_match(completion, path_ctx, &ty, &mut item); }; item } @@ -453,6 +451,29 @@ fn compute_ref_match( None } +fn path_ref_match( + completion: &CompletionContext<'_>, + path_ctx: &PathCompletionCtx, + ty: &hir::Type, + item: &mut Builder, +) { + if let Some(original_path) = &path_ctx.original_path { + // At least one char was typed by the user already, in that case look for the original path + if let Some(original_path) = completion.sema.original_ast_node(original_path.clone()) { + if let Some(ref_match) = compute_ref_match(completion, ty) { + item.ref_match(ref_match, original_path.syntax().text_range().start()); + } + } + } else { + // completion requested on an empty identifier, there is no path here yet. + // FIXME: This might create inconsistent completions where we show a ref match in macro inputs + // as long as nothing was typed yet + if let Some(ref_match) = compute_ref_match(completion, ty) { + item.ref_match(ref_match, completion.position.offset); + } + } +} + #[cfg(test)] mod tests { use std::cmp; diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs index 9cf64691298eb..3761208460476 100644 --- a/crates/ide-completion/src/render/function.rs +++ b/crates/ide-completion/src/render/function.rs @@ -79,18 +79,18 @@ fn render( ..ctx.completion_relevance() }); - if let Some(ref_match) = compute_ref_match(completion, &ret_type) { - match func_kind { - FuncKind::Function(path_ctx) => { - item.ref_match(ref_match, path_ctx.path.syntax().text_range().start()); - } - FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => { - if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) { + match func_kind { + FuncKind::Function(path_ctx) => { + super::path_ref_match(completion, path_ctx, &ret_type, &mut item); + } + FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => { + if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) { + if let Some(ref_match) = compute_ref_match(completion, &ret_type) { item.ref_match(ref_match, original_expr.syntax().text_range().start()); } } - _ => (), } + _ => (), } item.set_documentation(ctx.docs(func)) diff --git a/crates/ide-completion/src/render/literal.rs b/crates/ide-completion/src/render/literal.rs index af9c88a7e0a6c..0c791ac570c56 100644 --- a/crates/ide-completion/src/render/literal.rs +++ b/crates/ide-completion/src/render/literal.rs @@ -2,13 +2,12 @@ use hir::{db::HirDatabase, Documentation, HasAttrs, StructKind}; use ide_db::SymbolKind; -use syntax::AstNode; use crate::{ context::{CompletionContext, PathCompletionCtx, PathKind}, item::{Builder, CompletionItem}, render::{ - compute_ref_match, compute_type_match, + compute_type_match, variant::{ format_literal_label, format_literal_lookup, render_record_lit, render_tuple_lit, visible_fields, RenderedLiteral, @@ -125,9 +124,8 @@ fn render( type_match: compute_type_match(ctx.completion, &ty), ..ctx.completion_relevance() }); - if let Some(ref_match) = compute_ref_match(completion, &ty) { - item.ref_match(ref_match, path_ctx.path.syntax().text_range().start()); - } + + super::path_ref_match(completion, path_ctx, &ty, &mut item); if let Some(import_to_add) = ctx.import_to_add { item.add_import(import_to_add); From 16a0eb1829b569e2d1e1046a60fd7e25aa35bfcf Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Aug 2022 15:45:02 +0200 Subject: [PATCH 28/53] Avoid error popup when using in Live Share --- editors/code/src/main.ts | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index a9847dd2a6521..ae145234792c7 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -33,7 +33,7 @@ export function outputChannel() { } export interface RustAnalyzerExtensionApi { - client: lc.LanguageClient; + client?: lc.LanguageClient; } export async function activate( @@ -48,6 +48,23 @@ export async function activate( } async function tryActivate(context: vscode.ExtensionContext): Promise { + // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if + // only those are in use. + // (r-a still somewhat works with Live Share, because commands are tunneled to the host) + const folders = (vscode.workspace.workspaceFolders || []).filter((folder) => + folder.uri.scheme == "file" + ); + const rustDocuments = vscode.workspace.textDocuments.filter((document) => + isRustDocument(document) + ); + + if (folders.length == 0 && rustDocuments.length == 0) { + // FIXME: Ideally we would choose not to activate at all (and avoid registering + // non-functional editor commands), but VS Code doesn't seem to have a good way of doing + // that + return {}; + } + const config = new Config(context); const state = new PersistentState(context.globalState); const serverPath = await bootstrap(context, config, state).catch((err) => { @@ -60,18 +77,11 @@ async function tryActivate(context: vscode.ExtensionContext): Promise - isRustDocument(document) - ); - if (rustDocuments.length > 0) { - ctx = await Ctx.create(config, context, serverPath, { - kind: "Detached Files", - files: rustDocuments, - }); - } else { - throw new Error("no rust files are opened"); - } + if (folders.length === 0) { + ctx = await Ctx.create(config, context, serverPath, { + kind: "Detached Files", + files: rustDocuments, + }); } else { // Note: we try to start the server before we activate type hints so that it // registers its `onDidChangeDocument` handler before us. From dcbbb7f211771fc08281312310067469e58efa0b Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Aug 2022 15:56:02 +0200 Subject: [PATCH 29/53] =?UTF-8?q?ForGoT=20tO=20RuN=20prEttIeR=C2=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- editors/code/src/main.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index ae145234792c7..e9b62e0cc2578 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -51,14 +51,14 @@ async function tryActivate(context: vscode.ExtensionContext): Promise - folder.uri.scheme == "file" + const folders = (vscode.workspace.workspaceFolders || []).filter( + (folder) => folder.uri.scheme === "file" ); const rustDocuments = vscode.workspace.textDocuments.filter((document) => isRustDocument(document) ); - if (folders.length == 0 && rustDocuments.length == 0) { + if (folders.length === 0 && rustDocuments.length === 0) { // FIXME: Ideally we would choose not to activate at all (and avoid registering // non-functional editor commands), but VS Code doesn't seem to have a good way of doing // that From 8969655ed6cb6cbee260e1931d546ee7077b9349 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Aug 2022 16:31:59 +0200 Subject: [PATCH 30/53] Allow leading `|` in more pattern positions --- crates/parser/src/grammar/patterns.rs | 13 ++++-- .../parser/inline/ok/0024_slice_pat.rast | 23 +++++++++++ .../parser/inline/ok/0024_slice_pat.rs | 1 + .../inline/ok/0026_tuple_pat_fields.rast | 23 +++++++++++ .../parser/inline/ok/0026_tuple_pat_fields.rs | 1 + .../parser/inline/ok/0111_tuple_pat.rast | 40 +++++++++++++++++++ .../parser/inline/ok/0111_tuple_pat.rs | 1 + 7 files changed, 98 insertions(+), 4 deletions(-) diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs index 7e21a808da0a4..bc1224af9b212 100644 --- a/crates/parser/src/grammar/patterns.rs +++ b/crates/parser/src/grammar/patterns.rs @@ -13,6 +13,8 @@ pub(super) const PATTERN_FIRST: TokenSet = T![.], ])); +const PAT_TOP_FIRST: TokenSet = PATTERN_FIRST.union(TokenSet::new(&[T![|]])); + pub(crate) fn pattern(p: &mut Parser<'_>) { pattern_r(p, PAT_RECOVERY_SET); } @@ -228,6 +230,7 @@ fn path_or_macro_pat(p: &mut Parser<'_>) -> CompletedMarker { // let S(_) = (); // let S(_,) = (); // let S(_, .. , x) = (); +// let S(| a) = (); // } fn tuple_pat_fields(p: &mut Parser<'_>) { assert!(p.at(T!['('])); @@ -363,6 +366,7 @@ fn ref_pat(p: &mut Parser<'_>) -> CompletedMarker { // let (a,) = (); // let (..) = (); // let () = (); +// let (| a | a, | b) = ((),()); // } fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker { assert!(p.at(T!['('])); @@ -373,13 +377,13 @@ fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker { let mut has_rest = false; while !p.at(EOF) && !p.at(T![')']) { has_pat = true; - if !p.at_ts(PATTERN_FIRST) { + if !p.at_ts(PAT_TOP_FIRST) { p.error("expected a pattern"); break; } has_rest |= p.at(T![..]); - pattern(p); + pattern_top(p); if !p.at(T![')']) { has_comma = true; p.expect(T![,]); @@ -393,6 +397,7 @@ fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker { // test slice_pat // fn main() { // let [a, b, ..] = []; +// let [| a, ..] = []; // } fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker { assert!(p.at(T!['['])); @@ -405,12 +410,12 @@ fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker { fn pat_list(p: &mut Parser<'_>, ket: SyntaxKind) { while !p.at(EOF) && !p.at(ket) { - if !p.at_ts(PATTERN_FIRST) { + if !p.at_ts(PAT_TOP_FIRST) { p.error("expected a pattern"); break; } - pattern(p); + pattern_top(p); if !p.at(ket) { p.expect(T![,]); } diff --git a/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast b/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast index 235a9d7f404cf..dff72ba886fe8 100644 --- a/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast +++ b/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast @@ -37,6 +37,29 @@ SOURCE_FILE L_BRACK "[" R_BRACK "]" SEMICOLON ";" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + SLICE_PAT + L_BRACK "[" + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "a" + COMMA "," + WHITESPACE " " + REST_PAT + DOT2 ".." + R_BRACK "]" + WHITESPACE " " + EQ "=" + WHITESPACE " " + ARRAY_EXPR + L_BRACK "[" + R_BRACK "]" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs b/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs index 7955973b952a7..855ba89b1e9d9 100644 --- a/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs +++ b/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs @@ -1,3 +1,4 @@ fn main() { let [a, b, ..] = []; + let [| a, ..] = []; } diff --git a/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast b/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast index 3cdaf32b5721c..55baf2fdcb4f6 100644 --- a/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast +++ b/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast @@ -100,6 +100,29 @@ SOURCE_FILE L_PAREN "(" R_PAREN ")" SEMICOLON ";" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + TUPLE_STRUCT_PAT + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + L_PAREN "(" + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "a" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs b/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs index 0dfe63629679b..8ec6f4ca93e03 100644 --- a/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs +++ b/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs @@ -3,4 +3,5 @@ fn foo() { let S(_) = (); let S(_,) = (); let S(_, .. , x) = (); + let S(| a) = (); } diff --git a/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast b/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast index cebe98c43aa62..1a01e0f69381f 100644 --- a/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast +++ b/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast @@ -85,6 +85,46 @@ SOURCE_FILE L_PAREN "(" R_PAREN ")" SEMICOLON ";" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + TUPLE_PAT + L_PAREN "(" + PIPE "|" + WHITESPACE " " + OR_PAT + IDENT_PAT + NAME + IDENT "a" + WHITESPACE " " + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "a" + COMMA "," + WHITESPACE " " + PIPE "|" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "b" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + COMMA "," + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + R_PAREN ")" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs b/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs index ba719879d4c1a..fbd7f48f66bd9 100644 --- a/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs +++ b/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs @@ -3,4 +3,5 @@ fn main() { let (a,) = (); let (..) = (); let () = (); + let (| a | a, | b) = ((),()); } From 0cc1a89e08b26a7e9aa4b215f9e3ccc1b667ff58 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Aug 2022 16:47:26 +0200 Subject: [PATCH 31/53] Add a short blurb about VS Code Live Share to the manual --- docs/user/manual.adoc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index c482fcbed0e01..9bd3b6a692b1a 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -861,3 +861,14 @@ For example, if you want to run https://crates.io/crates/cargo-watch[`cargo watc "isBackground": true } ``` + +==== Live Share + +VS Code Live Share has partial support for rust-analyzer. + +Live Share _requires_ the official Microsoft build of VS Code, OSS builds will not work correctly. + +The host's rust-analyzer instance will be shared with all guests joining the session. +The guests do not have to have the rust-analyzer extension installed for this to work. + +If you are joining a Live Share session and _do_ have rust-analyzer installed locally, commands from the command palette will not work correctly since they will attempt to communicate with the local server. From 580441286994284c0c6a2f9a093c4f4fc0c41950 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Aug 2022 17:46:29 +0200 Subject: [PATCH 32/53] Register decorator token type to avoid panic --- crates/rust-analyzer/src/semantic_tokens.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index b3f5493bf2078..4493da19c122e 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs @@ -32,6 +32,7 @@ macro_rules! define_semantic_token_types { SemanticTokenType::TYPE_PARAMETER, SemanticTokenType::TYPE, SemanticTokenType::VARIABLE, + SemanticTokenType::DECORATOR, $($ident),* ]; }; From 322e7060de89b855d254dcc62309d8cb4dd5db56 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Aug 2022 17:50:45 +0200 Subject: [PATCH 33/53] Resolve doc links on impl blocks --- crates/ide/src/doc_links.rs | 2 +- .../src/syntax_highlighting/test_data/highlight_doctest.html | 2 +- crates/ide/src/syntax_highlighting/tests.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 582e9fe7e808c..92ce26b422e1d 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -184,10 +184,10 @@ pub(crate) fn resolve_doc_path_for_def( Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns), Definition::Macro(it) => it.resolve_doc_path(db, link, ns), Definition::Field(it) => it.resolve_doc_path(db, link, ns), + Definition::SelfType(it) => it.resolve_doc_path(db, link, ns), Definition::BuiltinAttr(_) | Definition::ToolModule(_) | Definition::BuiltinType(_) - | Definition::SelfType(_) | Definition::Local(_) | Definition::GenericParam(_) | Definition::Label(_) diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index a747b4bc1f9c0..eef5baea98392 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html @@ -56,7 +56,7 @@ bar: bool, } -/// This is an impl with a code block. +/// This is an impl of [`Foo`] with a code block. /// /// ``` /// fn foo() { diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 51ddea63ac136..46cc667fc454f 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -624,7 +624,7 @@ struct Foo { bar: bool, } -/// This is an impl with a code block. +/// This is an impl of [`Foo`] with a code block. /// /// ``` /// fn foo() { From 715e3fc1199628f8badb90f918182aca1b074410 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 23 Aug 2022 18:06:32 +0200 Subject: [PATCH 34/53] Re-export standard semantic token types and mods --- crates/rust-analyzer/src/semantic_tokens.rs | 186 +++++++++++--------- crates/rust-analyzer/src/to_proto.rs | 52 +++--- 2 files changed, 133 insertions(+), 105 deletions(-) diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index 4493da19c122e..c48410ed55e98 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs @@ -8,102 +8,130 @@ use lsp_types::{ }; macro_rules! define_semantic_token_types { - ($(($ident:ident, $string:literal)),*$(,)?) => { - $(pub(crate) const $ident: SemanticTokenType = SemanticTokenType::new($string);)* + ( + standard { + $($standard:ident),*$(,)? + } + custom { + $(($custom:ident, $string:literal)),*$(,)? + } + + ) => { + $(pub(crate) const $standard: SemanticTokenType = SemanticTokenType::$standard;)* + $(pub(crate) const $custom: SemanticTokenType = SemanticTokenType::new($string);)* pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[ - SemanticTokenType::CLASS, - SemanticTokenType::COMMENT, - SemanticTokenType::ENUM_MEMBER, - SemanticTokenType::ENUM, - SemanticTokenType::FUNCTION, - SemanticTokenType::INTERFACE, - SemanticTokenType::KEYWORD, - SemanticTokenType::MACRO, - SemanticTokenType::METHOD, - SemanticTokenType::NAMESPACE, - SemanticTokenType::NUMBER, - SemanticTokenType::OPERATOR, - SemanticTokenType::PARAMETER, - SemanticTokenType::PROPERTY, - SemanticTokenType::REGEXP, - SemanticTokenType::STRING, - SemanticTokenType::STRUCT, - SemanticTokenType::TYPE_PARAMETER, - SemanticTokenType::TYPE, - SemanticTokenType::VARIABLE, - SemanticTokenType::DECORATOR, - $($ident),* + $(SemanticTokenType::$standard,)* + $($custom),* ]; }; } define_semantic_token_types![ - (ANGLE, "angle"), - (ARITHMETIC, "arithmetic"), - (ATTRIBUTE_BRACKET, "attributeBracket"), - (BITWISE, "bitwise"), - (BOOLEAN, "boolean"), - (BRACE, "brace"), - (BRACKET, "bracket"), - (BUILTIN_ATTRIBUTE, "builtinAttribute"), - (BUILTIN_TYPE, "builtinType"), - (CHAR, "character"), - (COLON, "colon"), - (COMMA, "comma"), - (COMPARISON, "comparison"), - (CONST_PARAMETER, "constParameter"), - (DERIVE, "derive"), - (DERIVE_HELPER, "deriveHelper"), - (DOT, "dot"), - (ESCAPE_SEQUENCE, "escapeSequence"), - (FORMAT_SPECIFIER, "formatSpecifier"), - (GENERIC, "generic"), - (LABEL, "label"), - (LIFETIME, "lifetime"), - (LOGICAL, "logical"), - (MACRO_BANG, "macroBang"), - (PARENTHESIS, "parenthesis"), - (PUNCTUATION, "punctuation"), - (SELF_KEYWORD, "selfKeyword"), - (SELF_TYPE_KEYWORD, "selfTypeKeyword"), - (SEMICOLON, "semicolon"), - (TYPE_ALIAS, "typeAlias"), - (TOOL_MODULE, "toolModule"), - (UNION, "union"), - (UNRESOLVED_REFERENCE, "unresolvedReference"), + standard { + COMMENT, + DECORATOR, + ENUM_MEMBER, + ENUM, + FUNCTION, + INTERFACE, + KEYWORD, + MACRO, + METHOD, + NAMESPACE, + NUMBER, + OPERATOR, + PARAMETER, + PROPERTY, + STRING, + STRUCT, + TYPE_PARAMETER, + VARIABLE, + } + + custom { + (ANGLE, "angle"), + (ARITHMETIC, "arithmetic"), + (ATTRIBUTE, "attribute"), + (ATTRIBUTE_BRACKET, "attributeBracket"), + (BITWISE, "bitwise"), + (BOOLEAN, "boolean"), + (BRACE, "brace"), + (BRACKET, "bracket"), + (BUILTIN_ATTRIBUTE, "builtinAttribute"), + (BUILTIN_TYPE, "builtinType"), + (CHAR, "character"), + (COLON, "colon"), + (COMMA, "comma"), + (COMPARISON, "comparison"), + (CONST_PARAMETER, "constParameter"), + (DERIVE, "derive"), + (DERIVE_HELPER, "deriveHelper"), + (DOT, "dot"), + (ESCAPE_SEQUENCE, "escapeSequence"), + (FORMAT_SPECIFIER, "formatSpecifier"), + (GENERIC, "generic"), + (LABEL, "label"), + (LIFETIME, "lifetime"), + (LOGICAL, "logical"), + (MACRO_BANG, "macroBang"), + (PARENTHESIS, "parenthesis"), + (PUNCTUATION, "punctuation"), + (SELF_KEYWORD, "selfKeyword"), + (SELF_TYPE_KEYWORD, "selfTypeKeyword"), + (SEMICOLON, "semicolon"), + (TYPE_ALIAS, "typeAlias"), + (TOOL_MODULE, "toolModule"), + (UNION, "union"), + (UNRESOLVED_REFERENCE, "unresolvedReference"), + } ]; macro_rules! define_semantic_token_modifiers { - ($(($ident:ident, $string:literal)),*$(,)?) => { - $(pub(crate) const $ident: SemanticTokenModifier = SemanticTokenModifier::new($string);)* + ( + standard { + $($standard:ident),*$(,)? + } + custom { + $(($custom:ident, $string:literal)),*$(,)? + } + + ) => { + + $(pub(crate) const $standard: SemanticTokenModifier = SemanticTokenModifier::$standard;)* + $(pub(crate) const $custom: SemanticTokenModifier = SemanticTokenModifier::new($string);)* pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[ - SemanticTokenModifier::DOCUMENTATION, - SemanticTokenModifier::DECLARATION, - SemanticTokenModifier::STATIC, - SemanticTokenModifier::DEFAULT_LIBRARY, - $($ident),* + $(SemanticTokenModifier::$standard,)* + $($custom),* ]; }; } define_semantic_token_modifiers![ - (ASYNC, "async"), - (ATTRIBUTE_MODIFIER, "attribute"), - (CALLABLE, "callable"), - (CONSTANT, "constant"), - (CONSUMING, "consuming"), - (CONTROL_FLOW, "controlFlow"), - (CRATE_ROOT, "crateRoot"), - (INJECTED, "injected"), - (INTRA_DOC_LINK, "intraDocLink"), - (LIBRARY, "library"), - (MUTABLE, "mutable"), - (PUBLIC, "public"), - (REFERENCE, "reference"), - (TRAIT_MODIFIER, "trait"), - (UNSAFE, "unsafe"), + standard { + DOCUMENTATION, + DECLARATION, + STATIC, + DEFAULT_LIBRARY, + } + custom { + (ASYNC, "async"), + (ATTRIBUTE_MODIFIER, "attribute"), + (CALLABLE, "callable"), + (CONSTANT, "constant"), + (CONSUMING, "consuming"), + (CONTROL_FLOW, "controlFlow"), + (CRATE_ROOT, "crateRoot"), + (INJECTED, "injected"), + (INTRA_DOC_LINK, "intraDocLink"), + (LIBRARY, "library"), + (MUTABLE, "mutable"), + (PUBLIC, "public"), + (REFERENCE, "reference"), + (TRAIT_MODIFIER, "trait"), + (UNSAFE, "unsafe"), + } ]; #[derive(Default)] diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 99f7b573999e5..102cd60295043 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -558,64 +558,64 @@ fn semantic_token_type_and_modifiers( let mut mods = semantic_tokens::ModifierSet::default(); let type_ = match highlight.tag { HlTag::Symbol(symbol) => match symbol { - SymbolKind::Attribute => lsp_types::SemanticTokenType::DECORATOR, + SymbolKind::Attribute => semantic_tokens::DECORATOR, SymbolKind::Derive => semantic_tokens::DERIVE, SymbolKind::DeriveHelper => semantic_tokens::DERIVE_HELPER, - SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE, + SymbolKind::Module => semantic_tokens::NAMESPACE, SymbolKind::Impl => semantic_tokens::TYPE_ALIAS, - SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, - SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, + SymbolKind::Field => semantic_tokens::PROPERTY, + SymbolKind::TypeParam => semantic_tokens::TYPE_PARAMETER, SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER, SymbolKind::LifetimeParam => semantic_tokens::LIFETIME, SymbolKind::Label => semantic_tokens::LABEL, - SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER, + SymbolKind::ValueParam => semantic_tokens::PARAMETER, SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD, SymbolKind::SelfType => semantic_tokens::SELF_TYPE_KEYWORD, - SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE, + SymbolKind::Local => semantic_tokens::VARIABLE, SymbolKind::Function => { if highlight.mods.contains(HlMod::Associated) { - lsp_types::SemanticTokenType::METHOD + semantic_tokens::METHOD } else { - lsp_types::SemanticTokenType::FUNCTION + semantic_tokens::FUNCTION } } SymbolKind::Const => { mods |= semantic_tokens::CONSTANT; - mods |= lsp_types::SemanticTokenModifier::STATIC; - lsp_types::SemanticTokenType::VARIABLE + mods |= semantic_tokens::STATIC; + semantic_tokens::VARIABLE } SymbolKind::Static => { - mods |= lsp_types::SemanticTokenModifier::STATIC; - lsp_types::SemanticTokenType::VARIABLE + mods |= semantic_tokens::STATIC; + semantic_tokens::VARIABLE } - SymbolKind::Struct => lsp_types::SemanticTokenType::STRUCT, - SymbolKind::Enum => lsp_types::SemanticTokenType::ENUM, - SymbolKind::Variant => lsp_types::SemanticTokenType::ENUM_MEMBER, + SymbolKind::Struct => semantic_tokens::STRUCT, + SymbolKind::Enum => semantic_tokens::ENUM, + SymbolKind::Variant => semantic_tokens::ENUM_MEMBER, SymbolKind::Union => semantic_tokens::UNION, SymbolKind::TypeAlias => semantic_tokens::TYPE_ALIAS, - SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE, - SymbolKind::Macro => lsp_types::SemanticTokenType::MACRO, + SymbolKind::Trait => semantic_tokens::INTERFACE, + SymbolKind::Macro => semantic_tokens::MACRO, SymbolKind::BuiltinAttr => semantic_tokens::BUILTIN_ATTRIBUTE, SymbolKind::ToolModule => semantic_tokens::TOOL_MODULE, }, HlTag::AttributeBracket => semantic_tokens::ATTRIBUTE_BRACKET, HlTag::BoolLiteral => semantic_tokens::BOOLEAN, HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, - HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER, + HlTag::ByteLiteral | HlTag::NumericLiteral => semantic_tokens::NUMBER, HlTag::CharLiteral => semantic_tokens::CHAR, - HlTag::Comment => lsp_types::SemanticTokenType::COMMENT, + HlTag::Comment => semantic_tokens::COMMENT, HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, - HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD, + HlTag::Keyword => semantic_tokens::KEYWORD, HlTag::None => semantic_tokens::GENERIC, HlTag::Operator(op) => match op { HlOperator::Bitwise => semantic_tokens::BITWISE, HlOperator::Arithmetic => semantic_tokens::ARITHMETIC, HlOperator::Logical => semantic_tokens::LOGICAL, HlOperator::Comparison => semantic_tokens::COMPARISON, - HlOperator::Other => lsp_types::SemanticTokenType::OPERATOR, + HlOperator::Other => semantic_tokens::OPERATOR, }, - HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING, + HlTag::StringLiteral => semantic_tokens::STRING, HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE, HlTag::Punctuation(punct) => match punct { HlPunct::Bracket => semantic_tokens::BRACKET, @@ -640,16 +640,16 @@ fn semantic_token_type_and_modifiers( HlMod::Consuming => semantic_tokens::CONSUMING, HlMod::ControlFlow => semantic_tokens::CONTROL_FLOW, HlMod::CrateRoot => semantic_tokens::CRATE_ROOT, - HlMod::DefaultLibrary => lsp_types::SemanticTokenModifier::DEFAULT_LIBRARY, - HlMod::Definition => lsp_types::SemanticTokenModifier::DECLARATION, - HlMod::Documentation => lsp_types::SemanticTokenModifier::DOCUMENTATION, + HlMod::DefaultLibrary => semantic_tokens::DEFAULT_LIBRARY, + HlMod::Definition => semantic_tokens::DECLARATION, + HlMod::Documentation => semantic_tokens::DOCUMENTATION, HlMod::Injected => semantic_tokens::INJECTED, HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK, HlMod::Library => semantic_tokens::LIBRARY, HlMod::Mutable => semantic_tokens::MUTABLE, HlMod::Public => semantic_tokens::PUBLIC, HlMod::Reference => semantic_tokens::REFERENCE, - HlMod::Static => lsp_types::SemanticTokenModifier::STATIC, + HlMod::Static => semantic_tokens::STATIC, HlMod::Trait => semantic_tokens::TRAIT_MODIFIER, HlMod::Unsafe => semantic_tokens::UNSAFE, }; From 71c15f2a442df1760c535ebec51768187209cd10 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Thu, 25 Aug 2022 13:11:14 +0530 Subject: [PATCH 35/53] add test --- .../src/handlers/extract_type_alias.rs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/crates/ide-assists/src/handlers/extract_type_alias.rs b/crates/ide-assists/src/handlers/extract_type_alias.rs index af584cdb4384a..c0586169bc951 100644 --- a/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -357,4 +357,27 @@ impl<'outer, Outer, const OUTER: usize> () { "#, ); } + + #[test] + fn issue_11197 () { + check_assist(extract_type_alias, + r#" +struct Foo +where + [T; N]: Sized, +{ + arr: $0[T; N]$0, +} + "#, + r#" +type $0Type = [T; N]; + +struct Foo +where + [T; N]: Sized, +{ + arr: Type, +} + "#); + } } From 9480b38189f1246fc96a58036fcfbc5527ae6516 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Thu, 25 Aug 2022 13:11:51 +0530 Subject: [PATCH 36/53] extract const generic in ArrayType --- .../src/handlers/extract_type_alias.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/crates/ide-assists/src/handlers/extract_type_alias.rs b/crates/ide-assists/src/handlers/extract_type_alias.rs index c0586169bc951..0e031a793bf8d 100644 --- a/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -171,6 +171,25 @@ fn collect_used_generics<'gp>( 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); + } + } + } + } + } + }, _ => (), }); // stable resort to lifetime, type, const From 0d7ba13b7227c66774decc059d96246ac05558da Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Thu, 25 Aug 2022 13:17:50 +0530 Subject: [PATCH 37/53] style: run tidy tests --- crates/ide-assists/src/handlers/extract_type_alias.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_type_alias.rs b/crates/ide-assists/src/handlers/extract_type_alias.rs index 0e031a793bf8d..03aa8601d14e1 100644 --- a/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -189,7 +189,7 @@ fn collect_used_generics<'gp>( } } } - }, + } _ => (), }); // stable resort to lifetime, type, const @@ -378,8 +378,9 @@ impl<'outer, Outer, const OUTER: usize> () { } #[test] - fn issue_11197 () { - check_assist(extract_type_alias, + fn issue_11197() { + check_assist( + extract_type_alias, r#" struct Foo where @@ -397,6 +398,7 @@ where { arr: Type, } - "#); + "#, + ); } } From 10617938b1c9a0ee873762c6806483e0ead209f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 25 Aug 2022 21:33:42 +0300 Subject: [PATCH 38/53] Remove unused UpdatesChannel type --- editors/code/src/config.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index b83582a344a98..07e899eb0aa76 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -3,8 +3,6 @@ import * as vscode from "vscode"; import { Env } from "./client"; import { log } from "./util"; -export type UpdatesChannel = "stable" | "nightly"; - export type RunnableEnvCfg = | undefined | Record From d025c5d8d6c3088062bb3cb642e05dd709152e3d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 25 Aug 2022 20:31:02 +0200 Subject: [PATCH 39/53] Make use of NoHash hashing for FileId and CrateId --- Cargo.lock | 2 + crates/base-db/src/input.rs | 40 +++++++---- crates/base-db/src/lib.rs | 12 ++-- crates/hir-def/src/test_db.rs | 4 +- crates/hir-ty/src/test_db.rs | 6 +- crates/ide-db/src/lib.rs | 3 +- crates/ide-db/src/line_index.rs | 6 +- crates/ide-db/src/search.rs | 22 +++--- crates/ide-db/src/source_change.rs | 11 ++- crates/ide-ssr/Cargo.toml | 1 + crates/ide-ssr/src/lib.rs | 10 ++- crates/ide/src/prime_caches.rs | 5 +- crates/ide/src/references.rs | 5 +- crates/ide/src/view_crate_graph.rs | 5 +- crates/project-model/src/workspace.rs | 4 +- crates/rust-analyzer/src/diagnostics.rs | 15 ++-- crates/rust-analyzer/src/global_state.rs | 7 +- crates/stdx/src/hash.rs | 87 ++++++++++++++++++++++++ crates/stdx/src/lib.rs | 1 + crates/vfs/Cargo.toml | 3 +- crates/vfs/src/file_set.rs | 3 +- crates/vfs/src/lib.rs | 9 ++- 22 files changed, 189 insertions(+), 72 deletions(-) create mode 100644 crates/stdx/src/hash.rs diff --git a/Cargo.lock b/Cargo.lock index 8f4a17dc5cac6..9f10d92c4e3ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -704,6 +704,7 @@ dependencies = [ "ide-db", "itertools", "parser", + "stdx", "syntax", "test-utils", "text-edit", @@ -1921,6 +1922,7 @@ dependencies = [ "indexmap", "paths", "rustc-hash", + "stdx", ] [[package]] diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 9580ce8007c76..b388e47dee6e4 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -9,10 +9,11 @@ use std::{fmt, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc}; use cfg::CfgOptions; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashMap; +use stdx::hash::{NoHashHashMap, NoHashHashSet}; use syntax::SmolStr; use tt::Subtree; -use vfs::{file_set::FileSet, FileId, VfsPath}; +use vfs::{file_set::FileSet, AnchoredPath, FileId, VfsPath}; /// 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 @@ -31,22 +32,30 @@ pub struct SourceRoot { /// Libraries are considered mostly immutable, this assumption is used to /// optimize salsa's query structure pub is_library: bool, - pub(crate) file_set: FileSet, + file_set: FileSet, } impl SourceRoot { pub fn new_local(file_set: FileSet) -> SourceRoot { SourceRoot { is_library: false, file_set } } + pub fn new_library(file_set: FileSet) -> SourceRoot { SourceRoot { is_library: true, file_set } } + pub fn path_for_file(&self, file: &FileId) -> Option<&VfsPath> { self.file_set.path_for_file(file) } + pub fn file_for_path(&self, path: &VfsPath) -> Option<&FileId> { self.file_set.file_for_path(path) } + + pub fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { + self.file_set.resolve_path(path) + } + pub fn iter(&self) -> impl Iterator + '_ { self.file_set.iter() } @@ -72,12 +81,19 @@ impl SourceRoot { /// #[derive(Debug, Clone, Default /* Serialize, Deserialize */)] pub struct CrateGraph { - arena: FxHashMap, + arena: NoHashHashMap, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 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); @@ -342,7 +358,7 @@ impl CrateGraph { // Check if adding a dep from `from` to `to` creates a cycle. To figure // that out, look for a path in the *opposite* direction, from `to` to // `from`. - if let Some(path) = self.find_path(&mut FxHashSet::default(), dep.crate_id, from) { + if let Some(path) = self.find_path(&mut NoHashHashSet::default(), dep.crate_id, from) { let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect(); let err = CyclicDependenciesError { path }; assert!(err.from().0 == from && err.to().0 == dep.crate_id); @@ -365,7 +381,7 @@ impl CrateGraph { /// including the crate itself. pub fn transitive_deps(&self, of: CrateId) -> impl Iterator { let mut worklist = vec![of]; - let mut deps = FxHashSet::default(); + let mut deps = NoHashHashSet::default(); while let Some(krate) = worklist.pop() { if !deps.insert(krate) { @@ -382,10 +398,10 @@ impl CrateGraph { /// including the crate itself. pub fn transitive_rev_deps(&self, of: CrateId) -> impl Iterator { let mut worklist = vec![of]; - let mut rev_deps = FxHashSet::default(); + let mut rev_deps = NoHashHashSet::default(); rev_deps.insert(of); - let mut inverted_graph = FxHashMap::<_, Vec<_>>::default(); + let mut inverted_graph = NoHashHashMap::<_, Vec<_>>::default(); self.arena.iter().for_each(|(&krate, data)| { data.dependencies .iter() @@ -409,7 +425,7 @@ impl CrateGraph { /// come before the crate itself). pub fn crates_in_topological_order(&self) -> Vec { let mut res = Vec::new(); - let mut visited = FxHashSet::default(); + let mut visited = NoHashHashSet::default(); for krate in self.arena.keys().copied() { go(self, &mut visited, &mut res, krate); @@ -419,7 +435,7 @@ impl CrateGraph { fn go( graph: &CrateGraph, - visited: &mut FxHashSet, + visited: &mut NoHashHashSet, res: &mut Vec, source: CrateId, ) { @@ -459,7 +475,7 @@ impl CrateGraph { fn find_path( &self, - visited: &mut FxHashSet, + visited: &mut NoHashHashSet, from: CrateId, to: CrateId, ) -> Option> { diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 2d0a95b09d9a1..da11e4ae7bb96 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -8,7 +8,7 @@ pub mod fixture; use std::{panic, sync::Arc}; -use rustc_hash::FxHashSet; +use stdx::hash::NoHashHashSet; use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; pub use crate::{ @@ -58,7 +58,7 @@ pub trait FileLoader { /// Text of the file. fn file_text(&self, file_id: FileId) -> Arc; fn resolve_path(&self, path: AnchoredPath<'_>) -> Option; - fn relevant_crates(&self, file_id: FileId) -> Arc>; + fn relevant_crates(&self, file_id: FileId) -> Arc>; } /// Database which stores all significant input facts: source code and project @@ -94,10 +94,10 @@ pub trait SourceDatabaseExt: SourceDatabase { #[salsa::input] fn source_root(&self, id: SourceRootId) -> Arc; - fn source_root_crates(&self, id: SourceRootId) -> Arc>; + fn source_root_crates(&self, id: SourceRootId) -> Arc>; } -fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc> { +fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc> { let graph = db.crate_graph(); let res = graph .iter() @@ -120,10 +120,10 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { // FIXME: this *somehow* should be platform agnostic... let source_root = self.0.file_source_root(path.anchor); let source_root = self.0.source_root(source_root); - source_root.file_set.resolve_path(path) + source_root.resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { let _p = profile::span("relevant_crates"); let source_root = self.0.file_source_root(file_id); self.0.source_root_crates(source_root) diff --git a/crates/hir-def/src/test_db.rs b/crates/hir-def/src/test_db.rs index 9cdc18d6b66fd..b7908bddaa1cf 100644 --- a/crates/hir-def/src/test_db.rs +++ b/crates/hir-def/src/test_db.rs @@ -10,7 +10,7 @@ use base_db::{ SourceDatabase, Upcast, }; use hir_expand::{db::AstDatabase, InFile}; -use rustc_hash::FxHashSet; +use stdx::hash::NoHashHashSet; use syntax::{algo, ast, AstNode}; use crate::{ @@ -76,7 +76,7 @@ impl FileLoader for TestDB { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { FileLoaderDelegate(self).resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } diff --git a/crates/hir-ty/src/test_db.rs b/crates/hir-ty/src/test_db.rs index dc7252f7072d8..118e5311e9a64 100644 --- a/crates/hir-ty/src/test_db.rs +++ b/crates/hir-ty/src/test_db.rs @@ -10,7 +10,7 @@ use base_db::{ }; use hir_def::{db::DefDatabase, ModuleId}; use hir_expand::db::AstDatabase; -use rustc_hash::{FxHashMap, FxHashSet}; +use stdx::hash::{NoHashHashMap, NoHashHashSet}; use syntax::TextRange; use test_utils::extract_annotations; @@ -80,7 +80,7 @@ impl FileLoader for TestDB { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { FileLoaderDelegate(self).resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } @@ -102,7 +102,7 @@ impl TestDB { self.module_for_file_opt(file_id).unwrap() } - pub(crate) fn extract_annotations(&self) -> FxHashMap> { + pub(crate) fn extract_annotations(&self) -> NoHashHashMap> { let mut files = Vec::new(); let crate_graph = self.crate_graph(); for krate in crate_graph.iter() { diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs index 966bba616f627..1ec62a8425a39 100644 --- a/crates/ide-db/src/lib.rs +++ b/crates/ide-db/src/lib.rs @@ -52,6 +52,7 @@ use hir::{ db::{AstDatabase, DefDatabase, HirDatabase}, symbols::FileSymbolKind, }; +use stdx::hash::NoHashHashSet; use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; @@ -118,7 +119,7 @@ impl FileLoader for RootDatabase { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option { FileLoaderDelegate(self).resolve_path(path) } - fn relevant_crates(&self, file_id: FileId) -> Arc> { + fn relevant_crates(&self, file_id: FileId) -> Arc> { FileLoaderDelegate(self).relevant_crates(file_id) } } diff --git a/crates/ide-db/src/line_index.rs b/crates/ide-db/src/line_index.rs index 68ad07ee83fde..75d49ff2fd77f 100644 --- a/crates/ide-db/src/line_index.rs +++ b/crates/ide-db/src/line_index.rs @@ -2,7 +2,7 @@ //! representation. use std::{iter, mem}; -use rustc_hash::FxHashMap; +use stdx::hash::NoHashHashMap; use syntax::{TextRange, TextSize}; #[derive(Clone, Debug, PartialEq, Eq)] @@ -10,7 +10,7 @@ pub struct LineIndex { /// Offset the the beginning of each line, zero-based pub(crate) newlines: Vec, /// List of non-ASCII characters on each line - pub(crate) utf16_lines: FxHashMap>, + pub(crate) utf16_lines: NoHashHashMap>, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -55,7 +55,7 @@ impl Utf16Char { impl LineIndex { pub fn new(text: &str) -> LineIndex { - let mut utf16_lines = FxHashMap::default(); + let mut utf16_lines = NoHashHashMap::default(); let mut utf16_chars = Vec::new(); let mut newlines = vec![0.into()]; diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 2f4aa113170a6..7deffe8e0f637 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -9,7 +9,7 @@ use std::{mem, sync::Arc}; use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility}; use once_cell::unsync::Lazy; -use rustc_hash::FxHashMap; +use stdx::hash::NoHashHashMap; use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; use crate::{ @@ -20,7 +20,7 @@ use crate::{ #[derive(Debug, Default, Clone)] pub struct UsageSearchResult { - pub references: FxHashMap>, + pub references: NoHashHashMap>, } impl UsageSearchResult { @@ -45,7 +45,7 @@ impl UsageSearchResult { impl IntoIterator for UsageSearchResult { type Item = (FileId, Vec); - type IntoIter = > as IntoIterator>::IntoIter; + type IntoIter = > as IntoIterator>::IntoIter; fn into_iter(self) -> Self::IntoIter { self.references.into_iter() @@ -78,17 +78,17 @@ pub enum ReferenceCategory { /// e.g. for things like local variables. #[derive(Clone, Debug)] pub struct SearchScope { - entries: FxHashMap>, + entries: NoHashHashMap>, } impl SearchScope { - fn new(entries: FxHashMap>) -> SearchScope { + fn new(entries: NoHashHashMap>) -> SearchScope { SearchScope { entries } } /// Build a search scope spanning the entire crate graph of files. fn crate_graph(db: &RootDatabase) -> SearchScope { - let mut entries = FxHashMap::default(); + let mut entries = NoHashHashMap::default(); let graph = db.crate_graph(); for krate in graph.iter() { @@ -102,7 +102,7 @@ impl SearchScope { /// Build a search scope spanning all the reverse dependencies of the given crate. fn reverse_dependencies(db: &RootDatabase, of: hir::Crate) -> SearchScope { - let mut entries = FxHashMap::default(); + let mut entries = NoHashHashMap::default(); for rev_dep in of.transitive_reverse_dependencies(db) { let root_file = rev_dep.root_file(db); let source_root_id = db.file_source_root(root_file); @@ -117,14 +117,12 @@ impl SearchScope { let root_file = of.root_file(db); let source_root_id = db.file_source_root(root_file); let source_root = db.source_root(source_root_id); - SearchScope { - entries: source_root.iter().map(|id| (id, None)).collect::>(), - } + SearchScope { entries: source_root.iter().map(|id| (id, None)).collect() } } /// Build a search scope spanning the given module and all its submodules. fn module_and_children(db: &RootDatabase, module: hir::Module) -> SearchScope { - let mut entries = FxHashMap::default(); + let mut entries = NoHashHashMap::default(); let (file_id, range) = { let InFile { file_id, value } = module.definition_source(db); @@ -157,7 +155,7 @@ impl SearchScope { /// Build an empty search scope. pub fn empty() -> SearchScope { - SearchScope::new(FxHashMap::default()) + SearchScope::new(NoHashHashMap::default()) } /// Build a empty search scope spanning the given file. diff --git a/crates/ide-db/src/source_change.rs b/crates/ide-db/src/source_change.rs index 21314ad74ef93..8e338061df433 100644 --- a/crates/ide-db/src/source_change.rs +++ b/crates/ide-db/src/source_change.rs @@ -6,8 +6,7 @@ use std::{collections::hash_map::Entry, iter, mem}; use base_db::{AnchoredPathBuf, FileId}; -use rustc_hash::FxHashMap; -use stdx::never; +use stdx::{hash::NoHashHashMap, never}; use syntax::{algo, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize}; use text_edit::{TextEdit, TextEditBuilder}; @@ -15,7 +14,7 @@ use crate::SnippetCap; #[derive(Default, Debug, Clone)] pub struct SourceChange { - pub source_file_edits: FxHashMap, + pub source_file_edits: NoHashHashMap, pub file_system_edits: Vec, pub is_snippet: bool, } @@ -24,7 +23,7 @@ impl SourceChange { /// Creates a new SourceChange with the given label /// from the edits. pub fn from_edits( - source_file_edits: FxHashMap, + source_file_edits: NoHashHashMap, file_system_edits: Vec, ) -> Self { SourceChange { source_file_edits, file_system_edits, is_snippet: false } @@ -78,8 +77,8 @@ impl Extend for SourceChange { } } -impl From> for SourceChange { - fn from(source_file_edits: FxHashMap) -> SourceChange { +impl From> for SourceChange { + fn from(source_file_edits: NoHashHashMap) -> SourceChange { SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false } } } diff --git a/crates/ide-ssr/Cargo.toml b/crates/ide-ssr/Cargo.toml index d36dd02d45c59..73314e0f330bc 100644 --- a/crates/ide-ssr/Cargo.toml +++ b/crates/ide-ssr/Cargo.toml @@ -20,6 +20,7 @@ parser = { path = "../parser", version = "0.0.0" } syntax = { path = "../syntax", version = "0.0.0" } ide-db = { path = "../ide-db", version = "0.0.0" } hir = { path = "../hir", version = "0.0.0" } +stdx = { path = "../stdx", version = "0.0.0" } [dev-dependencies] test-utils = { path = "../test-utils" } diff --git a/crates/ide-ssr/src/lib.rs b/crates/ide-ssr/src/lib.rs index 739e0ccb436db..d9834ee63adcc 100644 --- a/crates/ide-ssr/src/lib.rs +++ b/crates/ide-ssr/src/lib.rs @@ -86,11 +86,9 @@ pub use crate::{errors::SsrError, from_comment::ssr_from_comment, matching::Matc use crate::{errors::bail, matching::MatchFailureReason}; use hir::Semantics; -use ide_db::{ - base_db::{FileId, FilePosition, FileRange}, - FxHashMap, -}; +use ide_db::base_db::{FileId, FilePosition, FileRange}; use resolving::ResolvedRule; +use stdx::hash::NoHashHashMap; use syntax::{ast, AstNode, SyntaxNode, TextRange}; use text_edit::TextEdit; @@ -170,9 +168,9 @@ impl<'db> MatchFinder<'db> { } /// Finds matches for all added rules and returns edits for all found matches. - pub fn edits(&self) -> FxHashMap { + pub fn edits(&self) -> NoHashHashMap { use ide_db::base_db::SourceDatabaseExt; - let mut matches_by_file = FxHashMap::default(); + let mut matches_by_file = NoHashHashMap::default(); for m in self.matches().matches { matches_by_file .entry(m.range.file_id) diff --git a/crates/ide/src/prime_caches.rs b/crates/ide/src/prime_caches.rs index 296270036002b..87b3ef380c594 100644 --- a/crates/ide/src/prime_caches.rs +++ b/crates/ide/src/prime_caches.rs @@ -12,8 +12,9 @@ use ide_db::{ salsa::{Database, ParallelDatabase, Snapshot}, Cancelled, CrateGraph, CrateId, SourceDatabase, SourceDatabaseExt, }, - FxHashSet, FxIndexMap, + FxIndexMap, }; +use stdx::hash::NoHashHashSet; use crate::RootDatabase; @@ -141,7 +142,7 @@ pub(crate) fn parallel_prime_caches( } } -fn compute_crates_to_prime(db: &RootDatabase, graph: &CrateGraph) -> FxHashSet { +fn compute_crates_to_prime(db: &RootDatabase, graph: &CrateGraph) -> NoHashHashSet { // We're only interested in the workspace crates and the `ImportMap`s of their direct // dependencies, though in practice the latter also compute the `DefMap`s. // We don't prime transitive dependencies because they're generally not visible in diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 1a6beec1881b0..99614b645e48f 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -14,8 +14,9 @@ use ide_db::{ base_db::FileId, defs::{Definition, NameClass, NameRefClass}, search::{ReferenceCategory, SearchScope, UsageSearchResult}, - FxHashMap, RootDatabase, + RootDatabase, }; +use stdx::hash::NoHashHashMap; use syntax::{ algo::find_node_at_offset, ast::{self, HasName}, @@ -29,7 +30,7 @@ use crate::{FilePosition, NavigationTarget, TryToNav}; #[derive(Debug, Clone)] pub struct ReferenceSearchResult { pub declaration: Option, - pub references: FxHashMap)>>, + pub references: NoHashHashMap)>>, } #[derive(Debug, Clone)] diff --git a/crates/ide/src/view_crate_graph.rs b/crates/ide/src/view_crate_graph.rs index bf7b7efe28228..17a1e385b7724 100644 --- a/crates/ide/src/view_crate_graph.rs +++ b/crates/ide/src/view_crate_graph.rs @@ -3,8 +3,9 @@ use std::sync::Arc; use dot::{Id, LabelText}; use ide_db::{ base_db::{CrateGraph, CrateId, Dependency, SourceDatabase, SourceDatabaseExt}, - FxHashSet, RootDatabase, + RootDatabase, }; +use stdx::hash::NoHashHashSet; // Feature: View Crate Graph // @@ -41,7 +42,7 @@ pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result, - crates_to_render: FxHashSet, + crates_to_render: NoHashHashSet, } type Edge<'a> = (CrateId, &'a Dependency); diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 8d6f50f5587c5..818bbed6af2ec 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -13,7 +13,7 @@ use cfg::{CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; -use stdx::always; +use stdx::{always, hash::NoHashHashMap}; use crate::{ build_scripts::BuildScriptOutput, @@ -471,7 +471,7 @@ fn project_json_to_crate_graph( .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load)); let mut cfg_cache: FxHashMap<&str, Vec> = FxHashMap::default(); - let crates: FxHashMap = project + let crates: NoHashHashMap = project .crates() .filter_map(|(crate_id, krate)| { let file_path = &krate.root_module; diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs index 09150c77d7dd1..f516c194da467 100644 --- a/crates/rust-analyzer/src/diagnostics.rs +++ b/crates/rust-analyzer/src/diagnostics.rs @@ -4,11 +4,12 @@ pub(crate) mod to_proto; use std::{mem, sync::Arc}; use ide::FileId; -use rustc_hash::{FxHashMap, FxHashSet}; +use ide_db::FxHashMap; +use stdx::hash::{NoHashHashMap, NoHashHashSet}; use crate::lsp_ext; -pub(crate) type CheckFixes = Arc>>>; +pub(crate) type CheckFixes = Arc>>>; #[derive(Debug, Default, Clone)] pub struct DiagnosticsMapConfig { @@ -19,12 +20,12 @@ pub struct DiagnosticsMapConfig { #[derive(Debug, Default, Clone)] pub(crate) struct DiagnosticCollection { - // FIXME: should be FxHashMap> - pub(crate) native: FxHashMap>, + // FIXME: should be NoHashHashMap> + pub(crate) native: NoHashHashMap>, // FIXME: should be Vec - pub(crate) check: FxHashMap>>, + pub(crate) check: NoHashHashMap>>, pub(crate) check_fixes: CheckFixes, - changes: FxHashSet, + changes: NoHashHashSet, } #[derive(Debug, Clone)] @@ -105,7 +106,7 @@ impl DiagnosticCollection { native.chain(check) } - pub(crate) fn take_changes(&mut self) -> Option> { + pub(crate) fn take_changes(&mut self) -> Option> { if self.changes.is_empty() { return None; } diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index c55bbbbe6ef7c..706e1742dffde 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -14,6 +14,7 @@ use parking_lot::{Mutex, RwLock}; use proc_macro_api::ProcMacroServer; use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts}; use rustc_hash::FxHashMap; +use stdx::hash::NoHashHashMap; use vfs::AnchoredPathBuf; use crate::{ @@ -67,7 +68,7 @@ pub(crate) struct GlobalState { pub(crate) flycheck_sender: Sender, pub(crate) flycheck_receiver: Receiver, - pub(crate) vfs: Arc)>>, + pub(crate) vfs: Arc)>>, pub(crate) vfs_config_version: u32, pub(crate) vfs_progress_config_version: u32, pub(crate) vfs_progress_n_total: usize, @@ -113,7 +114,7 @@ pub(crate) struct GlobalStateSnapshot { pub(crate) check_fixes: CheckFixes, mem_docs: MemDocs, pub(crate) semantic_tokens_cache: Arc>>, - vfs: Arc)>>, + vfs: Arc)>>, pub(crate) workspaces: Arc>, } @@ -157,7 +158,7 @@ impl GlobalState { flycheck_sender, flycheck_receiver, - vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), + vfs: Arc::new(RwLock::new((vfs::Vfs::default(), NoHashHashMap::default()))), vfs_config_version: 0, vfs_progress_config_version: 0, vfs_progress_n_total: 0, diff --git a/crates/stdx/src/hash.rs b/crates/stdx/src/hash.rs new file mode 100644 index 0000000000000..bf7d71eb03a18 --- /dev/null +++ b/crates/stdx/src/hash.rs @@ -0,0 +1,87 @@ +use std::{ + hash::{BuildHasher, Hasher}, + marker::PhantomData, +}; + +pub type NoHashHashMap = std::collections::HashMap>; +pub type NoHashHashSet = std::collections::HashSet>; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct NoHashHasherBuilder(PhantomData); + +impl Default for NoHashHasherBuilder { + fn default() -> Self { + Self(Default::default()) + } +} + +pub trait NoHashHashable {} +impl NoHashHashable for usize {} +impl NoHashHashable for u32 {} + +pub struct NoHashHasher(u64); + +impl BuildHasher for NoHashHasherBuilder { + type Hasher = NoHashHasher; + fn build_hasher(&self) -> Self::Hasher { + NoHashHasher(0) + } +} + +impl Hasher for NoHashHasher { + fn finish(&self) -> u64 { + self.0 + } + + fn write(&mut self, _: &[u8]) { + unimplemented!("NoHashHasher should only be used for hashing primitive integers") + } + + fn write_u8(&mut self, i: u8) { + self.0 = i as u64; + } + + fn write_u16(&mut self, i: u16) { + self.0 = i as u64; + } + + fn write_u32(&mut self, i: u32) { + self.0 = i as u64; + } + + fn write_u64(&mut self, i: u64) { + self.0 = i as u64; + } + + fn write_u128(&mut self, i: u128) { + self.0 = i as u64; + } + + fn write_usize(&mut self, i: usize) { + self.0 = i as u64; + } + + fn write_i8(&mut self, i: i8) { + self.0 = i as u64; + } + + fn write_i16(&mut self, i: i16) { + self.0 = i as u64; + } + + fn write_i32(&mut self, i: i32) { + self.0 = i as u64; + } + + fn write_i64(&mut self, i: i64) { + self.0 = i as u64; + } + + fn write_i128(&mut self, i: i128) { + self.0 = i as u64; + } + + fn write_isize(&mut self, i: isize) { + self.0 = i as u64; + } +} diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index b4d45206c44ea..51e109798d1df 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs @@ -7,6 +7,7 @@ use std::{cmp::Ordering, ops, time::Instant}; use std::{io as sio, iter}; mod macros; +pub mod hash; pub mod process; pub mod panic_context; pub mod non_empty_vec; diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml index c6377348784a4..d7549a2841539 100644 --- a/crates/vfs/Cargo.toml +++ b/crates/vfs/Cargo.toml @@ -12,6 +12,7 @@ doctest = false [dependencies] rustc-hash = "1.1.0" fst = "0.4.7" +indexmap = "1.9.1" paths = { path = "../paths", version = "0.0.0" } -indexmap = "1.9.1" +stdx = { path = "../stdx", version = "0.0.0" } diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs index 6a89263e53988..e0ef737b3fc09 100644 --- a/crates/vfs/src/file_set.rs +++ b/crates/vfs/src/file_set.rs @@ -6,6 +6,7 @@ use std::fmt; use fst::{IntoStreamer, Streamer}; use rustc_hash::FxHashMap; +use stdx::hash::NoHashHashMap; use crate::{AnchoredPath, FileId, Vfs, VfsPath}; @@ -13,7 +14,7 @@ use crate::{AnchoredPath, FileId, Vfs, VfsPath}; #[derive(Default, Clone, Eq, PartialEq)] pub struct FileSet { files: FxHashMap, - paths: FxHashMap, + paths: NoHashHashMap, } impl FileSet { diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 7badb1c363b44..afc9a0fa6fb20 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -59,9 +59,16 @@ pub use paths::{AbsPath, AbsPathBuf}; /// Handle to a file in [`Vfs`] /// /// Most functions in rust-analyzer use this when they need to refer to a file. -#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] pub struct FileId(pub u32); +impl stdx::hash::NoHashHashable for FileId {} +impl std::hash::Hash for FileId { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + /// Storage for all files read by rust-analyzer. /// /// For more information see the [crate-level](crate) documentation. From 0c9375b829034b342c78b324b3aab3a497838055 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 25 Aug 2022 20:43:53 +0200 Subject: [PATCH 40/53] Remove u/i128 hashing overloads from NoHashHasher::Hasher impl --- crates/stdx/src/hash.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crates/stdx/src/hash.rs b/crates/stdx/src/hash.rs index bf7d71eb03a18..1f04fce148870 100644 --- a/crates/stdx/src/hash.rs +++ b/crates/stdx/src/hash.rs @@ -53,10 +53,6 @@ impl Hasher for NoHashHasher { self.0 = i as u64; } - fn write_u128(&mut self, i: u128) { - self.0 = i as u64; - } - fn write_usize(&mut self, i: usize) { self.0 = i as u64; } @@ -77,10 +73,6 @@ impl Hasher for NoHashHasher { self.0 = i as u64; } - fn write_i128(&mut self, i: i128) { - self.0 = i as u64; - } - fn write_isize(&mut self, i: isize) { self.0 = i as u64; } From 5b6aefe56532b1766e5fde76deeabf79e1ceb94e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 25 Aug 2022 21:06:35 +0200 Subject: [PATCH 41/53] Update test fixtures --- crates/project-model/src/tests.rs | 714 +++++++++++++++--------------- crates/stdx/src/hash.rs | 1 + 2 files changed, 358 insertions(+), 357 deletions(-) diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index 8d0fa757c2e17..9ccb6e9101ef4 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -185,10 +185,10 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { is_proc_macro: false, }, CrateId( - 2, + 1, ): CrateData { root_file_id: FileId( - 3, + 2, ), edition: Edition2018, version: Some( @@ -197,9 +197,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { display_name: Some( CrateDisplayName { crate_name: CrateName( - "an_example", + "hello_world", ), - canonical_name: "an-example", + canonical_name: "hello-world", }, ), cfg_options: CfgOptions( @@ -260,77 +260,85 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { is_proc_macro: false, }, CrateId( - 4, + 2, ): CrateData { root_file_id: FileId( - 5, + 3, ), - edition: Edition2015, + edition: Edition2018, version: Some( - "0.2.98", + "0.1.0", ), display_name: Some( CrateDisplayName { crate_name: CrateName( - "libc", + "an_example", ), - canonical_name: "libc", + canonical_name: "an-example", }, ), cfg_options: CfgOptions( [ "debug_assertions", - "feature=default", - "feature=std", ], ), potential_cfg_options: CfgOptions( [ "debug_assertions", - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", ], ), env: Env { entries: { "CARGO_PKG_LICENSE": "", "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - "CARGO_PKG_VERSION": "0.2.98", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "libc", + "CARGO_CRATE_NAME": "hello_world", "CARGO_PKG_LICENSE_FILE": "", "CARGO_PKG_HOMEPAGE": "", "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "libc", - "CARGO_PKG_VERSION_PATCH": "98", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", "CARGO": "cargo", "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "2", + "CARGO_PKG_VERSION_MINOR": "1", "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [], + dependencies: [ + Dependency { + crate_id: CrateId( + 0, + ), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: CrateId( + 4, + ), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], proc_macro: Err( "crate has not (yet) been built", ), origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), + repo: None, }, is_proc_macro: false, }, CrateId( - 1, + 3, ): CrateData { root_file_id: FileId( - 2, + 4, ), edition: Edition2018, version: Some( @@ -339,9 +347,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { display_name: Some( CrateDisplayName { crate_name: CrateName( - "hello_world", + "it", ), - canonical_name: "hello-world", + canonical_name: "it", }, ), cfg_options: CfgOptions( @@ -402,77 +410,69 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { is_proc_macro: false, }, CrateId( - 3, + 4, ): CrateData { root_file_id: FileId( - 4, + 5, ), - edition: Edition2018, + edition: Edition2015, version: Some( - "0.1.0", + "0.2.98", ), display_name: Some( CrateDisplayName { crate_name: CrateName( - "it", + "libc", ), - canonical_name: "it", + canonical_name: "libc", }, ), cfg_options: CfgOptions( [ "debug_assertions", + "feature=default", + "feature=std", ], ), potential_cfg_options: CfgOptions( [ "debug_assertions", + "feature=align", + "feature=const-extern-fn", + "feature=default", + "feature=extra_traits", + "feature=rustc-dep-of-std", + "feature=std", + "feature=use_std", ], ), env: Env { entries: { "CARGO_PKG_LICENSE": "", "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", + "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", + "CARGO_PKG_VERSION": "0.2.98", "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", + "CARGO_CRATE_NAME": "libc", "CARGO_PKG_LICENSE_FILE": "", "CARGO_PKG_HOMEPAGE": "", "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", + "CARGO_PKG_NAME": "libc", + "CARGO_PKG_VERSION_PATCH": "98", "CARGO": "cargo", "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_MINOR": "2", "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], + dependencies: [], proc_macro: Err( "crate has not (yet) been built", ), origin: CratesIo { - repo: None, + repo: Some( + "https://github.com/rust-lang/libc", + ), }, is_proc_macro: false, }, @@ -567,10 +567,10 @@ fn cargo_hello_world_project_model_with_selective_overrides() { is_proc_macro: false, }, CrateId( - 2, + 1, ): CrateData { root_file_id: FileId( - 3, + 2, ), edition: Edition2018, version: Some( @@ -579,9 +579,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() { display_name: Some( CrateDisplayName { crate_name: CrateName( - "an_example", + "hello_world", ), - canonical_name: "an-example", + canonical_name: "hello-world", }, ), cfg_options: CfgOptions( @@ -644,77 +644,10 @@ fn cargo_hello_world_project_model_with_selective_overrides() { is_proc_macro: false, }, CrateId( - 4, - ): CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2015, - version: Some( - "0.2.98", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "libc", - ), - canonical_name: "libc", - }, - ), - cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=default", - "feature=std", - ], - ), - potential_cfg_options: CfgOptions( - [ - "debug_assertions", - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", - ], - ), - env: Env { - entries: { - "CARGO_PKG_LICENSE": "", - "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - "CARGO_PKG_VERSION": "0.2.98", - "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "libc", - "CARGO_PKG_LICENSE_FILE": "", - "CARGO_PKG_HOMEPAGE": "", - "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "libc", - "CARGO_PKG_VERSION_PATCH": "98", - "CARGO": "cargo", - "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "2", - "CARGO_PKG_VERSION_PRE": "", - }, - }, - dependencies: [], - proc_macro: Err( - "crate has not (yet) been built", - ), - origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), - }, - is_proc_macro: false, - }, - CrateId( - 1, + 2, ): CrateData { root_file_id: FileId( - 2, + 3, ), edition: Edition2018, version: Some( @@ -723,9 +656,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() { display_name: Some( CrateDisplayName { crate_name: CrateName( - "hello_world", + "an_example", ), - canonical_name: "hello-world", + canonical_name: "an-example", }, ), cfg_options: CfgOptions( @@ -864,92 +797,91 @@ fn cargo_hello_world_project_model_with_selective_overrides() { }, is_proc_macro: false, }, - }, - }"#]], - ) -} - -#[test] -fn cargo_hello_world_project_model() { - let crate_graph = load_cargo("hello-world-metadata.json"); - check_crate_graph( - crate_graph, - expect![[r#" - CrateGraph { - arena: { CrateId( - 0, + 4, ): CrateData { root_file_id: FileId( - 1, + 5, ), - edition: Edition2018, + edition: Edition2015, version: Some( - "0.1.0", + "0.2.98", ), display_name: Some( CrateDisplayName { crate_name: CrateName( - "hello_world", + "libc", ), - canonical_name: "hello-world", + canonical_name: "libc", }, ), cfg_options: CfgOptions( [ "debug_assertions", - "test", + "feature=default", + "feature=std", ], ), potential_cfg_options: CfgOptions( [ "debug_assertions", - "test", + "feature=align", + "feature=const-extern-fn", + "feature=default", + "feature=extra_traits", + "feature=rustc-dep-of-std", + "feature=std", + "feature=use_std", ], ), env: Env { entries: { "CARGO_PKG_LICENSE": "", "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$hello-world", - "CARGO_PKG_VERSION": "0.1.0", + "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", + "CARGO_PKG_VERSION": "0.2.98", "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "hello_world", + "CARGO_CRATE_NAME": "libc", "CARGO_PKG_LICENSE_FILE": "", "CARGO_PKG_HOMEPAGE": "", "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "hello-world", - "CARGO_PKG_VERSION_PATCH": "0", + "CARGO_PKG_NAME": "libc", + "CARGO_PKG_VERSION_PATCH": "98", "CARGO": "cargo", "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "1", + "CARGO_PKG_VERSION_MINOR": "2", "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: CrateId( - 4, - ), - name: CrateName( - "libc", - ), - prelude: true, - }, - ], + dependencies: [], proc_macro: Err( "crate has not (yet) been built", ), origin: CratesIo { - repo: None, + repo: Some( + "https://github.com/rust-lang/libc", + ), }, is_proc_macro: false, }, + }, + }"#]], + ) +} + +#[test] +fn cargo_hello_world_project_model() { + let crate_graph = load_cargo("hello-world-metadata.json"); + check_crate_graph( + crate_graph, + expect![[r#" + CrateGraph { + arena: { CrateId( - 2, + 0, ): CrateData { root_file_id: FileId( - 3, + 1, ), edition: Edition2018, version: Some( @@ -958,9 +890,9 @@ fn cargo_hello_world_project_model() { display_name: Some( CrateDisplayName { crate_name: CrateName( - "an_example", + "hello_world", ), - canonical_name: "an-example", + canonical_name: "hello-world", }, ), cfg_options: CfgOptions( @@ -995,15 +927,6 @@ fn cargo_hello_world_project_model() { }, }, dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "hello_world", - ), - prelude: true, - }, Dependency { crate_id: CrateId( 4, @@ -1023,77 +946,87 @@ fn cargo_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 4, + 1, ): CrateData { root_file_id: FileId( - 5, + 2, ), - edition: Edition2015, + edition: Edition2018, version: Some( - "0.2.98", + "0.1.0", ), display_name: Some( CrateDisplayName { crate_name: CrateName( - "libc", + "hello_world", ), - canonical_name: "libc", + canonical_name: "hello-world", }, ), cfg_options: CfgOptions( [ "debug_assertions", - "feature=default", - "feature=std", + "test", ], ), potential_cfg_options: CfgOptions( [ "debug_assertions", - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", + "test", ], ), env: Env { entries: { "CARGO_PKG_LICENSE": "", "CARGO_PKG_VERSION_MAJOR": "0", - "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - "CARGO_PKG_VERSION": "0.2.98", + "CARGO_MANIFEST_DIR": "$ROOT$hello-world", + "CARGO_PKG_VERSION": "0.1.0", "CARGO_PKG_AUTHORS": "", - "CARGO_CRATE_NAME": "libc", + "CARGO_CRATE_NAME": "hello_world", "CARGO_PKG_LICENSE_FILE": "", "CARGO_PKG_HOMEPAGE": "", "CARGO_PKG_DESCRIPTION": "", - "CARGO_PKG_NAME": "libc", - "CARGO_PKG_VERSION_PATCH": "98", + "CARGO_PKG_NAME": "hello-world", + "CARGO_PKG_VERSION_PATCH": "0", "CARGO": "cargo", "CARGO_PKG_REPOSITORY": "", - "CARGO_PKG_VERSION_MINOR": "2", + "CARGO_PKG_VERSION_MINOR": "1", "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [], + dependencies: [ + Dependency { + crate_id: CrateId( + 0, + ), + name: CrateName( + "hello_world", + ), + prelude: true, + }, + Dependency { + crate_id: CrateId( + 4, + ), + name: CrateName( + "libc", + ), + prelude: true, + }, + ], proc_macro: Err( "crate has not (yet) been built", ), origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), + repo: None, }, is_proc_macro: false, }, CrateId( - 1, + 2, ): CrateData { root_file_id: FileId( - 2, + 3, ), edition: Edition2018, version: Some( @@ -1102,9 +1035,9 @@ fn cargo_hello_world_project_model() { display_name: Some( CrateDisplayName { crate_name: CrateName( - "hello_world", + "an_example", ), - canonical_name: "hello-world", + canonical_name: "an-example", }, ), cfg_options: CfgOptions( @@ -1243,6 +1176,73 @@ fn cargo_hello_world_project_model() { }, is_proc_macro: false, }, + CrateId( + 4, + ): CrateData { + root_file_id: FileId( + 5, + ), + edition: Edition2015, + version: Some( + "0.2.98", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "libc", + ), + canonical_name: "libc", + }, + ), + cfg_options: CfgOptions( + [ + "debug_assertions", + "feature=default", + "feature=std", + ], + ), + potential_cfg_options: CfgOptions( + [ + "debug_assertions", + "feature=align", + "feature=const-extern-fn", + "feature=default", + "feature=extra_traits", + "feature=rustc-dep-of-std", + "feature=std", + "feature=use_std", + ], + ), + env: Env { + entries: { + "CARGO_PKG_LICENSE": "", + "CARGO_PKG_VERSION_MAJOR": "0", + "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", + "CARGO_PKG_VERSION": "0.2.98", + "CARGO_PKG_AUTHORS": "", + "CARGO_CRATE_NAME": "libc", + "CARGO_PKG_LICENSE_FILE": "", + "CARGO_PKG_HOMEPAGE": "", + "CARGO_PKG_DESCRIPTION": "", + "CARGO_PKG_NAME": "libc", + "CARGO_PKG_VERSION_PATCH": "98", + "CARGO": "cargo", + "CARGO_PKG_REPOSITORY": "", + "CARGO_PKG_VERSION_MINOR": "2", + "CARGO_PKG_VERSION_PRE": "", + }, + }, + dependencies: [], + proc_macro: Err( + "crate has not (yet) been built", + ), + origin: CratesIo { + repo: Some( + "https://github.com/rust-lang/libc", + ), + }, + is_proc_macro: false, + }, }, }"#]], ) @@ -1301,19 +1301,53 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 10, + 1, ): CrateData { root_file_id: FileId( - 11, + 2, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "unwind", + "core", ), - canonical_name: "unwind", + canonical_name: "core", + }, + ), + cfg_options: CfgOptions( + [], + ), + potential_cfg_options: CfgOptions( + [], + ), + env: Env { + entries: {}, + }, + dependencies: [], + proc_macro: Err( + "no proc macro loaded for sysroot crate", + ), + origin: Lang( + Core, + ), + is_proc_macro: false, + }, + CrateId( + 2, + ): CrateData { + root_file_id: FileId( + 3, + ), + edition: Edition2018, + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "panic_abort", + ), + canonical_name: "panic_abort", }, ), cfg_options: CfgOptions( @@ -1335,19 +1369,19 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 7, + 3, ): CrateData { root_file_id: FileId( - 8, + 4, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "std_detect", + "panic_unwind", ), - canonical_name: "std_detect", + canonical_name: "panic_unwind", }, ), cfg_options: CfgOptions( @@ -1413,19 +1447,19 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 1, + 5, ): CrateData { root_file_id: FileId( - 2, + 6, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "core", + "profiler_builtins", ), - canonical_name: "core", + canonical_name: "profiler_builtins", }, ), cfg_options: CfgOptions( @@ -1442,24 +1476,24 @@ fn rust_project_hello_world_project_model() { "no proc macro loaded for sysroot crate", ), origin: Lang( - Core, + Other, ), is_proc_macro: false, }, CrateId( - 11, + 6, ): CrateData { root_file_id: FileId( - 12, + 7, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "hello_world", + "std", ), - canonical_name: "hello_world", + canonical_name: "std", }, ), cfg_options: CfgOptions( @@ -1472,6 +1506,15 @@ fn rust_project_hello_world_project_model() { entries: {}, }, dependencies: [ + Dependency { + crate_id: CrateId( + 0, + ), + name: CrateName( + "alloc", + ), + prelude: true, + }, Dependency { crate_id: CrateId( 1, @@ -1483,19 +1526,46 @@ fn rust_project_hello_world_project_model() { }, Dependency { crate_id: CrateId( - 0, + 2, ), name: CrateName( - "alloc", + "panic_abort", ), prelude: true, }, Dependency { crate_id: CrateId( - 6, + 3, ), name: CrateName( - "std", + "panic_unwind", + ), + prelude: true, + }, + Dependency { + crate_id: CrateId( + 5, + ), + name: CrateName( + "profiler_builtins", + ), + prelude: true, + }, + Dependency { + crate_id: CrateId( + 7, + ), + name: CrateName( + "std_detect", + ), + prelude: true, + }, + Dependency { + crate_id: CrateId( + 8, + ), + name: CrateName( + "term", ), prelude: true, }, @@ -1506,31 +1576,40 @@ fn rust_project_hello_world_project_model() { name: CrateName( "test", ), - prelude: false, + prelude: true, + }, + Dependency { + crate_id: CrateId( + 10, + ), + name: CrateName( + "unwind", + ), + prelude: true, }, ], proc_macro: Err( - "no proc macro dylib present", + "no proc macro loaded for sysroot crate", + ), + origin: Lang( + Std, ), - origin: CratesIo { - repo: None, - }, is_proc_macro: false, }, CrateId( - 8, + 7, ): CrateData { root_file_id: FileId( - 9, + 8, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "term", + "std_detect", ), - canonical_name: "term", + canonical_name: "std_detect", }, ), cfg_options: CfgOptions( @@ -1552,19 +1631,19 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 5, + 8, ): CrateData { root_file_id: FileId( - 6, + 9, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "profiler_builtins", + "term", ), - canonical_name: "profiler_builtins", + canonical_name: "term", }, ), cfg_options: CfgOptions( @@ -1586,19 +1665,19 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 2, + 9, ): CrateData { root_file_id: FileId( - 3, + 10, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "panic_abort", + "test", ), - canonical_name: "panic_abort", + canonical_name: "test", }, ), cfg_options: CfgOptions( @@ -1615,24 +1694,24 @@ fn rust_project_hello_world_project_model() { "no proc macro loaded for sysroot crate", ), origin: Lang( - Other, + Test, ), is_proc_macro: false, }, CrateId( - 9, + 10, ): CrateData { root_file_id: FileId( - 10, + 11, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "test", + "unwind", ), - canonical_name: "test", + canonical_name: "unwind", }, ), cfg_options: CfgOptions( @@ -1649,24 +1728,24 @@ fn rust_project_hello_world_project_model() { "no proc macro loaded for sysroot crate", ), origin: Lang( - Test, + Other, ), is_proc_macro: false, }, CrateId( - 6, + 11, ): CrateData { root_file_id: FileId( - 7, + 12, ), edition: Edition2018, version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( - "std", + "hello_world", ), - canonical_name: "std", + canonical_name: "hello_world", }, ), cfg_options: CfgOptions( @@ -1679,15 +1758,6 @@ fn rust_project_hello_world_project_model() { entries: {}, }, dependencies: [ - Dependency { - crate_id: CrateId( - 0, - ), - name: CrateName( - "alloc", - ), - prelude: true, - }, Dependency { crate_id: CrateId( 1, @@ -1699,46 +1769,19 @@ fn rust_project_hello_world_project_model() { }, Dependency { crate_id: CrateId( - 2, - ), - name: CrateName( - "panic_abort", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 3, - ), - name: CrateName( - "panic_unwind", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 5, - ), - name: CrateName( - "profiler_builtins", - ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 7, + 0, ), name: CrateName( - "std_detect", + "alloc", ), prelude: true, }, Dependency { crate_id: CrateId( - 8, + 6, ), name: CrateName( - "term", + "std", ), prelude: true, }, @@ -1749,58 +1792,15 @@ fn rust_project_hello_world_project_model() { name: CrateName( "test", ), - prelude: true, - }, - Dependency { - crate_id: CrateId( - 10, - ), - name: CrateName( - "unwind", - ), - prelude: true, + prelude: false, }, ], proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Std, - ), - is_proc_macro: false, - }, - CrateId( - 3, - ): CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "panic_unwind", - ), - canonical_name: "panic_unwind", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], + "no proc macro dylib present", ), - env: Env { - entries: {}, + origin: CratesIo { + repo: None, }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), is_proc_macro: false, }, }, diff --git a/crates/stdx/src/hash.rs b/crates/stdx/src/hash.rs index 1f04fce148870..9909d71bdf066 100644 --- a/crates/stdx/src/hash.rs +++ b/crates/stdx/src/hash.rs @@ -1,3 +1,4 @@ +//! A none hashing [`Hasher`] implementation. use std::{ hash::{BuildHasher, Hasher}, marker::PhantomData, From 78a7a816bf3a913cc978a08f3a02426ac0d29703 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 26 Aug 2022 19:40:01 +0200 Subject: [PATCH 42/53] minor: Simplify --- crates/hir-ty/src/lower.rs | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 8b360337a82c8..3f6d0844e9c1f 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -6,7 +6,7 @@ //! //! This usually involves resolving names, collecting generic arguments etc. use std::{ - cell::{Cell, RefCell}, + cell::{Cell, RefCell, RefMut}, iter, sync::Arc, }; @@ -330,26 +330,26 @@ impl<'a> TyLoweringContext<'a> { } } TypeRef::Macro(macro_call) => { - let (expander, recursion_start) = { - let mut expander = self.expander.borrow_mut(); - if expander.is_some() { - (Some(expander), false) - } else { - *expander = Some(Expander::new( - self.db.upcast(), - macro_call.file_id, - self.resolver.module(), - )); - (Some(expander), true) + let (mut expander, recursion_start) = { + match RefMut::filter_map(self.expander.borrow_mut(), Option::as_mut) { + Ok(expander) => (expander, false), + Err(expander) => ( + RefMut::map(expander, |it| { + it.insert(Expander::new( + self.db.upcast(), + macro_call.file_id, + self.resolver.module(), + )) + }), + true, + ), } }; - let ty = if let Some(mut expander) = expander { - let expander_mut = expander.as_mut().unwrap(); + let ty = { let macro_call = macro_call.to_node(self.db.upcast()); - match expander_mut.enter_expand::(self.db.upcast(), macro_call) { + match expander.enter_expand::(self.db.upcast(), macro_call) { Ok(ExpandResult { value: Some((mark, expanded)), .. }) => { - let ctx = - LowerCtx::new(self.db.upcast(), expander_mut.current_file_id()); + let ctx = LowerCtx::new(self.db.upcast(), expander.current_file_id()); let type_ref = TypeRef::from_ast(&ctx, expanded); drop(expander); @@ -364,8 +364,6 @@ impl<'a> TyLoweringContext<'a> { } _ => None, } - } else { - None }; if recursion_start { *self.expander.borrow_mut() = None; From 1dd47b04c0c1b822fc85406ae540bb28396cfefd Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 27 Aug 2022 11:34:15 -0400 Subject: [PATCH 43/53] Set DebuginfoKind::Pdb in msvc_base This PDB setting was added to `windows_msvc_base` in https://github.com/rust-lang/rust/pull/98051. It's also needed for the UEFI targets, and since `uefi_msvc_base` and `windows_msvc_base` are the only things that inherit from `msvc_base`, just move the PDB setting up to `mscv_base` to cover both. Fixes https://github.com/rust-lang/rust/issues/101071 --- compiler/rustc_target/src/spec/msvc_base.rs | 3 ++- compiler/rustc_target/src/spec/windows_msvc_base.rs | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs index ec9609a2b26a1..b3cd38a6ec3de 100644 --- a/compiler/rustc_target/src/spec/msvc_base.rs +++ b/compiler/rustc_target/src/spec/msvc_base.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions}; +use crate::spec::{DebuginfoKind, LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions}; use std::borrow::Cow; pub fn opts() -> TargetOptions { @@ -20,6 +20,7 @@ pub fn opts() -> TargetOptions { // where `*.pdb` files show up next to the final artifact. split_debuginfo: SplitDebuginfo::Packed, supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Packed]), + debuginfo_kind: DebuginfoKind::Pdb, ..Default::default() } diff --git a/compiler/rustc_target/src/spec/windows_msvc_base.rs b/compiler/rustc_target/src/spec/windows_msvc_base.rs index 67282c1954114..21062c337d825 100644 --- a/compiler/rustc_target/src/spec/windows_msvc_base.rs +++ b/compiler/rustc_target/src/spec/windows_msvc_base.rs @@ -1,4 +1,4 @@ -use crate::spec::{cvs, DebuginfoKind, TargetOptions}; +use crate::spec::{cvs, TargetOptions}; pub fn opts() -> TargetOptions { let base = super::msvc_base::opts(); @@ -28,7 +28,6 @@ pub fn opts() -> TargetOptions { // not ever be possible for us to pass this flag. no_default_libraries: false, has_thread_local: true, - debuginfo_kind: DebuginfoKind::Pdb, ..base } From 9ad0a8c4673059c22d2f55e14b8ee05f47237f80 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 28 Aug 2022 11:54:46 +0200 Subject: [PATCH 44/53] Move empty diagnostics workaround back into the server --- crates/rust-analyzer/src/main_loop.rs | 27 ++++++++++++++++++++++++++- editors/code/src/client.ts | 16 ---------------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 122aba2f7d926..3cfbc2e4e4503 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -328,8 +328,33 @@ impl GlobalState { } let uri = file_id_to_url(&self.vfs.read().0, file_id); - let diagnostics = + let mut diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect::>(); + + // VSCode assumes diagnostic messages to be non-empty strings, so we need to patch + // empty diagnostics. Neither the docs of VSCode nor the LSP spec say whether + // diagnostic messages are actually allowed to be empty or not and patching this + // in the VSCode client does not work as the assertion happens in the protocol + // conversion. So this hack is here to stay, and will be considered a hack + // until the LSP decides to state that empty messages are allowed. + + // See https://github.com/rust-lang/rust-analyzer/issues/11404 + // See https://github.com/rust-lang/rust-analyzer/issues/13130 + let patch_empty = |message: &mut String| { + if message.is_empty() { + *message = " ".to_string(); + } + }; + + for d in &mut diagnostics { + patch_empty(&mut d.message); + if let Some(dri) = &mut d.related_information { + for dri in dri { + patch_empty(&mut dri.message); + } + } + } + let version = from_proto::vfs_path(&uri) .map(|path| self.mem_docs.get(&path).map(|it| it.version)) .unwrap_or_default(); diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 719d2734643f4..05d4d08f70b62 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -99,22 +99,6 @@ 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 = " "; - } - if (diagnostic.relatedInformation) { - for (const relatedInformation of diagnostic.relatedInformation) { - if (!relatedInformation.message) { - relatedInformation.message = " "; - } - } - } - } - next(uri, diagnostics); - }, async provideHover( document: vscode.TextDocument, position: vscode.Position, From 4d95035083d4b3ce36a465ff4be916bf9bd8ee67 Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Mon, 29 Aug 2022 20:14:06 +0200 Subject: [PATCH 45/53] add tracking issue number to const_slice_split_at_not_mut --- library/core/src/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 38f05f471cde5..d5706c388f004 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1541,7 +1541,7 @@ impl [T] { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_slice_split_at_not_mut", issue = "none")] + #[rustc_const_unstable(feature = "const_slice_split_at_not_mut", issue = "101158")] #[inline] #[track_caller] #[must_use] From f6252a48621ef444ab0a4cb6e7d90315cd4702ec Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Tue, 30 Aug 2022 19:06:19 +0900 Subject: [PATCH 46/53] remove path string --- .../src/infer/error_reporting/mod.rs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 465508e12058f..e2b8bdb93eaf9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2044,22 +2044,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { (exp_found.expected.kind(), exp_found.found.kind()) { if let ty::Adt(found_def, found_substs) = *found_ty.kind() { - let path_str = format!("{:?}", exp_def); if exp_def == &found_def { - let opt_msg = "you can convert from `&Option` to `Option<&T>` using \ - `.as_ref()`"; - let result_msg = "you can convert from `&Result` to \ - `Result<&T, &E>` using `.as_ref()`"; let have_as_ref = &[ - ("std::option::Option", opt_msg), - ("core::option::Option", opt_msg), - ("std::result::Result", result_msg), - ("core::result::Result", result_msg), + ( + sym::Option, + "you can convert from `&Option` to `Option<&T>` using \ + `.as_ref()`", + ), + ( + sym::Result, + "you can convert from `&Result` to \ + `Result<&T, &E>` using `.as_ref()`", + ), ]; - if let Some(msg) = have_as_ref - .iter() - .find_map(|(path, msg)| (&path_str == path).then_some(msg)) - { + if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| { + self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg) + }) { let mut show_suggestion = true; for (exp_ty, found_ty) in iter::zip(exp_substs.types(), found_substs.types()) From 2f9bd1a2366f2048de4846e0933bb35485d5d91e Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 30 Aug 2022 03:06:22 -0700 Subject: [PATCH 47/53] Avoid zeroing large stack buffers in stdio on Windows --- library/std/src/sys/windows/stdio.rs | 41 ++++++++++++++++++---------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs index a001d6b985823..2b11332714d9c 100644 --- a/library/std/src/sys/windows/stdio.rs +++ b/library/std/src/sys/windows/stdio.rs @@ -3,6 +3,7 @@ use crate::char::decode_utf16; use crate::cmp; use crate::io; +use crate::mem::MaybeUninit; use crate::os::windows::io::{FromRawHandle, IntoRawHandle}; use crate::ptr; use crate::str; @@ -169,13 +170,14 @@ fn write( } fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result { - let mut utf16 = [0u16; MAX_BUFFER_SIZE / 2]; + let mut utf16: [MaybeUninit; MAX_BUFFER_SIZE / 2] = MaybeUninit::uninit_array(); let mut len_utf16 = 0; for (chr, dest) in utf8.encode_utf16().zip(utf16.iter_mut()) { - *dest = chr; + *dest = MaybeUninit::new(chr); len_utf16 += 1; } - let utf16 = &utf16[..len_utf16]; + // Safety: We've initialized `len_utf16` values. + let utf16: &[u16] = unsafe { MaybeUninit::slice_assume_init_ref(&utf16[..len_utf16]) }; let mut written = write_u16s(handle, &utf16)?; @@ -250,11 +252,14 @@ impl io::Read for Stdin { return Ok(bytes_copied); } else if buf.len() - bytes_copied < 4 { // Not enough space to get a UTF-8 byte. We will use the incomplete UTF8. - let mut utf16_buf = [0u16; 1]; + let mut utf16_buf = [MaybeUninit::new(1); 1]; // Read one u16 character. let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, 1, &mut self.surrogate)?; // Read bytes, using the (now-empty) self.incomplete_utf8 as extra space. - let read_bytes = utf16_to_utf8(&utf16_buf[..read], &mut self.incomplete_utf8.bytes)?; + let read_bytes = utf16_to_utf8( + unsafe { MaybeUninit::slice_assume_init_ref(&utf16_buf[..read]) }, + &mut self.incomplete_utf8.bytes, + )?; // Read in the bytes from incomplete_utf8 until the buffer is full. self.incomplete_utf8.len = read_bytes as u8; @@ -262,15 +267,18 @@ impl io::Read for Stdin { bytes_copied += self.incomplete_utf8.read(&mut buf[bytes_copied..]); Ok(bytes_copied) } else { - let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2]; + let mut utf16_buf: [MaybeUninit; MAX_BUFFER_SIZE / 2] = + MaybeUninit::uninit_array(); // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets // lost. let amount = cmp::min(buf.len() / 3, utf16_buf.len()); let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?; - - match utf16_to_utf8(&utf16_buf[..read], buf) { + // Safety `read_u16s_fixup_surrogates` returns the number of items + // initialized. + let utf16s = unsafe { MaybeUninit::slice_assume_init_ref(&utf16_buf[..read]) }; + match utf16_to_utf8(utf16s, buf) { Ok(value) => return Ok(bytes_copied + value), Err(e) => return Err(e), } @@ -283,14 +291,14 @@ impl io::Read for Stdin { // This is a best effort, and might not work if we are not the only reader on Stdin. fn read_u16s_fixup_surrogates( handle: c::HANDLE, - buf: &mut [u16], + buf: &mut [MaybeUninit], mut amount: usize, surrogate: &mut u16, ) -> io::Result { // Insert possibly remaining unpaired surrogate from last read. let mut start = 0; if *surrogate != 0 { - buf[0] = *surrogate; + buf[0] = MaybeUninit::new(*surrogate); *surrogate = 0; start = 1; if amount == 1 { @@ -303,7 +311,10 @@ fn read_u16s_fixup_surrogates( let mut amount = read_u16s(handle, &mut buf[start..amount])? + start; if amount > 0 { - let last_char = buf[amount - 1]; + // Safety: The returned `amount` is the number of values initialized, + // and it is not 0, so we know that `buf[amount - 1]` have been + // initialized. + let last_char = unsafe { buf[amount - 1].assume_init() }; if last_char >= 0xD800 && last_char <= 0xDBFF { // high surrogate *surrogate = last_char; @@ -313,7 +324,8 @@ fn read_u16s_fixup_surrogates( Ok(amount) } -fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result { +// Returns `Ok(n)` if it initialized `n` values in `buf`. +fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit]) -> io::Result { // Configure the `pInputControl` parameter to not only return on `\r\n` but also Ctrl-Z, the // traditional DOS method to indicate end of character stream / user input (SUB). // See #38274 and https://stackoverflow.com/questions/43836040/win-api-readconsole. @@ -346,8 +358,9 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result { } break; } - - if amount > 0 && buf[amount as usize - 1] == CTRL_Z { + // Safety: if `amount > 0`, then that many bytes were written, so + // `buf[amount as usize - 1]` has been initialized. + if amount > 0 && unsafe { buf[amount as usize - 1].assume_init() } == CTRL_Z { amount -= 1; } Ok(amount as usize) From 5663bb3f1c4637e36d6b6c3879b43e4f9e5bb347 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 30 Aug 2022 15:03:22 +0200 Subject: [PATCH 48/53] Add test for issue #85872 This has been fixed by the LLVM 15 upgrade, add a codegen test. Fixes #85872. --- .../codegen/issue-85872-multiple-reverse.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/codegen/issue-85872-multiple-reverse.rs diff --git a/src/test/codegen/issue-85872-multiple-reverse.rs b/src/test/codegen/issue-85872-multiple-reverse.rs new file mode 100644 index 0000000000000..591a1aca74747 --- /dev/null +++ b/src/test/codegen/issue-85872-multiple-reverse.rs @@ -0,0 +1,20 @@ +// min-llvm-version: 15.0.0 +// compile-flags: -O + +#![crate_type = "lib"] + +#[no_mangle] +pub fn u16_be_to_arch(mut data: [u8; 2]) -> [u8; 2] { + // CHECK-LABEL: @u16_be_to_arch + // CHECK: @llvm.bswap.i16 + data.reverse(); + data +} + +#[no_mangle] +pub fn u32_be_to_arch(mut data: [u8; 4]) -> [u8; 4] { + // CHECK-LABEL: @u32_be_to_arch + // CHECK: @llvm.bswap.i32 + data.reverse(); + data +} From 1b8b2dc2ff9196ba4532c7d6f2775e2112bfc060 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 30 Aug 2022 06:10:55 -0700 Subject: [PATCH 49/53] Avoid `MaybeUninit::uninit_array()` --- library/std/src/sys/windows/stdio.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs index 2b11332714d9c..70c9b14a08fa7 100644 --- a/library/std/src/sys/windows/stdio.rs +++ b/library/std/src/sys/windows/stdio.rs @@ -170,7 +170,7 @@ fn write( } fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result { - let mut utf16: [MaybeUninit; MAX_BUFFER_SIZE / 2] = MaybeUninit::uninit_array(); + let mut utf16 = [MaybeUninit::::uninit(); MAX_BUFFER_SIZE / 2]; let mut len_utf16 = 0; for (chr, dest) in utf8.encode_utf16().zip(utf16.iter_mut()) { *dest = MaybeUninit::new(chr); @@ -252,7 +252,7 @@ impl io::Read for Stdin { return Ok(bytes_copied); } else if buf.len() - bytes_copied < 4 { // Not enough space to get a UTF-8 byte. We will use the incomplete UTF8. - let mut utf16_buf = [MaybeUninit::new(1); 1]; + let mut utf16_buf = [MaybeUninit::new(0); 1]; // Read one u16 character. let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, 1, &mut self.surrogate)?; // Read bytes, using the (now-empty) self.incomplete_utf8 as extra space. @@ -267,8 +267,8 @@ impl io::Read for Stdin { bytes_copied += self.incomplete_utf8.read(&mut buf[bytes_copied..]); Ok(bytes_copied) } else { - let mut utf16_buf: [MaybeUninit; MAX_BUFFER_SIZE / 2] = - MaybeUninit::uninit_array(); + let mut utf16_buf = [MaybeUninit::::uninit(); MAX_BUFFER_SIZE / 2]; + // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets // lost. From 10a42dfa32d87978385e7fa990665c0bcafbde66 Mon Sep 17 00:00:00 2001 From: Andrew Pollack Date: Tue, 23 Aug 2022 19:06:49 +0000 Subject: [PATCH 50/53] Adding new Fuchsia rustup docs... reworking walkthrough --- src/doc/rustc/src/platform-support/fuchsia.md | 521 ++++++++++++++---- 1 file changed, 425 insertions(+), 96 deletions(-) diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 8b204949a6eef..e6503405dbcba 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -5,14 +5,10 @@ [Fuchsia] is a modern open source operating system that's simple, secure, updatable, and performant. -[Fuchsia]: https://fuchsia.dev/ - ## Target maintainers The [Fuchsia team]: -[Fuchsia team]: https://team-api.infra.rust-lang.org/v1/teams/fuchsia.json - - Tyler Mandry ([@tmandry](https://github.com/tmandry)) - Dan Johnson ([@computerdruid](https://github.com/computerdruid)) - David Koloski ([@djkoloski](https://github.com/djkoloski)) @@ -24,27 +20,162 @@ the members reported by the API. The API should be considered to be authoritative if this occurs. Instead of pinging individual members, use `@rustbot ping fuchsia` to contact the team on GitHub. +## Table of contents + +1. [Requirements](#requirements) +1. [Walkthrough structure](#walkthrough-structure) +1. [Compiling a Rust binary targeting Fuchsia](#compiling-a-rust-binary-targeting-fuchsia) + 1. [Targeting Fuchsia with rustup and cargo](#targeting-fuchsia-with-rustup-and-cargo) + 1. [Targeting Fuchsia with a compiler built from source](#targeting-fuchsia-with-a-compiler-built-from-source) +1. [Creating a Fuchsia package](#creating-a-fuchsia-package) + 1. [Creating a Fuchsia component](#creating-a-fuchsia-component) + 1. [Building a Fuchsia package](#building-a-fuchsia-package) +1. [Publishing a Fuchsia package](#publishing-a-fuchsia-package) + 1. [Creating a Fuchsia package repository](#creating-a-fuchsia-package-repository) + 1. [Publishing Fuchsia package to repository](#publishing-fuchsia-package-to-repository) +1. [Running a Fuchsia component on an emulator](#running-a-fuchsia-component-on-an-emulator) + 1. [Starting the Fuchsia emulator](#starting-the-fuchsia-emulator) + 1. [Watching emulator logs](#watching-emulator-logs) + 1. [Serving a Fuchsia package](#serving-a-fuchsia-package) + 1. [Running a Fuchsia component](#running-a-fuchsia-component) +1. [`.gitignore` extensions](#gitignore-extensions) +1. [Testing](#testing) + 1. [Running unit tests](#running-unit-tests) + 1. [Running the compiler test suite](#running-the-compiler-test-suite) + ## Requirements -This target is cross-compiled from a host environment. Development may be done -from the [source tree] or using the Fuchsia SDK. +This target is cross-compiled from a host environment. You will need a recent +copy of the [Fuchsia SDK], which provides the tools, libraries, and binaries +required to build and link programs for Fuchsia. -[source tree]: https://fuchsia.dev/fuchsia-src/get-started/learn/build +Development may also be done from the [source tree]. -Fuchsia targets support std and follow the `sysv64` calling convention on +Fuchsia targets support `std` and follow the `sysv64` calling convention on x86_64. Fuchsia binaries use the ELF file format. -## Building the target +## Walkthrough structure + +This walkthrough will cover: + +1. Compiling a Rust binary targeting Fuchsia. +1. Building a Fuchsia package. +1. Publishing and running a Fuchsia package to a Fuchsia emulator. + +For the purposes of this walkthrough, we will only target `x86_64-fuchsia`. + +## Compiling a Rust binary targeting Fuchsia + +Today, there are two main ways to build a Rust binary targeting Fuchsia +using the Fuchsia SDK: +1. Allow [rustup] to handle the installation of Fuchsia targets for you. +1. Build a toolchain locally that can target Fuchsia. + +### Targeting Fuchsia with rustup and cargo + +The easiest way to build a Rust binary targeting Fuchsia is by allowing [rustup] +to handle the installation of Fuchsia targets for you. This can be done by issuing +the following commands: + +```sh +rustup target add x86_64-fuchsia +rustup target add aarch_64-fuchsia +``` + +After installing our Fuchsia targets, we can now compile a Rust binary that targets +Fuchsia. + +To create our Rust project, we can issue a standard `cargo` command as follows: + +**From base working directory** +```sh +cargo new hello_fuchsia +``` + +The rest of this walkthrough will take place from `hello_fuchsia`, so we can +change into that directory now: + +```sh +cd hello_fuchsia +``` + +*Note: From this point onwards, all commands will be issued from the `hello_fuchsia/` +directory, and all `hello_fuchsia/` prefixes will be removed from references for sake of brevity.* + +We can edit our `src/main.rs` to include a test as follows: + +**`src/main.rs`** +```rust +fn main() { + println!("Hello Fuchsia!"); +} + +#[test] +fn it_works() { + assert_eq!(2 + 2, 4); +} +``` + +In addition to the standard workspace created, we will want to create a +`.cargo/config.toml` file to link necessary libraries +during compilation: + +**`.cargo/config.toml`** +```txt +[target.x86_64-fuchsia] + +rustflags = [ + "-Lnative", "/arch/x64/sysroot/lib", + "-Lnative", "/arch/x64/lib" +] +``` + +*Note: Make sure to fill out `` with the path to the downloaded [Fuchsia SDK].* + +In total, our new project will look like: + +**Current directory structure** +```txt +hello_fuchsia/ +┣━ src/ +┃ ┗━ main.rs +┣━ Cargo.toml +┗━ .cargo/ + ┗━ config.toml +``` + +Finally, we can build our rust binary as: + +```sh +cargo build --target x86_64-fuchsia +``` + +Now we have a Rust binary at `target/x86_64-fuchsia/debug/hello_fuchsia`, +targeting our desired Fuchsia target. + +**Current directory structure** +```txt +hello_fuchsia/ +┣━ src/ +┃ ┗━ main.rs +┣━ target/ +┃ ┗━ x86_64-fuchsia/ +┃ ┗━ debug/ +┃ ┗━ hello_fuchsia +┣━ Cargo.toml +┗━ .cargo/ + ┗━ config.toml +``` + +### Targeting Fuchsia with a compiler built from source + +An alternative to the first workflow is to target Fuchsia by using +`rustc` built from source. Before building Rust for Fuchsia, you'll need a clang toolchain that supports Fuchsia as well. A recent version (14+) of clang should be sufficient to compile Rust for Fuchsia. -You'll also need a recent copy of the [Fuchsia SDK], which provides the tools -and binaries required to build and link programs for Fuchsia. - -[Fuchsia SDK]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core - x86-64 and AArch64 Fuchsia targets can be enabled using the following configuration. @@ -75,15 +206,21 @@ export CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/ These can be run together in a shell environment by executing `(source config-env.sh && ./x.py install)`. -## Building Rust programs +Once `rustc` is installed, we can create a new working directory to work from, +`hello_fuchsia` along with `hello_fuchsia/src`: -After compiling Rust binaries, you'll need to build a component, package it, and -serve it to a Fuchsia device or emulator. All of this can be done using the -Fuchsia SDK. +```sh +mkdir hello_fuchsia +cd hello_fuchsia +mkdir src +``` + +*Note: From this point onwards, all commands will be issued from the `hello_fuchsia/` +directory, and all `hello_fuchsia/` prefixes will be removed from references for sake of brevity.* -As an example, we'll compile and run this simple program on a Fuchsia emulator: +There, we can create a new file named `src/hello_fuchsia.rs`: -**`hello_fuchsia.rs`** +**`src/hello_fuchsia.rs`** ```rust fn main() { println!("Hello Fuchsia!"); @@ -95,31 +232,87 @@ fn it_works() { } ``` -Create a new file named `hello_fuchsia.rs` and fill out its contents with that -code. +**Current directory structure** +```txt +hello_fuchsia/ +┗━ src/ + ┗━ hello_fuchsia.rs +``` + +Using your freshly installed `rustc`, you can compile a binary for Fuchsia using +the following options: + +* `--target x86_64-fuchsia`/`--target aarch64-fuchsia`: Targets the Fuchsia + platform of your choice +* `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from + the SDK +* `-Lnative ${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia kernel + libraries from the SDK + +Putting it all together: + +```sh +# Configure these for the Fuchsia target of your choice +TARGET_ARCH="" +ARCH="" + +rustc \ + --target ${TARGET_ARCH} \ + -Lnative=${SDK_PATH}/arch/${ARCH}/lib \ + -Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib \ + --out-dir bin src/hello_fuchsia.rs +``` + +**Current directory structure** +```txt +hello_fuchsia/ +┣━ src/ +┃ ┗━ hello_fuchsia.rs +┗━ bin/ + ┗━ hello_fuchsia +``` -### Create a package +## Creating a Fuchsia package +Before moving on, double check your directory structure: + +**Current directory structure** +```txt +hello_fuchsia/ +┣━ src/ (if using rustc) +┃ ┗━ hello_fuchsia.rs ... +┣━ bin/ ... +┃ ┗━ hello_fuchsia ... +┣━ src/ (if using cargo) +┃ ┗━ main.rs ... +┗━ target/ ... + ┗━ x86_64-fuchsia/ ... + ┗━ debug/ ... + ┗━ hello_fuchsia ... +``` + +With our Rust binary built, we can move to creating a Fuchsia package. On Fuchsia, a package is the unit of distribution for software. We'll need to create a new package directory where we will place files like our finished -binary and any data it may need. The working directory will have this layout: +binary and any data it may need. + +To start, make the `pkg`, and `pkg/meta` directories: +```sh +mkdir pkg +mkdir pkg/meta +``` + +**Current directory structure** ```txt -hello_fuchsia.rs -hello_fuchsia.cml -package -┣━ bin -┃ ┗━ hello_fuchsia -┣━ meta -┃ ┣━ package -┃ ┗━ hello_fuchsia.cm -┗━ hello_fuchsia.manifest +hello_fuchsia/ +┗━ pkg/ + ┗━ meta/ ``` -Make the `package`, `package/bin`, and `package/meta` directories and create the -following files inside: +Now, create the following files inside: -**`package/meta/package`** +**`pkg/meta/package`** ```json { "name": "hello_fuchsia", @@ -130,13 +323,14 @@ following files inside: The `package` file describes our package's name and version number. Every package must contain one. -**`package/hello_fuchsia.manifest`** +**`pkg/hello_fuchsia.manifest`** ```txt -bin/hello_fuchsia=package/bin/hello_fuchsia +bin/hello_fuchsia=target/x86_64-fuchsia/debug/hello_fuchsia # If using cargo... +bin/hello_fuchsia=bin/hello_fuchsia # If using rustc... lib/ld.so.1=/arch/x64/sysroot/dist/lib/ld.so.1 lib/libfdio.so=/arch/x64/dist/libfdio.so -meta/package=package/meta/package -meta/hello_fuchsia.cm=package/meta/hello_fuchsia.cm +meta/package=pkg/meta/package +meta/hello_fuchsia.cm=pkg/meta/hello_fuchsia.cm ``` *Note: Relative manifest paths are resolved starting from the working directory @@ -144,42 +338,26 @@ of `pm`. Make sure to fill out `` with the path to the downloaded SDK.* The `.manifest` file will be used to describe the contents of the package by -relating their location when installed to their location on the file system. You -can use this to make a package pull files from other places, but for this -example we'll just be placing everything in the `package` directory. - -### Compiling a binary - -Using your freshly compiled `rustc`, you can compile a binary for Fuchsia using -the following options: +relating their location when installed to their location on the file system. The +`bin/hello_fuchsia=` entry will be different depending on how your Rust binary +was built, so choose accordingly. -* `--target x86_64-fuchsia`/`--target aarch64-fuchsia`: Targets the Fuchsia - platform of your choice -* `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from - the SDK -* `-Lnative ${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia kernel - libraries from the SDK - -Putting it all together: - -```sh -# Configure these for the Fuchsia target of your choice -TARGET_ARCH="" -ARCH="" - -rustc --target ${TARGET_ARCH} -Lnative=${SDK_PATH}/arch/${ARCH}/lib -Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib -o package/bin/hello_fuchsia hello_fuchsia.rs +**Current directory structure** +```txt +hello_fuchsia/ +┗━ pkg/ + ┣━ meta/ + ┃ ┗━ package + ┗━ hello_fuchsia.manifest ``` -### Bulding a component +### Creating a Fuchsia component -On Fuchsia, components require a component manifest written in Fuchia's markup +On Fuchsia, components require a component manifest written in Fuchsia's markup language called CML. The Fuchsia devsite contains an [overview of CML] and a [reference for the file format]. Here's a basic one that can run our single binary: -[overview of CML]: https://fuchsia.dev/fuchsia-src/concepts/components/v2/component_manifests -[reference for the file format]: https://fuchsia.dev/reference/cml - -**`hello_fuchsia.cml`** +**`pkg/hello_fuchsia.cml`** ```txt { include: [ "syslog/client.shard.cml" ], @@ -190,43 +368,152 @@ language called CML. The Fuchsia devsite contains an [overview of CML] and a } ``` +```txt +hello_fuchsia/ +┗━ pkg/ + ┣━ meta/ + ┃ ┗━ package + ┣━ hello_fuchsia.manifest + ┗━ hello_fuchsia.cml +``` + Now we can compile that CML into a component manifest: ```sh -${SDK_PATH}/tools/${ARCH}/cmc compile hello_fuchsia.cml --includepath ${SDK_PATH}/pkg -o package/meta/hello_fuchsia.cm +${SDK_PATH}/tools/${ARCH}/cmc compile \ + pkg/hello_fuchsia.cml \ + --includepath ${SDK_PATH}/pkg \ + -o pkg/meta/hello_fuchsia.cm +``` + +**Current directory structure** +```txt +hello_fuchsia/ +┗━ pkg/ + ┣━ meta/ + ┃ ┣━ package + ┃ ┗━ hello_fuchsia.cm + ┣━ hello_fuchsia.manifest + ┗━ hello_fuchsia.cml ``` -`--includepath` tells the compiler where to look for `include`s from our CML. -In our case, we're only using `syslog/client.shard.cml`. +*Note: `--includepath` tells the compiler where to look for `include`s from our CML. +In our case, we're only using `syslog/client.shard.cml`.* -### Building and publishing a package +### Building a Fuchsia package -Next, we'll build our package as defined by our manifest: +Next, we'll build a package manifest as defined by our manifest: ```sh -${SDK_PATH}/tools/${ARCH}/pm -o hello_fuchsia -m package/hello_fuchsia.manifest build -output-package-manifest hello_fuchsia_manifest +${SDK_PATH}/tools/${ARCH}/pm \ + -o hello_fuchsia_manifest \ + -m pkg/hello_fuchsia.manifest \ + build \ + -output-package-manifest hello_fuchsia_package_manifest ``` -This will produce `hello_fuchsia_manifest` which is a package manifest we can -publish directly to a repository. We can set up that repository with: +This will produce `pkg/hello_fuchsia_manifest/` which is a package manifest we can +publish directly to a repository. + +**Current directory structure** +```txt +hello_fuchsia/ +┗━ pkg/ + ┣━ meta/ + ┃ ┣━ package + ┃ ┗━ hello_fuchsia.cm + ┣━ hello_fuchsia_manifest/ + ┃ ┗━ ... + ┣━ hello_fuchsia.manifest + ┣━ hello_fuchsia.cml + ┗━ hello_fuchsia_package_manifest +``` + +We are now ready to publish the package. + +## Publishing a Fuchsia package + +With our package and component manifests setup, +we can now publish our package. The first step will +be to create a Fuchsia package repository to publish +to. + +### Creating a Fuchsia package repository + +We can set up our repository with: ```sh -${SDK_PATH}/tools/${ARCH}/pm newrepo -repo repo +${SDK_PATH}/tools/${ARCH}/pm newrepo \ + -repo pkg/repo +``` + +**Current directory structure** +```txt +hello_fuchsia/ +┗━ pkg/ + ┣━ meta/ + ┃ ┣━ package + ┃ ┗━ hello_fuchsia.cm + ┣━ hello_fuchsia_manifest/ + ┃ ┗━ ... + ┣━ repo/ + ┃ ┗━ ... + ┣━ hello_fuchsia.manifest + ┣━ hello_fuchsia.cml + ┗━ hello_fuchsia_package_manifest ``` -And then publish our new package to that repository with: +## Publishing Fuchsia package to repository + +We can publish our new package to that repository with: ```sh -${SDK_PATH}/tools/${ARCH}/pm publish -repo repo -lp -f <(echo "hello_fuchsia_manifest") +${SDK_PATH}/tools/${ARCH}/pm publish \ + -repo repo \ + -lp -f <(echo "hello_fuchsia_package_manifest") ``` Then we can add it to `ffx`'s package server as `hello-fuchsia` using: ```sh -${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm repo -r hello-fuchsia +${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \ + repo \ + -r hello-fuchsia +``` + +## Running a Fuchsia component on an emulator + +At this point, we are ready to run our Fuchsia +component. For reference, our final directory +structure will look like: + +**Final directory structure** +```txt +hello_fuchsia/ +┣━ src/ (if using rustc) +┃ ┗━ hello_fuchsia.rs ... +┣━ bin/ ... +┃ ┗━ hello_fuchsia ... +┣━ src/ (if using cargo) +┃ ┗━ main.rs ... +┣━ target/ ... +┃ ┗━ x86_64-fuchsia/ ... +┃ ┗━ debug/ ... +┃ ┗━ hello_fuchsia ... +┗━ pkg/ + ┣━ meta/ + ┃ ┣━ package + ┃ ┗━ hello_fuchsia.cm + ┣━ hello_fuchsia_manifest/ + ┃ ┗━ ... + ┣━ repo/ + ┃ ┗━ ... + ┣━ hello_fuchsia.manifest + ┣━ hello_fuchsia.cml + ┗━ hello_fuchsia_package_manifest ``` -### Starting the emulator +### Starting the Fuchsia emulator Start a Fuchsia emulator in a new terminal using: @@ -235,50 +522,83 @@ ${SDK_PATH}/tools/${ARCH}/ffx product-bundle get workstation_eng.qemu-${ARCH} ${SDK_PATH}/tools/${ARCH}/ffx emu start workstation_eng.qemu-${ARCH} --headless ``` -Once the emulator is running, start a package repository server to serve our -package to the emulator: +### Watching emulator logs +Once the emulator is running, open a separate terminal to watch the emulator logs: + +**In separate terminal** ```sh -${SDK_PATH}/tools/${ARCH}/ffx repository server start +${SDK_PATH}/tools/${ARCH}/ffx log \ + --since now ``` -Once the repository server is up and running, register our repository: +### Serving a Fuchsia package + +Now, start a package repository server to serve our +package to the emulator: ```sh -${SDK_PATH}/tools/${ARCH}/ffx target repository register --repository hello-fuchsia +${SDK_PATH}/tools/${ARCH}/ffx repository server start ``` -And watch the logs from the emulator in a separate terminal: +Once the repository server is up and running, register our repository: ```sh -${SDK_PATH}/tools/${ARCH}/ffx log --since now +${SDK_PATH}/tools/${ARCH}/ffx target repository register \ + --repository hello-fuchsia ``` +### Running a Fuchsia component + Finally, run the component: ```sh -${SDK_PATH}/tools/${ARCH}/ffx component run fuchsia-pkg://hello-fuchsia/hello_fuchsia#meta/hello_fuchsia.cm +${SDK_PATH}/tools/${ARCH}/ffx component run \ + fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm ``` On reruns of the component, the `--recreate` argument may also need to be passed. ```sh -${SDK_PATH}/tools/${ARCH}/ffx component run --recreate fuchsia-pkg://hello-fuchsia/hello_fuchsia#meta/hello_fuchsia.cm +${SDK_PATH}/tools/${ARCH}/ffx component run \ + --recreate \ + fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm +``` + +## `.gitignore` extensions + +Optionally, we can create/extend our `.gitignore` file to ignore files and +directories that are not helpful to track: + +```txt +pkg/repo +pkg/meta/hello_fuchsia.cm +pkg/hello_fuchsia_manifest +pkg/hello_fuchsia_package_manifest ``` ## Testing ### Running unit tests -Tests can be run in the same way as a regular binary, simply by passing `--test` -to the `rustc` invocation and then repackaging and rerunning. The test harness -will run the applicable unit tests. +Tests can be run in the same way as a regular binary. + +* If using `cargo`, you can simply pass `test --no-run` +to the `cargo` invocation and then repackage and rerun the Fuchsia package. From our previous example, +this would look like `cargo test --target x86_64-fuchsia --no-run`, and moving the executable +binary path found from the line `Executable unittests src/main.rs (target/x86_64-fuchsia/debug/deps/hello_fuchsia-)` +into `pkg/hello_fuchsia.manifest`. + +* If using the compiled `rustc`, you can simply pass `--test` +to the `rustc` invocation and then repackage and rerun the Fuchsia package. + +The test harness will run the applicable unit tests. Often when testing, you may want to pass additional command line arguments to your binary. Additional arguments can be set in the component manifest: -**`hello_fuchsia.cml`** +**`pkg/hello_fuchsia.cml`** ```txt { include: [ "syslog/client.shard.cml" ], @@ -293,11 +613,20 @@ your binary. Additional arguments can be set in the component manifest: This will pass the argument `it_works` to the binary, filtering the tests to only those tests that match the pattern. There are many more configuration options available in CML including environment variables. More documentation is -available on the [Fuchsia devsite](https://fuchsia.dev/reference/cml). +available on the [Fuchsia devsite]. ### Running the compiler test suite Running the Rust test suite on Fuchsia is [not currently supported], but work is underway to enable it. +[Fuchsia team]: https://team-api.infra.rust-lang.org/v1/teams/fuchsia.json +[Fuchsia]: https://fuchsia.dev/ +[source tree]: https://fuchsia.dev/fuchsia-src/get-started/learn/build +[rustup]: https://rustup.rs/ +[cargo]: https://doc.rust-lang.org/cargo/ +[Fuchsia SDK]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core +[overview of CML]: https://fuchsia.dev/fuchsia-src/concepts/components/v2/component_manifests +[reference for the file format]: https://fuchsia.dev/reference/cml +[Fuchsia devsite]: https://fuchsia.dev/reference/cml [not currently supported]: https://fxbug.dev/105393 From 18340bd52be4176648ef703fae0e87b5cac765d2 Mon Sep 17 00:00:00 2001 From: andrewpollack Date: Tue, 30 Aug 2022 16:06:27 -0700 Subject: [PATCH 51/53] Update src/doc/rustc/src/platform-support/fuchsia.md Co-authored-by: Tyler Mandry --- src/doc/rustc/src/platform-support/fuchsia.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index e6503405dbcba..2b0d7e4d1752d 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -473,7 +473,7 @@ ${SDK_PATH}/tools/${ARCH}/pm publish \ -lp -f <(echo "hello_fuchsia_package_manifest") ``` -Then we can add it to `ffx`'s package server as `hello-fuchsia` using: +Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using: ```sh ${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \ From c52d99f6e2174c5af74098884bcfeaf04e64b8a8 Mon Sep 17 00:00:00 2001 From: andrewpollack Date: Tue, 30 Aug 2022 16:06:36 -0700 Subject: [PATCH 52/53] Update src/doc/rustc/src/platform-support/fuchsia.md Co-authored-by: Tyler Mandry --- src/doc/rustc/src/platform-support/fuchsia.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 2b0d7e4d1752d..c2a1613f288c5 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -541,7 +541,7 @@ package to the emulator: ${SDK_PATH}/tools/${ARCH}/ffx repository server start ``` -Once the repository server is up and running, register our repository: +Once the repository server is up and running, register it with the target Fuchsia system running in the emulator: ```sh ${SDK_PATH}/tools/${ARCH}/ffx target repository register \ From 437879f20e081640a711bc6b34ddcc94a387d11a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 30 Aug 2022 16:18:42 -0700 Subject: [PATCH 53/53] Update books --- src/doc/book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rustc-dev-guide | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/book b/src/doc/book index 42ca0ef484fcc..0a5421ceb2383 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 42ca0ef484fcc8437a0682cee23abe4b7c407d52 +Subproject commit 0a5421ceb238357b3634fb75234eba4d1dad643c diff --git a/src/doc/nomicon b/src/doc/nomicon index 8e6aa3448515a..d880e6ac2acf1 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 8e6aa3448515a0654e347b5e2510f1d4bc4d5a64 +Subproject commit d880e6ac2acf133dce640da24b9fb692844f02d4 diff --git a/src/doc/reference b/src/doc/reference index e647eb102890e..f62e93c28323e 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit e647eb102890e8927f488bea12672b079eff8d9d +Subproject commit f62e93c28323ed9637d0a205a0c256498674a509 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index d3daa1f28e169..04892c1a6fc14 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit d3daa1f28e169087becbc5e2b49ac91ca0405a44 +Subproject commit 04892c1a6fc145602ac7367945fda9d4ee83c9fb