aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock22
-rw-r--r--crates/completion/src/render.rs3
-rw-r--r--crates/hir/src/code_model.rs27
-rw-r--r--crates/hir/src/diagnostics.rs2
-rw-r--r--crates/hir/src/semantics/source_to_def.rs10
-rw-r--r--crates/hir_def/src/db.rs15
-rw-r--r--crates/hir_def/src/find_path.rs27
-rw-r--r--crates/hir_def/src/import_map.rs2
-rw-r--r--crates/hir_def/src/item_tree.rs13
-rw-r--r--crates/hir_def/src/item_tree/lower.rs2
-rw-r--r--crates/hir_def/src/lib.rs19
-rw-r--r--crates/hir_def/src/nameres.rs75
-rw-r--r--crates/hir_def/src/nameres/collector.rs27
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs63
-rw-r--r--crates/hir_def/src/nameres/tests.rs62
-rw-r--r--crates/hir_def/src/nameres/tests/block.rs26
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs16
-rw-r--r--crates/hir_def/src/path.rs1
-rw-r--r--crates/hir_def/src/resolver.rs2
-rw-r--r--crates/hir_def/src/test_db.rs6
-rw-r--r--crates/hir_expand/src/builtin_macro.rs26
-rw-r--r--crates/hir_expand/src/name.rs3
-rw-r--r--crates/hir_ty/src/diagnostics.rs116
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs85
-rw-r--r--crates/hir_ty/src/test_db.rs2
-rw-r--r--crates/ide/src/diagnostics.rs3
-rw-r--r--crates/ide/src/diagnostics/fixes.rs33
-rw-r--r--crates/ide/src/display/navigation_target.rs12
-rw-r--r--crates/ide/src/references.rs16
-rw-r--r--crates/ide_db/src/symbol_index.rs14
-rw-r--r--crates/parser/src/grammar/items/consts.rs2
-rw-r--r--crates/profile/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/config.rs7
-rw-r--r--crates/rust-analyzer/src/handlers.rs70
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/validation.rs16
-rw-r--r--crates/syntax/test_data/parser/err/0047_mutable_const_item.rast22
-rw-r--r--crates/syntax/test_data/parser/err/0047_mutable_const_item.rs1
-rw-r--r--crates/syntax/test_data/parser/ok/0024_const_item.rast23
-rw-r--r--crates/syntax/test_data/parser/ok/0024_const_item.rs1
-rw-r--r--docs/dev/README.md6
-rw-r--r--docs/dev/style.md7
-rw-r--r--docs/user/generated_config.adoc2
-rw-r--r--editors/code/package.json5
-rw-r--r--editors/code/src/config.ts1
-rw-r--r--editors/code/src/main.ts2
-rw-r--r--editors/code/src/net.ts25
47 files changed, 619 insertions, 305 deletions
diff --git a/Cargo.lock b/Cargo.lock
index bf1b9e417..efd1c6d33 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -275,9 +275,9 @@ checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"
275 275
276[[package]] 276[[package]]
277name = "countme" 277name = "countme"
278version = "2.0.0-pre.2" 278version = "2.0.0"
279source = "registry+https://github.com/rust-lang/crates.io-index" 279source = "registry+https://github.com/rust-lang/crates.io-index"
280checksum = "c5716604cba7c02a846ecad3f4a3fd2d2b641faccc2a24a51efb21aff0d01f35" 280checksum = "4f8038ded86523aa26c1321dfe8bb432707d0a3e2608f9d0108803727546e089"
281dependencies = [ 281dependencies = [
282 "dashmap", 282 "dashmap",
283 "once_cell", 283 "once_cell",
@@ -1400,9 +1400,9 @@ checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
1400 1400
1401[[package]] 1401[[package]]
1402name = "rowan" 1402name = "rowan"
1403version = "0.12.1" 1403version = "0.12.2"
1404source = "registry+https://github.com/rust-lang/crates.io-index" 1404source = "registry+https://github.com/rust-lang/crates.io-index"
1405checksum = "24c2d78254049413f9d73495f883e7fa0b7a7d4b88468cd72a3bbbd0ad585cd1" 1405checksum = "5e05df24c035422fb2b845d66ef3542d6c4f8572eafe077175a30787b0254207"
1406dependencies = [ 1406dependencies = [
1407 "countme", 1407 "countme",
1408 "hashbrown", 1408 "hashbrown",
@@ -1663,9 +1663,9 @@ dependencies = [
1663 1663
1664[[package]] 1664[[package]]
1665name = "syn" 1665name = "syn"
1666version = "1.0.58" 1666version = "1.0.59"
1667source = "registry+https://github.com/rust-lang/crates.io-index" 1667source = "registry+https://github.com/rust-lang/crates.io-index"
1668checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" 1668checksum = "07cb8b1b4ebf86a89ee88cbd201b022b94138c623644d035185c84d3f41b7e66"
1669dependencies = [ 1669dependencies = [
1670 "proc-macro2", 1670 "proc-macro2",
1671 "quote", 1671 "quote",
@@ -1742,11 +1742,11 @@ dependencies = [
1742 1742
1743[[package]] 1743[[package]]
1744name = "thread_local" 1744name = "thread_local"
1745version = "1.1.0" 1745version = "1.1.1"
1746source = "registry+https://github.com/rust-lang/crates.io-index" 1746source = "registry+https://github.com/rust-lang/crates.io-index"
1747checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" 1747checksum = "301bdd13d23c49672926be451130892d274d3ba0b410c18e00daa7990ff38d99"
1748dependencies = [ 1748dependencies = [
1749 "lazy_static", 1749 "once_cell",
1750] 1750]
1751 1751
1752[[package]] 1752[[package]]
@@ -1897,9 +1897,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
1897 1897
1898[[package]] 1898[[package]]
1899name = "ungrammar" 1899name = "ungrammar"
1900version = "1.9.3" 1900version = "1.10.0"
1901source = "registry+https://github.com/rust-lang/crates.io-index" 1901source = "registry+https://github.com/rust-lang/crates.io-index"
1902checksum = "f5901372c0f3a6a1a9d880aef134c8eaf5e54409343637508c0a344270b42d7b" 1902checksum = "ce24866975a8858d3a35eba845efc6b42962c5067afd2bc1a07b9ce0108d335c"
1903 1903
1904[[package]] 1904[[package]]
1905name = "unicase" 1905name = "unicase"
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index 6eb20df2b..e11b881ca 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -201,8 +201,7 @@ impl<'a> Render<'a> {
201 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module), 201 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
202 ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt { 202 ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
203 hir::Adt::Struct(_) => SymbolKind::Struct, 203 hir::Adt::Struct(_) => SymbolKind::Struct,
204 // FIXME: add CompletionItemKind::Union 204 hir::Adt::Union(_) => SymbolKind::Union,
205 hir::Adt::Union(_) => SymbolKind::Struct,
206 hir::Adt::Enum(_) => SymbolKind::Enum, 205 hir::Adt::Enum(_) => SymbolKind::Enum,
207 }), 206 }),
208 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const), 207 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index d9b4cdfce..e9bb4f541 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -18,8 +18,8 @@ use hir_def::{
18 type_ref::{Mutability, TypeRef}, 18 type_ref::{Mutability, TypeRef},
19 AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, 19 AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId,
20 DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, 20 DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId,
21 LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId, 21 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
22 TypeAliasId, TypeParamId, UnionId, 22 TypeParamId, UnionId,
23}; 23};
24use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; 24use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility};
25use hir_expand::{ 25use hir_expand::{
@@ -90,8 +90,8 @@ impl Crate {
90 } 90 }
91 91
92 pub fn root_module(self, db: &dyn HirDatabase) -> Module { 92 pub fn root_module(self, db: &dyn HirDatabase) -> Module {
93 let module_id = db.crate_def_map(self.id).root(); 93 let def_map = db.crate_def_map(self.id);
94 Module::new(self, module_id) 94 Module { id: def_map.module_id(def_map.root()) }
95 } 95 }
96 96
97 pub fn root_file(self, db: &dyn HirDatabase) -> FileId { 97 pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
@@ -275,10 +275,6 @@ impl ModuleDef {
275} 275}
276 276
277impl Module { 277impl Module {
278 pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module {
279 Module { id: ModuleId::top_level(krate.id, crate_module_id) }
280 }
281
282 /// Name of this module. 278 /// Name of this module.
283 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { 279 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
284 let def_map = self.id.def_map(db.upcast()); 280 let def_map = self.id.def_map(db.upcast());
@@ -302,7 +298,7 @@ impl Module {
302 /// in the module tree of any target in `Cargo.toml`. 298 /// in the module tree of any target in `Cargo.toml`.
303 pub fn crate_root(self, db: &dyn HirDatabase) -> Module { 299 pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
304 let def_map = db.crate_def_map(self.id.krate()); 300 let def_map = db.crate_def_map(self.id.krate());
305 self.with_module_id(def_map.root()) 301 Module { id: def_map.module_id(def_map.root()) }
306 } 302 }
307 303
308 /// Iterates over all child modules. 304 /// Iterates over all child modules.
@@ -311,7 +307,7 @@ impl Module {
311 let children = def_map[self.id.local_id] 307 let children = def_map[self.id.local_id]
312 .children 308 .children
313 .iter() 309 .iter()
314 .map(|(_, module_id)| self.with_module_id(*module_id)) 310 .map(|(_, module_id)| Module { id: def_map.module_id(*module_id) })
315 .collect::<Vec<_>>(); 311 .collect::<Vec<_>>();
316 children.into_iter() 312 children.into_iter()
317 } 313 }
@@ -321,7 +317,7 @@ impl Module {
321 // FIXME: handle block expressions as modules (their parent is in a different DefMap) 317 // FIXME: handle block expressions as modules (their parent is in a different DefMap)
322 let def_map = self.id.def_map(db.upcast()); 318 let def_map = self.id.def_map(db.upcast());
323 let parent_id = def_map[self.id.local_id].parent?; 319 let parent_id = def_map[self.id.local_id].parent?;
324 Some(self.with_module_id(parent_id)) 320 Some(Module { id: def_map.module_id(parent_id) })
325 } 321 }
326 322
327 pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> { 323 pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
@@ -406,10 +402,6 @@ impl Module {
406 def_map[self.id.local_id].scope.impls().map(Impl::from).collect() 402 def_map[self.id.local_id].scope.impls().map(Impl::from).collect()
407 } 403 }
408 404
409 pub(crate) fn with_module_id(self, module_id: LocalModuleId) -> Module {
410 Module::new(self.krate(), module_id)
411 }
412
413 /// Finds a path that can be used to refer to the given item from within 405 /// Finds a path that can be used to refer to the given item from within
414 /// this module, if possible. 406 /// this module, if possible.
415 pub fn find_use_path(self, db: &dyn DefDatabase, item: impl Into<ItemInNs>) -> Option<ModPath> { 407 pub fn find_use_path(self, db: &dyn DefDatabase, item: impl Into<ItemInNs>) -> Option<ModPath> {
@@ -1013,8 +1005,9 @@ impl MacroDef {
1013 /// early, in `hir_expand`, where modules simply do not exist yet. 1005 /// early, in `hir_expand`, where modules simply do not exist yet.
1014 pub fn module(self, db: &dyn HirDatabase) -> Option<Module> { 1006 pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
1015 let krate = self.id.krate; 1007 let krate = self.id.krate;
1016 let module_id = db.crate_def_map(krate).root(); 1008 let def_map = db.crate_def_map(krate);
1017 Some(Module::new(Crate { id: krate }, module_id)) 1009 let module_id = def_map.root();
1010 Some(Module { id: def_map.module_id(module_id) })
1018 } 1011 }
1019 1012
1020 /// XXX: this parses the file 1013 /// XXX: this parses the file
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 447faa04f..5343a036c 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -5,5 +5,5 @@ pub use hir_expand::diagnostics::{
5}; 5};
6pub use hir_ty::diagnostics::{ 6pub use hir_ty::diagnostics::{
7 IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, 7 IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr,
8 NoSuchField, RemoveThisSemicolon, 8 NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap,
9}; 9};
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index faede3269..6c612ee86 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -30,13 +30,12 @@ pub(super) struct SourceToDefCtx<'a, 'b> {
30impl SourceToDefCtx<'_, '_> { 30impl SourceToDefCtx<'_, '_> {
31 pub(super) fn file_to_def(&mut self, file: FileId) -> Option<ModuleId> { 31 pub(super) fn file_to_def(&mut self, file: FileId) -> Option<ModuleId> {
32 let _p = profile::span("SourceBinder::to_module_def"); 32 let _p = profile::span("SourceBinder::to_module_def");
33 let (krate, local_id) = self.db.relevant_crates(file).iter().find_map(|&crate_id| { 33 self.db.relevant_crates(file).iter().find_map(|&crate_id| {
34 // FIXME: inner items 34 // FIXME: inner items
35 let crate_def_map = self.db.crate_def_map(crate_id); 35 let crate_def_map = self.db.crate_def_map(crate_id);
36 let local_id = crate_def_map.modules_for_file(file).next()?; 36 let local_id = crate_def_map.modules_for_file(file).next()?;
37 Some((crate_id, local_id)) 37 Some(crate_def_map.module_id(local_id))
38 })?; 38 })
39 Some(ModuleId::top_level(krate, local_id))
40 } 39 }
41 40
42 pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> { 41 pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> {
@@ -63,8 +62,7 @@ impl SourceToDefCtx<'_, '_> {
63 let child_name = src.value.name()?.as_name(); 62 let child_name = src.value.name()?.as_name();
64 let def_map = parent_module.def_map(self.db.upcast()); 63 let def_map = parent_module.def_map(self.db.upcast());
65 let child_id = *def_map[parent_module.local_id].children.get(&child_name)?; 64 let child_id = *def_map[parent_module.local_id].children.get(&child_name)?;
66 // FIXME: handle block expression modules 65 Some(def_map.module_id(child_id))
67 Some(ModuleId::top_level(parent_module.krate(), child_id))
68 } 66 }
69 67
70 pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> { 68 pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> {
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index a87c80b8a..aef7e1f6c 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -2,9 +2,9 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use base_db::{salsa, CrateId, SourceDatabase, Upcast}; 4use base_db::{salsa, CrateId, SourceDatabase, Upcast};
5use hir_expand::{db::AstDatabase, AstId, HirFileId}; 5use hir_expand::{db::AstDatabase, HirFileId};
6use la_arena::ArenaMap; 6use la_arena::ArenaMap;
7use syntax::{ast, SmolStr}; 7use syntax::SmolStr;
8 8
9use crate::{ 9use crate::{
10 adt::{EnumData, StructData}, 10 adt::{EnumData, StructData},
@@ -16,9 +16,10 @@ use crate::{
16 item_tree::ItemTree, 16 item_tree::ItemTree,
17 lang_item::{LangItemTarget, LangItems}, 17 lang_item::{LangItemTarget, LangItems},
18 nameres::DefMap, 18 nameres::DefMap,
19 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, 19 AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId,
20 GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId, StaticLoc, StructId, 20 FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId,
21 StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, 21 StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId,
22 UnionLoc, VariantId,
22}; 23};
23 24
24#[salsa::query_group(InternDatabaseStorage)] 25#[salsa::query_group(InternDatabaseStorage)]
@@ -41,6 +42,8 @@ pub trait InternDatabase: SourceDatabase {
41 fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; 42 fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId;
42 #[salsa::interned] 43 #[salsa::interned]
43 fn intern_impl(&self, loc: ImplLoc) -> ImplId; 44 fn intern_impl(&self, loc: ImplLoc) -> ImplId;
45 #[salsa::interned]
46 fn intern_block(&self, loc: BlockLoc) -> BlockId;
44} 47}
45 48
46#[salsa::query_group(DefDatabaseStorage)] 49#[salsa::query_group(DefDatabaseStorage)]
@@ -56,7 +59,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
56 fn crate_def_map_query(&self, krate: CrateId) -> Arc<DefMap>; 59 fn crate_def_map_query(&self, krate: CrateId) -> Arc<DefMap>;
57 60
58 #[salsa::invoke(DefMap::block_def_map_query)] 61 #[salsa::invoke(DefMap::block_def_map_query)]
59 fn block_def_map(&self, krate: CrateId, block: AstId<ast::BlockExpr>) -> Arc<DefMap>; 62 fn block_def_map(&self, block: BlockId) -> Arc<DefMap>;
60 63
61 #[salsa::invoke(StructData::struct_data_query)] 64 #[salsa::invoke(StructData::struct_data_query)]
62 fn struct_data(&self, id: StructId) -> Arc<StructData>; 65 fn struct_data(&self, id: StructId) -> Arc<StructData>;
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index c01b6daf2..94a1d567d 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -53,12 +53,8 @@ fn check_self_super(def_map: &DefMap, item: ItemInNs, from: ModuleId) -> Option<
53 Some(ModPath::from_segments(PathKind::Super(0), Vec::new())) 53 Some(ModPath::from_segments(PathKind::Super(0), Vec::new()))
54 } else if let Some(parent_id) = def_map[from.local_id].parent { 54 } else if let Some(parent_id) = def_map[from.local_id].parent {
55 // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) 55 // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
56 if item 56 let parent_id = def_map.module_id(parent_id);
57 == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { 57 if item == ItemInNs::Types(ModuleDefId::ModuleId(parent_id)) {
58 krate: from.krate,
59 local_id: parent_id,
60 }))
61 {
62 Some(ModPath::from_segments(PathKind::Super(1), Vec::new())) 58 Some(ModPath::from_segments(PathKind::Super(1), Vec::new()))
63 } else { 59 } else {
64 None 60 None
@@ -120,12 +116,8 @@ fn find_path_inner(
120 } 116 }
121 117
122 // - if the item is the crate root, return `crate` 118 // - if the item is the crate root, return `crate`
123 if item 119 let root = def_map.module_id(def_map.root());
124 == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { 120 if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) {
125 krate: from.krate,
126 local_id: def_map.root(),
127 }))
128 {
129 return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); 121 return Some(ModPath::from_segments(PathKind::Crate, Vec::new()));
130 } 122 }
131 123
@@ -175,7 +167,7 @@ fn find_path_inner(
175 167
176 // - otherwise, look for modules containing (reexporting) it and import it from one of those 168 // - otherwise, look for modules containing (reexporting) it and import it from one of those
177 169
178 let crate_root = ModuleId { local_id: def_map.root(), krate: from.krate }; 170 let crate_root = def_map.module_id(def_map.root());
179 let crate_attrs = db.attrs(crate_root.into()); 171 let crate_attrs = db.attrs(crate_root.into());
180 let prefer_no_std = crate_attrs.by_key("no_std").exists(); 172 let prefer_no_std = crate_attrs.by_key("no_std").exists();
181 let mut best_path = None; 173 let mut best_path = None;
@@ -288,14 +280,11 @@ fn find_local_import_locations(
288 // Compute the initial worklist. We start with all direct child modules of `from` as well as all 280 // Compute the initial worklist. We start with all direct child modules of `from` as well as all
289 // of its (recursive) parent modules. 281 // of its (recursive) parent modules.
290 let data = &def_map[from.local_id]; 282 let data = &def_map[from.local_id];
291 let mut worklist = data 283 let mut worklist =
292 .children 284 data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>();
293 .values()
294 .map(|child| ModuleId { krate: from.krate, local_id: *child })
295 .collect::<Vec<_>>();
296 let mut parent = data.parent; 285 let mut parent = data.parent;
297 while let Some(p) = parent { 286 while let Some(p) = parent {
298 worklist.push(ModuleId { krate: from.krate, local_id: p }); 287 worklist.push(def_map.module_id(p));
299 parent = def_map[p].parent; 288 parent = def_map[p].parent;
300 } 289 }
301 290
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 0b7830445..0a3dc7956 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -75,7 +75,7 @@ impl ImportMap {
75 75
76 // We look only into modules that are public(ly reexported), starting with the crate root. 76 // We look only into modules that are public(ly reexported), starting with the crate root.
77 let empty = ImportPath { segments: vec![] }; 77 let empty = ImportPath { segments: vec![] };
78 let root = ModuleId { krate, local_id: def_map.root() }; 78 let root = def_map.module_id(def_map.root());
79 let mut worklist = vec![(root, empty)]; 79 let mut worklist = vec![(root, empty)];
80 while let Some((module, mod_path)) = worklist.pop() { 80 while let Some((module, mod_path)) = worklist.pop() {
81 let ext_def_map; 81 let ext_def_map;
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index b8d7608e7..1e5c94660 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -66,7 +66,7 @@ impl GenericParamsId {
66} 66}
67 67
68/// The item tree of a source file. 68/// The item tree of a source file.
69#[derive(Debug, Eq, PartialEq)] 69#[derive(Debug, Default, Eq, PartialEq)]
70pub struct ItemTree { 70pub struct ItemTree {
71 _c: Count<Self>, 71 _c: Count<Self>,
72 72
@@ -82,7 +82,7 @@ impl ItemTree {
82 let syntax = if let Some(node) = db.parse_or_expand(file_id) { 82 let syntax = if let Some(node) = db.parse_or_expand(file_id) {
83 node 83 node
84 } else { 84 } else {
85 return Arc::new(Self::empty()); 85 return Default::default();
86 }; 86 };
87 87
88 let hygiene = Hygiene::new(db.upcast(), file_id); 88 let hygiene = Hygiene::new(db.upcast(), file_id);
@@ -118,15 +118,6 @@ impl ItemTree {
118 Arc::new(item_tree) 118 Arc::new(item_tree)
119 } 119 }
120 120
121 fn empty() -> Self {
122 Self {
123 _c: Count::new(),
124 top_level: Default::default(),
125 attrs: Default::default(),
126 data: Default::default(),
127 }
128 }
129
130 fn shrink_to_fit(&mut self) { 121 fn shrink_to_fit(&mut self) {
131 if let Some(data) = &mut self.data { 122 if let Some(data) = &mut self.data {
132 let ItemTreeData { 123 let ItemTreeData {
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index ce470fc3b..8a71376b9 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -43,7 +43,7 @@ pub(super) struct Ctx {
43impl Ctx { 43impl Ctx {
44 pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { 44 pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self {
45 Self { 45 Self {
46 tree: ItemTree::empty(), 46 tree: ItemTree::default(),
47 hygiene, 47 hygiene,
48 file, 48 file,
49 source_ast_id_map: db.ast_id_map(file), 49 source_ast_id_map: db.ast_id_map(file),
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index c8dbb2aeb..42b50b5b7 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -74,16 +74,16 @@ use stdx::impl_from;
74#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 74#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
75pub struct ModuleId { 75pub struct ModuleId {
76 krate: CrateId, 76 krate: CrateId,
77 block: Option<BlockId>,
77 pub local_id: LocalModuleId, 78 pub local_id: LocalModuleId,
78} 79}
79 80
80impl ModuleId { 81impl ModuleId {
81 pub fn top_level(krate: CrateId, local_id: LocalModuleId) -> Self {
82 Self { krate, local_id }
83 }
84
85 pub fn def_map(&self, db: &dyn db::DefDatabase) -> Arc<DefMap> { 82 pub fn def_map(&self, db: &dyn db::DefDatabase) -> Arc<DefMap> {
86 db.crate_def_map(self.krate) 83 match self.block {
84 Some(block) => db.block_def_map(block),
85 None => db.crate_def_map(self.krate),
86 }
87 } 87 }
88 88
89 pub fn krate(&self) -> CrateId { 89 pub fn krate(&self) -> CrateId {
@@ -234,6 +234,15 @@ pub struct ImplId(salsa::InternId);
234type ImplLoc = ItemLoc<Impl>; 234type ImplLoc = ItemLoc<Impl>;
235impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); 235impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
236 236
237#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
238pub struct BlockId(salsa::InternId);
239#[derive(Debug, Hash, PartialEq, Eq, Clone)]
240pub struct BlockLoc {
241 ast_id: AstId<ast::BlockExpr>,
242 module: ModuleId,
243}
244impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
245
237#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 246#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
238pub struct TypeParamId { 247pub struct TypeParamId {
239 pub parent: GenericDefId, 248 pub parent: GenericDefId,
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index bd3ea9b8b..199771e9a 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -62,7 +62,7 @@ use la_arena::Arena;
62use profile::Count; 62use profile::Count;
63use rustc_hash::FxHashMap; 63use rustc_hash::FxHashMap;
64use stdx::format_to; 64use stdx::format_to;
65use syntax::{ast, AstNode}; 65use syntax::ast;
66 66
67use crate::{ 67use crate::{
68 db::DefDatabase, 68 db::DefDatabase,
@@ -70,14 +70,14 @@ use crate::{
70 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, 70 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
71 path::ModPath, 71 path::ModPath,
72 per_ns::PerNs, 72 per_ns::PerNs,
73 AstId, LocalModuleId, ModuleDefId, ModuleId, 73 AstId, BlockId, BlockLoc, LocalModuleId, ModuleDefId, ModuleId,
74}; 74};
75 75
76/// Contains all top-level defs from a macro-expanded crate 76/// Contains all top-level defs from a macro-expanded crate
77#[derive(Debug, PartialEq, Eq)] 77#[derive(Debug, PartialEq, Eq)]
78pub struct DefMap { 78pub struct DefMap {
79 _c: Count<Self>, 79 _c: Count<Self>,
80 parent: Option<Arc<DefMap>>, 80 block: Option<BlockInfo>,
81 root: LocalModuleId, 81 root: LocalModuleId,
82 modules: Arena<ModuleData>, 82 modules: Arena<ModuleData>,
83 krate: CrateId, 83 krate: CrateId,
@@ -91,6 +91,13 @@ pub struct DefMap {
91 diagnostics: Vec<DefDiagnostic>, 91 diagnostics: Vec<DefDiagnostic>,
92} 92}
93 93
94#[derive(Debug, PartialEq, Eq)]
95struct BlockInfo {
96 block: BlockId,
97 parent: Arc<DefMap>,
98 parent_module: LocalModuleId,
99}
100
94impl std::ops::Index<LocalModuleId> for DefMap { 101impl std::ops::Index<LocalModuleId> for DefMap {
95 type Output = ModuleData; 102 type Output = ModuleData;
96 fn index(&self, id: LocalModuleId) -> &ModuleData { 103 fn index(&self, id: LocalModuleId) -> &ModuleData {
@@ -190,15 +197,12 @@ impl DefMap {
190 Arc::new(def_map) 197 Arc::new(def_map)
191 } 198 }
192 199
193 pub(crate) fn block_def_map_query( 200 pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> {
194 db: &dyn DefDatabase, 201 let block: BlockLoc = db.lookup_intern_block(block_id);
195 krate: CrateId, 202 let item_tree = db.item_tree(block.ast_id.file_id);
196 block: AstId<ast::BlockExpr>, 203 let block_items = item_tree.inner_items_of_block(block.ast_id.value);
197 ) -> Arc<DefMap> {
198 let item_tree = db.item_tree(block.file_id);
199 let block_items = item_tree.inner_items_of_block(block.value);
200 204
201 let parent = parent_def_map(db, krate, block); 205 let parent = block.module.def_map(db);
202 206
203 if block_items.is_empty() { 207 if block_items.is_empty() {
204 // If there are no inner items, nothing new is brought into scope, so we can just return 208 // If there are no inner items, nothing new is brought into scope, so we can just return
@@ -206,10 +210,13 @@ impl DefMap {
206 return parent; 210 return parent;
207 } 211 }
208 212
209 let mut def_map = DefMap::empty(krate, parent.edition); 213 let block_info =
210 def_map.parent = Some(parent); 214 BlockInfo { block: block_id, parent, parent_module: block.module.local_id };
215
216 let mut def_map = DefMap::empty(block.module.krate, block_info.parent.edition);
217 def_map.block = Some(block_info);
211 218
212 let def_map = collector::collect_defs(db, def_map, Some(block.value)); 219 let def_map = collector::collect_defs(db, def_map, Some(block.ast_id.value));
213 Arc::new(def_map) 220 Arc::new(def_map)
214 } 221 }
215 222
@@ -218,7 +225,7 @@ impl DefMap {
218 let root = modules.alloc(ModuleData::default()); 225 let root = modules.alloc(ModuleData::default());
219 DefMap { 226 DefMap {
220 _c: Count::new(), 227 _c: Count::new(),
221 parent: None, 228 block: None,
222 krate, 229 krate,
223 edition, 230 edition,
224 extern_prelude: FxHashMap::default(), 231 extern_prelude: FxHashMap::default(),
@@ -265,6 +272,11 @@ impl DefMap {
265 self.extern_prelude.iter() 272 self.extern_prelude.iter()
266 } 273 }
267 274
275 pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId {
276 let block = self.block.as_ref().map(|b| b.block);
277 ModuleId { krate: self.krate, local_id, block }
278 }
279
268 pub(crate) fn resolve_path( 280 pub(crate) fn resolve_path(
269 &self, 281 &self,
270 db: &dyn DefDatabase, 282 db: &dyn DefDatabase,
@@ -282,9 +294,9 @@ impl DefMap {
282 pub fn dump(&self) -> String { 294 pub fn dump(&self) -> String {
283 let mut buf = String::new(); 295 let mut buf = String::new();
284 let mut current_map = self; 296 let mut current_map = self;
285 while let Some(parent) = &current_map.parent { 297 while let Some(block) = &current_map.block {
286 go(&mut buf, current_map, "block scope", current_map.root); 298 go(&mut buf, current_map, "block scope", current_map.root);
287 current_map = &**parent; 299 current_map = &*block.parent;
288 } 300 }
289 go(&mut buf, current_map, "crate", current_map.root); 301 go(&mut buf, current_map, "crate", current_map.root);
290 return buf; 302 return buf;
@@ -338,35 +350,6 @@ impl ModuleData {
338 } 350 }
339} 351}
340 352
341fn parent_def_map(
342 db: &dyn DefDatabase,
343 krate: CrateId,
344 block: AstId<ast::BlockExpr>,
345) -> Arc<DefMap> {
346 // FIXME: store this info in the item tree instead of reparsing here
347 let ast_id_map = db.ast_id_map(block.file_id);
348 let block_ptr = ast_id_map.get(block.value);
349 let root = match db.parse_or_expand(block.file_id) {
350 Some(it) => it,
351 None => {
352 return Arc::new(DefMap::empty(krate, Edition::Edition2018));
353 }
354 };
355 let ast = block_ptr.to_node(&root);
356
357 for ancestor in ast.syntax().ancestors().skip(1) {
358 if let Some(block_expr) = ast::BlockExpr::cast(ancestor) {
359 let ancestor_id = ast_id_map.ast_id(&block_expr);
360 let ast_id = InFile::new(block.file_id, ancestor_id);
361 let parent_map = db.block_def_map(krate, ast_id);
362 return parent_map;
363 }
364 }
365
366 // No enclosing block scope, so the parent is the crate-level DefMap.
367 db.crate_def_map(krate)
368}
369
370#[derive(Debug, Clone, PartialEq, Eq)] 353#[derive(Debug, Clone, PartialEq, Eq)]
371pub enum ModuleSource { 354pub enum ModuleSource {
372 SourceFile(ast::SourceFile), 355 SourceFile(ast::SourceFile),
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index adfcf879a..393170b32 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -37,8 +37,8 @@ use crate::{
37 per_ns::PerNs, 37 per_ns::PerNs,
38 visibility::{RawVisibility, Visibility}, 38 visibility::{RawVisibility, Visibility},
39 AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, 39 AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId,
40 FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, 40 FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc,
41 TraitLoc, TypeAliasLoc, UnionLoc, 41 TypeAliasLoc, UnionLoc,
42}; 42};
43 43
44const GLOB_RECURSION_LIMIT: usize = 100; 44const GLOB_RECURSION_LIMIT: usize = 100;
@@ -56,10 +56,9 @@ pub(super) fn collect_defs(
56 for dep in &crate_graph[def_map.krate].dependencies { 56 for dep in &crate_graph[def_map.krate].dependencies {
57 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); 57 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
58 let dep_def_map = db.crate_def_map(dep.crate_id); 58 let dep_def_map = db.crate_def_map(dep.crate_id);
59 def_map.extern_prelude.insert( 59 def_map
60 dep.as_name(), 60 .extern_prelude
61 ModuleId { krate: dep.crate_id, local_id: dep_def_map.root }.into(), 61 .insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into());
62 );
63 62
64 // look for the prelude 63 // look for the prelude
65 // If the dependency defines a prelude, we overwrite an already defined 64 // If the dependency defines a prelude, we overwrite an already defined
@@ -332,11 +331,9 @@ impl DefCollector<'_> {
332 // exported in type/value namespace. This function reduces the visibility of all items 331 // exported in type/value namespace. This function reduces the visibility of all items
333 // in the crate root that aren't proc macros. 332 // in the crate root that aren't proc macros.
334 let root = self.def_map.root; 333 let root = self.def_map.root;
334 let module_id = self.def_map.module_id(root);
335 let root = &mut self.def_map.modules[root]; 335 let root = &mut self.def_map.modules[root];
336 root.scope.censor_non_proc_macros(ModuleId { 336 root.scope.censor_non_proc_macros(module_id);
337 krate: self.def_map.krate,
338 local_id: self.def_map.root,
339 });
340 } 337 }
341 } 338 }
342 339
@@ -1029,8 +1026,7 @@ impl ModCollector<'_, '_> {
1029 continue; 1026 continue;
1030 } 1027 }
1031 } 1028 }
1032 let module = 1029 let module = self.def_collector.def_map.module_id(self.module_id);
1033 ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
1034 let container = ContainerId::ModuleId(module); 1030 let container = ContainerId::ModuleId(module);
1035 1031
1036 let mut def = None; 1032 let mut def = None;
@@ -1097,10 +1093,7 @@ impl ModCollector<'_, '_> {
1097 } 1093 }
1098 } 1094 }
1099 ModItem::Impl(imp) => { 1095 ModItem::Impl(imp) => {
1100 let module = ModuleId { 1096 let module = self.def_collector.def_map.module_id(self.module_id);
1101 krate: self.def_collector.def_map.krate,
1102 local_id: self.module_id,
1103 };
1104 let container = ContainerId::ModuleId(module); 1097 let container = ContainerId::ModuleId(module);
1105 let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) } 1098 let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) }
1106 .intern(self.def_collector.db); 1099 .intern(self.def_collector.db);
@@ -1343,7 +1336,7 @@ impl ModCollector<'_, '_> {
1343 modules[res].scope.define_legacy_macro(name, mac) 1336 modules[res].scope.define_legacy_macro(name, mac)
1344 } 1337 }
1345 modules[self.module_id].children.insert(name.clone(), res); 1338 modules[self.module_id].children.insert(name.clone(), res);
1346 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res }; 1339 let module = self.def_collector.def_map.module_id(res);
1347 let def: ModuleDefId = module.into(); 1340 let def: ModuleDefId = module.into();
1348 self.def_collector.def_map.modules[self.module_id].scope.define_def(def); 1341 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
1349 self.def_collector.update( 1342 self.def_collector.update(
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index 82528b792..419e465ed 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -10,9 +10,8 @@
10//! 10//!
11//! `ReachedFixedPoint` signals about this. 11//! `ReachedFixedPoint` signals about this.
12 12
13use std::iter::successors;
14
15use base_db::Edition; 13use base_db::Edition;
14use hir_expand::name;
16use hir_expand::name::Name; 15use hir_expand::name::Name;
17use test_utils::mark; 16use test_utils::mark;
18 17
@@ -23,7 +22,7 @@ use crate::{
23 path::{ModPath, PathKind}, 22 path::{ModPath, PathKind},
24 per_ns::PerNs, 23 per_ns::PerNs,
25 visibility::{RawVisibility, Visibility}, 24 visibility::{RawVisibility, Visibility},
26 AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, 25 AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId,
27}; 26};
28 27
29#[derive(Debug, Clone, Copy, PartialEq, Eq)] 28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -63,6 +62,10 @@ impl ResolvePathResult {
63 62
64impl DefMap { 63impl DefMap {
65 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { 64 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
65 if name == &name!(self) {
66 mark::hit!(extern_crate_self_as);
67 return PerNs::types(self.module_id(self.root).into(), Visibility::Public);
68 }
66 self.extern_prelude 69 self.extern_prelude
67 .get(name) 70 .get(name)
68 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)) 71 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public))
@@ -126,8 +129,8 @@ impl DefMap {
126 result.krate = result.krate.or(new.krate); 129 result.krate = result.krate.or(new.krate);
127 result.segment_index = result.segment_index.min(new.segment_index); 130 result.segment_index = result.segment_index.min(new.segment_index);
128 131
129 match &current_map.parent { 132 match &current_map.block {
130 Some(map) => current_map = map, 133 Some(block) => current_map = &block.parent,
131 None => return result, 134 None => return result,
132 } 135 }
133 } 136 }
@@ -146,21 +149,15 @@ impl DefMap {
146 PathKind::DollarCrate(krate) => { 149 PathKind::DollarCrate(krate) => {
147 if krate == self.krate { 150 if krate == self.krate {
148 mark::hit!(macro_dollar_crate_self); 151 mark::hit!(macro_dollar_crate_self);
149 PerNs::types( 152 PerNs::types(self.module_id(self.root).into(), Visibility::Public)
150 ModuleId { krate: self.krate, local_id: self.root }.into(),
151 Visibility::Public,
152 )
153 } else { 153 } else {
154 let def_map = db.crate_def_map(krate); 154 let def_map = db.crate_def_map(krate);
155 let module = ModuleId { krate, local_id: def_map.root }; 155 let module = def_map.module_id(def_map.root);
156 mark::hit!(macro_dollar_crate_other); 156 mark::hit!(macro_dollar_crate_other);
157 PerNs::types(module.into(), Visibility::Public) 157 PerNs::types(module.into(), Visibility::Public)
158 } 158 }
159 } 159 }
160 PathKind::Crate => PerNs::types( 160 PathKind::Crate => PerNs::types(self.module_id(self.root).into(), Visibility::Public),
161 ModuleId { krate: self.krate, local_id: self.root }.into(),
162 Visibility::Public,
163 ),
164 // plain import or absolute path in 2015: crate-relative with 161 // plain import or absolute path in 2015: crate-relative with
165 // fallback to extern prelude (with the simplification in 162 // fallback to extern prelude (with the simplification in
166 // rust-lang/rust#57745) 163 // rust-lang/rust#57745)
@@ -194,17 +191,35 @@ impl DefMap {
194 self.resolve_name_in_module(db, original_module, &segment, prefer_module) 191 self.resolve_name_in_module(db, original_module, &segment, prefer_module)
195 } 192 }
196 PathKind::Super(lvl) => { 193 PathKind::Super(lvl) => {
197 let m = successors(Some(original_module), |m| self.modules[*m].parent) 194 let mut module = original_module;
198 .nth(lvl as usize); 195 for i in 0..lvl {
199 if let Some(local_id) = m { 196 match self.modules[module].parent {
200 PerNs::types( 197 Some(it) => module = it,
201 ModuleId { krate: self.krate, local_id }.into(), 198 None => match &self.block {
202 Visibility::Public, 199 Some(block) => {
203 ) 200 // Look up remaining path in parent `DefMap`
204 } else { 201 let new_path = ModPath {
205 log::debug!("super path in root module"); 202 kind: PathKind::Super(lvl - i),
206 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 203 segments: path.segments.clone(),
204 };
205 log::debug!("`super` path: {} -> {} in parent map", path, new_path);
206 return block.parent.resolve_path_fp_with_macro(
207 db,
208 mode,
209 block.parent_module,
210 &new_path,
211 shadow,
212 );
213 }
214 None => {
215 log::debug!("super path in root module");
216 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
217 }
218 },
219 }
207 } 220 }
221
222 PerNs::types(self.module_id(module).into(), Visibility::Public)
208 } 223 }
209 PathKind::Abs => { 224 PathKind::Abs => {
210 // 2018-style absolute path -- only extern prelude 225 // 2018-style absolute path -- only extern prelude
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index 73e3a4702..b36d0b59b 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -8,12 +8,12 @@ mod block;
8 8
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use base_db::{fixture::WithFixture, SourceDatabase}; 11use base_db::{fixture::WithFixture, FilePosition, SourceDatabase};
12use expect_test::{expect, Expect}; 12use expect_test::{expect, Expect};
13use hir_expand::db::AstDatabase; 13use syntax::AstNode;
14use test_utils::mark; 14use test_utils::mark;
15 15
16use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; 16use crate::{db::DefDatabase, nameres::*, test_db::TestDB, Lookup};
17 17
18fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { 18fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> {
19 let db = TestDB::with_files(ra_fixture); 19 let db = TestDB::with_files(ra_fixture);
@@ -23,14 +23,58 @@ fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> {
23 23
24fn compute_block_def_map(ra_fixture: &str) -> Arc<DefMap> { 24fn compute_block_def_map(ra_fixture: &str) -> Arc<DefMap> {
25 let (db, position) = TestDB::with_position(ra_fixture); 25 let (db, position) = TestDB::with_position(ra_fixture);
26
27 // FIXME: perhaps we should make this use body lowering tests instead?
28
26 let module = db.module_for_file(position.file_id); 29 let module = db.module_for_file(position.file_id);
27 let ast_map = db.ast_id_map(position.file_id.into()); 30 let mut def_map = db.crate_def_map(module.krate);
28 let ast = db.parse(position.file_id); 31 while let Some(new_def_map) = descend_def_map_at_position(&db, position, def_map.clone()) {
29 let block: ast::BlockExpr = 32 def_map = new_def_map;
30 syntax::algo::find_node_at_offset(&ast.syntax_node(), position.offset).unwrap(); 33 }
31 let block_id = ast_map.ast_id(&block); 34
35 // FIXME: select the right module, not the root
36
37 def_map
38}
39
40fn descend_def_map_at_position(
41 db: &dyn DefDatabase,
42 position: FilePosition,
43 def_map: Arc<DefMap>,
44) -> Option<Arc<DefMap>> {
45 for (local_id, module_data) in def_map.modules() {
46 let mod_def = module_data.origin.definition_source(db);
47 let ast_map = db.ast_id_map(mod_def.file_id);
48 let item_tree = db.item_tree(mod_def.file_id);
49 let root = db.parse_or_expand(mod_def.file_id).unwrap();
50 for item in module_data.scope.declarations() {
51 match item {
52 ModuleDefId::FunctionId(it) => {
53 // Technically blocks can be inside any type (due to arrays and const generics),
54 // and also in const/static initializers. For tests we only really care about
55 // functions though.
56
57 let ast = ast_map.get(item_tree[it.lookup(db).id.value].ast_id).to_node(&root);
58
59 if ast.syntax().text_range().contains(position.offset) {
60 // Cursor inside function, descend into its body's DefMap.
61 // Note that we don't handle block *expressions* inside function bodies.
62 let ast_map = db.ast_id_map(position.file_id.into());
63 let ast_id = ast_map.ast_id(&ast.body().unwrap());
64 let block = BlockLoc {
65 ast_id: InFile::new(position.file_id.into(), ast_id),
66 module: def_map.module_id(local_id),
67 };
68 let block_id = db.intern_block(block);
69 return Some(db.block_def_map(block_id));
70 }
71 }
72 _ => continue,
73 }
74 }
75 }
32 76
33 db.block_def_map(module.krate, InFile::new(position.file_id.into(), block_id)) 77 None
34} 78}
35 79
36fn check(ra_fixture: &str, expect: Expect) { 80fn check(ra_fixture: &str, expect: Expect) {
diff --git a/crates/hir_def/src/nameres/tests/block.rs b/crates/hir_def/src/nameres/tests/block.rs
index 01d6326a7..470ca593e 100644
--- a/crates/hir_def/src/nameres/tests/block.rs
+++ b/crates/hir_def/src/nameres/tests/block.rs
@@ -95,3 +95,29 @@ fn outer() {
95 "#]], 95 "#]],
96 ); 96 );
97} 97}
98
99#[test]
100fn super_imports() {
101 check_at(
102 r#"
103mod module {
104 fn f() {
105 use super::Struct;
106 $0
107 }
108}
109
110struct Struct {}
111"#,
112 expect![[r#"
113 block scope
114 Struct: t
115 crate
116 Struct: t
117 module: t
118
119 crate::module
120 f: v
121 "#]],
122 );
123}
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index 58d69d3c6..e8e72e5ef 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -62,6 +62,22 @@ fn unresolved_extern_crate() {
62} 62}
63 63
64#[test] 64#[test]
65fn extern_crate_self_as() {
66 mark::check!(extern_crate_self_as);
67 check_diagnostics(
68 r"
69 //- /lib.rs
70 extern crate doesnotexist;
71 //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
72 // Should not error.
73 extern crate self as foo;
74 struct Foo;
75 use foo::Foo as Bar;
76 ",
77 );
78}
79
80#[test]
65fn dedup_unresolved_import_from_unresolved_crate() { 81fn dedup_unresolved_import_from_unresolved_crate() {
66 check_diagnostics( 82 check_diagnostics(
67 r" 83 r"
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index e34cd7f2f..84ea09b53 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -304,6 +304,7 @@ pub use hir_expand::name as __name;
304#[macro_export] 304#[macro_export]
305macro_rules! __known_path { 305macro_rules! __known_path {
306 (core::iter::IntoIterator) => {}; 306 (core::iter::IntoIterator) => {};
307 (core::iter::Iterator) => {};
307 (core::result::Result) => {}; 308 (core::result::Result) => {};
308 (core::option::Option) => {}; 309 (core::option::Option) => {};
309 (core::ops::Range) => {}; 310 (core::ops::Range) => {};
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 130c074f0..9021ea712 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -459,7 +459,7 @@ impl Resolver {
459 459
460 pub fn module(&self) -> Option<ModuleId> { 460 pub fn module(&self) -> Option<ModuleId> {
461 let (def_map, local_id) = self.module_scope()?; 461 let (def_map, local_id) = self.module_scope()?;
462 Some(ModuleId { krate: def_map.krate(), local_id }) 462 Some(def_map.module_id(local_id))
463 } 463 }
464 464
465 pub fn krate(&self) -> Option<CrateId> { 465 pub fn krate(&self) -> Option<CrateId> {
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs
index 4ff219fb7..c4e36eda5 100644
--- a/crates/hir_def/src/test_db.rs
+++ b/crates/hir_def/src/test_db.rs
@@ -15,7 +15,7 @@ use rustc_hash::FxHashSet;
15use syntax::{TextRange, TextSize}; 15use syntax::{TextRange, TextSize};
16use test_utils::extract_annotations; 16use test_utils::extract_annotations;
17 17
18use crate::{db::DefDatabase, ModuleDefId}; 18use crate::{db::DefDatabase, ModuleDefId, ModuleId};
19 19
20#[salsa::database( 20#[salsa::database(
21 base_db::SourceDatabaseExtStorage, 21 base_db::SourceDatabaseExtStorage,
@@ -72,12 +72,12 @@ impl FileLoader for TestDB {
72} 72}
73 73
74impl TestDB { 74impl TestDB {
75 pub(crate) fn module_for_file(&self, file_id: FileId) -> crate::ModuleId { 75 pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
76 for &krate in self.relevant_crates(file_id).iter() { 76 for &krate in self.relevant_crates(file_id).iter() {
77 let crate_def_map = self.crate_def_map(krate); 77 let crate_def_map = self.crate_def_map(krate);
78 for (local_id, data) in crate_def_map.modules() { 78 for (local_id, data) in crate_def_map.modules() {
79 if data.origin.file_id() == Some(file_id) { 79 if data.origin.file_id() == Some(file_id) {
80 return crate::ModuleId { krate, local_id }; 80 return crate_def_map.module_id(local_id);
81 } 81 }
82 } 82 }
83 } 83 }
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 80b60d59f..57bc6fbd7 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -327,17 +327,14 @@ fn concat_expand(
327 // concat works with string and char literals, so remove any quotes. 327 // concat works with string and char literals, so remove any quotes.
328 // It also works with integer, float and boolean literals, so just use the rest 328 // It also works with integer, float and boolean literals, so just use the rest
329 // as-is. 329 // as-is.
330 330 let component = unquote_str(&it).unwrap_or_else(|| it.text.to_string());
331 text += it 331 text.push_str(&component);
332 .text 332 }
333 .trim_start_matches(|c| match c { 333 // handle boolean literals
334 'r' | '#' | '\'' | '"' => true, 334 tt::TokenTree::Leaf(tt::Leaf::Ident(id))
335 _ => false, 335 if i % 2 == 0 && (id.text == "true" || id.text == "false") =>
336 }) 336 {
337 .trim_end_matches(|c| match c { 337 text.push_str(id.text.as_str());
338 '#' | '\'' | '"' => true,
339 _ => false,
340 });
341 } 338 }
342 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), 339 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
343 _ => { 340 _ => {
@@ -345,7 +342,6 @@ fn concat_expand(
345 } 342 }
346 } 343 }
347 } 344 }
348
349 ExpandResult { value: Some((quote!(#text), FragmentKind::Expr)), err } 345 ExpandResult { value: Some((quote!(#text), FragmentKind::Expr)), err }
350} 346}
351 347
@@ -745,12 +741,10 @@ mod tests {
745 r##" 741 r##"
746 #[rustc_builtin_macro] 742 #[rustc_builtin_macro]
747 macro_rules! concat {} 743 macro_rules! concat {}
748 concat!("foo", 0, r#"bar"#); 744 concat!("foo", "r", 0, r#"bar"#, false);
749 "##, 745 "##,
750 ); 746 );
751 747
752 assert_eq!(expanded, r#""foo0bar""#); 748 assert_eq!(expanded, r#""foor0barfalse""#);
753
754 // FIXME: `true`/`false` literals don't work.
755 } 749 }
756} 750}
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index d692cec14..c7609e90d 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -186,6 +186,9 @@ pub mod known {
186 Neg, 186 Neg,
187 Not, 187 Not,
188 Index, 188 Index,
189 // Components of known path (function name)
190 filter_map,
191 next,
189 // Builtin macros 192 // Builtin macros
190 file, 193 file,
191 column, 194 column,
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs
index 247da43f2..323c5f963 100644
--- a/crates/hir_ty/src/diagnostics.rs
+++ b/crates/hir_ty/src/diagnostics.rs
@@ -247,7 +247,7 @@ impl Diagnostic for RemoveThisSemicolon {
247 247
248// Diagnostic: break-outside-of-loop 248// Diagnostic: break-outside-of-loop
249// 249//
250// This diagnostic is triggered if `break` keyword is used outside of a loop. 250// This diagnostic is triggered if the `break` keyword is used outside of a loop.
251#[derive(Debug)] 251#[derive(Debug)]
252pub struct BreakOutsideOfLoop { 252pub struct BreakOutsideOfLoop {
253 pub file: HirFileId, 253 pub file: HirFileId,
@@ -271,7 +271,7 @@ impl Diagnostic for BreakOutsideOfLoop {
271 271
272// Diagnostic: missing-unsafe 272// Diagnostic: missing-unsafe
273// 273//
274// This diagnostic is triggered if operation marked as `unsafe` is used outside of `unsafe` function or block. 274// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block.
275#[derive(Debug)] 275#[derive(Debug)]
276pub struct MissingUnsafe { 276pub struct MissingUnsafe {
277 pub file: HirFileId, 277 pub file: HirFileId,
@@ -295,7 +295,7 @@ impl Diagnostic for MissingUnsafe {
295 295
296// Diagnostic: mismatched-arg-count 296// Diagnostic: mismatched-arg-count
297// 297//
298// This diagnostic is triggered if function is invoked with an incorrect amount of arguments. 298// This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
299#[derive(Debug)] 299#[derive(Debug)]
300pub struct MismatchedArgCount { 300pub struct MismatchedArgCount {
301 pub file: HirFileId, 301 pub file: HirFileId,
@@ -347,7 +347,7 @@ impl fmt::Display for CaseType {
347 347
348// Diagnostic: incorrect-ident-case 348// Diagnostic: incorrect-ident-case
349// 349//
350// This diagnostic is triggered if item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention]. 350// This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention].
351#[derive(Debug)] 351#[derive(Debug)]
352pub struct IncorrectCase { 352pub struct IncorrectCase {
353 pub file: HirFileId, 353 pub file: HirFileId,
@@ -386,6 +386,31 @@ impl Diagnostic for IncorrectCase {
386 } 386 }
387} 387}
388 388
389// Diagnostic: replace-filter-map-next-with-find-map
390//
391// This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`.
392#[derive(Debug)]
393pub struct ReplaceFilterMapNextWithFindMap {
394 pub file: HirFileId,
395 /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
396 pub next_expr: AstPtr<ast::Expr>,
397}
398
399impl Diagnostic for ReplaceFilterMapNextWithFindMap {
400 fn code(&self) -> DiagnosticCode {
401 DiagnosticCode("replace-filter-map-next-with-find-map")
402 }
403 fn message(&self) -> String {
404 "replace filter_map(..).next() with find_map(..)".to_string()
405 }
406 fn display_source(&self) -> InFile<SyntaxNodePtr> {
407 InFile { file_id: self.file, value: self.next_expr.clone().into() }
408 }
409 fn as_any(&self) -> &(dyn Any + Send + 'static) {
410 self
411 }
412}
413
389#[cfg(test)] 414#[cfg(test)]
390mod tests { 415mod tests {
391 use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; 416 use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
@@ -644,4 +669,87 @@ fn foo() { break; }
644 "#, 669 "#,
645 ); 670 );
646 } 671 }
672
673 // Register the required standard library types to make the tests work
674 fn add_filter_map_with_find_next_boilerplate(body: &str) -> String {
675 let prefix = r#"
676 //- /main.rs crate:main deps:core
677 use core::iter::Iterator;
678 use core::option::Option::{self, Some, None};
679 "#;
680 let suffix = r#"
681 //- /core/lib.rs crate:core
682 pub mod option {
683 pub enum Option<T> { Some(T), None }
684 }
685 pub mod iter {
686 pub trait Iterator {
687 type Item;
688 fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap }
689 fn next(&mut self) -> Option<Self::Item>;
690 }
691 pub struct FilterMap {}
692 impl Iterator for FilterMap {
693 type Item = i32;
694 fn next(&mut self) -> i32 { 7 }
695 }
696 }
697 "#;
698 format!("{}{}{}", prefix, body, suffix)
699 }
700
701 #[test]
702 fn replace_filter_map_next_with_find_map2() {
703 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
704 r#"
705 fn foo() {
706 let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next();
707 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..)
708 }
709 "#,
710 ));
711 }
712
713 #[test]
714 fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() {
715 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
716 r#"
717 fn foo() {
718 let m = [1, 2, 3]
719 .iter()
720 .filter_map(|x| if *x == 2 { Some (4) } else { None })
721 .len();
722 }
723 "#,
724 ));
725 }
726
727 #[test]
728 fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() {
729 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
730 r#"
731 fn foo() {
732 let m = [1, 2, 3]
733 .iter()
734 .filter_map(|x| if *x == 2 { Some (4) } else { None })
735 .map(|x| x + 2)
736 .len();
737 }
738 "#,
739 ));
740 }
741
742 #[test]
743 fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() {
744 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
745 r#"
746 fn foo() {
747 let m = [1, 2, 3]
748 .iter()
749 .filter_map(|x| if *x == 2 { Some (4) } else { None });
750 let n = m.next();
751 }
752 "#,
753 ));
754 }
647} 755}
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 107417c27..d740b7265 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -2,8 +2,10 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{expr::Statement, path::path, resolver::HasResolver, AdtId, DefWithBodyId}; 5use hir_def::{
6use hir_expand::diagnostics::DiagnosticSink; 6 expr::Statement, path::path, resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId,
7};
8use hir_expand::{diagnostics::DiagnosticSink, name};
7use rustc_hash::FxHashSet; 9use rustc_hash::FxHashSet;
8use syntax::{ast, AstPtr}; 10use syntax::{ast, AstPtr};
9 11
@@ -24,6 +26,8 @@ pub(crate) use hir_def::{
24 LocalFieldId, VariantId, 26 LocalFieldId, VariantId,
25}; 27};
26 28
29use super::ReplaceFilterMapNextWithFindMap;
30
27pub(super) struct ExprValidator<'a, 'b: 'a> { 31pub(super) struct ExprValidator<'a, 'b: 'a> {
28 owner: DefWithBodyId, 32 owner: DefWithBodyId,
29 infer: Arc<InferenceResult>, 33 infer: Arc<InferenceResult>,
@@ -40,6 +44,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
40 } 44 }
41 45
42 pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { 46 pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) {
47 self.check_for_filter_map_next(db);
48
43 let body = db.body(self.owner.into()); 49 let body = db.body(self.owner.into());
44 50
45 for (id, expr) in body.exprs.iter() { 51 for (id, expr) in body.exprs.iter() {
@@ -150,20 +156,76 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
150 } 156 }
151 } 157 }
152 158
153 fn validate_call(&mut self, db: &dyn HirDatabase, call_id: ExprId, expr: &Expr) -> Option<()> { 159 fn check_for_filter_map_next(&mut self, db: &dyn HirDatabase) {
160 // Find the FunctionIds for Iterator::filter_map and Iterator::next
161 let iterator_path = path![core::iter::Iterator];
162 let resolver = self.owner.resolver(db.upcast());
163 let iterator_trait_id = match resolver.resolve_known_trait(db.upcast(), &iterator_path) {
164 Some(id) => id,
165 None => return,
166 };
167 let iterator_trait_items = &db.trait_data(iterator_trait_id).items;
168 let filter_map_function_id =
169 match iterator_trait_items.iter().find(|item| item.0 == name![filter_map]) {
170 Some((_, AssocItemId::FunctionId(id))) => id,
171 _ => return,
172 };
173 let next_function_id = match iterator_trait_items.iter().find(|item| item.0 == name![next])
174 {
175 Some((_, AssocItemId::FunctionId(id))) => id,
176 _ => return,
177 };
178
179 // Search function body for instances of .filter_map(..).next()
180 let body = db.body(self.owner.into());
181 let mut prev = None;
182 for (id, expr) in body.exprs.iter() {
183 if let Expr::MethodCall { receiver, .. } = expr {
184 let function_id = match self.infer.method_resolution(id) {
185 Some(id) => id,
186 None => continue,
187 };
188
189 if function_id == *filter_map_function_id {
190 prev = Some(id);
191 continue;
192 }
193
194 if function_id == *next_function_id {
195 if let Some(filter_map_id) = prev {
196 if *receiver == filter_map_id {
197 let (_, source_map) = db.body_with_source_map(self.owner.into());
198 if let Ok(next_source_ptr) = source_map.expr_syntax(id) {
199 self.sink.push(ReplaceFilterMapNextWithFindMap {
200 file: next_source_ptr.file_id,
201 next_expr: next_source_ptr.value,
202 });
203 }
204 }
205 }
206 }
207 }
208 prev = None;
209 }
210 }
211
212 fn validate_call(&mut self, db: &dyn HirDatabase, call_id: ExprId, expr: &Expr) {
154 // Check that the number of arguments matches the number of parameters. 213 // Check that the number of arguments matches the number of parameters.
155 214
156 // FIXME: Due to shortcomings in the current type system implementation, only emit this 215 // FIXME: Due to shortcomings in the current type system implementation, only emit this
157 // diagnostic if there are no type mismatches in the containing function. 216 // diagnostic if there are no type mismatches in the containing function.
158 if self.infer.type_mismatches.iter().next().is_some() { 217 if self.infer.type_mismatches.iter().next().is_some() {
159 return None; 218 return;
160 } 219 }
161 220
162 let is_method_call = matches!(expr, Expr::MethodCall { .. }); 221 let is_method_call = matches!(expr, Expr::MethodCall { .. });
163 let (sig, args) = match expr { 222 let (sig, args) = match expr {
164 Expr::Call { callee, args } => { 223 Expr::Call { callee, args } => {
165 let callee = &self.infer.type_of_expr[*callee]; 224 let callee = &self.infer.type_of_expr[*callee];
166 let sig = callee.callable_sig(db)?; 225 let sig = match callee.callable_sig(db) {
226 Some(sig) => sig,
227 None => return,
228 };
167 (sig, args.clone()) 229 (sig, args.clone())
168 } 230 }
169 Expr::MethodCall { receiver, args, .. } => { 231 Expr::MethodCall { receiver, args, .. } => {
@@ -175,22 +237,25 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
175 // if the receiver is of unknown type, it's very likely we 237 // if the receiver is of unknown type, it's very likely we
176 // don't know enough to correctly resolve the method call. 238 // don't know enough to correctly resolve the method call.
177 // This is kind of a band-aid for #6975. 239 // This is kind of a band-aid for #6975.
178 return None; 240 return;
179 } 241 }
180 242
181 // FIXME: note that we erase information about substs here. This 243 // FIXME: note that we erase information about substs here. This
182 // is not right, but, luckily, doesn't matter as we care only 244 // is not right, but, luckily, doesn't matter as we care only
183 // about the number of params 245 // about the number of params
184 let callee = self.infer.method_resolution(call_id)?; 246 let callee = match self.infer.method_resolution(call_id) {
247 Some(callee) => callee,
248 None => return,
249 };
185 let sig = db.callable_item_signature(callee.into()).value; 250 let sig = db.callable_item_signature(callee.into()).value;
186 251
187 (sig, args) 252 (sig, args)
188 } 253 }
189 _ => return None, 254 _ => return,
190 }; 255 };
191 256
192 if sig.is_varargs { 257 if sig.is_varargs {
193 return None; 258 return;
194 } 259 }
195 260
196 let params = sig.params(); 261 let params = sig.params();
@@ -213,8 +278,6 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
213 }); 278 });
214 } 279 }
215 } 280 }
216
217 None
218 } 281 }
219 282
220 fn validate_match( 283 fn validate_match(
diff --git a/crates/hir_ty/src/test_db.rs b/crates/hir_ty/src/test_db.rs
index 09696fcf4..381b98ba8 100644
--- a/crates/hir_ty/src/test_db.rs
+++ b/crates/hir_ty/src/test_db.rs
@@ -83,7 +83,7 @@ impl TestDB {
83 let crate_def_map = self.crate_def_map(krate); 83 let crate_def_map = self.crate_def_map(krate);
84 for (local_id, data) in crate_def_map.modules() { 84 for (local_id, data) in crate_def_map.modules() {
85 if data.origin.file_id() == Some(file_id) { 85 if data.origin.file_id() == Some(file_id) {
86 return ModuleId::top_level(krate, local_id); 86 return crate_def_map.module_id(local_id);
87 } 87 }
88 } 88 }
89 } 89 }
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index b35bc2bae..8607139ba 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -136,6 +136,9 @@ pub(crate) fn diagnostics(
136 .on::<hir::diagnostics::IncorrectCase, _>(|d| { 136 .on::<hir::diagnostics::IncorrectCase, _>(|d| {
137 res.borrow_mut().push(warning_with_fix(d, &sema)); 137 res.borrow_mut().push(warning_with_fix(d, &sema));
138 }) 138 })
139 .on::<hir::diagnostics::ReplaceFilterMapNextWithFindMap, _>(|d| {
140 res.borrow_mut().push(warning_with_fix(d, &sema));
141 })
139 .on::<hir::diagnostics::InactiveCode, _>(|d| { 142 .on::<hir::diagnostics::InactiveCode, _>(|d| {
140 // If there's inactive code somewhere in a macro, don't propagate to the call-site. 143 // If there's inactive code somewhere in a macro, don't propagate to the call-site.
141 if d.display_source().file_id.expansion_info(db).is_some() { 144 if d.display_source().file_id.expansion_info(db).is_some() {
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index 579d5a308..cbfc66ab3 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -4,7 +4,7 @@ use hir::{
4 db::AstDatabase, 4 db::AstDatabase,
5 diagnostics::{ 5 diagnostics::{
6 Diagnostic, IncorrectCase, MissingFields, MissingOkOrSomeInTailExpr, NoSuchField, 6 Diagnostic, IncorrectCase, MissingFields, MissingOkOrSomeInTailExpr, NoSuchField,
7 RemoveThisSemicolon, UnresolvedModule, 7 RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, UnresolvedModule,
8 }, 8 },
9 HasSource, HirDisplay, InFile, Semantics, VariantDef, 9 HasSource, HirDisplay, InFile, Semantics, VariantDef,
10}; 10};
@@ -15,8 +15,8 @@ use ide_db::{
15}; 15};
16use syntax::{ 16use syntax::{
17 algo, 17 algo,
18 ast::{self, edit::IndentLevel, make}, 18 ast::{self, edit::IndentLevel, make, ArgListOwner},
19 AstNode, 19 AstNode, TextRange,
20}; 20};
21use text_edit::TextEdit; 21use text_edit::TextEdit;
22 22
@@ -144,6 +144,33 @@ impl DiagnosticWithFix for IncorrectCase {
144 } 144 }
145} 145}
146 146
147impl DiagnosticWithFix for ReplaceFilterMapNextWithFindMap {
148 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
149 let root = sema.db.parse_or_expand(self.file)?;
150 let next_expr = self.next_expr.to_node(&root);
151 let next_call = ast::MethodCallExpr::cast(next_expr.syntax().clone())?;
152
153 let filter_map_call = ast::MethodCallExpr::cast(next_call.receiver()?.syntax().clone())?;
154 let filter_map_name_range = filter_map_call.name_ref()?.ident_token()?.text_range();
155 let filter_map_args = filter_map_call.arg_list()?;
156
157 let range_to_replace =
158 TextRange::new(filter_map_name_range.start(), next_expr.syntax().text_range().end());
159 let replacement = format!("find_map{}", filter_map_args.syntax().text());
160 let trigger_range = next_expr.syntax().text_range();
161
162 let edit = TextEdit::replace(range_to_replace, replacement);
163
164 let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit);
165
166 Some(Fix::new(
167 "Replace filter_map(..).next() with find_map()",
168 source_change,
169 trigger_range,
170 ))
171 }
172}
173
147fn missing_record_expr_field_fix( 174fn missing_record_expr_field_fix(
148 sema: &Semantics<RootDatabase>, 175 sema: &Semantics<RootDatabase>,
149 usage_file_id: FileId, 176 usage_file_id: FileId,
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 16fa828ad..23d885218 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -173,6 +173,7 @@ impl ToNav for FileSymbol {
173 FileSymbolKind::Const => SymbolKind::Const, 173 FileSymbolKind::Const => SymbolKind::Const,
174 FileSymbolKind::Static => SymbolKind::Static, 174 FileSymbolKind::Static => SymbolKind::Static,
175 FileSymbolKind::Macro => SymbolKind::Macro, 175 FileSymbolKind::Macro => SymbolKind::Macro,
176 FileSymbolKind::Union => SymbolKind::Union,
176 }), 177 }),
177 full_range: self.range, 178 full_range: self.range,
178 focus_range: self.name_range, 179 focus_range: self.name_range,
@@ -434,13 +435,16 @@ impl TryToNav for hir::TypeParam {
434 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { 435 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
435 let src = self.source(db)?; 436 let src = self.source(db)?;
436 let full_range = match &src.value { 437 let full_range = match &src.value {
437 Either::Left(it) => it.syntax().text_range(), 438 Either::Left(it) => it
439 .name()
440 .map_or_else(|| it.syntax().text_range(), |name| name.syntax().text_range()),
438 Either::Right(it) => it.syntax().text_range(), 441 Either::Right(it) => it.syntax().text_range(),
439 }; 442 };
440 let focus_range = match &src.value { 443 let focus_range = match &src.value {
441 Either::Left(_) => None, 444 Either::Left(it) => it.name(),
442 Either::Right(it) => it.name().map(|it| it.syntax().text_range()), 445 Either::Right(it) => it.name(),
443 }; 446 }
447 .map(|it| it.syntax().text_range());
444 Some(NavigationTarget { 448 Some(NavigationTarget {
445 file_id: src.file_id.original_file(db), 449 file_id: src.file_id.original_file(db),
446 name: self.name(db).to_string().into(), 450 name: self.name(db).to_string().into(),
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 3a4f4d80b..40d9487eb 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -1098,4 +1098,20 @@ fn foo<const FOO$0: usize>() -> usize {
1098 "#]], 1098 "#]],
1099 ); 1099 );
1100 } 1100 }
1101
1102 #[test]
1103 fn test_find_self_ty_in_trait_def() {
1104 check(
1105 r#"
1106trait Foo {
1107 fn f() -> Self$0;
1108}
1109"#,
1110 expect![[r#"
1111 Self TypeParam FileId(0) 6..9 6..9 Other
1112
1113 FileId(0) 26..30 Other
1114 "#]],
1115 );
1116 }
1101} 1117}
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index e954bd72e..9ed9568ce 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -356,15 +356,16 @@ pub struct FileSymbol {
356 356
357#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] 357#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
358pub enum FileSymbolKind { 358pub enum FileSymbolKind {
359 Const,
360 Enum,
359 Function, 361 Function,
362 Macro,
363 Module,
364 Static,
360 Struct, 365 Struct,
361 Enum,
362 Trait, 366 Trait,
363 Module,
364 TypeAlias, 367 TypeAlias,
365 Const, 368 Union,
366 Static,
367 Macro,
368} 369}
369 370
370impl FileSymbolKind { 371impl FileSymbolKind {
@@ -375,6 +376,7 @@ impl FileSymbolKind {
375 | FileSymbolKind::Enum 376 | FileSymbolKind::Enum
376 | FileSymbolKind::Trait 377 | FileSymbolKind::Trait
377 | FileSymbolKind::TypeAlias 378 | FileSymbolKind::TypeAlias
379 | FileSymbolKind::Union
378 ) 380 )
379 } 381 }
380} 382}
@@ -425,6 +427,7 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
425 ast::Const(it) => decl(it), 427 ast::Const(it) => decl(it),
426 ast::Static(it) => decl(it), 428 ast::Static(it) => decl(it),
427 ast::MacroRules(it) => decl(it), 429 ast::MacroRules(it) => decl(it),
430 ast::Union(it) => decl(it),
428 _ => None, 431 _ => None,
429 } 432 }
430 } 433 }
@@ -443,6 +446,7 @@ fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
443 CONST => FileSymbolKind::Const, 446 CONST => FileSymbolKind::Const,
444 STATIC => FileSymbolKind::Static, 447 STATIC => FileSymbolKind::Static,
445 MACRO_RULES => FileSymbolKind::Macro, 448 MACRO_RULES => FileSymbolKind::Macro,
449 UNION => FileSymbolKind::Union,
446 kind => unreachable!("{:?}", kind), 450 kind => unreachable!("{:?}", kind),
447 }, 451 },
448 range: node.text_range(), 452 range: node.text_range(),
diff --git a/crates/parser/src/grammar/items/consts.rs b/crates/parser/src/grammar/items/consts.rs
index eb7d1f828..12130df40 100644
--- a/crates/parser/src/grammar/items/consts.rs
+++ b/crates/parser/src/grammar/items/consts.rs
@@ -13,7 +13,7 @@ pub(super) fn konst(p: &mut Parser, m: Marker) {
13fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) { 13fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) {
14 assert!(p.at(kw)); 14 assert!(p.at(kw));
15 p.bump(kw); 15 p.bump(kw);
16 p.eat(T![mut]); // FIXME: validator to forbid const mut 16 p.eat(T![mut]);
17 17
18 // Allow `_` in place of an identifier in a `const`. 18 // Allow `_` in place of an identifier in a `const`.
19 let is_const_underscore = kw == T![const] && p.eat(T![_]); 19 let is_const_underscore = kw == T![const] && p.eat(T![_]);
diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml
index cc7da27f7..4dd9acc98 100644
--- a/crates/profile/Cargo.toml
+++ b/crates/profile/Cargo.toml
@@ -14,7 +14,7 @@ once_cell = "1.3.1"
14cfg-if = "1" 14cfg-if = "1"
15libc = "0.2.73" 15libc = "0.2.73"
16la-arena = { version = "0.2.0", path = "../../lib/arena" } 16la-arena = { version = "0.2.0", path = "../../lib/arena" }
17countme = { version = "2.0.0-pre.2", features = ["enable"] } 17countme = { version = "2.0.0", features = ["enable"] }
18jemalloc-ctl = { version = "0.3.3", optional = true } 18jemalloc-ctl = { version = "0.3.3", optional = true }
19 19
20[target.'cfg(target_os = "linux")'.dependencies] 20[target.'cfg(target_os = "linux")'.dependencies]
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 3ddb9e19a..247bfe71e 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -147,6 +147,9 @@ config_data! {
147 /// Whether to show `Method References` lens. Only applies when 147 /// Whether to show `Method References` lens. Only applies when
148 /// `#rust-analyzer.lens.enable#` is set. 148 /// `#rust-analyzer.lens.enable#` is set.
149 lens_methodReferences: bool = "false", 149 lens_methodReferences: bool = "false",
150 /// Whether to show `References` lens. Only applies when
151 /// `#rust-analyzer.lens.enable#` is set.
152 lens_references: bool = "false",
150 153
151 /// Disable project auto-discovery in favor of explicitly specified set 154 /// Disable project auto-discovery in favor of explicitly specified set
152 /// of projects.\n\nElements must be paths pointing to `Cargo.toml`, 155 /// of projects.\n\nElements must be paths pointing to `Cargo.toml`,
@@ -221,6 +224,7 @@ pub struct LensConfig {
221 pub debug: bool, 224 pub debug: bool,
222 pub implementations: bool, 225 pub implementations: bool,
223 pub method_refs: bool, 226 pub method_refs: bool,
227 pub refs: bool, // for Struct, Enum, Union and Trait
224} 228}
225 229
226impl LensConfig { 230impl LensConfig {
@@ -237,7 +241,7 @@ impl LensConfig {
237 } 241 }
238 242
239 pub fn references(&self) -> bool { 243 pub fn references(&self) -> bool {
240 self.method_refs 244 self.method_refs || self.refs
241 } 245 }
242} 246}
243 247
@@ -593,6 +597,7 @@ impl Config {
593 debug: self.data.lens_enable && self.data.lens_debug, 597 debug: self.data.lens_enable && self.data.lens_debug,
594 implementations: self.data.lens_enable && self.data.lens_implementations, 598 implementations: self.data.lens_enable && self.data.lens_implementations,
595 method_refs: self.data.lens_enable && self.data.lens_methodReferences, 599 method_refs: self.data.lens_enable && self.data.lens_methodReferences,
600 refs: self.data.lens_enable && self.data.lens_references,
596 } 601 }
597 } 602 }
598 pub fn hover(&self) -> HoverConfig { 603 pub fn hover(&self) -> HoverConfig {
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 809452e6d..07204436c 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1112,42 +1112,48 @@ pub(crate) fn handle_code_lens(
1112 } 1112 }
1113 } 1113 }
1114 1114
1115 if lens_config.implementations { 1115 if lens_config.implementations || lens_config.refs {
1116 // Handle impls 1116 snap.analysis
1117 lenses.extend( 1117 .file_structure(file_id)?
1118 snap.analysis 1118 .into_iter()
1119 .file_structure(file_id)? 1119 .filter(|it| {
1120 .into_iter() 1120 matches!(
1121 .filter(|it| { 1121 it.kind,
1122 matches!( 1122 SymbolKind::Trait | SymbolKind::Struct | SymbolKind::Enum | SymbolKind::Union
1123 it.kind, 1123 )
1124 SymbolKind::Trait 1124 })
1125 | SymbolKind::Struct 1125 .for_each(|it| {
1126 | SymbolKind::Enum 1126 let range = to_proto::range(&line_index, it.node_range);
1127 | SymbolKind::Union 1127 let position = to_proto::position(&line_index, it.navigation_range.start());
1128 ) 1128 let doc_pos = lsp_types::TextDocumentPositionParams::new(
1129 }) 1129 params.text_document.clone(),
1130 .map(|it| { 1130 position,
1131 let range = to_proto::range(&line_index, it.node_range); 1131 );
1132 let pos = range.start; 1132 let goto_params = lsp_types::request::GotoImplementationParams {
1133 let lens_params = lsp_types::request::GotoImplementationParams { 1133 text_document_position_params: doc_pos.clone(),
1134 text_document_position_params: lsp_types::TextDocumentPositionParams::new( 1134 work_done_progress_params: Default::default(),
1135 params.text_document.clone(), 1135 partial_result_params: Default::default(),
1136 pos, 1136 };
1137 ), 1137
1138 work_done_progress_params: Default::default(), 1138 if lens_config.implementations {
1139 partial_result_params: Default::default(), 1139 lenses.push(CodeLens {
1140 };
1141 CodeLens {
1142 range, 1140 range,
1143 command: None, 1141 command: None,
1144 data: Some(to_value(CodeLensResolveData::Impls(lens_params)).unwrap()), 1142 data: Some(to_value(CodeLensResolveData::Impls(goto_params)).unwrap()),
1145 } 1143 })
1146 }), 1144 }
1147 ); 1145
1146 if lens_config.refs {
1147 lenses.push(CodeLens {
1148 range,
1149 command: None,
1150 data: Some(to_value(CodeLensResolveData::References(doc_pos)).unwrap()),
1151 })
1152 }
1153 });
1148 } 1154 }
1149 1155
1150 if lens_config.references() { 1156 if lens_config.method_refs {
1151 lenses.extend(snap.analysis.find_all_methods(file_id)?.into_iter().map(|it| { 1157 lenses.extend(snap.analysis.find_all_methods(file_id)?.into_iter().map(|it| {
1152 let range = to_proto::range(&line_index, it.range); 1158 let range = to_proto::range(&line_index, it.range);
1153 let position = to_proto::position(&line_index, it.range.start()); 1159 let position = to_proto::position(&line_index, it.range.start());
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 24298fbfa..e70fbba9c 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -12,7 +12,7 @@ doctest = false
12 12
13[dependencies] 13[dependencies]
14itertools = "0.10.0" 14itertools = "0.10.0"
15rowan = "0.12" 15rowan = "0.12.2"
16rustc_lexer = { version = "700.0.0", package = "rustc-ap-rustc_lexer" } 16rustc_lexer = { version = "700.0.0", package = "rustc-ap-rustc_lexer" }
17rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index 7694e8834..3e216fb70 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -1,4 +1,6 @@
1//! FIXME: write short doc here 1//! This module implements syntax validation that the parser doesn't handle.
2//!
3//! A failed validation emits a diagnostic.
2 4
3mod block; 5mod block;
4 6
@@ -92,6 +94,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
92 match_ast! { 94 match_ast! {
93 match node { 95 match node {
94 ast::Literal(it) => validate_literal(it, &mut errors), 96 ast::Literal(it) => validate_literal(it, &mut errors),
97 ast::Const(it) => validate_const(it, &mut errors),
95 ast::BlockExpr(it) => block::validate_block_expr(it, &mut errors), 98 ast::BlockExpr(it) => block::validate_block_expr(it, &mut errors),
96 ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), &mut errors), 99 ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), &mut errors),
97 ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), &mut errors), 100 ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), &mut errors),
@@ -362,3 +365,14 @@ fn validate_macro_rules(mac: ast::MacroRules, errors: &mut Vec<SyntaxError>) {
362 )); 365 ));
363 } 366 }
364} 367}
368
369fn validate_const(const_: ast::Const, errors: &mut Vec<SyntaxError>) {
370 if let Some(mut_token) = const_
371 .const_token()
372 .and_then(|t| t.next_token())
373 .and_then(|t| algo::skip_trivia_token(t, Direction::Next))
374 .filter(|t| t.kind() == T![mut])
375 {
376 errors.push(SyntaxError::new("const globals cannot be mutable", mut_token.text_range()));
377 }
378}
diff --git a/crates/syntax/test_data/parser/err/0047_mutable_const_item.rast b/crates/syntax/test_data/parser/err/0047_mutable_const_item.rast
new file mode 100644
index 000000000..c7eb312c9
--- /dev/null
+++ b/crates/syntax/test_data/parser/err/0047_mutable_const_item.rast
@@ -0,0 +1,22 @@
1[email protected]
2 [email protected]
3 [email protected] "const"
4 [email protected] " "
5 [email protected] "mut"
6 [email protected] " "
7 [email protected]
8 [email protected] "FOO"
9 [email protected] ":"
10 [email protected] " "
11 [email protected]
12 [email protected] "("
13 [email protected] ")"
14 [email protected] " "
15 [email protected] "="
16 [email protected] " "
17 [email protected]
18 [email protected] "("
19 [email protected] ")"
20 [email protected] ";"
21 [email protected] "\n"
22error 6..9: const globals cannot be mutable
diff --git a/crates/syntax/test_data/parser/err/0047_mutable_const_item.rs b/crates/syntax/test_data/parser/err/0047_mutable_const_item.rs
new file mode 100644
index 000000000..b34336f3f
--- /dev/null
+++ b/crates/syntax/test_data/parser/err/0047_mutable_const_item.rs
@@ -0,0 +1 @@
const mut FOO: () = ();
diff --git a/crates/syntax/test_data/parser/ok/0024_const_item.rast b/crates/syntax/test_data/parser/ok/0024_const_item.rast
index dd1b9c9a0..b89ed6f98 100644
--- a/crates/syntax/test_data/parser/ok/0024_const_item.rast
+++ b/crates/syntax/test_data/parser/ok/0024_const_item.rast
@@ -1,4 +1,4 @@
1SOURCE_FILE@0..64 1SOURCE_FILE@0..39
2 [email protected] 2 [email protected]
3 [email protected] "const" 3 [email protected] "const"
4 [email protected] " " 4 [email protected] " "
@@ -36,24 +36,3 @@ [email protected]
36 [email protected] "92" 36 [email protected] "92"
37 [email protected] ";" 37 [email protected] ";"
38 [email protected] "\n" 38 [email protected] "\n"
39 [email protected]
40 [email protected] "const"
41 [email protected] " "
42 [email protected] "mut"
43 [email protected] " "
44 [email protected]
45 [email protected] "BAR"
46 [email protected] ":"
47 [email protected] " "
48 [email protected]
49 [email protected]
50 [email protected]
51 [email protected]
52 [email protected] "u32"
53 [email protected] " "
54 [email protected] "="
55 [email protected] " "
56 [email protected]
57 [email protected] "62"
58 [email protected] ";"
59 [email protected] "\n"
diff --git a/crates/syntax/test_data/parser/ok/0024_const_item.rs b/crates/syntax/test_data/parser/ok/0024_const_item.rs
index a806a209d..1f2ffa0da 100644
--- a/crates/syntax/test_data/parser/ok/0024_const_item.rs
+++ b/crates/syntax/test_data/parser/ok/0024_const_item.rs
@@ -1,3 +1,2 @@
1const _: u32 = 0; 1const _: u32 = 0;
2const FOO: u32 = 92; 2const FOO: u32 = 92;
3const mut BAR: u32 = 62;
diff --git a/docs/dev/README.md b/docs/dev/README.md
index 24197b332..6bce38e56 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -43,6 +43,10 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0
43 while unactionable ones are effectively wont-fix. Each triaged issue should have one of these labels. 43 while unactionable ones are effectively wont-fix. Each triaged issue should have one of these labels.
44* [fun](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3Afun) 44* [fun](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3Afun)
45 is for cool, but probably hard stuff. 45 is for cool, but probably hard stuff.
46* [Design](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%Design)
47 is for moderate/large scale architecture discussion.
48 Also a kind of fun.
49 These issues should generally include a link to a Zulip discussion thread.
46 50
47# CI 51# CI
48 52
@@ -212,7 +216,7 @@ To log all communication between the server and the client, there are two choice
212 216
213* you can log on the server side, by running something like 217* you can log on the server side, by running something like
214 ``` 218 ```
215 env RA_LOG=gen_lsp_server=trace code . 219 env RA_LOG=lsp_server=debug code .
216 ``` 220 ```
217 221
218* you can log on the client side, by enabling `"rust-analyzer.trace.server": 222* you can log on the client side, by enabling `"rust-analyzer.trace.server":
diff --git a/docs/dev/style.md b/docs/dev/style.md
index 428cee3ad..6dc6868c2 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -294,8 +294,9 @@ Prefer `Default` even it has to be implemented manually.
294 294
295**Rationale:** less typing in the common case, uniformity. 295**Rationale:** less typing in the common case, uniformity.
296 296
297Use `Vec::new` rather than `vec![]`. **Rationale:** uniformity, strength 297Use `Vec::new` rather than `vec![]`.
298reduction. 298
299**Rationale:** uniformity, strength reduction.
299 300
300## Functions Over Objects 301## Functions Over Objects
301 302
@@ -479,7 +480,7 @@ pub fn reachable_nodes(node: Node) -> FxHashSet<Node> {
479} 480}
480``` 481```
481 482
482**Rational:** re-use allocations, accumulator style is more concise for complex cases. 483**Rationale:** re-use allocations, accumulator style is more concise for complex cases.
483 484
484# Style 485# Style
485 486
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index a76c99d1e..2f681b01a 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -86,6 +86,8 @@
86 Whether to show `Run` lens. Only applies when `#rust-analyzer.lens.enable#` is set. 86 Whether to show `Run` lens. Only applies when `#rust-analyzer.lens.enable#` is set.
87[[rust-analyzer.lens.methodReferences]]rust-analyzer.lens.methodReferences (default: `false`):: 87[[rust-analyzer.lens.methodReferences]]rust-analyzer.lens.methodReferences (default: `false`)::
88 Whether to show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set. 88 Whether to show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set.
89[[rust-analyzer.lens.references]]rust-analyzer.lens.references (default: `false`)::
90 Whether to show `References` lens. Only applies when `#rust-analyzer.lens.enable#` is set.
89[[rust-analyzer.linkedProjects]]rust-analyzer.linkedProjects (default: `[]`):: 91[[rust-analyzer.linkedProjects]]rust-analyzer.linkedProjects (default: `[]`)::
90 Disable project auto-discovery in favor of explicitly specified set of projects.\n\nElements must be paths pointing to `Cargo.toml`, `rust-project.json`, or JSON objects in `rust-project.json` format. 92 Disable project auto-discovery in favor of explicitly specified set of projects.\n\nElements must be paths pointing to `Cargo.toml`, `rust-project.json`, or JSON objects in `rust-project.json` format.
91[[rust-analyzer.lruCapacity]]rust-analyzer.lruCapacity (default: `null`):: 93[[rust-analyzer.lruCapacity]]rust-analyzer.lruCapacity (default: `null`)::
diff --git a/editors/code/package.json b/editors/code/package.json
index 3e6ebd7ed..2225cf1dd 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -633,6 +633,11 @@
633 "default": false, 633 "default": false,
634 "type": "boolean" 634 "type": "boolean"
635 }, 635 },
636 "rust-analyzer.lens.references": {
637 "markdownDescription": "Whether to show `References` lens. Only applies when `#rust-analyzer.lens.enable#` is set.",
638 "default": false,
639 "type": "boolean"
640 },
636 "rust-analyzer.linkedProjects": { 641 "rust-analyzer.linkedProjects": {
637 "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects.\\n\\nElements must be paths pointing to `Cargo.toml`, `rust-project.json`, or JSON objects in `rust-project.json` format.", 642 "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects.\\n\\nElements must be paths pointing to `Cargo.toml`, `rust-project.json`, or JSON objects in `rust-project.json` format.",
638 "default": [], 643 "default": [],
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index ebe4de1ea..ddb5cfbd3 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -144,6 +144,7 @@ export class Config {
144 debug: this.get<boolean>("lens.debug"), 144 debug: this.get<boolean>("lens.debug"),
145 implementations: this.get<boolean>("lens.implementations"), 145 implementations: this.get<boolean>("lens.implementations"),
146 methodReferences: this.get<boolean>("lens.methodReferences"), 146 methodReferences: this.get<boolean>("lens.methodReferences"),
147 references: this.get<boolean>("lens.references"),
147 }; 148 };
148 } 149 }
149 150
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 1edb7713d..1900d900a 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -208,7 +208,6 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
208 url: artifact.browser_download_url, 208 url: artifact.browser_download_url,
209 dest, 209 dest,
210 progressTitle: "Downloading rust-analyzer extension", 210 progressTitle: "Downloading rust-analyzer extension",
211 overwrite: true,
212 }); 211 });
213 }); 212 });
214 213
@@ -340,7 +339,6 @@ async function getServer(config: Config, state: PersistentState): Promise<string
340 progressTitle: "Downloading rust-analyzer server", 339 progressTitle: "Downloading rust-analyzer server",
341 gunzip: true, 340 gunzip: true,
342 mode: 0o755, 341 mode: 0o755,
343 overwrite: true,
344 }); 342 });
345 }); 343 });
346 344
diff --git a/editors/code/src/net.ts b/editors/code/src/net.ts
index 1ab21e726..d39dc1baf 100644
--- a/editors/code/src/net.ts
+++ b/editors/code/src/net.ts
@@ -73,23 +73,16 @@ interface DownloadOpts {
73 dest: string; 73 dest: string;
74 mode?: number; 74 mode?: number;
75 gunzip?: boolean; 75 gunzip?: boolean;
76 overwrite?: boolean;
77} 76}
78 77
79export async function download(opts: DownloadOpts) { 78export async function download(opts: DownloadOpts) {
80 // Put artifact into a temporary file (in the same dir for simplicity) 79 // Put artifact into a temporary file (in the same dir for simplicity)
81 // to prevent partially downloaded files when user kills vscode 80 // to prevent partially downloaded files when user kills vscode
81 // This also avoids overwriting running executables
82 const dest = path.parse(opts.dest); 82 const dest = path.parse(opts.dest);
83 const randomHex = crypto.randomBytes(5).toString("hex"); 83 const randomHex = crypto.randomBytes(5).toString("hex");
84 const tempFile = path.join(dest.dir, `${dest.name}${randomHex}`); 84 const tempFile = path.join(dest.dir, `${dest.name}${randomHex}`);
85 85
86 if (opts.overwrite) {
87 // Unlinking the exe file before moving new one on its place should prevent ETXTBSY error.
88 await fs.promises.unlink(opts.dest).catch(err => {
89 if (err.code !== "ENOENT") throw err;
90 });
91 }
92
93 await vscode.window.withProgress( 86 await vscode.window.withProgress(
94 { 87 {
95 location: vscode.ProgressLocation.Notification, 88 location: vscode.ProgressLocation.Notification,
@@ -99,13 +92,15 @@ export async function download(opts: DownloadOpts) {
99 async (progress, _cancellationToken) => { 92 async (progress, _cancellationToken) => {
100 let lastPercentage = 0; 93 let lastPercentage = 0;
101 await downloadFile(opts.url, tempFile, opts.mode, !!opts.gunzip, (readBytes, totalBytes) => { 94 await downloadFile(opts.url, tempFile, opts.mode, !!opts.gunzip, (readBytes, totalBytes) => {
102 const newPercentage = (readBytes / totalBytes) * 100; 95 const newPercentage = Math.round((readBytes / totalBytes) * 100);
103 progress.report({ 96 if (newPercentage !== lastPercentage) {
104 message: newPercentage.toFixed(0) + "%", 97 progress.report({
105 increment: newPercentage - lastPercentage 98 message: `${newPercentage.toFixed(0)}%`,
106 }); 99 increment: newPercentage - lastPercentage
107 100 });
108 lastPercentage = newPercentage; 101
102 lastPercentage = newPercentage;
103 }
109 }); 104 });
110 } 105 }
111 ); 106 );