diff options
author | Seivan Heidari <[email protected]> | 2019-12-23 14:35:31 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-12-23 14:35:31 +0000 |
commit | b21d9337d9200e2cfdc90b386591c72c302dc03e (patch) | |
tree | f81f5c08f821115cee26fa4d3ceaae88c7807fd5 /crates/ra_hir_def/src | |
parent | 18a0937585b836ec5ed054b9ae48e0156ab6d9ef (diff) | |
parent | ce07a2daa9e53aa86a769f8641b14c2878444fbc (diff) |
Merge branch 'master' into feature/themes
Diffstat (limited to 'crates/ra_hir_def/src')
35 files changed, 2419 insertions, 1514 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index 3666529b0..d9ea693e3 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs | |||
@@ -2,17 +2,18 @@ | |||
2 | 2 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use either::Either; | ||
5 | use hir_expand::{ | 6 | use hir_expand::{ |
6 | either::Either, | ||
7 | name::{AsName, Name}, | 7 | name::{AsName, Name}, |
8 | Source, | 8 | InFile, |
9 | }; | 9 | }; |
10 | use ra_arena::{map::ArenaMap, Arena}; | 10 | use ra_arena::{map::ArenaMap, Arena}; |
11 | use ra_prof::profile; | ||
11 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; | 12 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; |
12 | 13 | ||
13 | use crate::{ | 14 | use crate::{ |
14 | db::DefDatabase, trace::Trace, type_ref::TypeRef, AstItemDef, EnumId, HasChildSource, | 15 | db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, type_ref::TypeRef, EnumId, |
15 | LocalEnumVariantId, LocalStructFieldId, StructId, UnionId, VariantId, | 16 | LocalEnumVariantId, LocalStructFieldId, Lookup, StructId, UnionId, VariantId, |
16 | }; | 17 | }; |
17 | 18 | ||
18 | /// Note that we use `StructData` for unions as well! | 19 | /// Note that we use `StructData` for unions as well! |
@@ -50,14 +51,14 @@ pub struct StructFieldData { | |||
50 | 51 | ||
51 | impl StructData { | 52 | impl StructData { |
52 | pub(crate) fn struct_data_query(db: &impl DefDatabase, id: StructId) -> Arc<StructData> { | 53 | pub(crate) fn struct_data_query(db: &impl DefDatabase, id: StructId) -> Arc<StructData> { |
53 | let src = id.source(db); | 54 | let src = id.lookup(db).source(db); |
54 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 55 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); |
55 | let variant_data = VariantData::new(src.value.kind()); | 56 | let variant_data = VariantData::new(src.value.kind()); |
56 | let variant_data = Arc::new(variant_data); | 57 | let variant_data = Arc::new(variant_data); |
57 | Arc::new(StructData { name, variant_data }) | 58 | Arc::new(StructData { name, variant_data }) |
58 | } | 59 | } |
59 | pub(crate) fn union_data_query(db: &impl DefDatabase, id: UnionId) -> Arc<StructData> { | 60 | pub(crate) fn union_data_query(db: &impl DefDatabase, id: UnionId) -> Arc<StructData> { |
60 | let src = id.source(db); | 61 | let src = id.lookup(db).source(db); |
61 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 62 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); |
62 | let variant_data = VariantData::new( | 63 | let variant_data = VariantData::new( |
63 | src.value | 64 | src.value |
@@ -72,7 +73,8 @@ impl StructData { | |||
72 | 73 | ||
73 | impl EnumData { | 74 | impl EnumData { |
74 | pub(crate) fn enum_data_query(db: &impl DefDatabase, e: EnumId) -> Arc<EnumData> { | 75 | pub(crate) fn enum_data_query(db: &impl DefDatabase, e: EnumId) -> Arc<EnumData> { |
75 | let src = e.source(db); | 76 | let _p = profile("enum_data_query"); |
77 | let src = e.lookup(db).source(db); | ||
76 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 78 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); |
77 | let mut trace = Trace::new_for_arena(); | 79 | let mut trace = Trace::new_for_arena(); |
78 | lower_enum(&mut trace, &src.value); | 80 | lower_enum(&mut trace, &src.value); |
@@ -88,8 +90,8 @@ impl EnumData { | |||
88 | impl HasChildSource for EnumId { | 90 | impl HasChildSource for EnumId { |
89 | type ChildId = LocalEnumVariantId; | 91 | type ChildId = LocalEnumVariantId; |
90 | type Value = ast::EnumVariant; | 92 | type Value = ast::EnumVariant; |
91 | fn child_source(&self, db: &impl DefDatabase) -> Source<ArenaMap<Self::ChildId, Self::Value>> { | 93 | fn child_source(&self, db: &impl DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { |
92 | let src = self.source(db); | 94 | let src = self.lookup(db).source(db); |
93 | let mut trace = Trace::new_for_map(); | 95 | let mut trace = Trace::new_for_map(); |
94 | lower_enum(&mut trace, &src.value); | 96 | lower_enum(&mut trace, &src.value); |
95 | src.with_value(trace.into_map()) | 97 | src.with_value(trace.into_map()) |
@@ -145,7 +147,7 @@ impl HasChildSource for VariantId { | |||
145 | type ChildId = LocalStructFieldId; | 147 | type ChildId = LocalStructFieldId; |
146 | type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>; | 148 | type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>; |
147 | 149 | ||
148 | fn child_source(&self, db: &impl DefDatabase) -> Source<ArenaMap<Self::ChildId, Self::Value>> { | 150 | fn child_source(&self, db: &impl DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { |
149 | let src = match self { | 151 | let src = match self { |
150 | VariantId::EnumVariantId(it) => { | 152 | VariantId::EnumVariantId(it) => { |
151 | // I don't really like the fact that we call into parent source | 153 | // I don't really like the fact that we call into parent source |
@@ -153,8 +155,8 @@ impl HasChildSource for VariantId { | |||
153 | let src = it.parent.child_source(db); | 155 | let src = it.parent.child_source(db); |
154 | src.map(|map| map[it.local_id].kind()) | 156 | src.map(|map| map[it.local_id].kind()) |
155 | } | 157 | } |
156 | VariantId::StructId(it) => it.source(db).map(|it| it.kind()), | 158 | VariantId::StructId(it) => it.lookup(db).source(db).map(|it| it.kind()), |
157 | VariantId::UnionId(it) => it.source(db).map(|it| { | 159 | VariantId::UnionId(it) => it.lookup(db).source(db).map(|it| { |
158 | it.record_field_def_list() | 160 | it.record_field_def_list() |
159 | .map(ast::StructKind::Record) | 161 | .map(ast::StructKind::Record) |
160 | .unwrap_or(ast::StructKind::Unit) | 162 | .unwrap_or(ast::StructKind::Unit) |
@@ -184,7 +186,7 @@ fn lower_struct( | |||
184 | ast::StructKind::Tuple(fl) => { | 186 | ast::StructKind::Tuple(fl) => { |
185 | for (i, fd) in fl.fields().enumerate() { | 187 | for (i, fd) in fl.fields().enumerate() { |
186 | trace.alloc( | 188 | trace.alloc( |
187 | || Either::A(fd.clone()), | 189 | || Either::Left(fd.clone()), |
188 | || StructFieldData { | 190 | || StructFieldData { |
189 | name: Name::new_tuple_field(i), | 191 | name: Name::new_tuple_field(i), |
190 | type_ref: TypeRef::from_ast_opt(fd.type_ref()), | 192 | type_ref: TypeRef::from_ast_opt(fd.type_ref()), |
@@ -196,7 +198,7 @@ fn lower_struct( | |||
196 | ast::StructKind::Record(fl) => { | 198 | ast::StructKind::Record(fl) => { |
197 | for fd in fl.fields() { | 199 | for fd in fl.fields() { |
198 | trace.alloc( | 200 | trace.alloc( |
199 | || Either::B(fd.clone()), | 201 | || Either::Right(fd.clone()), |
200 | || StructFieldData { | 202 | || StructFieldData { |
201 | name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), | 203 | name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), |
202 | type_ref: TypeRef::from_ast_opt(fd.ascribed_type()), | 204 | type_ref: TypeRef::from_ast_opt(fd.ascribed_type()), |
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index fffb22201..9efa4970c 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs | |||
@@ -2,7 +2,8 @@ | |||
2 | 2 | ||
3 | use std::{ops, sync::Arc}; | 3 | use std::{ops, sync::Arc}; |
4 | 4 | ||
5 | use hir_expand::{either::Either, hygiene::Hygiene, AstId, Source}; | 5 | use either::Either; |
6 | use hir_expand::{hygiene::Hygiene, AstId, InFile}; | ||
6 | use mbe::ast_to_token_tree; | 7 | use mbe::ast_to_token_tree; |
7 | use ra_syntax::{ | 8 | use ra_syntax::{ |
8 | ast::{self, AstNode, AttrsOwner}, | 9 | ast::{self, AstNode, AttrsOwner}, |
@@ -11,7 +12,7 @@ use ra_syntax::{ | |||
11 | use tt::Subtree; | 12 | use tt::Subtree; |
12 | 13 | ||
13 | use crate::{ | 14 | use crate::{ |
14 | db::DefDatabase, path::Path, AdtId, AstItemDef, AttrDefId, HasChildSource, HasSource, Lookup, | 15 | db::DefDatabase, path::ModPath, src::HasChildSource, src::HasSource, AdtId, AttrDefId, Lookup, |
15 | }; | 16 | }; |
16 | 17 | ||
17 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | 18 | #[derive(Default, Debug, Clone, PartialEq, Eq)] |
@@ -44,8 +45,8 @@ impl Attrs { | |||
44 | AttrDefId::StructFieldId(it) => { | 45 | AttrDefId::StructFieldId(it) => { |
45 | let src = it.parent.child_source(db); | 46 | let src = it.parent.child_source(db); |
46 | match &src.value[it.local_id] { | 47 | match &src.value[it.local_id] { |
47 | Either::A(_tuple) => Attrs::default(), | 48 | Either::Left(_tuple) => Attrs::default(), |
48 | Either::B(record) => Attrs::from_attrs_owner(db, src.with_value(record)), | 49 | Either::Right(record) => Attrs::from_attrs_owner(db, src.with_value(record)), |
49 | } | 50 | } |
50 | } | 51 | } |
51 | AttrDefId::EnumVariantId(var_id) => { | 52 | AttrDefId::EnumVariantId(var_id) => { |
@@ -54,13 +55,15 @@ impl Attrs { | |||
54 | Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) | 55 | Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) |
55 | } | 56 | } |
56 | AttrDefId::AdtId(it) => match it { | 57 | AttrDefId::AdtId(it) => match it { |
57 | AdtId::StructId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), | 58 | AdtId::StructId(it) => attrs_from_loc(it.lookup(db), db), |
58 | AdtId::EnumId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), | 59 | AdtId::EnumId(it) => attrs_from_loc(it.lookup(db), db), |
59 | AdtId::UnionId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), | 60 | AdtId::UnionId(it) => attrs_from_loc(it.lookup(db), db), |
60 | }, | 61 | }, |
61 | AttrDefId::TraitId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), | 62 | AttrDefId::TraitId(it) => attrs_from_loc(it.lookup(db), db), |
62 | AttrDefId::MacroDefId(it) => attrs_from_ast(it.ast_id, db), | 63 | AttrDefId::MacroDefId(it) => { |
63 | AttrDefId::ImplId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), | 64 | it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) |
65 | } | ||
66 | AttrDefId::ImplId(it) => attrs_from_loc(it.lookup(db), db), | ||
64 | AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), | 67 | AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), |
65 | AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db), | 68 | AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db), |
66 | AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db), | 69 | AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db), |
@@ -68,7 +71,7 @@ impl Attrs { | |||
68 | } | 71 | } |
69 | } | 72 | } |
70 | 73 | ||
71 | fn from_attrs_owner(db: &impl DefDatabase, owner: Source<&dyn AttrsOwner>) -> Attrs { | 74 | fn from_attrs_owner(db: &impl DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs { |
72 | let hygiene = Hygiene::new(db, owner.file_id); | 75 | let hygiene = Hygiene::new(db, owner.file_id); |
73 | Attrs::new(owner.value, &hygiene) | 76 | Attrs::new(owner.value, &hygiene) |
74 | } | 77 | } |
@@ -91,7 +94,7 @@ impl Attrs { | |||
91 | 94 | ||
92 | #[derive(Debug, Clone, PartialEq, Eq)] | 95 | #[derive(Debug, Clone, PartialEq, Eq)] |
93 | pub struct Attr { | 96 | pub struct Attr { |
94 | pub(crate) path: Path, | 97 | pub(crate) path: ModPath, |
95 | pub(crate) input: Option<AttrInput>, | 98 | pub(crate) input: Option<AttrInput>, |
96 | } | 99 | } |
97 | 100 | ||
@@ -103,7 +106,7 @@ pub enum AttrInput { | |||
103 | 106 | ||
104 | impl Attr { | 107 | impl Attr { |
105 | fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { | 108 | fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { |
106 | let path = Path::from_src(ast.path()?, hygiene)?; | 109 | let path = ModPath::from_src(ast.path()?, hygiene)?; |
107 | let input = match ast.input() { | 110 | let input = match ast.input() { |
108 | None => None, | 111 | None => None, |
109 | Some(ast::AttrInput::Literal(lit)) => { | 112 | Some(ast::AttrInput::Literal(lit)) => { |
@@ -157,7 +160,7 @@ where | |||
157 | N: ast::AttrsOwner, | 160 | N: ast::AttrsOwner, |
158 | D: DefDatabase, | 161 | D: DefDatabase, |
159 | { | 162 | { |
160 | let src = Source::new(src.file_id(), src.to_node(db)); | 163 | let src = InFile::new(src.file_id, src.to_node(db)); |
161 | Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) | 164 | Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) |
162 | } | 165 | } |
163 | 166 | ||
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index a57a0176d..d3e4c50ae 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -3,58 +3,75 @@ | |||
3 | mod lower; | 3 | mod lower; |
4 | pub mod scope; | 4 | pub mod scope; |
5 | 5 | ||
6 | use std::{ops::Index, sync::Arc}; | 6 | use std::{mem, ops::Index, sync::Arc}; |
7 | 7 | ||
8 | use drop_bomb::DropBomb; | ||
9 | use either::Either; | ||
8 | use hir_expand::{ | 10 | use hir_expand::{ |
9 | either::Either, hygiene::Hygiene, AstId, HirFileId, MacroDefId, MacroFileKind, Source, | 11 | ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroCallKind, MacroDefId, |
10 | }; | 12 | }; |
11 | use ra_arena::{map::ArenaMap, Arena}; | 13 | use ra_arena::{map::ArenaMap, Arena}; |
14 | use ra_prof::profile; | ||
12 | use ra_syntax::{ast, AstNode, AstPtr}; | 15 | use ra_syntax::{ast, AstNode, AstPtr}; |
13 | use rustc_hash::FxHashMap; | 16 | use rustc_hash::FxHashMap; |
14 | 17 | ||
15 | use crate::{ | 18 | use crate::{ |
16 | db::DefDatabase, | 19 | db::DefDatabase, |
17 | expr::{Expr, ExprId, Pat, PatId}, | 20 | expr::{Expr, ExprId, Pat, PatId}, |
21 | item_scope::BuiltinShadowMode, | ||
22 | item_scope::ItemScope, | ||
18 | nameres::CrateDefMap, | 23 | nameres::CrateDefMap, |
19 | path::Path, | 24 | path::{ModPath, Path}, |
20 | DefWithBodyId, HasModule, HasSource, Lookup, ModuleId, | 25 | src::HasSource, |
26 | DefWithBodyId, HasModule, Lookup, ModuleId, | ||
21 | }; | 27 | }; |
22 | 28 | ||
23 | struct Expander { | 29 | pub(crate) struct Expander { |
24 | crate_def_map: Arc<CrateDefMap>, | 30 | crate_def_map: Arc<CrateDefMap>, |
25 | current_file_id: HirFileId, | 31 | current_file_id: HirFileId, |
26 | hygiene: Hygiene, | 32 | hygiene: Hygiene, |
33 | ast_id_map: Arc<AstIdMap>, | ||
27 | module: ModuleId, | 34 | module: ModuleId, |
28 | } | 35 | } |
29 | 36 | ||
30 | impl Expander { | 37 | impl Expander { |
31 | fn new(db: &impl DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander { | 38 | pub(crate) fn new( |
39 | db: &impl DefDatabase, | ||
40 | current_file_id: HirFileId, | ||
41 | module: ModuleId, | ||
42 | ) -> Expander { | ||
32 | let crate_def_map = db.crate_def_map(module.krate); | 43 | let crate_def_map = db.crate_def_map(module.krate); |
33 | let hygiene = Hygiene::new(db, current_file_id); | 44 | let hygiene = Hygiene::new(db, current_file_id); |
34 | Expander { crate_def_map, current_file_id, hygiene, module } | 45 | let ast_id_map = db.ast_id_map(current_file_id); |
46 | Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module } | ||
35 | } | 47 | } |
36 | 48 | ||
37 | fn enter_expand( | 49 | pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>( |
38 | &mut self, | 50 | &mut self, |
39 | db: &impl DefDatabase, | 51 | db: &DB, |
40 | macro_call: ast::MacroCall, | 52 | macro_call: ast::MacroCall, |
41 | ) -> Option<(Mark, ast::Expr)> { | 53 | ) -> Option<(Mark, T)> { |
42 | let ast_id = AstId::new( | 54 | let ast_id = AstId::new( |
43 | self.current_file_id, | 55 | self.current_file_id, |
44 | db.ast_id_map(self.current_file_id).ast_id(¯o_call), | 56 | db.ast_id_map(self.current_file_id).ast_id(¯o_call), |
45 | ); | 57 | ); |
46 | 58 | ||
47 | if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) { | 59 | if let Some(path) = macro_call.path().and_then(|path| self.parse_mod_path(path)) { |
48 | if let Some(def) = self.resolve_path_as_macro(db, &path) { | 60 | if let Some(def) = self.resolve_path_as_macro(db, &path) { |
49 | let call_id = def.as_call_id(db, ast_id); | 61 | let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id)); |
50 | let file_id = call_id.as_file(MacroFileKind::Expr); | 62 | let file_id = call_id.as_file(); |
51 | if let Some(node) = db.parse_or_expand(file_id) { | 63 | if let Some(node) = db.parse_or_expand(file_id) { |
52 | if let Some(expr) = ast::Expr::cast(node) { | 64 | if let Some(expr) = T::cast(node) { |
53 | log::debug!("macro expansion {:#?}", expr.syntax()); | 65 | log::debug!("macro expansion {:#?}", expr.syntax()); |
54 | 66 | ||
55 | let mark = Mark { file_id: self.current_file_id }; | 67 | let mark = Mark { |
68 | file_id: self.current_file_id, | ||
69 | ast_id_map: mem::take(&mut self.ast_id_map), | ||
70 | bomb: DropBomb::new("expansion mark dropped"), | ||
71 | }; | ||
56 | self.hygiene = Hygiene::new(db, file_id); | 72 | self.hygiene = Hygiene::new(db, file_id); |
57 | self.current_file_id = file_id; | 73 | self.current_file_id = file_id; |
74 | self.ast_id_map = db.ast_id_map(file_id); | ||
58 | 75 | ||
59 | return Some((mark, expr)); | 76 | return Some((mark, expr)); |
60 | } | 77 | } |
@@ -67,37 +84,44 @@ impl Expander { | |||
67 | None | 84 | None |
68 | } | 85 | } |
69 | 86 | ||
70 | fn exit(&mut self, db: &impl DefDatabase, mark: Mark) { | 87 | pub(crate) fn exit(&mut self, db: &impl DefDatabase, mut mark: Mark) { |
71 | self.hygiene = Hygiene::new(db, mark.file_id); | 88 | self.hygiene = Hygiene::new(db, mark.file_id); |
72 | self.current_file_id = mark.file_id; | 89 | self.current_file_id = mark.file_id; |
73 | std::mem::forget(mark); | 90 | self.ast_id_map = mem::take(&mut mark.ast_id_map); |
91 | mark.bomb.defuse(); | ||
74 | } | 92 | } |
75 | 93 | ||
76 | fn to_source<T>(&self, value: T) -> Source<T> { | 94 | pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> { |
77 | Source { file_id: self.current_file_id, value } | 95 | InFile { file_id: self.current_file_id, value } |
78 | } | 96 | } |
79 | 97 | ||
80 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { | 98 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { |
81 | Path::from_src(path, &self.hygiene) | 99 | Path::from_src(path, &self.hygiene) |
82 | } | 100 | } |
83 | 101 | ||
84 | fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> { | 102 | fn parse_mod_path(&mut self, path: ast::Path) -> Option<ModPath> { |
85 | self.crate_def_map.resolve_path(db, self.module.local_id, path).0.take_macros() | 103 | ModPath::from_src(path, &self.hygiene) |
86 | } | 104 | } |
87 | } | ||
88 | 105 | ||
89 | struct Mark { | 106 | fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &ModPath) -> Option<MacroDefId> { |
90 | file_id: HirFileId, | 107 | self.crate_def_map |
91 | } | 108 | .resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other) |
109 | .0 | ||
110 | .take_macros() | ||
111 | } | ||
92 | 112 | ||
93 | impl Drop for Mark { | 113 | fn ast_id<N: AstNode>(&self, item: &N) -> AstId<N> { |
94 | fn drop(&mut self) { | 114 | let file_local_id = self.ast_id_map.ast_id(item); |
95 | if !std::thread::panicking() { | 115 | AstId::new(self.current_file_id, file_local_id) |
96 | panic!("dropped mark") | ||
97 | } | ||
98 | } | 116 | } |
99 | } | 117 | } |
100 | 118 | ||
119 | pub(crate) struct Mark { | ||
120 | file_id: HirFileId, | ||
121 | ast_id_map: Arc<AstIdMap>, | ||
122 | bomb: DropBomb, | ||
123 | } | ||
124 | |||
101 | /// The body of an item (function, const etc.). | 125 | /// The body of an item (function, const etc.). |
102 | #[derive(Debug, Eq, PartialEq)] | 126 | #[derive(Debug, Eq, PartialEq)] |
103 | pub struct Body { | 127 | pub struct Body { |
@@ -112,13 +136,14 @@ pub struct Body { | |||
112 | pub params: Vec<PatId>, | 136 | pub params: Vec<PatId>, |
113 | /// The `ExprId` of the actual body expression. | 137 | /// The `ExprId` of the actual body expression. |
114 | pub body_expr: ExprId, | 138 | pub body_expr: ExprId, |
139 | pub item_scope: ItemScope, | ||
115 | } | 140 | } |
116 | 141 | ||
117 | pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; | 142 | pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; |
118 | pub type ExprSource = Source<ExprPtr>; | 143 | pub type ExprSource = InFile<ExprPtr>; |
119 | 144 | ||
120 | pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | 145 | pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; |
121 | pub type PatSource = Source<PatPtr>; | 146 | pub type PatSource = InFile<PatPtr>; |
122 | 147 | ||
123 | /// An item body together with the mapping from syntax nodes to HIR expression | 148 | /// An item body together with the mapping from syntax nodes to HIR expression |
124 | /// IDs. This is needed to go from e.g. a position in a file to the HIR | 149 | /// IDs. This is needed to go from e.g. a position in a file to the HIR |
@@ -145,6 +170,7 @@ impl Body { | |||
145 | db: &impl DefDatabase, | 170 | db: &impl DefDatabase, |
146 | def: DefWithBodyId, | 171 | def: DefWithBodyId, |
147 | ) -> (Arc<Body>, Arc<BodySourceMap>) { | 172 | ) -> (Arc<Body>, Arc<BodySourceMap>) { |
173 | let _p = profile("body_with_source_map_query"); | ||
148 | let mut params = None; | 174 | let mut params = None; |
149 | 175 | ||
150 | let (file_id, module, body) = match def { | 176 | let (file_id, module, body) = match def { |
@@ -166,7 +192,7 @@ impl Body { | |||
166 | } | 192 | } |
167 | }; | 193 | }; |
168 | let expander = Expander::new(db, file_id, module); | 194 | let expander = Expander::new(db, file_id, module); |
169 | let (body, source_map) = Body::new(db, expander, params, body); | 195 | let (body, source_map) = Body::new(db, def, expander, params, body); |
170 | (Arc::new(body), Arc::new(source_map)) | 196 | (Arc::new(body), Arc::new(source_map)) |
171 | } | 197 | } |
172 | 198 | ||
@@ -176,11 +202,12 @@ impl Body { | |||
176 | 202 | ||
177 | fn new( | 203 | fn new( |
178 | db: &impl DefDatabase, | 204 | db: &impl DefDatabase, |
205 | def: DefWithBodyId, | ||
179 | expander: Expander, | 206 | expander: Expander, |
180 | params: Option<ast::ParamList>, | 207 | params: Option<ast::ParamList>, |
181 | body: Option<ast::Expr>, | 208 | body: Option<ast::Expr>, |
182 | ) -> (Body, BodySourceMap) { | 209 | ) -> (Body, BodySourceMap) { |
183 | lower::lower(db, expander, params, body) | 210 | lower::lower(db, def, expander, params, body) |
184 | } | 211 | } |
185 | } | 212 | } |
186 | 213 | ||
@@ -205,8 +232,13 @@ impl BodySourceMap { | |||
205 | self.expr_map_back.get(expr).copied() | 232 | self.expr_map_back.get(expr).copied() |
206 | } | 233 | } |
207 | 234 | ||
208 | pub fn node_expr(&self, node: Source<&ast::Expr>) -> Option<ExprId> { | 235 | pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> { |
209 | let src = node.map(|it| Either::A(AstPtr::new(it))); | 236 | let src = node.map(|it| Either::Left(AstPtr::new(it))); |
237 | self.expr_map.get(&src).cloned() | ||
238 | } | ||
239 | |||
240 | pub fn field_init_shorthand_expr(&self, node: InFile<&ast::RecordField>) -> Option<ExprId> { | ||
241 | let src = node.map(|it| Either::Right(AstPtr::new(it))); | ||
210 | self.expr_map.get(&src).cloned() | 242 | self.expr_map.get(&src).cloned() |
211 | } | 243 | } |
212 | 244 | ||
@@ -214,8 +246,8 @@ impl BodySourceMap { | |||
214 | self.pat_map_back.get(pat).copied() | 246 | self.pat_map_back.get(pat).copied() |
215 | } | 247 | } |
216 | 248 | ||
217 | pub fn node_pat(&self, node: Source<&ast::Pat>) -> Option<PatId> { | 249 | pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> { |
218 | let src = node.map(|it| Either::A(AstPtr::new(it))); | 250 | let src = node.map(|it| Either::Left(AstPtr::new(it))); |
219 | self.pat_map.get(&src).cloned() | 251 | self.pat_map.get(&src).cloned() |
220 | } | 252 | } |
221 | 253 | ||
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 331736cb2..5323af097 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -1,14 +1,13 @@ | |||
1 | //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` | 1 | //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` |
2 | //! representation. | 2 | //! representation. |
3 | 3 | ||
4 | use hir_expand::{ | 4 | use either::Either; |
5 | either::Either, | 5 | |
6 | name::{self, AsName, Name}, | 6 | use hir_expand::name::{name, AsName, Name}; |
7 | }; | ||
8 | use ra_arena::Arena; | 7 | use ra_arena::Arena; |
9 | use ra_syntax::{ | 8 | use ra_syntax::{ |
10 | ast::{ | 9 | ast::{ |
11 | self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner, | 10 | self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner, |
12 | TypeAscriptionOwner, | 11 | TypeAscriptionOwner, |
13 | }, | 12 | }, |
14 | AstNode, AstPtr, | 13 | AstNode, AstPtr, |
@@ -26,23 +25,28 @@ use crate::{ | |||
26 | path::GenericArgs, | 25 | path::GenericArgs, |
27 | path::Path, | 26 | path::Path, |
28 | type_ref::{Mutability, TypeRef}, | 27 | type_ref::{Mutability, TypeRef}, |
28 | ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, StaticLoc, | ||
29 | StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, | ||
29 | }; | 30 | }; |
30 | 31 | ||
31 | pub(super) fn lower( | 32 | pub(super) fn lower( |
32 | db: &impl DefDatabase, | 33 | db: &impl DefDatabase, |
34 | def: DefWithBodyId, | ||
33 | expander: Expander, | 35 | expander: Expander, |
34 | params: Option<ast::ParamList>, | 36 | params: Option<ast::ParamList>, |
35 | body: Option<ast::Expr>, | 37 | body: Option<ast::Expr>, |
36 | ) -> (Body, BodySourceMap) { | 38 | ) -> (Body, BodySourceMap) { |
37 | ExprCollector { | 39 | ExprCollector { |
38 | expander, | ||
39 | db, | 40 | db, |
41 | def, | ||
42 | expander, | ||
40 | source_map: BodySourceMap::default(), | 43 | source_map: BodySourceMap::default(), |
41 | body: Body { | 44 | body: Body { |
42 | exprs: Arena::default(), | 45 | exprs: Arena::default(), |
43 | pats: Arena::default(), | 46 | pats: Arena::default(), |
44 | params: Vec::new(), | 47 | params: Vec::new(), |
45 | body_expr: ExprId::dummy(), | 48 | body_expr: ExprId::dummy(), |
49 | item_scope: Default::default(), | ||
46 | }, | 50 | }, |
47 | } | 51 | } |
48 | .collect(params, body) | 52 | .collect(params, body) |
@@ -50,6 +54,7 @@ pub(super) fn lower( | |||
50 | 54 | ||
51 | struct ExprCollector<DB> { | 55 | struct ExprCollector<DB> { |
52 | db: DB, | 56 | db: DB, |
57 | def: DefWithBodyId, | ||
53 | expander: Expander, | 58 | expander: Expander, |
54 | 59 | ||
55 | body: Body, | 60 | body: Body, |
@@ -70,11 +75,11 @@ where | |||
70 | let ptr = AstPtr::new(&self_param); | 75 | let ptr = AstPtr::new(&self_param); |
71 | let param_pat = self.alloc_pat( | 76 | let param_pat = self.alloc_pat( |
72 | Pat::Bind { | 77 | Pat::Bind { |
73 | name: name::SELF_PARAM, | 78 | name: name![self], |
74 | mode: BindingAnnotation::Unannotated, | 79 | mode: BindingAnnotation::Unannotated, |
75 | subpat: None, | 80 | subpat: None, |
76 | }, | 81 | }, |
77 | Either::B(ptr), | 82 | Either::Right(ptr), |
78 | ); | 83 | ); |
79 | self.body.params.push(param_pat); | 84 | self.body.params.push(param_pat); |
80 | } | 85 | } |
@@ -94,7 +99,7 @@ where | |||
94 | } | 99 | } |
95 | 100 | ||
96 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { | 101 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { |
97 | let ptr = Either::A(ptr); | 102 | let ptr = Either::Left(ptr); |
98 | let id = self.body.exprs.alloc(expr); | 103 | let id = self.body.exprs.alloc(expr); |
99 | let src = self.expander.to_source(ptr); | 104 | let src = self.expander.to_source(ptr); |
100 | self.source_map.expr_map.insert(src, id); | 105 | self.source_map.expr_map.insert(src, id); |
@@ -107,7 +112,7 @@ where | |||
107 | self.body.exprs.alloc(expr) | 112 | self.body.exprs.alloc(expr) |
108 | } | 113 | } |
109 | fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { | 114 | fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { |
110 | let ptr = Either::B(ptr); | 115 | let ptr = Either::Right(ptr); |
111 | let id = self.body.exprs.alloc(expr); | 116 | let id = self.body.exprs.alloc(expr); |
112 | let src = self.expander.to_source(ptr); | 117 | let src = self.expander.to_source(ptr); |
113 | self.source_map.expr_map.insert(src, id); | 118 | self.source_map.expr_map.insert(src, id); |
@@ -277,7 +282,7 @@ where | |||
277 | ast::Expr::ParenExpr(e) => { | 282 | ast::Expr::ParenExpr(e) => { |
278 | let inner = self.collect_expr_opt(e.expr()); | 283 | let inner = self.collect_expr_opt(e.expr()); |
279 | // make the paren expr point to the inner expression as well | 284 | // make the paren expr point to the inner expression as well |
280 | let src = self.expander.to_source(Either::A(syntax_ptr)); | 285 | let src = self.expander.to_source(Either::Left(syntax_ptr)); |
281 | self.source_map.expr_map.insert(src, inner); | 286 | self.source_map.expr_map.insert(src, inner); |
282 | inner | 287 | inner |
283 | } | 288 | } |
@@ -367,8 +372,9 @@ where | |||
367 | arg_types.push(type_ref); | 372 | arg_types.push(type_ref); |
368 | } | 373 | } |
369 | } | 374 | } |
375 | let ret_type = e.ret_type().and_then(|r| r.type_ref()).map(TypeRef::from_ast); | ||
370 | let body = self.collect_expr_opt(e.body()); | 376 | let body = self.collect_expr_opt(e.body()); |
371 | self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr) | 377 | self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) |
372 | } | 378 | } |
373 | ast::Expr::BinExpr(e) => { | 379 | ast::Expr::BinExpr(e) => { |
374 | let lhs = self.collect_expr_opt(e.lhs()); | 380 | let lhs = self.collect_expr_opt(e.lhs()); |
@@ -429,10 +435,17 @@ where | |||
429 | let index = self.collect_expr_opt(e.index()); | 435 | let index = self.collect_expr_opt(e.index()); |
430 | self.alloc_expr(Expr::Index { base, index }, syntax_ptr) | 436 | self.alloc_expr(Expr::Index { base, index }, syntax_ptr) |
431 | } | 437 | } |
432 | 438 | ast::Expr::RangeExpr(e) => { | |
433 | // FIXME implement HIR for these: | 439 | let lhs = e.start().map(|lhs| self.collect_expr(lhs)); |
434 | ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | 440 | let rhs = e.end().map(|rhs| self.collect_expr(rhs)); |
435 | ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | 441 | match e.op_kind() { |
442 | Some(range_type) => { | ||
443 | self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr) | ||
444 | } | ||
445 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
446 | } | ||
447 | } | ||
448 | // FIXME expand to statements in statement position | ||
436 | ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) { | 449 | ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) { |
437 | Some((mark, expansion)) => { | 450 | Some((mark, expansion)) => { |
438 | let id = self.collect_expr(expansion); | 451 | let id = self.collect_expr(expansion); |
@@ -441,6 +454,9 @@ where | |||
441 | } | 454 | } |
442 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | 455 | None => self.alloc_expr(Expr::Missing, syntax_ptr), |
443 | }, | 456 | }, |
457 | |||
458 | // FIXME implement HIR for these: | ||
459 | ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
444 | } | 460 | } |
445 | } | 461 | } |
446 | 462 | ||
@@ -458,6 +474,7 @@ where | |||
458 | Some(block) => block, | 474 | Some(block) => block, |
459 | None => return self.alloc_expr(Expr::Missing, syntax_node_ptr), | 475 | None => return self.alloc_expr(Expr::Missing, syntax_node_ptr), |
460 | }; | 476 | }; |
477 | self.collect_block_items(&block); | ||
461 | let statements = block | 478 | let statements = block |
462 | .statements() | 479 | .statements() |
463 | .map(|s| match s { | 480 | .map(|s| match s { |
@@ -474,6 +491,63 @@ where | |||
474 | self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr) | 491 | self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr) |
475 | } | 492 | } |
476 | 493 | ||
494 | fn collect_block_items(&mut self, block: &ast::Block) { | ||
495 | let container = ContainerId::DefWithBodyId(self.def); | ||
496 | for item in block.items() { | ||
497 | let (def, name): (ModuleDefId, Option<ast::Name>) = match item { | ||
498 | ast::ModuleItem::FnDef(def) => { | ||
499 | let ast_id = self.expander.ast_id(&def); | ||
500 | ( | ||
501 | FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(), | ||
502 | def.name(), | ||
503 | ) | ||
504 | } | ||
505 | ast::ModuleItem::TypeAliasDef(def) => { | ||
506 | let ast_id = self.expander.ast_id(&def); | ||
507 | ( | ||
508 | TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(), | ||
509 | def.name(), | ||
510 | ) | ||
511 | } | ||
512 | ast::ModuleItem::ConstDef(def) => { | ||
513 | let ast_id = self.expander.ast_id(&def); | ||
514 | ( | ||
515 | ConstLoc { container: container.into(), ast_id }.intern(self.db).into(), | ||
516 | def.name(), | ||
517 | ) | ||
518 | } | ||
519 | ast::ModuleItem::StaticDef(def) => { | ||
520 | let ast_id = self.expander.ast_id(&def); | ||
521 | (StaticLoc { container, ast_id }.intern(self.db).into(), def.name()) | ||
522 | } | ||
523 | ast::ModuleItem::StructDef(def) => { | ||
524 | let ast_id = self.expander.ast_id(&def); | ||
525 | (StructLoc { container, ast_id }.intern(self.db).into(), def.name()) | ||
526 | } | ||
527 | ast::ModuleItem::EnumDef(def) => { | ||
528 | let ast_id = self.expander.ast_id(&def); | ||
529 | (EnumLoc { container, ast_id }.intern(self.db).into(), def.name()) | ||
530 | } | ||
531 | ast::ModuleItem::UnionDef(def) => { | ||
532 | let ast_id = self.expander.ast_id(&def); | ||
533 | (UnionLoc { container, ast_id }.intern(self.db).into(), def.name()) | ||
534 | } | ||
535 | ast::ModuleItem::TraitDef(def) => { | ||
536 | let ast_id = self.expander.ast_id(&def); | ||
537 | (TraitLoc { container, ast_id }.intern(self.db).into(), def.name()) | ||
538 | } | ||
539 | ast::ModuleItem::ImplBlock(_) | ||
540 | | ast::ModuleItem::UseItem(_) | ||
541 | | ast::ModuleItem::ExternCrateItem(_) | ||
542 | | ast::ModuleItem::Module(_) => continue, | ||
543 | }; | ||
544 | self.body.item_scope.define_def(def); | ||
545 | if let Some(name) = name { | ||
546 | self.body.item_scope.push_res(name.as_name(), def.into()); | ||
547 | } | ||
548 | } | ||
549 | } | ||
550 | |||
477 | fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId { | 551 | fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId { |
478 | if let Some(block) = expr { | 552 | if let Some(block) = expr { |
479 | self.collect_block(block) | 553 | self.collect_block(block) |
@@ -541,7 +615,7 @@ where | |||
541 | ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing, | 615 | ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing, |
542 | }; | 616 | }; |
543 | let ptr = AstPtr::new(&pat); | 617 | let ptr = AstPtr::new(&pat); |
544 | self.alloc_pat(pattern, Either::A(ptr)) | 618 | self.alloc_pat(pattern, Either::Left(ptr)) |
545 | } | 619 | } |
546 | 620 | ||
547 | fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId { | 621 | fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId { |
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs index 625aa39dd..a63552327 100644 --- a/crates/ra_hir_def/src/body/scope.rs +++ b/crates/ra_hir_def/src/body/scope.rs | |||
@@ -171,7 +171,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope | |||
171 | 171 | ||
172 | #[cfg(test)] | 172 | #[cfg(test)] |
173 | mod tests { | 173 | mod tests { |
174 | use hir_expand::{name::AsName, Source}; | 174 | use hir_expand::{name::AsName, InFile}; |
175 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase}; | 175 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase}; |
176 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; | 176 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; |
177 | use test_utils::{assert_eq_text, covers, extract_offset}; | 177 | use test_utils::{assert_eq_text, covers, extract_offset}; |
@@ -183,8 +183,8 @@ mod tests { | |||
183 | let crate_def_map = db.crate_def_map(krate); | 183 | let crate_def_map = db.crate_def_map(krate); |
184 | 184 | ||
185 | let module = crate_def_map.modules_for_file(file_id).next().unwrap(); | 185 | let module = crate_def_map.modules_for_file(file_id).next().unwrap(); |
186 | let (_, res) = crate_def_map[module].scope.entries().next().unwrap(); | 186 | let (_, def) = crate_def_map[module].scope.entries().next().unwrap(); |
187 | match res.def.take_values().unwrap() { | 187 | match def.take_values().unwrap() { |
188 | ModuleDefId::FunctionId(it) => it, | 188 | ModuleDefId::FunctionId(it) => it, |
189 | _ => panic!(), | 189 | _ => panic!(), |
190 | } | 190 | } |
@@ -211,7 +211,7 @@ mod tests { | |||
211 | let (_body, source_map) = db.body_with_source_map(function.into()); | 211 | let (_body, source_map) = db.body_with_source_map(function.into()); |
212 | 212 | ||
213 | let expr_id = source_map | 213 | let expr_id = source_map |
214 | .node_expr(Source { file_id: file_id.into(), value: &marker.into() }) | 214 | .node_expr(InFile { file_id: file_id.into(), value: &marker.into() }) |
215 | .unwrap(); | 215 | .unwrap(); |
216 | let scope = scopes.scope_for(expr_id); | 216 | let scope = scopes.scope_for(expr_id); |
217 | 217 | ||
@@ -318,7 +318,7 @@ mod tests { | |||
318 | let expr_scope = { | 318 | let expr_scope = { |
319 | let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap(); | 319 | let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap(); |
320 | let expr_id = | 320 | let expr_id = |
321 | source_map.node_expr(Source { file_id: file_id.into(), value: &expr_ast }).unwrap(); | 321 | source_map.node_expr(InFile { file_id: file_id.into(), value: &expr_ast }).unwrap(); |
322 | scopes.scope_for(expr_id).unwrap() | 322 | scopes.scope_for(expr_id).unwrap() |
323 | }; | 323 | }; |
324 | 324 | ||
diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs index 5e8157144..d14901a9b 100644 --- a/crates/ra_hir_def/src/builtin_type.rs +++ b/crates/ra_hir_def/src/builtin_type.rs | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | use std::fmt; | 6 | use std::fmt; |
7 | 7 | ||
8 | use hir_expand::name::{self, Name}; | 8 | use hir_expand::name::{name, Name}; |
9 | 9 | ||
10 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | 10 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] |
11 | pub enum Signedness { | 11 | pub enum Signedness { |
@@ -52,26 +52,26 @@ pub enum BuiltinType { | |||
52 | impl BuiltinType { | 52 | impl BuiltinType { |
53 | #[rustfmt::skip] | 53 | #[rustfmt::skip] |
54 | pub const ALL: &'static [(Name, BuiltinType)] = &[ | 54 | pub const ALL: &'static [(Name, BuiltinType)] = &[ |
55 | (name::CHAR, BuiltinType::Char), | 55 | (name![char], BuiltinType::Char), |
56 | (name::BOOL, BuiltinType::Bool), | 56 | (name![bool], BuiltinType::Bool), |
57 | (name::STR, BuiltinType::Str ), | 57 | (name![str], BuiltinType::Str), |
58 | 58 | ||
59 | (name::ISIZE, BuiltinType::Int(BuiltinInt::ISIZE)), | 59 | (name![isize], BuiltinType::Int(BuiltinInt::ISIZE)), |
60 | (name::I8, BuiltinType::Int(BuiltinInt::I8)), | 60 | (name![i8], BuiltinType::Int(BuiltinInt::I8)), |
61 | (name::I16, BuiltinType::Int(BuiltinInt::I16)), | 61 | (name![i16], BuiltinType::Int(BuiltinInt::I16)), |
62 | (name::I32, BuiltinType::Int(BuiltinInt::I32)), | 62 | (name![i32], BuiltinType::Int(BuiltinInt::I32)), |
63 | (name::I64, BuiltinType::Int(BuiltinInt::I64)), | 63 | (name![i64], BuiltinType::Int(BuiltinInt::I64)), |
64 | (name::I128, BuiltinType::Int(BuiltinInt::I128)), | 64 | (name![i128], BuiltinType::Int(BuiltinInt::I128)), |
65 | 65 | ||
66 | (name::USIZE, BuiltinType::Int(BuiltinInt::USIZE)), | 66 | (name![usize], BuiltinType::Int(BuiltinInt::USIZE)), |
67 | (name::U8, BuiltinType::Int(BuiltinInt::U8)), | 67 | (name![u8], BuiltinType::Int(BuiltinInt::U8)), |
68 | (name::U16, BuiltinType::Int(BuiltinInt::U16)), | 68 | (name![u16], BuiltinType::Int(BuiltinInt::U16)), |
69 | (name::U32, BuiltinType::Int(BuiltinInt::U32)), | 69 | (name![u32], BuiltinType::Int(BuiltinInt::U32)), |
70 | (name::U64, BuiltinType::Int(BuiltinInt::U64)), | 70 | (name![u64], BuiltinType::Int(BuiltinInt::U64)), |
71 | (name::U128, BuiltinType::Int(BuiltinInt::U128)), | 71 | (name![u128], BuiltinType::Int(BuiltinInt::U128)), |
72 | 72 | ||
73 | (name::F32, BuiltinType::Float(BuiltinFloat::F32)), | 73 | (name![f32], BuiltinType::Float(BuiltinFloat::F32)), |
74 | (name::F64, BuiltinType::Float(BuiltinFloat::F64)), | 74 | (name![f64], BuiltinType::Float(BuiltinFloat::F64)), |
75 | ]; | 75 | ]; |
76 | } | 76 | } |
77 | 77 | ||
diff --git a/crates/ra_hir_def/src/child_by_source.rs b/crates/ra_hir_def/src/child_by_source.rs new file mode 100644 index 000000000..8b6c773ee --- /dev/null +++ b/crates/ra_hir_def/src/child_by_source.rs | |||
@@ -0,0 +1,177 @@ | |||
1 | //! When *constructing* `hir`, we start at some parent syntax node and recursively | ||
2 | //! lower the children. | ||
3 | //! | ||
4 | //! This modules allows one to go in the opposite direction: start with a syntax | ||
5 | //! node for a *child*, and get its hir. | ||
6 | |||
7 | use either::Either; | ||
8 | |||
9 | use crate::{ | ||
10 | db::DefDatabase, | ||
11 | dyn_map::DynMap, | ||
12 | item_scope::ItemScope, | ||
13 | keys, | ||
14 | src::{HasChildSource, HasSource}, | ||
15 | AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, ImplId, Lookup, ModuleDefId, | ||
16 | ModuleId, StructFieldId, TraitId, VariantId, | ||
17 | }; | ||
18 | |||
19 | pub trait ChildBySource { | ||
20 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap; | ||
21 | } | ||
22 | |||
23 | impl ChildBySource for TraitId { | ||
24 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { | ||
25 | let mut res = DynMap::default(); | ||
26 | |||
27 | let data = db.trait_data(*self); | ||
28 | for (_name, item) in data.items.iter() { | ||
29 | match *item { | ||
30 | AssocItemId::FunctionId(func) => { | ||
31 | let src = func.lookup(db).source(db); | ||
32 | res[keys::FUNCTION].insert(src, func) | ||
33 | } | ||
34 | AssocItemId::ConstId(konst) => { | ||
35 | let src = konst.lookup(db).source(db); | ||
36 | res[keys::CONST].insert(src, konst) | ||
37 | } | ||
38 | AssocItemId::TypeAliasId(ty) => { | ||
39 | let src = ty.lookup(db).source(db); | ||
40 | res[keys::TYPE_ALIAS].insert(src, ty) | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | |||
45 | res | ||
46 | } | ||
47 | } | ||
48 | |||
49 | impl ChildBySource for ImplId { | ||
50 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { | ||
51 | let mut res = DynMap::default(); | ||
52 | |||
53 | let data = db.impl_data(*self); | ||
54 | for &item in data.items.iter() { | ||
55 | match item { | ||
56 | AssocItemId::FunctionId(func) => { | ||
57 | let src = func.lookup(db).source(db); | ||
58 | res[keys::FUNCTION].insert(src, func) | ||
59 | } | ||
60 | AssocItemId::ConstId(konst) => { | ||
61 | let src = konst.lookup(db).source(db); | ||
62 | res[keys::CONST].insert(src, konst) | ||
63 | } | ||
64 | AssocItemId::TypeAliasId(ty) => { | ||
65 | let src = ty.lookup(db).source(db); | ||
66 | res[keys::TYPE_ALIAS].insert(src, ty) | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | |||
71 | res | ||
72 | } | ||
73 | } | ||
74 | |||
75 | impl ChildBySource for ModuleId { | ||
76 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { | ||
77 | let crate_def_map = db.crate_def_map(self.krate); | ||
78 | let module_data = &crate_def_map[self.local_id]; | ||
79 | module_data.scope.child_by_source(db) | ||
80 | } | ||
81 | } | ||
82 | |||
83 | impl ChildBySource for ItemScope { | ||
84 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { | ||
85 | let mut res = DynMap::default(); | ||
86 | self.declarations().for_each(|item| add_module_def(db, &mut res, item)); | ||
87 | self.impls().for_each(|imp| add_impl(db, &mut res, imp)); | ||
88 | return res; | ||
89 | |||
90 | fn add_module_def(db: &impl DefDatabase, map: &mut DynMap, item: ModuleDefId) { | ||
91 | match item { | ||
92 | ModuleDefId::FunctionId(func) => { | ||
93 | let src = func.lookup(db).source(db); | ||
94 | map[keys::FUNCTION].insert(src, func) | ||
95 | } | ||
96 | ModuleDefId::ConstId(konst) => { | ||
97 | let src = konst.lookup(db).source(db); | ||
98 | map[keys::CONST].insert(src, konst) | ||
99 | } | ||
100 | ModuleDefId::StaticId(statik) => { | ||
101 | let src = statik.lookup(db).source(db); | ||
102 | map[keys::STATIC].insert(src, statik) | ||
103 | } | ||
104 | ModuleDefId::TypeAliasId(ty) => { | ||
105 | let src = ty.lookup(db).source(db); | ||
106 | map[keys::TYPE_ALIAS].insert(src, ty) | ||
107 | } | ||
108 | ModuleDefId::TraitId(trait_) => { | ||
109 | let src = trait_.lookup(db).source(db); | ||
110 | map[keys::TRAIT].insert(src, trait_) | ||
111 | } | ||
112 | ModuleDefId::AdtId(adt) => match adt { | ||
113 | AdtId::StructId(strukt) => { | ||
114 | let src = strukt.lookup(db).source(db); | ||
115 | map[keys::STRUCT].insert(src, strukt) | ||
116 | } | ||
117 | AdtId::UnionId(union_) => { | ||
118 | let src = union_.lookup(db).source(db); | ||
119 | map[keys::UNION].insert(src, union_) | ||
120 | } | ||
121 | AdtId::EnumId(enum_) => { | ||
122 | let src = enum_.lookup(db).source(db); | ||
123 | map[keys::ENUM].insert(src, enum_) | ||
124 | } | ||
125 | }, | ||
126 | _ => (), | ||
127 | } | ||
128 | } | ||
129 | fn add_impl(db: &impl DefDatabase, map: &mut DynMap, imp: ImplId) { | ||
130 | let src = imp.lookup(db).source(db); | ||
131 | map[keys::IMPL].insert(src, imp) | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | impl ChildBySource for VariantId { | ||
137 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { | ||
138 | let mut res = DynMap::default(); | ||
139 | |||
140 | let arena_map = self.child_source(db); | ||
141 | let arena_map = arena_map.as_ref(); | ||
142 | for (local_id, source) in arena_map.value.iter() { | ||
143 | let id = StructFieldId { parent: *self, local_id }; | ||
144 | match source { | ||
145 | Either::Left(source) => { | ||
146 | res[keys::TUPLE_FIELD].insert(arena_map.with_value(source.clone()), id) | ||
147 | } | ||
148 | Either::Right(source) => { | ||
149 | res[keys::RECORD_FIELD].insert(arena_map.with_value(source.clone()), id) | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | res | ||
154 | } | ||
155 | } | ||
156 | |||
157 | impl ChildBySource for EnumId { | ||
158 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { | ||
159 | let mut res = DynMap::default(); | ||
160 | |||
161 | let arena_map = self.child_source(db); | ||
162 | let arena_map = arena_map.as_ref(); | ||
163 | for (local_id, source) in arena_map.value.iter() { | ||
164 | let id = EnumVariantId { parent: *self, local_id }; | ||
165 | res[keys::ENUM_VARIANT].insert(arena_map.with_value(source.clone()), id) | ||
166 | } | ||
167 | |||
168 | res | ||
169 | } | ||
170 | } | ||
171 | |||
172 | impl ChildBySource for DefWithBodyId { | ||
173 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { | ||
174 | let body = db.body(*self); | ||
175 | body.item_scope.child_by_source(db) | ||
176 | } | ||
177 | } | ||
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index fee10b237..1aa9a9b7d 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -3,16 +3,17 @@ | |||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_expand::{ | 5 | use hir_expand::{ |
6 | name::{self, AsName, Name}, | 6 | name::{name, AsName, Name}, |
7 | AstId, | 7 | AstId, InFile, |
8 | }; | 8 | }; |
9 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; | 9 | use ra_syntax::ast::{self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner}; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | db::DefDatabase, | 12 | db::DefDatabase, |
13 | src::HasSource, | ||
13 | type_ref::{Mutability, TypeRef}, | 14 | type_ref::{Mutability, TypeRef}, |
14 | AssocItemId, AstItemDef, ConstId, ConstLoc, ContainerId, FunctionId, FunctionLoc, HasSource, | 15 | AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, |
15 | ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | 16 | ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, |
16 | }; | 17 | }; |
17 | 18 | ||
18 | #[derive(Debug, Clone, PartialEq, Eq)] | 19 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -36,7 +37,7 @@ impl FunctionData { | |||
36 | let self_type = if let Some(type_ref) = self_param.ascribed_type() { | 37 | let self_type = if let Some(type_ref) = self_param.ascribed_type() { |
37 | TypeRef::from_ast(type_ref) | 38 | TypeRef::from_ast(type_ref) |
38 | } else { | 39 | } else { |
39 | let self_type = TypeRef::Path(name::SELF_TYPE.into()); | 40 | let self_type = TypeRef::Path(name![Self].into()); |
40 | match self_param.kind() { | 41 | match self_param.kind() { |
41 | ast::SelfParamKind::Owned => self_type, | 42 | ast::SelfParamKind::Owned => self_type, |
42 | ast::SelfParamKind::Ref => { | 43 | ast::SelfParamKind::Ref => { |
@@ -93,12 +94,12 @@ pub struct TraitData { | |||
93 | 94 | ||
94 | impl TraitData { | 95 | impl TraitData { |
95 | pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: TraitId) -> Arc<TraitData> { | 96 | pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: TraitId) -> Arc<TraitData> { |
96 | let src = tr.source(db); | 97 | let src = tr.lookup(db).source(db); |
97 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 98 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); |
98 | let auto = src.value.is_auto(); | 99 | let auto = src.value.is_auto(); |
99 | let ast_id_map = db.ast_id_map(src.file_id); | 100 | let ast_id_map = db.ast_id_map(src.file_id); |
100 | 101 | ||
101 | let container = ContainerId::TraitId(tr); | 102 | let container = AssocContainerId::TraitId(tr); |
102 | let items = if let Some(item_list) = src.value.item_list() { | 103 | let items = if let Some(item_list) = src.value.item_list() { |
103 | item_list | 104 | item_list |
104 | .impl_items() | 105 | .impl_items() |
@@ -166,46 +167,24 @@ pub struct ImplData { | |||
166 | 167 | ||
167 | impl ImplData { | 168 | impl ImplData { |
168 | pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc<ImplData> { | 169 | pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc<ImplData> { |
169 | let src = id.source(db); | 170 | let impl_loc = id.lookup(db); |
170 | let items = db.ast_id_map(src.file_id); | 171 | let src = impl_loc.source(db); |
171 | 172 | ||
172 | let target_trait = src.value.target_trait().map(TypeRef::from_ast); | 173 | let target_trait = src.value.target_trait().map(TypeRef::from_ast); |
173 | let target_type = TypeRef::from_ast_opt(src.value.target_type()); | 174 | let target_type = TypeRef::from_ast_opt(src.value.target_type()); |
174 | let is_negative = src.value.is_negative(); | 175 | let is_negative = src.value.is_negative(); |
176 | let module_id = impl_loc.container.module(db); | ||
175 | 177 | ||
176 | let items = if let Some(item_list) = src.value.item_list() { | 178 | let mut items = Vec::new(); |
177 | item_list | 179 | if let Some(item_list) = src.value.item_list() { |
178 | .impl_items() | 180 | items.extend(collect_impl_items(db, item_list.impl_items(), src.file_id, id)); |
179 | .map(|item_node| match item_node { | 181 | items.extend(collect_impl_items_in_macros( |
180 | ast::ImplItem::FnDef(it) => { | 182 | db, |
181 | let def = FunctionLoc { | 183 | module_id, |
182 | container: ContainerId::ImplId(id), | 184 | &src.with_value(item_list), |
183 | ast_id: AstId::new(src.file_id, items.ast_id(&it)), | 185 | id, |
184 | } | 186 | )); |
185 | .intern(db); | 187 | } |
186 | def.into() | ||
187 | } | ||
188 | ast::ImplItem::ConstDef(it) => { | ||
189 | let def = ConstLoc { | ||
190 | container: ContainerId::ImplId(id), | ||
191 | ast_id: AstId::new(src.file_id, items.ast_id(&it)), | ||
192 | } | ||
193 | .intern(db); | ||
194 | def.into() | ||
195 | } | ||
196 | ast::ImplItem::TypeAliasDef(it) => { | ||
197 | let def = TypeAliasLoc { | ||
198 | container: ContainerId::ImplId(id), | ||
199 | ast_id: AstId::new(src.file_id, items.ast_id(&it)), | ||
200 | } | ||
201 | .intern(db); | ||
202 | def.into() | ||
203 | } | ||
204 | }) | ||
205 | .collect() | ||
206 | } else { | ||
207 | Vec::new() | ||
208 | }; | ||
209 | 188 | ||
210 | let res = ImplData { target_trait, target_type, items, is_negative }; | 189 | let res = ImplData { target_trait, target_type, items, is_negative }; |
211 | Arc::new(res) | 190 | Arc::new(res) |
@@ -236,3 +215,92 @@ impl ConstData { | |||
236 | ConstData { name, type_ref } | 215 | ConstData { name, type_ref } |
237 | } | 216 | } |
238 | } | 217 | } |
218 | |||
219 | fn collect_impl_items_in_macros( | ||
220 | db: &impl DefDatabase, | ||
221 | module_id: ModuleId, | ||
222 | impl_block: &InFile<ast::ItemList>, | ||
223 | id: ImplId, | ||
224 | ) -> Vec<AssocItemId> { | ||
225 | let mut expander = Expander::new(db, impl_block.file_id, module_id); | ||
226 | let mut res = Vec::new(); | ||
227 | |||
228 | // We set a limit to protect against infinite recursion | ||
229 | let limit = 100; | ||
230 | |||
231 | for m in impl_block.value.syntax().children().filter_map(ast::MacroCall::cast) { | ||
232 | res.extend(collect_impl_items_in_macro(db, &mut expander, m, id, limit)) | ||
233 | } | ||
234 | |||
235 | res | ||
236 | } | ||
237 | |||
238 | fn collect_impl_items_in_macro( | ||
239 | db: &impl DefDatabase, | ||
240 | expander: &mut Expander, | ||
241 | m: ast::MacroCall, | ||
242 | id: ImplId, | ||
243 | limit: usize, | ||
244 | ) -> Vec<AssocItemId> { | ||
245 | if limit == 0 { | ||
246 | return Vec::new(); | ||
247 | } | ||
248 | |||
249 | if let Some((mark, items)) = expander.enter_expand(db, m) { | ||
250 | let items: InFile<ast::MacroItems> = expander.to_source(items); | ||
251 | let mut res = collect_impl_items( | ||
252 | db, | ||
253 | items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())), | ||
254 | items.file_id, | ||
255 | id, | ||
256 | ); | ||
257 | // Recursive collect macros | ||
258 | // Note that ast::ModuleItem do not include ast::MacroCall | ||
259 | // We cannot use ModuleItemOwner::items here | ||
260 | for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) { | ||
261 | res.extend(collect_impl_items_in_macro(db, expander, it, id, limit - 1)) | ||
262 | } | ||
263 | expander.exit(db, mark); | ||
264 | res | ||
265 | } else { | ||
266 | Vec::new() | ||
267 | } | ||
268 | } | ||
269 | |||
270 | fn collect_impl_items( | ||
271 | db: &impl DefDatabase, | ||
272 | impl_items: impl Iterator<Item = ImplItem>, | ||
273 | file_id: crate::HirFileId, | ||
274 | id: ImplId, | ||
275 | ) -> Vec<AssocItemId> { | ||
276 | let items = db.ast_id_map(file_id); | ||
277 | |||
278 | impl_items | ||
279 | .map(|item_node| match item_node { | ||
280 | ast::ImplItem::FnDef(it) => { | ||
281 | let def = FunctionLoc { | ||
282 | container: AssocContainerId::ImplId(id), | ||
283 | ast_id: AstId::new(file_id, items.ast_id(&it)), | ||
284 | } | ||
285 | .intern(db); | ||
286 | def.into() | ||
287 | } | ||
288 | ast::ImplItem::ConstDef(it) => { | ||
289 | let def = ConstLoc { | ||
290 | container: AssocContainerId::ImplId(id), | ||
291 | ast_id: AstId::new(file_id, items.ast_id(&it)), | ||
292 | } | ||
293 | .intern(db); | ||
294 | def.into() | ||
295 | } | ||
296 | ast::ImplItem::TypeAliasDef(it) => { | ||
297 | let def = TypeAliasLoc { | ||
298 | container: AssocContainerId::ImplId(id), | ||
299 | ast_id: AstId::new(file_id, items.ast_id(&it)), | ||
300 | } | ||
301 | .intern(db); | ||
302 | def.into() | ||
303 | } | ||
304 | }) | ||
305 | .collect() | ||
306 | } | ||
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index ef5611ffc..c55fd4111 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs | |||
@@ -3,7 +3,7 @@ use std::sync::Arc; | |||
3 | 3 | ||
4 | use hir_expand::{db::AstDatabase, HirFileId}; | 4 | use hir_expand::{db::AstDatabase, HirFileId}; |
5 | use ra_db::{salsa, CrateId, SourceDatabase}; | 5 | use ra_db::{salsa, CrateId, SourceDatabase}; |
6 | use ra_syntax::{ast, SmolStr}; | 6 | use ra_syntax::SmolStr; |
7 | 7 | ||
8 | use crate::{ | 8 | use crate::{ |
9 | adt::{EnumData, StructData}, | 9 | adt::{EnumData, StructData}, |
@@ -13,13 +13,10 @@ use crate::{ | |||
13 | docs::Documentation, | 13 | docs::Documentation, |
14 | generics::GenericParams, | 14 | generics::GenericParams, |
15 | lang_item::{LangItemTarget, LangItems}, | 15 | lang_item::{LangItemTarget, LangItems}, |
16 | nameres::{ | 16 | nameres::{raw::RawItems, CrateDefMap}, |
17 | raw::{ImportSourceMap, RawItems}, | 17 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, |
18 | CrateDefMap, | 18 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, |
19 | }, | 19 | TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, |
20 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, FunctionId, FunctionLoc, GenericDefId, | ||
21 | ImplId, ItemLoc, ModuleId, StaticId, StaticLoc, StructId, TraitId, TypeAliasId, TypeAliasLoc, | ||
22 | UnionId, | ||
23 | }; | 20 | }; |
24 | 21 | ||
25 | #[salsa::query_group(InternDatabaseStorage)] | 22 | #[salsa::query_group(InternDatabaseStorage)] |
@@ -27,31 +24,25 @@ pub trait InternDatabase: SourceDatabase { | |||
27 | #[salsa::interned] | 24 | #[salsa::interned] |
28 | fn intern_function(&self, loc: FunctionLoc) -> FunctionId; | 25 | fn intern_function(&self, loc: FunctionLoc) -> FunctionId; |
29 | #[salsa::interned] | 26 | #[salsa::interned] |
30 | fn intern_struct(&self, loc: ItemLoc<ast::StructDef>) -> StructId; | 27 | fn intern_struct(&self, loc: StructLoc) -> StructId; |
31 | #[salsa::interned] | 28 | #[salsa::interned] |
32 | fn intern_union(&self, loc: ItemLoc<ast::UnionDef>) -> UnionId; | 29 | fn intern_union(&self, loc: UnionLoc) -> UnionId; |
33 | #[salsa::interned] | 30 | #[salsa::interned] |
34 | fn intern_enum(&self, loc: ItemLoc<ast::EnumDef>) -> EnumId; | 31 | fn intern_enum(&self, loc: EnumLoc) -> EnumId; |
35 | #[salsa::interned] | 32 | #[salsa::interned] |
36 | fn intern_const(&self, loc: ConstLoc) -> ConstId; | 33 | fn intern_const(&self, loc: ConstLoc) -> ConstId; |
37 | #[salsa::interned] | 34 | #[salsa::interned] |
38 | fn intern_static(&self, loc: StaticLoc) -> StaticId; | 35 | fn intern_static(&self, loc: StaticLoc) -> StaticId; |
39 | #[salsa::interned] | 36 | #[salsa::interned] |
40 | fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> TraitId; | 37 | fn intern_trait(&self, loc: TraitLoc) -> TraitId; |
41 | #[salsa::interned] | 38 | #[salsa::interned] |
42 | fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; | 39 | fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; |
43 | #[salsa::interned] | 40 | #[salsa::interned] |
44 | fn intern_impl(&self, loc: ItemLoc<ast::ImplBlock>) -> ImplId; | 41 | fn intern_impl(&self, loc: ImplLoc) -> ImplId; |
45 | } | 42 | } |
46 | 43 | ||
47 | #[salsa::query_group(DefDatabaseStorage)] | 44 | #[salsa::query_group(DefDatabaseStorage)] |
48 | pub trait DefDatabase: InternDatabase + AstDatabase { | 45 | pub trait DefDatabase: InternDatabase + AstDatabase { |
49 | #[salsa::invoke(RawItems::raw_items_with_source_map_query)] | ||
50 | fn raw_items_with_source_map( | ||
51 | &self, | ||
52 | file_id: HirFileId, | ||
53 | ) -> (Arc<RawItems>, Arc<ImportSourceMap>); | ||
54 | |||
55 | #[salsa::invoke(RawItems::raw_items_query)] | 46 | #[salsa::invoke(RawItems::raw_items_query)] |
56 | fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; | 47 | fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; |
57 | 48 | ||
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs index eda9b2269..095498429 100644 --- a/crates/ra_hir_def/src/diagnostics.rs +++ b/crates/ra_hir_def/src/diagnostics.rs | |||
@@ -6,7 +6,7 @@ use hir_expand::diagnostics::Diagnostic; | |||
6 | use ra_db::RelativePathBuf; | 6 | use ra_db::RelativePathBuf; |
7 | use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; | 7 | use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; |
8 | 8 | ||
9 | use hir_expand::{HirFileId, Source}; | 9 | use hir_expand::{HirFileId, InFile}; |
10 | 10 | ||
11 | #[derive(Debug)] | 11 | #[derive(Debug)] |
12 | pub struct UnresolvedModule { | 12 | pub struct UnresolvedModule { |
@@ -19,8 +19,8 @@ impl Diagnostic for UnresolvedModule { | |||
19 | fn message(&self) -> String { | 19 | fn message(&self) -> String { |
20 | "unresolved module".to_string() | 20 | "unresolved module".to_string() |
21 | } | 21 | } |
22 | fn source(&self) -> Source<SyntaxNodePtr> { | 22 | fn source(&self) -> InFile<SyntaxNodePtr> { |
23 | Source { file_id: self.file, value: self.decl.into() } | 23 | InFile { file_id: self.file, value: self.decl.into() } |
24 | } | 24 | } |
25 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 25 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
26 | self | 26 | self |
diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs index 34ed9b7a5..b29f142e3 100644 --- a/crates/ra_hir_def/src/docs.rs +++ b/crates/ra_hir_def/src/docs.rs | |||
@@ -5,10 +5,14 @@ | |||
5 | 5 | ||
6 | use std::sync::Arc; | 6 | use std::sync::Arc; |
7 | 7 | ||
8 | use hir_expand::either::Either; | 8 | use either::Either; |
9 | use ra_syntax::ast; | 9 | use ra_syntax::ast; |
10 | 10 | ||
11 | use crate::{db::DefDatabase, AdtId, AstItemDef, AttrDefId, HasChildSource, HasSource, Lookup}; | 11 | use crate::{ |
12 | db::DefDatabase, | ||
13 | src::{HasChildSource, HasSource}, | ||
14 | AdtId, AttrDefId, Lookup, | ||
15 | }; | ||
12 | 16 | ||
13 | /// Holds documentation | 17 | /// Holds documentation |
14 | #[derive(Debug, Clone, PartialEq, Eq)] | 18 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -42,21 +46,21 @@ impl Documentation { | |||
42 | AttrDefId::StructFieldId(it) => { | 46 | AttrDefId::StructFieldId(it) => { |
43 | let src = it.parent.child_source(db); | 47 | let src = it.parent.child_source(db); |
44 | match &src.value[it.local_id] { | 48 | match &src.value[it.local_id] { |
45 | Either::A(_tuple) => None, | 49 | Either::Left(_tuple) => None, |
46 | Either::B(record) => docs_from_ast(record), | 50 | Either::Right(record) => docs_from_ast(record), |
47 | } | 51 | } |
48 | } | 52 | } |
49 | AttrDefId::AdtId(it) => match it { | 53 | AttrDefId::AdtId(it) => match it { |
50 | AdtId::StructId(it) => docs_from_ast(&it.source(db).value), | 54 | AdtId::StructId(it) => docs_from_ast(&it.lookup(db).source(db).value), |
51 | AdtId::EnumId(it) => docs_from_ast(&it.source(db).value), | 55 | AdtId::EnumId(it) => docs_from_ast(&it.lookup(db).source(db).value), |
52 | AdtId::UnionId(it) => docs_from_ast(&it.source(db).value), | 56 | AdtId::UnionId(it) => docs_from_ast(&it.lookup(db).source(db).value), |
53 | }, | 57 | }, |
54 | AttrDefId::EnumVariantId(it) => { | 58 | AttrDefId::EnumVariantId(it) => { |
55 | let src = it.parent.child_source(db); | 59 | let src = it.parent.child_source(db); |
56 | docs_from_ast(&src.value[it.local_id]) | 60 | docs_from_ast(&src.value[it.local_id]) |
57 | } | 61 | } |
58 | AttrDefId::TraitId(it) => docs_from_ast(&it.source(db).value), | 62 | AttrDefId::TraitId(it) => docs_from_ast(&it.lookup(db).source(db).value), |
59 | AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id.to_node(db)), | 63 | AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id?.to_node(db)), |
60 | AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value), | 64 | AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value), |
61 | AttrDefId::StaticId(it) => docs_from_ast(&it.lookup(db).source(db).value), | 65 | AttrDefId::StaticId(it) => docs_from_ast(&it.lookup(db).source(db).value), |
62 | AttrDefId::FunctionId(it) => docs_from_ast(&it.lookup(db).source(db).value), | 66 | AttrDefId::FunctionId(it) => docs_from_ast(&it.lookup(db).source(db).value), |
diff --git a/crates/ra_hir_def/src/dyn_map.rs b/crates/ra_hir_def/src/dyn_map.rs new file mode 100644 index 000000000..6f269d7b0 --- /dev/null +++ b/crates/ra_hir_def/src/dyn_map.rs | |||
@@ -0,0 +1,108 @@ | |||
1 | //! This module defines a `DynMap` -- a container for heterogeneous maps. | ||
2 | //! | ||
3 | //! This means that `DynMap` stores a bunch of hash maps inside, and those maps | ||
4 | //! can be of different types. | ||
5 | //! | ||
6 | //! It is used like this: | ||
7 | //! | ||
8 | //! ``` | ||
9 | //! // keys define submaps of a `DynMap` | ||
10 | //! const STRING_TO_U32: Key<String, u32> = Key::new(); | ||
11 | //! const U32_TO_VEC: Key<u32, Vec<bool>> = Key::new(); | ||
12 | //! | ||
13 | //! // Note: concrete type, no type params! | ||
14 | //! let mut map = DynMap::new(); | ||
15 | //! | ||
16 | //! // To access a specific map, index the `DynMap` by `Key`: | ||
17 | //! map[STRING_TO_U32].insert("hello".to_string(), 92); | ||
18 | //! let value = map[U32_TO_VEC].get(92); | ||
19 | //! assert!(value.is_none()); | ||
20 | //! ``` | ||
21 | //! | ||
22 | //! This is a work of fiction. Any similarities to Kotlin's `BindingContext` are | ||
23 | //! a coincidence. | ||
24 | use std::{ | ||
25 | hash::Hash, | ||
26 | marker::PhantomData, | ||
27 | ops::{Index, IndexMut}, | ||
28 | }; | ||
29 | |||
30 | use anymap::Map; | ||
31 | use rustc_hash::FxHashMap; | ||
32 | |||
33 | pub struct Key<K, V, P = (K, V)> { | ||
34 | _phantom: PhantomData<(K, V, P)>, | ||
35 | } | ||
36 | |||
37 | impl<K, V, P> Key<K, V, P> { | ||
38 | pub(crate) const fn new() -> Key<K, V, P> { | ||
39 | Key { _phantom: PhantomData } | ||
40 | } | ||
41 | } | ||
42 | |||
43 | impl<K, V, P> Copy for Key<K, V, P> {} | ||
44 | |||
45 | impl<K, V, P> Clone for Key<K, V, P> { | ||
46 | fn clone(&self) -> Key<K, V, P> { | ||
47 | *self | ||
48 | } | ||
49 | } | ||
50 | |||
51 | pub trait Policy { | ||
52 | type K; | ||
53 | type V; | ||
54 | |||
55 | fn insert(map: &mut DynMap, key: Self::K, value: Self::V); | ||
56 | fn get<'a>(map: &'a DynMap, key: &Self::K) -> Option<&'a Self::V>; | ||
57 | } | ||
58 | |||
59 | impl<K: Hash + Eq + 'static, V: 'static> Policy for (K, V) { | ||
60 | type K = K; | ||
61 | type V = V; | ||
62 | fn insert(map: &mut DynMap, key: K, value: V) { | ||
63 | map.map.entry::<FxHashMap<K, V>>().or_insert_with(Default::default).insert(key, value); | ||
64 | } | ||
65 | fn get<'a>(map: &'a DynMap, key: &K) -> Option<&'a V> { | ||
66 | map.map.get::<FxHashMap<K, V>>()?.get(key) | ||
67 | } | ||
68 | } | ||
69 | |||
70 | pub struct DynMap { | ||
71 | pub(crate) map: Map, | ||
72 | } | ||
73 | |||
74 | impl Default for DynMap { | ||
75 | fn default() -> Self { | ||
76 | DynMap { map: Map::new() } | ||
77 | } | ||
78 | } | ||
79 | |||
80 | #[repr(transparent)] | ||
81 | pub struct KeyMap<KEY> { | ||
82 | map: DynMap, | ||
83 | _phantom: PhantomData<KEY>, | ||
84 | } | ||
85 | |||
86 | impl<P: Policy> KeyMap<Key<P::K, P::V, P>> { | ||
87 | pub fn insert(&mut self, key: P::K, value: P::V) { | ||
88 | P::insert(&mut self.map, key, value) | ||
89 | } | ||
90 | pub fn get(&self, key: &P::K) -> Option<&P::V> { | ||
91 | P::get(&self.map, key) | ||
92 | } | ||
93 | } | ||
94 | |||
95 | impl<P: Policy> Index<Key<P::K, P::V, P>> for DynMap { | ||
96 | type Output = KeyMap<Key<P::K, P::V, P>>; | ||
97 | fn index(&self, _key: Key<P::K, P::V, P>) -> &Self::Output { | ||
98 | // Safe due to `#[repr(transparent)]`. | ||
99 | unsafe { std::mem::transmute::<&DynMap, &KeyMap<Key<P::K, P::V, P>>>(self) } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | impl<P: Policy> IndexMut<Key<P::K, P::V, P>> for DynMap { | ||
104 | fn index_mut(&mut self, _key: Key<P::K, P::V, P>) -> &mut Self::Output { | ||
105 | // Safe due to `#[repr(transparent)]`. | ||
106 | unsafe { std::mem::transmute::<&mut DynMap, &mut KeyMap<Key<P::K, P::V, P>>>(self) } | ||
107 | } | ||
108 | } | ||
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs index 04c1d8f69..a75ef9970 100644 --- a/crates/ra_hir_def/src/expr.rs +++ b/crates/ra_hir_def/src/expr.rs | |||
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | use hir_expand::name::Name; | 15 | use hir_expand::name::Name; |
16 | use ra_arena::{impl_arena_id, RawId}; | 16 | use ra_arena::{impl_arena_id, RawId}; |
17 | use ra_syntax::ast::RangeOp; | ||
17 | 18 | ||
18 | use crate::{ | 19 | use crate::{ |
19 | builtin_type::{BuiltinFloat, BuiltinInt}, | 20 | builtin_type::{BuiltinFloat, BuiltinInt}, |
@@ -130,6 +131,11 @@ pub enum Expr { | |||
130 | rhs: ExprId, | 131 | rhs: ExprId, |
131 | op: Option<BinaryOp>, | 132 | op: Option<BinaryOp>, |
132 | }, | 133 | }, |
134 | Range { | ||
135 | lhs: Option<ExprId>, | ||
136 | rhs: Option<ExprId>, | ||
137 | range_type: RangeOp, | ||
138 | }, | ||
133 | Index { | 139 | Index { |
134 | base: ExprId, | 140 | base: ExprId, |
135 | index: ExprId, | 141 | index: ExprId, |
@@ -137,6 +143,7 @@ pub enum Expr { | |||
137 | Lambda { | 143 | Lambda { |
138 | args: Vec<PatId>, | 144 | args: Vec<PatId>, |
139 | arg_types: Vec<Option<TypeRef>>, | 145 | arg_types: Vec<Option<TypeRef>>, |
146 | ret_type: Option<TypeRef>, | ||
140 | body: ExprId, | 147 | body: ExprId, |
141 | }, | 148 | }, |
142 | Tuple { | 149 | Tuple { |
@@ -288,6 +295,14 @@ impl Expr { | |||
288 | f(*lhs); | 295 | f(*lhs); |
289 | f(*rhs); | 296 | f(*rhs); |
290 | } | 297 | } |
298 | Expr::Range { lhs, rhs, .. } => { | ||
299 | if let Some(lhs) = rhs { | ||
300 | f(*lhs); | ||
301 | } | ||
302 | if let Some(rhs) = lhs { | ||
303 | f(*rhs); | ||
304 | } | ||
305 | } | ||
291 | Expr::Index { base, index } => { | 306 | Expr::Index { base, index } => { |
292 | f(*base); | 307 | f(*base); |
293 | f(*index); | 308 | f(*index); |
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index 3f94e40e4..e9c28c730 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs | |||
@@ -4,20 +4,29 @@ | |||
4 | //! in rustc. | 4 | //! in rustc. |
5 | use std::sync::Arc; | 5 | use std::sync::Arc; |
6 | 6 | ||
7 | use hir_expand::name::{self, AsName, Name}; | 7 | use either::Either; |
8 | use hir_expand::{ | ||
9 | name::{name, AsName, Name}, | ||
10 | InFile, | ||
11 | }; | ||
12 | use ra_arena::{map::ArenaMap, Arena}; | ||
13 | use ra_db::FileId; | ||
8 | use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; | 14 | use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; |
9 | 15 | ||
10 | use crate::{ | 16 | use crate::{ |
17 | child_by_source::ChildBySource, | ||
11 | db::DefDatabase, | 18 | db::DefDatabase, |
19 | dyn_map::DynMap, | ||
20 | keys, | ||
21 | src::HasChildSource, | ||
22 | src::HasSource, | ||
12 | type_ref::{TypeBound, TypeRef}, | 23 | type_ref::{TypeBound, TypeRef}, |
13 | AdtId, AstItemDef, ContainerId, GenericDefId, HasSource, Lookup, | 24 | AdtId, GenericDefId, LocalTypeParamId, Lookup, TypeParamId, |
14 | }; | 25 | }; |
15 | 26 | ||
16 | /// Data about a generic parameter (to a function, struct, impl, ...). | 27 | /// Data about a generic parameter (to a function, struct, impl, ...). |
17 | #[derive(Clone, PartialEq, Eq, Debug)] | 28 | #[derive(Clone, PartialEq, Eq, Debug)] |
18 | pub struct GenericParam { | 29 | pub struct TypeParamData { |
19 | // FIXME: give generic params proper IDs | ||
20 | pub idx: u32, | ||
21 | pub name: Name, | 30 | pub name: Name, |
22 | pub default: Option<TypeRef>, | 31 | pub default: Option<TypeRef>, |
23 | } | 32 | } |
@@ -25,8 +34,8 @@ pub struct GenericParam { | |||
25 | /// Data about the generic parameters of a function, struct, impl, etc. | 34 | /// Data about the generic parameters of a function, struct, impl, etc. |
26 | #[derive(Clone, PartialEq, Eq, Debug)] | 35 | #[derive(Clone, PartialEq, Eq, Debug)] |
27 | pub struct GenericParams { | 36 | pub struct GenericParams { |
28 | pub parent_params: Option<Arc<GenericParams>>, | 37 | pub types: Arena<LocalTypeParamId, TypeParamData>, |
29 | pub params: Vec<GenericParam>, | 38 | // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>, |
30 | pub where_predicates: Vec<WherePredicate>, | 39 | pub where_predicates: Vec<WherePredicate>, |
31 | } | 40 | } |
32 | 41 | ||
@@ -40,63 +49,87 @@ pub struct WherePredicate { | |||
40 | pub bound: TypeBound, | 49 | pub bound: TypeBound, |
41 | } | 50 | } |
42 | 51 | ||
52 | type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>; | ||
53 | |||
43 | impl GenericParams { | 54 | impl GenericParams { |
44 | pub(crate) fn generic_params_query( | 55 | pub(crate) fn generic_params_query( |
45 | db: &impl DefDatabase, | 56 | db: &impl DefDatabase, |
46 | def: GenericDefId, | 57 | def: GenericDefId, |
47 | ) -> Arc<GenericParams> { | 58 | ) -> Arc<GenericParams> { |
48 | let parent_generics = parent_generic_def(db, def).map(|it| db.generic_params(it)); | 59 | let (params, _source_map) = GenericParams::new(db, def.into()); |
49 | Arc::new(GenericParams::new(db, def.into(), parent_generics)) | 60 | Arc::new(params) |
50 | } | 61 | } |
51 | 62 | ||
52 | fn new( | 63 | fn new(db: &impl DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { |
53 | db: &impl DefDatabase, | 64 | let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() }; |
54 | def: GenericDefId, | 65 | let mut sm = ArenaMap::default(); |
55 | parent_params: Option<Arc<GenericParams>>, | ||
56 | ) -> GenericParams { | ||
57 | let mut generics = | ||
58 | GenericParams { params: Vec::new(), parent_params, where_predicates: Vec::new() }; | ||
59 | let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32; | ||
60 | // FIXME: add `: Sized` bound for everything except for `Self` in traits | 66 | // FIXME: add `: Sized` bound for everything except for `Self` in traits |
61 | match def { | 67 | let file_id = match def { |
62 | GenericDefId::FunctionId(it) => generics.fill(&it.lookup(db).source(db).value, start), | 68 | GenericDefId::FunctionId(it) => { |
63 | GenericDefId::AdtId(AdtId::StructId(it)) => generics.fill(&it.source(db).value, start), | 69 | let src = it.lookup(db).source(db); |
64 | GenericDefId::AdtId(AdtId::UnionId(it)) => generics.fill(&it.source(db).value, start), | 70 | generics.fill(&mut sm, &src.value); |
65 | GenericDefId::AdtId(AdtId::EnumId(it)) => generics.fill(&it.source(db).value, start), | 71 | src.file_id |
72 | } | ||
73 | GenericDefId::AdtId(AdtId::StructId(it)) => { | ||
74 | let src = it.lookup(db).source(db); | ||
75 | generics.fill(&mut sm, &src.value); | ||
76 | src.file_id | ||
77 | } | ||
78 | GenericDefId::AdtId(AdtId::UnionId(it)) => { | ||
79 | let src = it.lookup(db).source(db); | ||
80 | generics.fill(&mut sm, &src.value); | ||
81 | src.file_id | ||
82 | } | ||
83 | GenericDefId::AdtId(AdtId::EnumId(it)) => { | ||
84 | let src = it.lookup(db).source(db); | ||
85 | generics.fill(&mut sm, &src.value); | ||
86 | src.file_id | ||
87 | } | ||
66 | GenericDefId::TraitId(it) => { | 88 | GenericDefId::TraitId(it) => { |
89 | let src = it.lookup(db).source(db); | ||
90 | |||
67 | // traits get the Self type as an implicit first type parameter | 91 | // traits get the Self type as an implicit first type parameter |
68 | generics.params.push(GenericParam { | 92 | let self_param_id = |
69 | idx: start, | 93 | generics.types.alloc(TypeParamData { name: name![Self], default: None }); |
70 | name: name::SELF_TYPE, | 94 | sm.insert(self_param_id, Either::Left(src.value.clone())); |
71 | default: None, | ||
72 | }); | ||
73 | generics.fill(&it.source(db).value, start + 1); | ||
74 | // add super traits as bounds on Self | 95 | // add super traits as bounds on Self |
75 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar | 96 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar |
76 | let self_param = TypeRef::Path(name::SELF_TYPE.into()); | 97 | let self_param = TypeRef::Path(name![Self].into()); |
77 | generics.fill_bounds(&it.source(db).value, self_param); | 98 | generics.fill_bounds(&src.value, self_param); |
99 | |||
100 | generics.fill(&mut sm, &src.value); | ||
101 | src.file_id | ||
102 | } | ||
103 | GenericDefId::TypeAliasId(it) => { | ||
104 | let src = it.lookup(db).source(db); | ||
105 | generics.fill(&mut sm, &src.value); | ||
106 | src.file_id | ||
78 | } | 107 | } |
79 | GenericDefId::TypeAliasId(it) => generics.fill(&it.lookup(db).source(db).value, start), | ||
80 | // Note that we don't add `Self` here: in `impl`s, `Self` is not a | 108 | // Note that we don't add `Self` here: in `impl`s, `Self` is not a |
81 | // type-parameter, but rather is a type-alias for impl's target | 109 | // type-parameter, but rather is a type-alias for impl's target |
82 | // type, so this is handled by the resolver. | 110 | // type, so this is handled by the resolver. |
83 | GenericDefId::ImplId(it) => generics.fill(&it.source(db).value, start), | 111 | GenericDefId::ImplId(it) => { |
84 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {} | 112 | let src = it.lookup(db).source(db); |
85 | } | 113 | generics.fill(&mut sm, &src.value); |
114 | src.file_id | ||
115 | } | ||
116 | // We won't be using this ID anyway | ||
117 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(), | ||
118 | }; | ||
86 | 119 | ||
87 | generics | 120 | (generics, InFile::new(file_id, sm)) |
88 | } | 121 | } |
89 | 122 | ||
90 | fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) { | 123 | fn fill(&mut self, sm: &mut SourceMap, node: &dyn TypeParamsOwner) { |
91 | if let Some(params) = node.type_param_list() { | 124 | if let Some(params) = node.type_param_list() { |
92 | self.fill_params(params, start) | 125 | self.fill_params(sm, params) |
93 | } | 126 | } |
94 | if let Some(where_clause) = node.where_clause() { | 127 | if let Some(where_clause) = node.where_clause() { |
95 | self.fill_where_predicates(where_clause); | 128 | self.fill_where_predicates(where_clause); |
96 | } | 129 | } |
97 | } | 130 | } |
98 | 131 | ||
99 | fn fill_bounds(&mut self, node: &impl ast::TypeBoundsOwner, type_ref: TypeRef) { | 132 | fn fill_bounds(&mut self, node: &dyn ast::TypeBoundsOwner, type_ref: TypeRef) { |
100 | for bound in | 133 | for bound in |
101 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) | 134 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) |
102 | { | 135 | { |
@@ -104,13 +137,14 @@ impl GenericParams { | |||
104 | } | 137 | } |
105 | } | 138 | } |
106 | 139 | ||
107 | fn fill_params(&mut self, params: ast::TypeParamList, start: u32) { | 140 | fn fill_params(&mut self, sm: &mut SourceMap, params: ast::TypeParamList) { |
108 | for (idx, type_param) in params.type_params().enumerate() { | 141 | for type_param in params.type_params() { |
109 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); | 142 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); |
110 | // FIXME: Use `Path::from_src` | 143 | // FIXME: Use `Path::from_src` |
111 | let default = type_param.default_type().map(TypeRef::from_ast); | 144 | let default = type_param.default_type().map(TypeRef::from_ast); |
112 | let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default }; | 145 | let param = TypeParamData { name: name.clone(), default }; |
113 | self.params.push(param); | 146 | let param_id = self.types.alloc(param); |
147 | sm.insert(param_id, Either::Right(type_param.clone())); | ||
114 | 148 | ||
115 | let type_ref = TypeRef::Path(name.into()); | 149 | let type_ref = TypeRef::Path(name.into()); |
116 | self.fill_bounds(&type_param, type_ref); | 150 | self.fill_bounds(&type_param, type_ref); |
@@ -139,45 +173,31 @@ impl GenericParams { | |||
139 | self.where_predicates.push(WherePredicate { type_ref, bound }); | 173 | self.where_predicates.push(WherePredicate { type_ref, bound }); |
140 | } | 174 | } |
141 | 175 | ||
142 | pub fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { | 176 | pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { |
143 | self.params.iter().find(|p| &p.name == name) | 177 | self.types.iter().find_map(|(id, p)| if &p.name == name { Some(id) } else { None }) |
144 | } | ||
145 | |||
146 | pub fn count_parent_params(&self) -> usize { | ||
147 | self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0) | ||
148 | } | ||
149 | |||
150 | pub fn count_params_including_parent(&self) -> usize { | ||
151 | let parent_count = self.count_parent_params(); | ||
152 | parent_count + self.params.len() | ||
153 | } | ||
154 | |||
155 | fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) { | ||
156 | if let Some(parent) = &self.parent_params { | ||
157 | parent.for_each_param(f); | ||
158 | } | ||
159 | self.params.iter().for_each(f); | ||
160 | } | 178 | } |
179 | } | ||
161 | 180 | ||
162 | pub fn params_including_parent(&self) -> Vec<&GenericParam> { | 181 | impl HasChildSource for GenericDefId { |
163 | let mut vec = Vec::with_capacity(self.count_params_including_parent()); | 182 | type ChildId = LocalTypeParamId; |
164 | self.for_each_param(&mut |p| vec.push(p)); | 183 | type Value = Either<ast::TraitDef, ast::TypeParam>; |
165 | vec | 184 | fn child_source(&self, db: &impl DefDatabase) -> InFile<SourceMap> { |
185 | let (_, sm) = GenericParams::new(db, *self); | ||
186 | sm | ||
166 | } | 187 | } |
167 | } | 188 | } |
168 | 189 | ||
169 | fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option<GenericDefId> { | 190 | impl ChildBySource for GenericDefId { |
170 | let container = match def { | 191 | fn child_by_source(&self, db: &impl DefDatabase) -> DynMap { |
171 | GenericDefId::FunctionId(it) => it.lookup(db).container, | 192 | let mut res = DynMap::default(); |
172 | GenericDefId::TypeAliasId(it) => it.lookup(db).container, | 193 | let arena_map = self.child_source(db); |
173 | GenericDefId::ConstId(it) => it.lookup(db).container, | 194 | let arena_map = arena_map.as_ref(); |
174 | GenericDefId::EnumVariantId(it) => return Some(it.parent.into()), | 195 | for (local_id, src) in arena_map.value.iter() { |
175 | GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None, | 196 | let id = TypeParamId { parent: *self, local_id }; |
176 | }; | 197 | if let Either::Right(type_param) = src { |
177 | 198 | res[keys::TYPE_PARAM].insert(arena_map.with_value(type_param.clone()), id) | |
178 | match container { | 199 | } |
179 | ContainerId::ImplId(it) => Some(it.into()), | 200 | } |
180 | ContainerId::TraitId(it) => Some(it.into()), | 201 | res |
181 | ContainerId::ModuleId(_) => None, | ||
182 | } | 202 | } |
183 | } | 203 | } |
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs new file mode 100644 index 000000000..b0288ee8d --- /dev/null +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -0,0 +1,172 @@ | |||
1 | //! Describes items defined or visible (ie, imported) in a certain scope. | ||
2 | //! This is shared between modules and blocks. | ||
3 | |||
4 | use hir_expand::name::Name; | ||
5 | use once_cell::sync::Lazy; | ||
6 | use rustc_hash::FxHashMap; | ||
7 | |||
8 | use crate::{per_ns::PerNs, AdtId, BuiltinType, ImplId, MacroDefId, ModuleDefId, TraitId}; | ||
9 | |||
10 | #[derive(Debug, Default, PartialEq, Eq)] | ||
11 | pub struct ItemScope { | ||
12 | visible: FxHashMap<Name, PerNs>, | ||
13 | defs: Vec<ModuleDefId>, | ||
14 | impls: Vec<ImplId>, | ||
15 | /// Macros visible in current module in legacy textual scope | ||
16 | /// | ||
17 | /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first. | ||
18 | /// If it yields no result, then it turns to module scoped `macros`. | ||
19 | /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped, | ||
20 | /// and only normal scoped `macros` will be searched in. | ||
21 | /// | ||
22 | /// Note that this automatically inherit macros defined textually before the definition of module itself. | ||
23 | /// | ||
24 | /// Module scoped macros will be inserted into `items` instead of here. | ||
25 | // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will | ||
26 | // be all resolved to the last one defined if shadowing happens. | ||
27 | legacy_macros: FxHashMap<Name, MacroDefId>, | ||
28 | } | ||
29 | |||
30 | static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { | ||
31 | BuiltinType::ALL | ||
32 | .iter() | ||
33 | .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into()))) | ||
34 | .collect() | ||
35 | }); | ||
36 | |||
37 | /// Shadow mode for builtin type which can be shadowed by module. | ||
38 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
39 | pub(crate) enum BuiltinShadowMode { | ||
40 | // Prefer Module | ||
41 | Module, | ||
42 | // Prefer Other Types | ||
43 | Other, | ||
44 | } | ||
45 | |||
46 | /// Legacy macros can only be accessed through special methods like `get_legacy_macros`. | ||
47 | /// Other methods will only resolve values, types and module scoped macros only. | ||
48 | impl ItemScope { | ||
49 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { | ||
50 | //FIXME: shadowing | ||
51 | self.visible.iter().chain(BUILTIN_SCOPE.iter()).map(|(n, def)| (n, *def)) | ||
52 | } | ||
53 | |||
54 | pub fn entries_without_primitives<'a>( | ||
55 | &'a self, | ||
56 | ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { | ||
57 | self.visible.iter().map(|(n, def)| (n, *def)) | ||
58 | } | ||
59 | |||
60 | pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { | ||
61 | self.defs.iter().copied() | ||
62 | } | ||
63 | |||
64 | pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ { | ||
65 | self.impls.iter().copied() | ||
66 | } | ||
67 | |||
68 | /// Iterate over all module scoped macros | ||
69 | pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { | ||
70 | self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) | ||
71 | } | ||
72 | |||
73 | /// Iterate over all legacy textual scoped macros visible at the end of the module | ||
74 | pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { | ||
75 | self.legacy_macros.iter().map(|(name, def)| (name, *def)) | ||
76 | } | ||
77 | |||
78 | /// Get a name from current module scope, legacy macros are not included | ||
79 | pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> PerNs { | ||
80 | match shadow { | ||
81 | BuiltinShadowMode::Module => self | ||
82 | .visible | ||
83 | .get(name) | ||
84 | .or_else(|| BUILTIN_SCOPE.get(name)) | ||
85 | .copied() | ||
86 | .unwrap_or_else(PerNs::none), | ||
87 | BuiltinShadowMode::Other => { | ||
88 | let item = self.visible.get(name).copied(); | ||
89 | if let Some(def) = item { | ||
90 | if let Some(ModuleDefId::ModuleId(_)) = def.take_types() { | ||
91 | return BUILTIN_SCOPE | ||
92 | .get(name) | ||
93 | .copied() | ||
94 | .or(item) | ||
95 | .unwrap_or_else(PerNs::none); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | item.or_else(|| BUILTIN_SCOPE.get(name).copied()).unwrap_or_else(PerNs::none) | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { | ||
105 | self.visible.values().filter_map(|def| match def.take_types() { | ||
106 | Some(ModuleDefId::TraitId(t)) => Some(t), | ||
107 | _ => None, | ||
108 | }) | ||
109 | } | ||
110 | |||
111 | pub(crate) fn define_def(&mut self, def: ModuleDefId) { | ||
112 | self.defs.push(def) | ||
113 | } | ||
114 | |||
115 | pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> { | ||
116 | self.legacy_macros.get(name).copied() | ||
117 | } | ||
118 | |||
119 | pub(crate) fn define_impl(&mut self, imp: ImplId) { | ||
120 | self.impls.push(imp) | ||
121 | } | ||
122 | |||
123 | pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) { | ||
124 | self.legacy_macros.insert(name, mac); | ||
125 | } | ||
126 | |||
127 | pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { | ||
128 | let mut changed = false; | ||
129 | let existing = self.visible.entry(name.clone()).or_default(); | ||
130 | |||
131 | if existing.types.is_none() && def.types.is_some() { | ||
132 | existing.types = def.types; | ||
133 | changed = true; | ||
134 | } | ||
135 | if existing.values.is_none() && def.values.is_some() { | ||
136 | existing.values = def.values; | ||
137 | changed = true; | ||
138 | } | ||
139 | if existing.macros.is_none() && def.macros.is_some() { | ||
140 | existing.macros = def.macros; | ||
141 | changed = true; | ||
142 | } | ||
143 | |||
144 | changed | ||
145 | } | ||
146 | |||
147 | pub(crate) fn collect_resolutions(&self) -> Vec<(Name, PerNs)> { | ||
148 | self.visible.iter().map(|(name, res)| (name.clone(), res.clone())).collect() | ||
149 | } | ||
150 | |||
151 | pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { | ||
152 | self.legacy_macros.clone() | ||
153 | } | ||
154 | } | ||
155 | |||
156 | impl From<ModuleDefId> for PerNs { | ||
157 | fn from(def: ModuleDefId) -> PerNs { | ||
158 | match def { | ||
159 | ModuleDefId::ModuleId(_) => PerNs::types(def), | ||
160 | ModuleDefId::FunctionId(_) => PerNs::values(def), | ||
161 | ModuleDefId::AdtId(adt) => match adt { | ||
162 | AdtId::StructId(_) | AdtId::UnionId(_) => PerNs::both(def, def), | ||
163 | AdtId::EnumId(_) => PerNs::types(def), | ||
164 | }, | ||
165 | ModuleDefId::EnumVariantId(_) => PerNs::both(def, def), | ||
166 | ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def), | ||
167 | ModuleDefId::TraitId(_) => PerNs::types(def), | ||
168 | ModuleDefId::TypeAliasId(_) => PerNs::types(def), | ||
169 | ModuleDefId::BuiltinType(_) => PerNs::types(def), | ||
170 | } | ||
171 | } | ||
172 | } | ||
diff --git a/crates/ra_hir_def/src/keys.rs b/crates/ra_hir_def/src/keys.rs new file mode 100644 index 000000000..d844f7a62 --- /dev/null +++ b/crates/ra_hir_def/src/keys.rs | |||
@@ -0,0 +1,56 @@ | |||
1 | //! keys to be used with `DynMap` | ||
2 | |||
3 | use std::marker::PhantomData; | ||
4 | |||
5 | use hir_expand::InFile; | ||
6 | use ra_syntax::{ast, AstNode, AstPtr}; | ||
7 | use rustc_hash::FxHashMap; | ||
8 | |||
9 | use crate::{ | ||
10 | dyn_map::{DynMap, Policy}, | ||
11 | ConstId, EnumId, EnumVariantId, FunctionId, ImplId, StaticId, StructFieldId, StructId, TraitId, | ||
12 | TypeAliasId, TypeParamId, UnionId, | ||
13 | }; | ||
14 | |||
15 | pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>; | ||
16 | |||
17 | pub const FUNCTION: Key<ast::FnDef, FunctionId> = Key::new(); | ||
18 | pub const CONST: Key<ast::ConstDef, ConstId> = Key::new(); | ||
19 | pub const STATIC: Key<ast::StaticDef, StaticId> = Key::new(); | ||
20 | pub const TYPE_ALIAS: Key<ast::TypeAliasDef, TypeAliasId> = Key::new(); | ||
21 | pub const IMPL: Key<ast::ImplBlock, ImplId> = Key::new(); | ||
22 | pub const TRAIT: Key<ast::TraitDef, TraitId> = Key::new(); | ||
23 | pub const STRUCT: Key<ast::StructDef, StructId> = Key::new(); | ||
24 | pub const UNION: Key<ast::UnionDef, UnionId> = Key::new(); | ||
25 | pub const ENUM: Key<ast::EnumDef, EnumId> = Key::new(); | ||
26 | |||
27 | pub const ENUM_VARIANT: Key<ast::EnumVariant, EnumVariantId> = Key::new(); | ||
28 | pub const TUPLE_FIELD: Key<ast::TupleFieldDef, StructFieldId> = Key::new(); | ||
29 | pub const RECORD_FIELD: Key<ast::RecordFieldDef, StructFieldId> = Key::new(); | ||
30 | pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); | ||
31 | |||
32 | /// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are | ||
33 | /// equal if they point to exactly the same object. | ||
34 | /// | ||
35 | /// In general, we do not guarantee that we have exactly one instance of a | ||
36 | /// syntax tree for each file. We probably should add such guarantee, but, for | ||
37 | /// the time being, we will use identity-less AstPtr comparison. | ||
38 | pub struct AstPtrPolicy<AST, ID> { | ||
39 | _phantom: PhantomData<(AST, ID)>, | ||
40 | } | ||
41 | |||
42 | impl<AST: AstNode + 'static, ID: 'static> Policy for AstPtrPolicy<AST, ID> { | ||
43 | type K = InFile<AST>; | ||
44 | type V = ID; | ||
45 | fn insert(map: &mut DynMap, key: InFile<AST>, value: ID) { | ||
46 | let key = key.as_ref().map(AstPtr::new); | ||
47 | map.map | ||
48 | .entry::<FxHashMap<InFile<AstPtr<AST>>, ID>>() | ||
49 | .or_insert_with(Default::default) | ||
50 | .insert(key, value); | ||
51 | } | ||
52 | fn get<'a>(map: &'a DynMap, key: &InFile<AST>) -> Option<&'a ID> { | ||
53 | let key = key.as_ref().map(AstPtr::new); | ||
54 | map.map.get::<FxHashMap<InFile<AstPtr<AST>>, ID>>()?.get(&key) | ||
55 | } | ||
56 | } | ||
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs index f4fdbdcfc..cef061837 100644 --- a/crates/ra_hir_def/src/lang_item.rs +++ b/crates/ra_hir_def/src/lang_item.rs | |||
@@ -81,7 +81,7 @@ impl LangItems { | |||
81 | // Look for impl targets | 81 | // Look for impl targets |
82 | let def_map = db.crate_def_map(module.krate); | 82 | let def_map = db.crate_def_map(module.krate); |
83 | let module_data = &def_map[module.local_id]; | 83 | let module_data = &def_map[module.local_id]; |
84 | for &impl_block in module_data.impls.iter() { | 84 | for impl_block in module_data.scope.impls() { |
85 | self.collect_lang_item(db, impl_block, LangItemTarget::ImplBlockId) | 85 | self.collect_lang_item(db, impl_block, LangItemTarget::ImplBlockId) |
86 | } | 86 | } |
87 | 87 | ||
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index bc5530896..f6c7f38d1 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -15,6 +15,10 @@ pub mod type_ref; | |||
15 | pub mod builtin_type; | 15 | pub mod builtin_type; |
16 | pub mod diagnostics; | 16 | pub mod diagnostics; |
17 | pub mod per_ns; | 17 | pub mod per_ns; |
18 | pub mod item_scope; | ||
19 | |||
20 | pub mod dyn_map; | ||
21 | pub mod keys; | ||
18 | 22 | ||
19 | pub mod adt; | 23 | pub mod adt; |
20 | pub mod data; | 24 | pub mod data; |
@@ -29,23 +33,23 @@ pub mod resolver; | |||
29 | mod trace; | 33 | mod trace; |
30 | pub mod nameres; | 34 | pub mod nameres; |
31 | 35 | ||
36 | pub mod src; | ||
37 | pub mod child_by_source; | ||
38 | |||
32 | #[cfg(test)] | 39 | #[cfg(test)] |
33 | mod test_db; | 40 | mod test_db; |
34 | #[cfg(test)] | 41 | #[cfg(test)] |
35 | mod marks; | 42 | mod marks; |
36 | 43 | ||
37 | use std::hash::{Hash, Hasher}; | 44 | use std::hash::Hash; |
38 | 45 | ||
39 | use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId, MacroDefId, Source}; | 46 | use hir_expand::{ast_id_map::FileAstId, AstId, HirFileId, InFile, MacroDefId}; |
40 | use ra_arena::{impl_arena_id, map::ArenaMap, RawId}; | 47 | use ra_arena::{impl_arena_id, RawId}; |
41 | use ra_db::{impl_intern_key, salsa, CrateId}; | 48 | use ra_db::{impl_intern_key, salsa, CrateId}; |
42 | use ra_syntax::{ast, AstNode}; | 49 | use ra_syntax::{ast, AstNode}; |
43 | 50 | ||
44 | use crate::{builtin_type::BuiltinType, db::InternDatabase}; | 51 | use crate::body::Expander; |
45 | 52 | use crate::builtin_type::BuiltinType; | |
46 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
47 | pub struct LocalImportId(RawId); | ||
48 | impl_arena_id!(LocalImportId); | ||
49 | 53 | ||
50 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 54 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
51 | pub struct ModuleId { | 55 | pub struct ModuleId { |
@@ -59,122 +63,57 @@ pub struct ModuleId { | |||
59 | pub struct LocalModuleId(RawId); | 63 | pub struct LocalModuleId(RawId); |
60 | impl_arena_id!(LocalModuleId); | 64 | impl_arena_id!(LocalModuleId); |
61 | 65 | ||
62 | #[derive(Debug)] | 66 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
63 | pub struct ItemLoc<N: AstNode> { | 67 | pub struct ItemLoc<N: AstNode> { |
64 | pub(crate) module: ModuleId, | 68 | pub container: ContainerId, |
65 | ast_id: AstId<N>, | 69 | pub ast_id: AstId<N>, |
66 | } | ||
67 | |||
68 | impl<N: AstNode> PartialEq for ItemLoc<N> { | ||
69 | fn eq(&self, other: &Self) -> bool { | ||
70 | self.module == other.module && self.ast_id == other.ast_id | ||
71 | } | ||
72 | } | ||
73 | impl<N: AstNode> Eq for ItemLoc<N> {} | ||
74 | impl<N: AstNode> Hash for ItemLoc<N> { | ||
75 | fn hash<H: Hasher>(&self, hasher: &mut H) { | ||
76 | self.module.hash(hasher); | ||
77 | self.ast_id.hash(hasher); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | impl<N: AstNode> Clone for ItemLoc<N> { | ||
82 | fn clone(&self) -> ItemLoc<N> { | ||
83 | ItemLoc { module: self.module, ast_id: self.ast_id } | ||
84 | } | ||
85 | } | 70 | } |
86 | 71 | ||
87 | #[derive(Clone, Copy)] | 72 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
88 | pub struct LocationCtx<DB> { | 73 | pub struct AssocItemLoc<N: AstNode> { |
89 | db: DB, | 74 | pub container: AssocContainerId, |
90 | module: ModuleId, | 75 | pub ast_id: AstId<N>, |
91 | file_id: HirFileId, | ||
92 | } | 76 | } |
93 | 77 | ||
94 | impl<'a, DB> LocationCtx<&'a DB> { | 78 | macro_rules! impl_intern { |
95 | pub fn new(db: &'a DB, module: ModuleId, file_id: HirFileId) -> LocationCtx<&'a DB> { | 79 | ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => { |
96 | LocationCtx { db, module, file_id } | 80 | impl_intern_key!($id); |
97 | } | ||
98 | } | ||
99 | 81 | ||
100 | pub trait AstItemDef<N: AstNode>: salsa::InternKey + Clone { | 82 | impl Intern for $loc { |
101 | fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self; | 83 | type ID = $id; |
102 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>; | 84 | fn intern(self, db: &impl db::DefDatabase) -> $id { |
85 | db.$intern(self) | ||
86 | } | ||
87 | } | ||
103 | 88 | ||
104 | fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self { | 89 | impl Lookup for $id { |
105 | let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) }; | 90 | type Data = $loc; |
106 | Self::intern(ctx.db, loc) | 91 | fn lookup(&self, db: &impl db::DefDatabase) -> $loc { |
107 | } | 92 | db.$lookup(*self) |
108 | fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source<N> { | 93 | } |
109 | let loc = self.lookup_intern(db); | 94 | } |
110 | let value = loc.ast_id.to_node(db); | 95 | }; |
111 | Source { file_id: loc.ast_id.file_id(), value } | ||
112 | } | ||
113 | fn module(self, db: &impl InternDatabase) -> ModuleId { | ||
114 | let loc = self.lookup_intern(db); | ||
115 | loc.module | ||
116 | } | ||
117 | } | 96 | } |
118 | 97 | ||
119 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 98 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
120 | pub struct FunctionId(salsa::InternId); | 99 | pub struct FunctionId(salsa::InternId); |
121 | impl_intern_key!(FunctionId); | 100 | type FunctionLoc = AssocItemLoc<ast::FnDef>; |
122 | 101 | impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); | |
123 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
124 | pub struct FunctionLoc { | ||
125 | pub container: ContainerId, | ||
126 | pub ast_id: AstId<ast::FnDef>, | ||
127 | } | ||
128 | |||
129 | impl Intern for FunctionLoc { | ||
130 | type ID = FunctionId; | ||
131 | fn intern(self, db: &impl db::DefDatabase) -> FunctionId { | ||
132 | db.intern_function(self) | ||
133 | } | ||
134 | } | ||
135 | |||
136 | impl Lookup for FunctionId { | ||
137 | type Data = FunctionLoc; | ||
138 | fn lookup(&self, db: &impl db::DefDatabase) -> FunctionLoc { | ||
139 | db.lookup_intern_function(*self) | ||
140 | } | ||
141 | } | ||
142 | 102 | ||
143 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 103 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
144 | pub struct StructId(salsa::InternId); | 104 | pub struct StructId(salsa::InternId); |
145 | impl_intern_key!(StructId); | 105 | type StructLoc = ItemLoc<ast::StructDef>; |
146 | impl AstItemDef<ast::StructDef> for StructId { | 106 | impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); |
147 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self { | ||
148 | db.intern_struct(loc) | ||
149 | } | ||
150 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> { | ||
151 | db.lookup_intern_struct(self) | ||
152 | } | ||
153 | } | ||
154 | 107 | ||
155 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 108 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
156 | pub struct UnionId(salsa::InternId); | 109 | pub struct UnionId(salsa::InternId); |
157 | impl_intern_key!(UnionId); | 110 | pub type UnionLoc = ItemLoc<ast::UnionDef>; |
158 | impl AstItemDef<ast::UnionDef> for UnionId { | 111 | impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); |
159 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::UnionDef>) -> Self { | ||
160 | db.intern_union(loc) | ||
161 | } | ||
162 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::UnionDef> { | ||
163 | db.lookup_intern_union(self) | ||
164 | } | ||
165 | } | ||
166 | 112 | ||
167 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 113 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
168 | pub struct EnumId(salsa::InternId); | 114 | pub struct EnumId(salsa::InternId); |
169 | impl_intern_key!(EnumId); | 115 | pub type EnumLoc = ItemLoc<ast::EnumDef>; |
170 | impl AstItemDef<ast::EnumDef> for EnumId { | 116 | impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); |
171 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::EnumDef>) -> Self { | ||
172 | db.intern_enum(loc) | ||
173 | } | ||
174 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> { | ||
175 | db.lookup_intern_enum(self) | ||
176 | } | ||
177 | } | ||
178 | 117 | ||
179 | // FIXME: rename to `VariantId`, only enums can ave variants | 118 | // FIXME: rename to `VariantId`, only enums can ave variants |
180 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 119 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -199,98 +138,38 @@ impl_arena_id!(LocalStructFieldId); | |||
199 | 138 | ||
200 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 139 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
201 | pub struct ConstId(salsa::InternId); | 140 | pub struct ConstId(salsa::InternId); |
202 | impl_intern_key!(ConstId); | 141 | type ConstLoc = AssocItemLoc<ast::ConstDef>; |
203 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 142 | impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const); |
204 | pub struct ConstLoc { | ||
205 | pub container: ContainerId, | ||
206 | pub ast_id: AstId<ast::ConstDef>, | ||
207 | } | ||
208 | |||
209 | impl Intern for ConstLoc { | ||
210 | type ID = ConstId; | ||
211 | fn intern(self, db: &impl db::DefDatabase) -> ConstId { | ||
212 | db.intern_const(self) | ||
213 | } | ||
214 | } | ||
215 | |||
216 | impl Lookup for ConstId { | ||
217 | type Data = ConstLoc; | ||
218 | fn lookup(&self, db: &impl db::DefDatabase) -> ConstLoc { | ||
219 | db.lookup_intern_const(*self) | ||
220 | } | ||
221 | } | ||
222 | 143 | ||
223 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 144 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
224 | pub struct StaticId(salsa::InternId); | 145 | pub struct StaticId(salsa::InternId); |
225 | impl_intern_key!(StaticId); | 146 | pub type StaticLoc = ItemLoc<ast::StaticDef>; |
226 | 147 | impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); | |
227 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
228 | pub struct StaticLoc { | ||
229 | pub container: ModuleId, | ||
230 | pub ast_id: AstId<ast::StaticDef>, | ||
231 | } | ||
232 | |||
233 | impl Intern for StaticLoc { | ||
234 | type ID = StaticId; | ||
235 | fn intern(self, db: &impl db::DefDatabase) -> StaticId { | ||
236 | db.intern_static(self) | ||
237 | } | ||
238 | } | ||
239 | |||
240 | impl Lookup for StaticId { | ||
241 | type Data = StaticLoc; | ||
242 | fn lookup(&self, db: &impl db::DefDatabase) -> StaticLoc { | ||
243 | db.lookup_intern_static(*self) | ||
244 | } | ||
245 | } | ||
246 | 148 | ||
247 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 149 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
248 | pub struct TraitId(salsa::InternId); | 150 | pub struct TraitId(salsa::InternId); |
249 | impl_intern_key!(TraitId); | 151 | pub type TraitLoc = ItemLoc<ast::TraitDef>; |
250 | impl AstItemDef<ast::TraitDef> for TraitId { | 152 | impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); |
251 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TraitDef>) -> Self { | ||
252 | db.intern_trait(loc) | ||
253 | } | ||
254 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TraitDef> { | ||
255 | db.lookup_intern_trait(self) | ||
256 | } | ||
257 | } | ||
258 | 153 | ||
259 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 154 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
260 | pub struct TypeAliasId(salsa::InternId); | 155 | pub struct TypeAliasId(salsa::InternId); |
261 | impl_intern_key!(TypeAliasId); | 156 | type TypeAliasLoc = AssocItemLoc<ast::TypeAliasDef>; |
262 | 157 | impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); | |
263 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
264 | pub struct TypeAliasLoc { | ||
265 | pub container: ContainerId, | ||
266 | pub ast_id: AstId<ast::TypeAliasDef>, | ||
267 | } | ||
268 | 158 | ||
269 | impl Intern for TypeAliasLoc { | 159 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
270 | type ID = TypeAliasId; | 160 | pub struct ImplId(salsa::InternId); |
271 | fn intern(self, db: &impl db::DefDatabase) -> TypeAliasId { | 161 | type ImplLoc = ItemLoc<ast::ImplBlock>; |
272 | db.intern_type_alias(self) | 162 | impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); |
273 | } | ||
274 | } | ||
275 | 163 | ||
276 | impl Lookup for TypeAliasId { | 164 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
277 | type Data = TypeAliasLoc; | 165 | pub struct TypeParamId { |
278 | fn lookup(&self, db: &impl db::DefDatabase) -> TypeAliasLoc { | 166 | pub parent: GenericDefId, |
279 | db.lookup_intern_type_alias(*self) | 167 | pub local_id: LocalTypeParamId, |
280 | } | ||
281 | } | 168 | } |
282 | 169 | ||
283 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 170 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
284 | pub struct ImplId(salsa::InternId); | 171 | pub struct LocalTypeParamId(RawId); |
285 | impl_intern_key!(ImplId); | 172 | impl_arena_id!(LocalTypeParamId); |
286 | impl AstItemDef<ast::ImplBlock> for ImplId { | ||
287 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ImplBlock>) -> Self { | ||
288 | db.intern_impl(loc) | ||
289 | } | ||
290 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ImplBlock> { | ||
291 | db.lookup_intern_impl(self) | ||
292 | } | ||
293 | } | ||
294 | 173 | ||
295 | macro_rules! impl_froms { | 174 | macro_rules! impl_froms { |
296 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { | 175 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { |
@@ -314,9 +193,16 @@ macro_rules! impl_froms { | |||
314 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 193 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
315 | pub enum ContainerId { | 194 | pub enum ContainerId { |
316 | ModuleId(ModuleId), | 195 | ModuleId(ModuleId), |
196 | DefWithBodyId(DefWithBodyId), | ||
197 | } | ||
198 | |||
199 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
200 | pub enum AssocContainerId { | ||
201 | ContainerId(ContainerId), | ||
317 | ImplId(ImplId), | 202 | ImplId(ImplId), |
318 | TraitId(TraitId), | 203 | TraitId(TraitId), |
319 | } | 204 | } |
205 | impl_froms!(AssocContainerId: ContainerId); | ||
320 | 206 | ||
321 | /// A Data Type | 207 | /// A Data Type |
322 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 208 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
@@ -459,43 +345,39 @@ pub trait HasModule { | |||
459 | fn module(&self, db: &impl db::DefDatabase) -> ModuleId; | 345 | fn module(&self, db: &impl db::DefDatabase) -> ModuleId; |
460 | } | 346 | } |
461 | 347 | ||
462 | impl HasModule for FunctionLoc { | 348 | impl HasModule for ContainerId { |
463 | fn module(&self, db: &impl db::DefDatabase) -> ModuleId { | 349 | fn module(&self, db: &impl db::DefDatabase) -> ModuleId { |
464 | match self.container { | 350 | match *self { |
465 | ContainerId::ModuleId(it) => it, | 351 | ContainerId::ModuleId(it) => it, |
466 | ContainerId::ImplId(it) => it.module(db), | 352 | ContainerId::DefWithBodyId(it) => it.module(db), |
467 | ContainerId::TraitId(it) => it.module(db), | ||
468 | } | 353 | } |
469 | } | 354 | } |
470 | } | 355 | } |
471 | 356 | ||
472 | impl HasModule for TypeAliasLoc { | 357 | impl HasModule for AssocContainerId { |
473 | fn module(&self, db: &impl db::DefDatabase) -> ModuleId { | 358 | fn module(&self, db: &impl db::DefDatabase) -> ModuleId { |
474 | match self.container { | 359 | match *self { |
475 | ContainerId::ModuleId(it) => it, | 360 | AssocContainerId::ContainerId(it) => it.module(db), |
476 | ContainerId::ImplId(it) => it.module(db), | 361 | AssocContainerId::ImplId(it) => it.lookup(db).container.module(db), |
477 | ContainerId::TraitId(it) => it.module(db), | 362 | AssocContainerId::TraitId(it) => it.lookup(db).container.module(db), |
478 | } | 363 | } |
479 | } | 364 | } |
480 | } | 365 | } |
481 | 366 | ||
482 | impl HasModule for ConstLoc { | 367 | impl<N: AstNode> HasModule for AssocItemLoc<N> { |
483 | fn module(&self, db: &impl db::DefDatabase) -> ModuleId { | 368 | fn module(&self, db: &impl db::DefDatabase) -> ModuleId { |
484 | match self.container { | 369 | self.container.module(db) |
485 | ContainerId::ModuleId(it) => it, | ||
486 | ContainerId::ImplId(it) => it.module(db), | ||
487 | ContainerId::TraitId(it) => it.module(db), | ||
488 | } | ||
489 | } | 370 | } |
490 | } | 371 | } |
491 | 372 | ||
492 | impl HasModule for AdtId { | 373 | impl HasModule for AdtId { |
493 | fn module(&self, db: &impl db::DefDatabase) -> ModuleId { | 374 | fn module(&self, db: &impl db::DefDatabase) -> ModuleId { |
494 | match self { | 375 | match self { |
495 | AdtId::StructId(it) => it.module(db), | 376 | AdtId::StructId(it) => it.lookup(db).container, |
496 | AdtId::UnionId(it) => it.module(db), | 377 | AdtId::UnionId(it) => it.lookup(db).container, |
497 | AdtId::EnumId(it) => it.module(db), | 378 | AdtId::EnumId(it) => it.lookup(db).container, |
498 | } | 379 | } |
380 | .module(db) | ||
499 | } | 381 | } |
500 | } | 382 | } |
501 | 383 | ||
@@ -509,58 +391,22 @@ impl HasModule for DefWithBodyId { | |||
509 | } | 391 | } |
510 | } | 392 | } |
511 | 393 | ||
512 | impl HasModule for StaticLoc { | 394 | impl HasModule for GenericDefId { |
513 | fn module(&self, _db: &impl db::DefDatabase) -> ModuleId { | 395 | fn module(&self, db: &impl db::DefDatabase) -> ModuleId { |
514 | self.container | 396 | match self { |
515 | } | 397 | GenericDefId::FunctionId(it) => it.lookup(db).module(db), |
516 | } | 398 | GenericDefId::AdtId(it) => it.module(db), |
517 | 399 | GenericDefId::TraitId(it) => it.lookup(db).container.module(db), | |
518 | pub trait HasSource { | 400 | GenericDefId::TypeAliasId(it) => it.lookup(db).module(db), |
519 | type Value; | 401 | GenericDefId::ImplId(it) => it.lookup(db).container.module(db), |
520 | fn source(&self, db: &impl db::DefDatabase) -> Source<Self::Value>; | 402 | GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container.module(db), |
521 | } | 403 | GenericDefId::ConstId(it) => it.lookup(db).module(db), |
522 | 404 | } | |
523 | impl HasSource for FunctionLoc { | ||
524 | type Value = ast::FnDef; | ||
525 | |||
526 | fn source(&self, db: &impl db::DefDatabase) -> Source<ast::FnDef> { | ||
527 | let node = self.ast_id.to_node(db); | ||
528 | Source::new(self.ast_id.file_id(), node) | ||
529 | } | ||
530 | } | ||
531 | |||
532 | impl HasSource for TypeAliasLoc { | ||
533 | type Value = ast::TypeAliasDef; | ||
534 | |||
535 | fn source(&self, db: &impl db::DefDatabase) -> Source<ast::TypeAliasDef> { | ||
536 | let node = self.ast_id.to_node(db); | ||
537 | Source::new(self.ast_id.file_id(), node) | ||
538 | } | ||
539 | } | ||
540 | |||
541 | impl HasSource for ConstLoc { | ||
542 | type Value = ast::ConstDef; | ||
543 | |||
544 | fn source(&self, db: &impl db::DefDatabase) -> Source<ast::ConstDef> { | ||
545 | let node = self.ast_id.to_node(db); | ||
546 | Source::new(self.ast_id.file_id(), node) | ||
547 | } | 405 | } |
548 | } | 406 | } |
549 | 407 | ||
550 | impl HasSource for StaticLoc { | 408 | impl HasModule for StaticLoc { |
551 | type Value = ast::StaticDef; | 409 | fn module(&self, db: &impl db::DefDatabase) -> ModuleId { |
552 | 410 | self.container.module(db) | |
553 | fn source(&self, db: &impl db::DefDatabase) -> Source<ast::StaticDef> { | ||
554 | let node = self.ast_id.to_node(db); | ||
555 | Source::new(self.ast_id.file_id(), node) | ||
556 | } | 411 | } |
557 | } | 412 | } |
558 | |||
559 | pub trait HasChildSource { | ||
560 | type ChildId; | ||
561 | type Value; | ||
562 | fn child_source( | ||
563 | &self, | ||
564 | db: &impl db::DefDatabase, | ||
565 | ) -> Source<ArenaMap<Self::ChildId, Self::Value>>; | ||
566 | } | ||
diff --git a/crates/ra_hir_def/src/marks.rs b/crates/ra_hir_def/src/marks.rs index 65239ca0a..457ba4abe 100644 --- a/crates/ra_hir_def/src/marks.rs +++ b/crates/ra_hir_def/src/marks.rs | |||
@@ -5,6 +5,7 @@ test_utils::marks!( | |||
5 | name_res_works_for_broken_modules | 5 | name_res_works_for_broken_modules |
6 | can_import_enum_variant | 6 | can_import_enum_variant |
7 | glob_enum | 7 | glob_enum |
8 | glob_enum_group | ||
8 | glob_across_crates | 9 | glob_across_crates |
9 | std_prelude | 10 | std_prelude |
10 | macro_rules_from_other_crates_are_visible_with_macro_use | 11 | macro_rules_from_other_crates_are_visible_with_macro_use |
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index 2359386c2..5d4ca73a3 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs | |||
@@ -57,24 +57,23 @@ mod tests; | |||
57 | 57 | ||
58 | use std::sync::Arc; | 58 | use std::sync::Arc; |
59 | 59 | ||
60 | use hir_expand::{ | 60 | use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile}; |
61 | ast_id_map::FileAstId, diagnostics::DiagnosticSink, either::Either, name::Name, MacroDefId, | ||
62 | Source, | ||
63 | }; | ||
64 | use once_cell::sync::Lazy; | ||
65 | use ra_arena::Arena; | 61 | use ra_arena::Arena; |
66 | use ra_db::{CrateId, Edition, FileId}; | 62 | use ra_db::{CrateId, Edition, FileId, FilePosition}; |
67 | use ra_prof::profile; | 63 | use ra_prof::profile; |
68 | use ra_syntax::ast; | 64 | use ra_syntax::{ |
65 | ast::{self, AstNode}, | ||
66 | SyntaxNode, | ||
67 | }; | ||
69 | use rustc_hash::FxHashMap; | 68 | use rustc_hash::FxHashMap; |
70 | 69 | ||
71 | use crate::{ | 70 | use crate::{ |
72 | builtin_type::BuiltinType, | ||
73 | db::DefDatabase, | 71 | db::DefDatabase, |
72 | item_scope::{BuiltinShadowMode, ItemScope}, | ||
74 | nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, | 73 | nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, |
75 | path::Path, | 74 | path::ModPath, |
76 | per_ns::PerNs, | 75 | per_ns::PerNs, |
77 | AstId, FunctionId, ImplId, LocalImportId, LocalModuleId, ModuleDefId, ModuleId, TraitId, | 76 | AstId, LocalModuleId, ModuleDefId, ModuleId, |
78 | }; | 77 | }; |
79 | 78 | ||
80 | /// Contains all top-level defs from a macro-expanded crate | 79 | /// Contains all top-level defs from a macro-expanded crate |
@@ -100,106 +99,76 @@ impl std::ops::Index<LocalModuleId> for CrateDefMap { | |||
100 | } | 99 | } |
101 | } | 100 | } |
102 | 101 | ||
103 | #[derive(Default, Debug, PartialEq, Eq)] | 102 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] |
104 | pub struct ModuleData { | 103 | pub enum ModuleOrigin { |
105 | pub parent: Option<LocalModuleId>, | 104 | CrateRoot { |
106 | pub children: FxHashMap<Name, LocalModuleId>, | 105 | definition: FileId, |
107 | pub scope: ModuleScope, | 106 | }, |
108 | |||
109 | // FIXME: these can't be both null, we need a three-state enum here. | ||
110 | /// None for root | ||
111 | pub declaration: Option<AstId<ast::Module>>, | ||
112 | /// None for inline modules. | ||
113 | /// | ||
114 | /// Note that non-inline modules, by definition, live inside non-macro file. | 107 | /// Note that non-inline modules, by definition, live inside non-macro file. |
115 | pub definition: Option<FileId>, | 108 | File { |
116 | 109 | declaration: AstId<ast::Module>, | |
117 | pub impls: Vec<ImplId>, | 110 | definition: FileId, |
118 | } | 111 | }, |
119 | 112 | Inline { | |
120 | #[derive(Default, Debug, PartialEq, Eq)] | 113 | definition: AstId<ast::Module>, |
121 | pub(crate) struct Declarations { | 114 | }, |
122 | fns: FxHashMap<FileAstId<ast::FnDef>, FunctionId>, | ||
123 | } | 115 | } |
124 | 116 | ||
125 | #[derive(Debug, Default, PartialEq, Eq)] | 117 | impl Default for ModuleOrigin { |
126 | pub struct ModuleScope { | 118 | fn default() -> Self { |
127 | items: FxHashMap<Name, Resolution>, | 119 | ModuleOrigin::CrateRoot { definition: FileId(0) } |
128 | /// Macros visable in current module in legacy textual scope | ||
129 | /// | ||
130 | /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first. | ||
131 | /// If it yields no result, then it turns to module scoped `macros`. | ||
132 | /// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped, | ||
133 | /// and only normal scoped `macros` will be searched in. | ||
134 | /// | ||
135 | /// Note that this automatically inherit macros defined textually before the definition of module itself. | ||
136 | /// | ||
137 | /// Module scoped macros will be inserted into `items` instead of here. | ||
138 | // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will | ||
139 | // be all resolved to the last one defined if shadowing happens. | ||
140 | legacy_macros: FxHashMap<Name, MacroDefId>, | ||
141 | } | ||
142 | |||
143 | static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| { | ||
144 | BuiltinType::ALL | ||
145 | .iter() | ||
146 | .map(|(name, ty)| { | ||
147 | (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None }) | ||
148 | }) | ||
149 | .collect() | ||
150 | }); | ||
151 | |||
152 | /// Legacy macros can only be accessed through special methods like `get_legacy_macros`. | ||
153 | /// Other methods will only resolve values, types and module scoped macros only. | ||
154 | impl ModuleScope { | ||
155 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a { | ||
156 | //FIXME: shadowing | ||
157 | self.items.iter().chain(BUILTIN_SCOPE.iter()) | ||
158 | } | ||
159 | |||
160 | pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { | ||
161 | self.entries() | ||
162 | .filter_map(|(_name, res)| if res.import.is_none() { Some(res.def) } else { None }) | ||
163 | .flat_map(|per_ns| { | ||
164 | per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter()) | ||
165 | }) | ||
166 | } | ||
167 | |||
168 | /// Iterate over all module scoped macros | ||
169 | pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { | ||
170 | self.items | ||
171 | .iter() | ||
172 | .filter_map(|(name, res)| res.def.take_macros().map(|macro_| (name, macro_))) | ||
173 | } | 120 | } |
121 | } | ||
174 | 122 | ||
175 | /// Iterate over all legacy textual scoped macros visable at the end of the module | 123 | impl ModuleOrigin { |
176 | pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { | 124 | pub(crate) fn not_sure_file(file: Option<FileId>, declaration: AstId<ast::Module>) -> Self { |
177 | self.legacy_macros.iter().map(|(name, def)| (name, *def)) | 125 | match file { |
126 | None => ModuleOrigin::Inline { definition: declaration }, | ||
127 | Some(definition) => ModuleOrigin::File { declaration, definition }, | ||
128 | } | ||
178 | } | 129 | } |
179 | 130 | ||
180 | /// Get a name from current module scope, legacy macros are not included | 131 | fn declaration(&self) -> Option<AstId<ast::Module>> { |
181 | pub fn get(&self, name: &Name) -> Option<&Resolution> { | 132 | match self { |
182 | self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)) | 133 | ModuleOrigin::File { declaration: module, .. } |
134 | | ModuleOrigin::Inline { definition: module, .. } => Some(*module), | ||
135 | ModuleOrigin::CrateRoot { .. } => None, | ||
136 | } | ||
183 | } | 137 | } |
184 | 138 | ||
185 | pub fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { | 139 | pub fn file_id(&self) -> Option<FileId> { |
186 | self.items.values().filter_map(|r| match r.def.take_types() { | 140 | match self { |
187 | Some(ModuleDefId::TraitId(t)) => Some(t), | 141 | ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => { |
142 | Some(*definition) | ||
143 | } | ||
188 | _ => None, | 144 | _ => None, |
189 | }) | 145 | } |
190 | } | 146 | } |
191 | 147 | ||
192 | fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> { | 148 | /// Returns a node which defines this module. |
193 | self.legacy_macros.get(name).copied() | 149 | /// That is, a file or a `mod foo {}` with items. |
150 | fn definition_source(&self, db: &impl DefDatabase) -> InFile<ModuleSource> { | ||
151 | match self { | ||
152 | ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => { | ||
153 | let file_id = *definition; | ||
154 | let sf = db.parse(file_id).tree(); | ||
155 | return InFile::new(file_id.into(), ModuleSource::SourceFile(sf)); | ||
156 | } | ||
157 | ModuleOrigin::Inline { definition } => { | ||
158 | InFile::new(definition.file_id, ModuleSource::Module(definition.to_node(db))) | ||
159 | } | ||
160 | } | ||
194 | } | 161 | } |
195 | } | 162 | } |
196 | 163 | ||
197 | #[derive(Debug, Clone, PartialEq, Eq, Default)] | 164 | #[derive(Default, Debug, PartialEq, Eq)] |
198 | pub struct Resolution { | 165 | pub struct ModuleData { |
199 | /// None for unresolved | 166 | pub parent: Option<LocalModuleId>, |
200 | pub def: PerNs, | 167 | pub children: FxHashMap<Name, LocalModuleId>, |
201 | /// ident by which this is imported into local scope. | 168 | pub scope: ItemScope, |
202 | pub import: Option<LocalImportId>, | 169 | |
170 | /// Where does this module come from? | ||
171 | pub origin: ModuleOrigin, | ||
203 | } | 172 | } |
204 | 173 | ||
205 | impl CrateDefMap { | 174 | impl CrateDefMap { |
@@ -241,7 +210,7 @@ impl CrateDefMap { | |||
241 | pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ { | 210 | pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ { |
242 | self.modules | 211 | self.modules |
243 | .iter() | 212 | .iter() |
244 | .filter(move |(_id, data)| data.definition == Some(file_id)) | 213 | .filter(move |(_id, data)| data.origin.file_id() == Some(file_id)) |
245 | .map(|(id, _data)| id) | 214 | .map(|(id, _data)| id) |
246 | } | 215 | } |
247 | 216 | ||
@@ -249,33 +218,62 @@ impl CrateDefMap { | |||
249 | &self, | 218 | &self, |
250 | db: &impl DefDatabase, | 219 | db: &impl DefDatabase, |
251 | original_module: LocalModuleId, | 220 | original_module: LocalModuleId, |
252 | path: &Path, | 221 | path: &ModPath, |
222 | shadow: BuiltinShadowMode, | ||
253 | ) -> (PerNs, Option<usize>) { | 223 | ) -> (PerNs, Option<usize>) { |
254 | let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); | 224 | let res = |
225 | self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow); | ||
255 | (res.resolved_def, res.segment_index) | 226 | (res.resolved_def, res.segment_index) |
256 | } | 227 | } |
257 | } | 228 | } |
258 | 229 | ||
259 | impl ModuleData { | 230 | impl ModuleData { |
260 | /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. | 231 | /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. |
261 | pub fn definition_source( | 232 | pub fn definition_source(&self, db: &impl DefDatabase) -> InFile<ModuleSource> { |
262 | &self, | 233 | self.origin.definition_source(db) |
263 | db: &impl DefDatabase, | ||
264 | ) -> Source<Either<ast::SourceFile, ast::Module>> { | ||
265 | if let Some(file_id) = self.definition { | ||
266 | let sf = db.parse(file_id).tree(); | ||
267 | return Source::new(file_id.into(), Either::A(sf)); | ||
268 | } | ||
269 | let decl = self.declaration.unwrap(); | ||
270 | Source::new(decl.file_id(), Either::B(decl.to_node(db))) | ||
271 | } | 234 | } |
272 | 235 | ||
273 | /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. | 236 | /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. |
274 | /// `None` for the crate root. | 237 | /// `None` for the crate root or block. |
275 | pub fn declaration_source(&self, db: &impl DefDatabase) -> Option<Source<ast::Module>> { | 238 | pub fn declaration_source(&self, db: &impl DefDatabase) -> Option<InFile<ast::Module>> { |
276 | let decl = self.declaration?; | 239 | let decl = self.origin.declaration()?; |
277 | let value = decl.to_node(db); | 240 | let value = decl.to_node(db); |
278 | Some(Source { file_id: decl.file_id(), value }) | 241 | Some(InFile { file_id: decl.file_id, value }) |
242 | } | ||
243 | } | ||
244 | |||
245 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
246 | pub enum ModuleSource { | ||
247 | SourceFile(ast::SourceFile), | ||
248 | Module(ast::Module), | ||
249 | } | ||
250 | |||
251 | impl ModuleSource { | ||
252 | // FIXME: this methods do not belong here | ||
253 | pub fn from_position(db: &impl DefDatabase, position: FilePosition) -> ModuleSource { | ||
254 | let parse = db.parse(position.file_id); | ||
255 | match &ra_syntax::algo::find_node_at_offset::<ast::Module>( | ||
256 | parse.tree().syntax(), | ||
257 | position.offset, | ||
258 | ) { | ||
259 | Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()), | ||
260 | _ => { | ||
261 | let source_file = parse.tree(); | ||
262 | ModuleSource::SourceFile(source_file) | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | |||
267 | pub fn from_child_node(db: &impl DefDatabase, child: InFile<&SyntaxNode>) -> ModuleSource { | ||
268 | if let Some(m) = | ||
269 | child.value.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) | ||
270 | { | ||
271 | ModuleSource::Module(m) | ||
272 | } else { | ||
273 | let file_id = child.file_id.original_file(db); | ||
274 | let source_file = db.parse(file_id).tree(); | ||
275 | ModuleSource::SourceFile(source_file) | ||
276 | } | ||
279 | } | 277 | } |
280 | } | 278 | } |
281 | 279 | ||
@@ -309,7 +307,7 @@ mod diagnostics { | |||
309 | } | 307 | } |
310 | let decl = declaration.to_node(db); | 308 | let decl = declaration.to_node(db); |
311 | sink.push(UnresolvedModule { | 309 | sink.push(UnresolvedModule { |
312 | file: declaration.file_id(), | 310 | file: declaration.file_id, |
313 | decl: AstPtr::new(&decl), | 311 | decl: AstPtr::new(&decl), |
314 | candidate: candidate.clone(), | 312 | candidate: candidate.clone(), |
315 | }) | 313 | }) |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index fd8245113..b9f40d3dd 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -4,14 +4,15 @@ | |||
4 | //! resolves imports and expands macros. | 4 | //! resolves imports and expands macros. |
5 | 5 | ||
6 | use hir_expand::{ | 6 | use hir_expand::{ |
7 | builtin_derive::find_builtin_derive, | ||
7 | builtin_macro::find_builtin_macro, | 8 | builtin_macro::find_builtin_macro, |
8 | name::{self, AsName, Name}, | 9 | name::{name, AsName, Name}, |
9 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind, | 10 | HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, |
10 | }; | 11 | }; |
11 | use ra_cfg::CfgOptions; | 12 | use ra_cfg::CfgOptions; |
12 | use ra_db::{CrateId, FileId}; | 13 | use ra_db::{CrateId, FileId}; |
13 | use ra_syntax::ast; | 14 | use ra_syntax::ast; |
14 | use rustc_hash::{FxHashMap, FxHashSet}; | 15 | use rustc_hash::FxHashMap; |
15 | use test_utils::tested_by; | 16 | use test_utils::tested_by; |
16 | 17 | ||
17 | use crate::{ | 18 | use crate::{ |
@@ -19,13 +20,12 @@ use crate::{ | |||
19 | db::DefDatabase, | 20 | db::DefDatabase, |
20 | nameres::{ | 21 | nameres::{ |
21 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, | 22 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, |
22 | raw, CrateDefMap, ModuleData, Resolution, ResolveMode, | 23 | raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, |
23 | }, | 24 | }, |
24 | path::{Path, PathKind}, | 25 | path::{ModPath, PathKind}, |
25 | per_ns::PerNs, | 26 | per_ns::PerNs, |
26 | AdtId, AstId, AstItemDef, ConstLoc, ContainerId, EnumId, EnumVariantId, FunctionLoc, ImplId, | 27 | AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern, |
27 | Intern, LocalImportId, LocalModuleId, LocationCtx, ModuleDefId, ModuleId, StaticLoc, StructId, | 28 | LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, |
28 | TraitId, TypeAliasLoc, UnionId, | ||
29 | }; | 29 | }; |
30 | 30 | ||
31 | pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { | 31 | pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { |
@@ -57,68 +57,63 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C | |||
57 | def_map, | 57 | def_map, |
58 | glob_imports: FxHashMap::default(), | 58 | glob_imports: FxHashMap::default(), |
59 | unresolved_imports: Vec::new(), | 59 | unresolved_imports: Vec::new(), |
60 | resolved_imports: Vec::new(), | ||
61 | |||
60 | unexpanded_macros: Vec::new(), | 62 | unexpanded_macros: Vec::new(), |
63 | unexpanded_attribute_macros: Vec::new(), | ||
61 | mod_dirs: FxHashMap::default(), | 64 | mod_dirs: FxHashMap::default(), |
62 | macro_stack_monitor: MacroStackMonitor::default(), | ||
63 | poison_macros: FxHashSet::default(), | ||
64 | cfg_options, | 65 | cfg_options, |
65 | }; | 66 | }; |
66 | collector.collect(); | 67 | collector.collect(); |
67 | collector.finish() | 68 | collector.finish() |
68 | } | 69 | } |
69 | 70 | ||
70 | #[derive(Default)] | 71 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
71 | struct MacroStackMonitor { | 72 | enum PartialResolvedImport { |
72 | counts: FxHashMap<MacroDefId, u32>, | 73 | /// None of any namespaces is resolved |
73 | 74 | Unresolved, | |
74 | /// Mainly use for test | 75 | /// One of namespaces is resolved |
75 | validator: Option<Box<dyn Fn(u32) -> bool>>, | 76 | Indeterminate(PerNs), |
77 | /// All namespaces are resolved, OR it is came from other crate | ||
78 | Resolved(PerNs), | ||
76 | } | 79 | } |
77 | 80 | ||
78 | impl MacroStackMonitor { | 81 | impl PartialResolvedImport { |
79 | fn increase(&mut self, macro_def_id: MacroDefId) { | 82 | fn namespaces(&self) -> PerNs { |
80 | *self.counts.entry(macro_def_id).or_default() += 1; | 83 | match self { |
81 | } | 84 | PartialResolvedImport::Unresolved => PerNs::none(), |
82 | 85 | PartialResolvedImport::Indeterminate(ns) => *ns, | |
83 | fn decrease(&mut self, macro_def_id: MacroDefId) { | 86 | PartialResolvedImport::Resolved(ns) => *ns, |
84 | *self.counts.entry(macro_def_id).or_default() -= 1; | 87 | } |
85 | } | 88 | } |
89 | } | ||
86 | 90 | ||
87 | fn is_poison(&self, macro_def_id: MacroDefId) -> bool { | 91 | #[derive(Clone, Debug, Eq, PartialEq)] |
88 | let cur = *self.counts.get(¯o_def_id).unwrap_or(&0); | 92 | struct ImportDirective { |
93 | module_id: LocalModuleId, | ||
94 | import_id: raw::Import, | ||
95 | import: raw::ImportData, | ||
96 | status: PartialResolvedImport, | ||
97 | } | ||
89 | 98 | ||
90 | if let Some(validator) = &self.validator { | 99 | #[derive(Clone, Debug, Eq, PartialEq)] |
91 | validator(cur) | 100 | struct MacroDirective { |
92 | } else { | 101 | module_id: LocalModuleId, |
93 | cur > 100 | 102 | ast_id: AstId<ast::MacroCall>, |
94 | } | 103 | path: ModPath, |
95 | } | 104 | legacy: Option<MacroCallId>, |
96 | } | 105 | } |
97 | 106 | ||
98 | /// Walks the tree of module recursively | 107 | /// Walks the tree of module recursively |
99 | struct DefCollector<'a, DB> { | 108 | struct DefCollector<'a, DB> { |
100 | db: &'a DB, | 109 | db: &'a DB, |
101 | def_map: CrateDefMap, | 110 | def_map: CrateDefMap, |
102 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, LocalImportId)>>, | 111 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, raw::Import)>>, |
103 | unresolved_imports: Vec<(LocalModuleId, LocalImportId, raw::ImportData)>, | 112 | unresolved_imports: Vec<ImportDirective>, |
104 | unexpanded_macros: Vec<(LocalModuleId, AstId<ast::MacroCall>, Path)>, | 113 | resolved_imports: Vec<ImportDirective>, |
114 | unexpanded_macros: Vec<MacroDirective>, | ||
115 | unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, ModPath)>, | ||
105 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, | 116 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, |
106 | |||
107 | /// Some macro use `$tt:tt which mean we have to handle the macro perfectly | ||
108 | /// To prevent stack overflow, we add a deep counter here for prevent that. | ||
109 | macro_stack_monitor: MacroStackMonitor, | ||
110 | /// Some macros are not well-behavior, which leads to infinite loop | ||
111 | /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } } | ||
112 | /// We mark it down and skip it in collector | ||
113 | /// | ||
114 | /// FIXME: | ||
115 | /// Right now it only handle a poison macro in a single crate, | ||
116 | /// such that if other crate try to call that macro, | ||
117 | /// the whole process will do again until it became poisoned in that crate. | ||
118 | /// We should handle this macro set globally | ||
119 | /// However, do we want to put it as a global variable? | ||
120 | poison_macros: FxHashSet<MacroDefId>, | ||
121 | |||
122 | cfg_options: &'a CfgOptions, | 117 | cfg_options: &'a CfgOptions, |
123 | } | 118 | } |
124 | 119 | ||
@@ -131,7 +126,7 @@ where | |||
131 | let file_id = crate_graph.crate_root(self.def_map.krate); | 126 | let file_id = crate_graph.crate_root(self.def_map.krate); |
132 | let raw_items = self.db.raw_items(file_id.into()); | 127 | let raw_items = self.db.raw_items(file_id.into()); |
133 | let module_id = self.def_map.root; | 128 | let module_id = self.def_map.root; |
134 | self.def_map.modules[module_id].definition = Some(file_id); | 129 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; |
135 | ModCollector { | 130 | ModCollector { |
136 | def_collector: &mut *self, | 131 | def_collector: &mut *self, |
137 | module_id, | 132 | module_id, |
@@ -145,9 +140,11 @@ where | |||
145 | let mut i = 0; | 140 | let mut i = 0; |
146 | loop { | 141 | loop { |
147 | self.db.check_canceled(); | 142 | self.db.check_canceled(); |
148 | match (self.resolve_imports(), self.resolve_macros()) { | 143 | self.resolve_imports(); |
149 | (ReachedFixedPoint::Yes, ReachedFixedPoint::Yes) => break, | 144 | |
150 | _ => i += 1, | 145 | match self.resolve_macros() { |
146 | ReachedFixedPoint::Yes => break, | ||
147 | ReachedFixedPoint::No => i += 1, | ||
151 | } | 148 | } |
152 | if i == 1000 { | 149 | if i == 1000 { |
153 | log::error!("name resolution is stuck"); | 150 | log::error!("name resolution is stuck"); |
@@ -155,10 +152,26 @@ where | |||
155 | } | 152 | } |
156 | } | 153 | } |
157 | 154 | ||
155 | // Resolve all indeterminate resolved imports again | ||
156 | // As some of the macros will expand newly import shadowing partial resolved imports | ||
157 | // FIXME: We maybe could skip this, if we handle the Indetermine imports in `resolve_imports` | ||
158 | // correctly | ||
159 | let partial_resolved = self.resolved_imports.iter().filter_map(|directive| { | ||
160 | if let PartialResolvedImport::Indeterminate(_) = directive.status { | ||
161 | let mut directive = directive.clone(); | ||
162 | directive.status = PartialResolvedImport::Unresolved; | ||
163 | Some(directive) | ||
164 | } else { | ||
165 | None | ||
166 | } | ||
167 | }); | ||
168 | self.unresolved_imports.extend(partial_resolved); | ||
169 | self.resolve_imports(); | ||
170 | |||
158 | let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 171 | let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); |
159 | // show unresolved imports in completion, etc | 172 | // show unresolved imports in completion, etc |
160 | for (module_id, import, import_data) in unresolved_imports { | 173 | for directive in unresolved_imports { |
161 | self.record_resolved_import(module_id, PerNs::none(), import, &import_data) | 174 | self.record_resolved_import(&directive) |
162 | } | 175 | } |
163 | } | 176 | } |
164 | 177 | ||
@@ -201,24 +214,20 @@ where | |||
201 | // In Rust, `#[macro_export]` macros are unconditionally visible at the | 214 | // In Rust, `#[macro_export]` macros are unconditionally visible at the |
202 | // crate root, even if the parent modules is **not** visible. | 215 | // crate root, even if the parent modules is **not** visible. |
203 | if export { | 216 | if export { |
204 | self.update( | 217 | self.update(self.def_map.root, &[(name, PerNs::macros(macro_))]); |
205 | self.def_map.root, | ||
206 | None, | ||
207 | &[(name, Resolution { def: PerNs::macros(macro_), import: None })], | ||
208 | ); | ||
209 | } | 218 | } |
210 | } | 219 | } |
211 | 220 | ||
212 | /// Define a legacy textual scoped macro in module | 221 | /// Define a legacy textual scoped macro in module |
213 | /// | 222 | /// |
214 | /// We use a map `legacy_macros` to store all legacy textual scoped macros visable per module. | 223 | /// We use a map `legacy_macros` to store all legacy textual scoped macros visible per module. |
215 | /// It will clone all macros from parent legacy scope, whose definition is prior to | 224 | /// It will clone all macros from parent legacy scope, whose definition is prior to |
216 | /// the definition of current module. | 225 | /// the definition of current module. |
217 | /// And also, `macro_use` on a module will import all legacy macros visable inside to | 226 | /// And also, `macro_use` on a module will import all legacy macros visible inside to |
218 | /// current legacy scope, with possible shadowing. | 227 | /// current legacy scope, with possible shadowing. |
219 | fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, macro_: MacroDefId) { | 228 | fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroDefId) { |
220 | // Always shadowing | 229 | // Always shadowing |
221 | self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_); | 230 | self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); |
222 | } | 231 | } |
223 | 232 | ||
224 | /// Import macros from `#[macro_use] extern crate`. | 233 | /// Import macros from `#[macro_use] extern crate`. |
@@ -259,31 +268,43 @@ where | |||
259 | } | 268 | } |
260 | } | 269 | } |
261 | 270 | ||
262 | fn resolve_imports(&mut self) -> ReachedFixedPoint { | 271 | /// Import resolution |
263 | let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 272 | /// |
264 | let mut resolved = Vec::new(); | 273 | /// This is a fix point algorithm. We resolve imports until no forward |
265 | imports.retain(|(module_id, import, import_data)| { | 274 | /// progress in resolving imports is made |
266 | let (def, fp) = self.resolve_import(*module_id, import_data); | 275 | fn resolve_imports(&mut self) { |
267 | if fp == ReachedFixedPoint::Yes { | 276 | let mut n_previous_unresolved = self.unresolved_imports.len() + 1; |
268 | resolved.push((*module_id, def, *import, import_data.clone())) | 277 | |
278 | while self.unresolved_imports.len() < n_previous_unresolved { | ||
279 | n_previous_unresolved = self.unresolved_imports.len(); | ||
280 | let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | ||
281 | for mut directive in imports { | ||
282 | directive.status = self.resolve_import(directive.module_id, &directive.import); | ||
283 | |||
284 | match directive.status { | ||
285 | PartialResolvedImport::Indeterminate(_) => { | ||
286 | self.record_resolved_import(&directive); | ||
287 | // FIXME: For avoid performance regression, | ||
288 | // we consider an imported resolved if it is indeterminate (i.e not all namespace resolved) | ||
289 | self.resolved_imports.push(directive) | ||
290 | } | ||
291 | PartialResolvedImport::Resolved(_) => { | ||
292 | self.record_resolved_import(&directive); | ||
293 | self.resolved_imports.push(directive) | ||
294 | } | ||
295 | PartialResolvedImport::Unresolved => { | ||
296 | self.unresolved_imports.push(directive); | ||
297 | } | ||
298 | } | ||
269 | } | 299 | } |
270 | fp == ReachedFixedPoint::No | ||
271 | }); | ||
272 | self.unresolved_imports = imports; | ||
273 | // Resolves imports, filling-in module scopes | ||
274 | let result = | ||
275 | if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No }; | ||
276 | for (module_id, def, import, import_data) in resolved { | ||
277 | self.record_resolved_import(module_id, def, import, &import_data) | ||
278 | } | 300 | } |
279 | result | ||
280 | } | 301 | } |
281 | 302 | ||
282 | fn resolve_import( | 303 | fn resolve_import( |
283 | &self, | 304 | &self, |
284 | module_id: LocalModuleId, | 305 | module_id: LocalModuleId, |
285 | import: &raw::ImportData, | 306 | import: &raw::ImportData, |
286 | ) -> (PerNs, ReachedFixedPoint) { | 307 | ) -> PartialResolvedImport { |
287 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); | 308 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); |
288 | if import.is_extern_crate { | 309 | if import.is_extern_crate { |
289 | let res = self.def_map.resolve_name_in_extern_prelude( | 310 | let res = self.def_map.resolve_name_in_extern_prelude( |
@@ -292,26 +313,45 @@ where | |||
292 | .as_ident() | 313 | .as_ident() |
293 | .expect("extern crate should have been desugared to one-element path"), | 314 | .expect("extern crate should have been desugared to one-element path"), |
294 | ); | 315 | ); |
295 | (res, ReachedFixedPoint::Yes) | 316 | PartialResolvedImport::Resolved(res) |
296 | } else { | 317 | } else { |
297 | let res = self.def_map.resolve_path_fp_with_macro( | 318 | let res = self.def_map.resolve_path_fp_with_macro( |
298 | self.db, | 319 | self.db, |
299 | ResolveMode::Import, | 320 | ResolveMode::Import, |
300 | module_id, | 321 | module_id, |
301 | &import.path, | 322 | &import.path, |
323 | BuiltinShadowMode::Module, | ||
302 | ); | 324 | ); |
303 | 325 | ||
304 | (res.resolved_def, res.reached_fixedpoint) | 326 | let def = res.resolved_def; |
327 | if res.reached_fixedpoint == ReachedFixedPoint::No { | ||
328 | return PartialResolvedImport::Unresolved; | ||
329 | } | ||
330 | |||
331 | if let Some(krate) = res.krate { | ||
332 | if krate != self.def_map.krate { | ||
333 | return PartialResolvedImport::Resolved(def); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | // Check whether all namespace is resolved | ||
338 | if def.take_types().is_some() | ||
339 | && def.take_values().is_some() | ||
340 | && def.take_macros().is_some() | ||
341 | { | ||
342 | PartialResolvedImport::Resolved(def) | ||
343 | } else { | ||
344 | PartialResolvedImport::Indeterminate(def) | ||
345 | } | ||
305 | } | 346 | } |
306 | } | 347 | } |
307 | 348 | ||
308 | fn record_resolved_import( | 349 | fn record_resolved_import(&mut self, directive: &ImportDirective) { |
309 | &mut self, | 350 | let module_id = directive.module_id; |
310 | module_id: LocalModuleId, | 351 | let import_id = directive.import_id; |
311 | def: PerNs, | 352 | let import = &directive.import; |
312 | import_id: LocalImportId, | 353 | let def = directive.status.namespaces(); |
313 | import: &raw::ImportData, | 354 | |
314 | ) { | ||
315 | if import.is_glob { | 355 | if import.is_glob { |
316 | log::debug!("glob import: {:?}", import); | 356 | log::debug!("glob import: {:?}", import); |
317 | match def.take_types() { | 357 | match def.take_types() { |
@@ -326,13 +366,9 @@ where | |||
326 | let scope = &item_map[m.local_id].scope; | 366 | let scope = &item_map[m.local_id].scope; |
327 | 367 | ||
328 | // Module scoped macros is included | 368 | // Module scoped macros is included |
329 | let items = scope | 369 | let items = scope.collect_resolutions(); |
330 | .items | ||
331 | .iter() | ||
332 | .map(|(name, res)| (name.clone(), res.clone())) | ||
333 | .collect::<Vec<_>>(); | ||
334 | 370 | ||
335 | self.update(module_id, Some(import_id), &items); | 371 | self.update(module_id, &items); |
336 | } else { | 372 | } else { |
337 | // glob import from same crate => we do an initial | 373 | // glob import from same crate => we do an initial |
338 | // import, and then need to propagate any further | 374 | // import, and then need to propagate any further |
@@ -340,18 +376,14 @@ where | |||
340 | let scope = &self.def_map[m.local_id].scope; | 376 | let scope = &self.def_map[m.local_id].scope; |
341 | 377 | ||
342 | // Module scoped macros is included | 378 | // Module scoped macros is included |
343 | let items = scope | 379 | let items = scope.collect_resolutions(); |
344 | .items | ||
345 | .iter() | ||
346 | .map(|(name, res)| (name.clone(), res.clone())) | ||
347 | .collect::<Vec<_>>(); | ||
348 | 380 | ||
349 | self.update(module_id, Some(import_id), &items); | 381 | self.update(module_id, &items); |
350 | // record the glob import in case we add further items | 382 | // record the glob import in case we add further items |
351 | self.glob_imports | 383 | let glob = self.glob_imports.entry(m.local_id).or_default(); |
352 | .entry(m.local_id) | 384 | if !glob.iter().any(|it| *it == (module_id, import_id)) { |
353 | .or_default() | 385 | glob.push((module_id, import_id)); |
354 | .push((module_id, import_id)); | 386 | } |
355 | } | 387 | } |
356 | } | 388 | } |
357 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { | 389 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { |
@@ -361,17 +393,14 @@ where | |||
361 | let resolutions = enum_data | 393 | let resolutions = enum_data |
362 | .variants | 394 | .variants |
363 | .iter() | 395 | .iter() |
364 | .filter_map(|(local_id, variant_data)| { | 396 | .map(|(local_id, variant_data)| { |
365 | let name = variant_data.name.clone(); | 397 | let name = variant_data.name.clone(); |
366 | let variant = EnumVariantId { parent: e, local_id }; | 398 | let variant = EnumVariantId { parent: e, local_id }; |
367 | let res = Resolution { | 399 | let res = PerNs::both(variant.into(), variant.into()); |
368 | def: PerNs::both(variant.into(), variant.into()), | 400 | (name, res) |
369 | import: Some(import_id), | ||
370 | }; | ||
371 | Some((name, res)) | ||
372 | }) | 401 | }) |
373 | .collect::<Vec<_>>(); | 402 | .collect::<Vec<_>>(); |
374 | self.update(module_id, Some(import_id), &resolutions); | 403 | self.update(module_id, &resolutions); |
375 | } | 404 | } |
376 | Some(d) => { | 405 | Some(d) => { |
377 | log::debug!("glob import {:?} from non-module/enum {:?}", import, d); | 406 | log::debug!("glob import {:?} from non-module/enum {:?}", import, d); |
@@ -383,7 +412,7 @@ where | |||
383 | } else { | 412 | } else { |
384 | match import.path.segments.last() { | 413 | match import.path.segments.last() { |
385 | Some(last_segment) => { | 414 | Some(last_segment) => { |
386 | let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone()); | 415 | let name = import.alias.clone().unwrap_or_else(|| last_segment.clone()); |
387 | log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); | 416 | log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); |
388 | 417 | ||
389 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 | 418 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 |
@@ -393,62 +422,31 @@ where | |||
393 | } | 422 | } |
394 | } | 423 | } |
395 | 424 | ||
396 | let resolution = Resolution { def, import: Some(import_id) }; | 425 | self.update(module_id, &[(name, def)]); |
397 | self.update(module_id, Some(import_id), &[(name, resolution)]); | ||
398 | } | 426 | } |
399 | None => tested_by!(bogus_paths), | 427 | None => tested_by!(bogus_paths), |
400 | } | 428 | } |
401 | } | 429 | } |
402 | } | 430 | } |
403 | 431 | ||
404 | fn update( | 432 | fn update(&mut self, module_id: LocalModuleId, resolutions: &[(Name, PerNs)]) { |
405 | &mut self, | 433 | self.update_recursive(module_id, resolutions, 0) |
406 | module_id: LocalModuleId, | ||
407 | import: Option<LocalImportId>, | ||
408 | resolutions: &[(Name, Resolution)], | ||
409 | ) { | ||
410 | self.update_recursive(module_id, import, resolutions, 0) | ||
411 | } | 434 | } |
412 | 435 | ||
413 | fn update_recursive( | 436 | fn update_recursive( |
414 | &mut self, | 437 | &mut self, |
415 | module_id: LocalModuleId, | 438 | module_id: LocalModuleId, |
416 | import: Option<LocalImportId>, | 439 | resolutions: &[(Name, PerNs)], |
417 | resolutions: &[(Name, Resolution)], | ||
418 | depth: usize, | 440 | depth: usize, |
419 | ) { | 441 | ) { |
420 | if depth > 100 { | 442 | if depth > 100 { |
421 | // prevent stack overflows (but this shouldn't be possible) | 443 | // prevent stack overflows (but this shouldn't be possible) |
422 | panic!("infinite recursion in glob imports!"); | 444 | panic!("infinite recursion in glob imports!"); |
423 | } | 445 | } |
424 | let module_items = &mut self.def_map.modules[module_id].scope; | 446 | let scope = &mut self.def_map.modules[module_id].scope; |
425 | let mut changed = false; | 447 | let mut changed = false; |
426 | for (name, res) in resolutions { | 448 | for (name, res) in resolutions { |
427 | let existing = module_items.items.entry(name.clone()).or_default(); | 449 | changed |= scope.push_res(name.clone(), *res); |
428 | |||
429 | if existing.def.types.is_none() && res.def.types.is_some() { | ||
430 | existing.def.types = res.def.types; | ||
431 | existing.import = import.or(res.import); | ||
432 | changed = true; | ||
433 | } | ||
434 | if existing.def.values.is_none() && res.def.values.is_some() { | ||
435 | existing.def.values = res.def.values; | ||
436 | existing.import = import.or(res.import); | ||
437 | changed = true; | ||
438 | } | ||
439 | if existing.def.macros.is_none() && res.def.macros.is_some() { | ||
440 | existing.def.macros = res.def.macros; | ||
441 | existing.import = import.or(res.import); | ||
442 | changed = true; | ||
443 | } | ||
444 | |||
445 | if existing.def.is_none() | ||
446 | && res.def.is_none() | ||
447 | && existing.import.is_none() | ||
448 | && res.import.is_some() | ||
449 | { | ||
450 | existing.import = res.import; | ||
451 | } | ||
452 | } | 450 | } |
453 | 451 | ||
454 | if !changed { | 452 | if !changed { |
@@ -461,27 +459,48 @@ where | |||
461 | .flat_map(|v| v.iter()) | 459 | .flat_map(|v| v.iter()) |
462 | .cloned() | 460 | .cloned() |
463 | .collect::<Vec<_>>(); | 461 | .collect::<Vec<_>>(); |
464 | for (glob_importing_module, glob_import) in glob_imports { | 462 | for (glob_importing_module, _glob_import) in glob_imports { |
465 | // We pass the glob import so that the tracked import in those modules is that glob import | 463 | // We pass the glob import so that the tracked import in those modules is that glob import |
466 | self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1); | 464 | self.update_recursive(glob_importing_module, resolutions, depth + 1); |
467 | } | 465 | } |
468 | } | 466 | } |
469 | 467 | ||
470 | fn resolve_macros(&mut self) -> ReachedFixedPoint { | 468 | fn resolve_macros(&mut self) -> ReachedFixedPoint { |
471 | let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); | 469 | let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); |
470 | let mut attribute_macros = | ||
471 | std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new()); | ||
472 | let mut resolved = Vec::new(); | 472 | let mut resolved = Vec::new(); |
473 | let mut res = ReachedFixedPoint::Yes; | 473 | let mut res = ReachedFixedPoint::Yes; |
474 | macros.retain(|(module_id, ast_id, path)| { | 474 | macros.retain(|directive| { |
475 | if let Some(call_id) = directive.legacy { | ||
476 | res = ReachedFixedPoint::No; | ||
477 | resolved.push((directive.module_id, call_id)); | ||
478 | return false; | ||
479 | } | ||
480 | |||
475 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | 481 | let resolved_res = self.def_map.resolve_path_fp_with_macro( |
476 | self.db, | 482 | self.db, |
477 | ResolveMode::Other, | 483 | ResolveMode::Other, |
478 | *module_id, | 484 | directive.module_id, |
479 | path, | 485 | &directive.path, |
486 | BuiltinShadowMode::Module, | ||
480 | ); | 487 | ); |
481 | 488 | ||
482 | if let Some(def) = resolved_res.resolved_def.take_macros() { | 489 | if let Some(def) = resolved_res.resolved_def.take_macros() { |
483 | let call_id = def.as_call_id(self.db, *ast_id); | 490 | let call_id = def.as_call_id(self.db, MacroCallKind::FnLike(directive.ast_id)); |
484 | resolved.push((*module_id, call_id, def)); | 491 | resolved.push((directive.module_id, call_id)); |
492 | res = ReachedFixedPoint::No; | ||
493 | return false; | ||
494 | } | ||
495 | |||
496 | true | ||
497 | }); | ||
498 | attribute_macros.retain(|(module_id, ast_id, path)| { | ||
499 | let resolved_res = self.resolve_attribute_macro(path); | ||
500 | |||
501 | if let Some(def) = resolved_res { | ||
502 | let call_id = def.as_call_id(self.db, MacroCallKind::Attr(*ast_id)); | ||
503 | resolved.push((*module_id, call_id)); | ||
485 | res = ReachedFixedPoint::No; | 504 | res = ReachedFixedPoint::No; |
486 | return false; | 505 | return false; |
487 | } | 506 | } |
@@ -490,44 +509,41 @@ where | |||
490 | }); | 509 | }); |
491 | 510 | ||
492 | self.unexpanded_macros = macros; | 511 | self.unexpanded_macros = macros; |
512 | self.unexpanded_attribute_macros = attribute_macros; | ||
493 | 513 | ||
494 | for (module_id, macro_call_id, macro_def_id) in resolved { | 514 | for (module_id, macro_call_id) in resolved { |
495 | self.collect_macro_expansion(module_id, macro_call_id, macro_def_id); | 515 | self.collect_macro_expansion(module_id, macro_call_id); |
496 | } | 516 | } |
497 | 517 | ||
498 | res | 518 | res |
499 | } | 519 | } |
500 | 520 | ||
501 | fn collect_macro_expansion( | 521 | fn resolve_attribute_macro(&self, path: &ModPath) -> Option<MacroDefId> { |
502 | &mut self, | 522 | // FIXME this is currently super hacky, just enough to support the |
503 | module_id: LocalModuleId, | 523 | // built-in derives |
504 | macro_call_id: MacroCallId, | 524 | if let Some(name) = path.as_ident() { |
505 | macro_def_id: MacroDefId, | 525 | // FIXME this should actually be handled with the normal name |
506 | ) { | 526 | // resolution; the std lib defines built-in stubs for the derives, |
507 | if self.poison_macros.contains(¯o_def_id) { | 527 | // but these are new-style `macro`s, which we don't support yet |
508 | return; | 528 | if let Some(def_id) = find_builtin_derive(name) { |
509 | } | 529 | return Some(def_id); |
510 | |||
511 | self.macro_stack_monitor.increase(macro_def_id); | ||
512 | |||
513 | if !self.macro_stack_monitor.is_poison(macro_def_id) { | ||
514 | let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items); | ||
515 | let raw_items = self.db.raw_items(file_id); | ||
516 | let mod_dir = self.mod_dirs[&module_id].clone(); | ||
517 | ModCollector { | ||
518 | def_collector: &mut *self, | ||
519 | file_id, | ||
520 | module_id, | ||
521 | raw_items: &raw_items, | ||
522 | mod_dir, | ||
523 | } | 530 | } |
524 | .collect(raw_items.items()); | ||
525 | } else { | ||
526 | log::error!("Too deep macro expansion: {:?}", macro_call_id); | ||
527 | self.poison_macros.insert(macro_def_id); | ||
528 | } | 531 | } |
532 | None | ||
533 | } | ||
529 | 534 | ||
530 | self.macro_stack_monitor.decrease(macro_def_id); | 535 | fn collect_macro_expansion(&mut self, module_id: LocalModuleId, macro_call_id: MacroCallId) { |
536 | let file_id: HirFileId = macro_call_id.as_file(); | ||
537 | let raw_items = self.db.raw_items(file_id); | ||
538 | let mod_dir = self.mod_dirs[&module_id].clone(); | ||
539 | ModCollector { | ||
540 | def_collector: &mut *self, | ||
541 | file_id, | ||
542 | module_id, | ||
543 | raw_items: &raw_items, | ||
544 | mod_dir, | ||
545 | } | ||
546 | .collect(raw_items.items()); | ||
531 | } | 547 | } |
532 | 548 | ||
533 | fn finish(self) -> CrateDefMap { | 549 | fn finish(self) -> CrateDefMap { |
@@ -581,20 +597,31 @@ where | |||
581 | raw::RawItemKind::Module(m) => { | 597 | raw::RawItemKind::Module(m) => { |
582 | self.collect_module(&self.raw_items[m], &item.attrs) | 598 | self.collect_module(&self.raw_items[m], &item.attrs) |
583 | } | 599 | } |
584 | raw::RawItemKind::Import(import_id) => self | 600 | raw::RawItemKind::Import(import_id) => { |
585 | .def_collector | 601 | self.def_collector.unresolved_imports.push(ImportDirective { |
586 | .unresolved_imports | 602 | module_id: self.module_id, |
587 | .push((self.module_id, import_id, self.raw_items[import_id].clone())), | 603 | import_id, |
588 | raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), | 604 | import: self.raw_items[import_id].clone(), |
605 | status: PartialResolvedImport::Unresolved, | ||
606 | }) | ||
607 | } | ||
608 | raw::RawItemKind::Def(def) => { | ||
609 | self.define_def(&self.raw_items[def], &item.attrs) | ||
610 | } | ||
589 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 611 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), |
590 | raw::RawItemKind::Impl(imp) => { | 612 | raw::RawItemKind::Impl(imp) => { |
591 | let module = ModuleId { | 613 | let module = ModuleId { |
592 | krate: self.def_collector.def_map.krate, | 614 | krate: self.def_collector.def_map.krate, |
593 | local_id: self.module_id, | 615 | local_id: self.module_id, |
594 | }; | 616 | }; |
595 | let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); | 617 | let container = ContainerId::ModuleId(module); |
596 | let imp_id = ImplId::from_ast_id(ctx, self.raw_items[imp].ast_id); | 618 | let ast_id = self.raw_items[imp].ast_id; |
597 | self.def_collector.def_map.modules[self.module_id].impls.push(imp_id) | 619 | let impl_id = |
620 | ImplLoc { container, ast_id: AstId::new(self.file_id, ast_id) } | ||
621 | .intern(self.def_collector.db); | ||
622 | self.def_collector.def_map.modules[self.module_id] | ||
623 | .scope | ||
624 | .define_impl(impl_id) | ||
598 | } | 625 | } |
599 | } | 626 | } |
600 | } | 627 | } |
@@ -667,72 +694,91 @@ where | |||
667 | let modules = &mut self.def_collector.def_map.modules; | 694 | let modules = &mut self.def_collector.def_map.modules; |
668 | let res = modules.alloc(ModuleData::default()); | 695 | let res = modules.alloc(ModuleData::default()); |
669 | modules[res].parent = Some(self.module_id); | 696 | modules[res].parent = Some(self.module_id); |
670 | modules[res].declaration = Some(declaration); | 697 | modules[res].origin = ModuleOrigin::not_sure_file(definition, declaration); |
671 | modules[res].definition = definition; | 698 | for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() { |
672 | modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone(); | 699 | modules[res].scope.define_legacy_macro(name, mac) |
700 | } | ||
673 | modules[self.module_id].children.insert(name.clone(), res); | 701 | modules[self.module_id].children.insert(name.clone(), res); |
674 | let resolution = Resolution { | 702 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res }; |
675 | def: PerNs::types( | 703 | let def: ModuleDefId = module.into(); |
676 | ModuleId { krate: self.def_collector.def_map.krate, local_id: res }.into(), | 704 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); |
677 | ), | 705 | self.def_collector.update(self.module_id, &[(name, def.into())]); |
678 | import: None, | ||
679 | }; | ||
680 | self.def_collector.update(self.module_id, None, &[(name, resolution)]); | ||
681 | res | 706 | res |
682 | } | 707 | } |
683 | 708 | ||
684 | fn define_def(&mut self, def: &raw::DefData) { | 709 | fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) { |
685 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; | 710 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; |
686 | let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); | 711 | // FIXME: check attrs to see if this is an attribute macro invocation; |
712 | // in which case we don't add the invocation, just a single attribute | ||
713 | // macro invocation | ||
687 | 714 | ||
688 | let name = def.name.clone(); | 715 | self.collect_derives(attrs, def); |
689 | let def: PerNs = match def.kind { | ||
690 | raw::DefKind::Function(ast_id) => { | ||
691 | let def = FunctionLoc { | ||
692 | container: ContainerId::ModuleId(module), | ||
693 | ast_id: AstId::new(self.file_id, ast_id), | ||
694 | } | ||
695 | .intern(self.def_collector.db); | ||
696 | 716 | ||
697 | PerNs::values(def.into()) | 717 | let name = def.name.clone(); |
718 | let container = ContainerId::ModuleId(module); | ||
719 | let def: ModuleDefId = match def.kind { | ||
720 | raw::DefKind::Function(ast_id) => FunctionLoc { | ||
721 | container: container.into(), | ||
722 | ast_id: AstId::new(self.file_id, ast_id), | ||
698 | } | 723 | } |
724 | .intern(self.def_collector.db) | ||
725 | .into(), | ||
699 | raw::DefKind::Struct(ast_id) => { | 726 | raw::DefKind::Struct(ast_id) => { |
700 | let id = StructId::from_ast_id(ctx, ast_id).into(); | 727 | StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) } |
701 | PerNs::both(id, id) | 728 | .intern(self.def_collector.db) |
729 | .into() | ||
702 | } | 730 | } |
703 | raw::DefKind::Union(ast_id) => { | 731 | raw::DefKind::Union(ast_id) => { |
704 | let id = UnionId::from_ast_id(ctx, ast_id).into(); | 732 | UnionLoc { container, ast_id: AstId::new(self.file_id, ast_id) } |
705 | PerNs::both(id, id) | 733 | .intern(self.def_collector.db) |
734 | .into() | ||
735 | } | ||
736 | raw::DefKind::Enum(ast_id) => { | ||
737 | EnumLoc { container, ast_id: AstId::new(self.file_id, ast_id) } | ||
738 | .intern(self.def_collector.db) | ||
739 | .into() | ||
706 | } | 740 | } |
707 | raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()), | ||
708 | raw::DefKind::Const(ast_id) => { | 741 | raw::DefKind::Const(ast_id) => { |
709 | let def = ConstLoc { | 742 | ConstLoc { container: container.into(), ast_id: AstId::new(self.file_id, ast_id) } |
710 | container: ContainerId::ModuleId(module), | 743 | .intern(self.def_collector.db) |
711 | ast_id: AstId::new(self.file_id, ast_id), | 744 | .into() |
712 | } | ||
713 | .intern(self.def_collector.db); | ||
714 | |||
715 | PerNs::values(def.into()) | ||
716 | } | 745 | } |
717 | raw::DefKind::Static(ast_id) => { | 746 | raw::DefKind::Static(ast_id) => { |
718 | let def = StaticLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) } | 747 | StaticLoc { container, ast_id: AstId::new(self.file_id, ast_id) } |
719 | .intern(self.def_collector.db); | 748 | .intern(self.def_collector.db) |
720 | 749 | .into() | |
721 | PerNs::values(def.into()) | ||
722 | } | 750 | } |
723 | raw::DefKind::Trait(ast_id) => PerNs::types(TraitId::from_ast_id(ctx, ast_id).into()), | 751 | raw::DefKind::Trait(ast_id) => { |
724 | raw::DefKind::TypeAlias(ast_id) => { | 752 | TraitLoc { container, ast_id: AstId::new(self.file_id, ast_id) } |
725 | let def = TypeAliasLoc { | 753 | .intern(self.def_collector.db) |
726 | container: ContainerId::ModuleId(module), | 754 | .into() |
727 | ast_id: AstId::new(self.file_id, ast_id), | ||
728 | } | ||
729 | .intern(self.def_collector.db); | ||
730 | |||
731 | PerNs::types(def.into()) | ||
732 | } | 755 | } |
756 | raw::DefKind::TypeAlias(ast_id) => TypeAliasLoc { | ||
757 | container: container.into(), | ||
758 | ast_id: AstId::new(self.file_id, ast_id), | ||
759 | } | ||
760 | .intern(self.def_collector.db) | ||
761 | .into(), | ||
733 | }; | 762 | }; |
734 | let resolution = Resolution { def, import: None }; | 763 | self.def_collector.def_map.modules[self.module_id].scope.define_def(def); |
735 | self.def_collector.update(self.module_id, None, &[(name, resolution)]) | 764 | self.def_collector.update(self.module_id, &[(name, def.into())]) |
765 | } | ||
766 | |||
767 | fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) { | ||
768 | for derive_subtree in attrs.by_key("derive").tt_values() { | ||
769 | // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree | ||
770 | for tt in &derive_subtree.token_trees { | ||
771 | let ident = match &tt { | ||
772 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident, | ||
773 | tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok | ||
774 | _ => continue, // anything else would be an error (which we currently ignore) | ||
775 | }; | ||
776 | let path = ModPath::from_tt_ident(ident); | ||
777 | |||
778 | let ast_id = AstId::new(self.file_id, def.kind.ast_id()); | ||
779 | self.def_collector.unexpanded_attribute_macros.push((self.module_id, ast_id, path)); | ||
780 | } | ||
781 | } | ||
736 | } | 782 | } |
737 | 783 | ||
738 | fn collect_macro(&mut self, mac: &raw::MacroData) { | 784 | fn collect_macro(&mut self, mac: &raw::MacroData) { |
@@ -758,8 +804,8 @@ where | |||
758 | if is_macro_rules(&mac.path) { | 804 | if is_macro_rules(&mac.path) { |
759 | if let Some(name) = &mac.name { | 805 | if let Some(name) = &mac.name { |
760 | let macro_id = MacroDefId { | 806 | let macro_id = MacroDefId { |
761 | ast_id, | 807 | ast_id: Some(ast_id), |
762 | krate: self.def_collector.def_map.krate, | 808 | krate: Some(self.def_collector.def_map.krate), |
763 | kind: MacroDefKind::Declarative, | 809 | kind: MacroDefKind::Declarative, |
764 | }; | 810 | }; |
765 | self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); | 811 | self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); |
@@ -767,14 +813,20 @@ where | |||
767 | return; | 813 | return; |
768 | } | 814 | } |
769 | 815 | ||
770 | // Case 2: try to resolve in legacy scope and expand macro_rules, triggering | 816 | // Case 2: try to resolve in legacy scope and expand macro_rules |
771 | // recursive item collection. | ||
772 | if let Some(macro_def) = mac.path.as_ident().and_then(|name| { | 817 | if let Some(macro_def) = mac.path.as_ident().and_then(|name| { |
773 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) | 818 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) |
774 | }) { | 819 | }) { |
775 | let macro_call_id = macro_def.as_call_id(self.def_collector.db, ast_id); | 820 | let macro_call_id = |
821 | macro_def.as_call_id(self.def_collector.db, MacroCallKind::FnLike(ast_id)); | ||
822 | |||
823 | self.def_collector.unexpanded_macros.push(MacroDirective { | ||
824 | module_id: self.module_id, | ||
825 | path: mac.path.clone(), | ||
826 | ast_id, | ||
827 | legacy: Some(macro_call_id), | ||
828 | }); | ||
776 | 829 | ||
777 | self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_def); | ||
778 | return; | 830 | return; |
779 | } | 831 | } |
780 | 832 | ||
@@ -782,13 +834,19 @@ where | |||
782 | // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only. | 834 | // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only. |
783 | let mut path = mac.path.clone(); | 835 | let mut path = mac.path.clone(); |
784 | if path.is_ident() { | 836 | if path.is_ident() { |
785 | path.kind = PathKind::Self_; | 837 | path.kind = PathKind::Super(0); |
786 | } | 838 | } |
787 | self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path)); | 839 | |
840 | self.def_collector.unexpanded_macros.push(MacroDirective { | ||
841 | module_id: self.module_id, | ||
842 | path, | ||
843 | ast_id, | ||
844 | legacy: None, | ||
845 | }); | ||
788 | } | 846 | } |
789 | 847 | ||
790 | fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { | 848 | fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { |
791 | let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); | 849 | let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros(); |
792 | for (name, macro_) in macros { | 850 | for (name, macro_) in macros { |
793 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); | 851 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); |
794 | } | 852 | } |
@@ -803,45 +861,35 @@ where | |||
803 | } | 861 | } |
804 | } | 862 | } |
805 | 863 | ||
806 | fn is_macro_rules(path: &Path) -> bool { | 864 | fn is_macro_rules(path: &ModPath) -> bool { |
807 | path.as_ident() == Some(&name::MACRO_RULES) | 865 | path.as_ident() == Some(&name![macro_rules]) |
808 | } | 866 | } |
809 | 867 | ||
810 | #[cfg(test)] | 868 | #[cfg(test)] |
811 | mod tests { | 869 | mod tests { |
870 | use crate::{db::DefDatabase, test_db::TestDB}; | ||
812 | use ra_arena::Arena; | 871 | use ra_arena::Arena; |
813 | use ra_db::{fixture::WithFixture, SourceDatabase}; | 872 | use ra_db::{fixture::WithFixture, SourceDatabase}; |
814 | use rustc_hash::FxHashSet; | ||
815 | |||
816 | use crate::{db::DefDatabase, test_db::TestDB}; | ||
817 | 873 | ||
818 | use super::*; | 874 | use super::*; |
819 | 875 | ||
820 | fn do_collect_defs( | 876 | fn do_collect_defs(db: &impl DefDatabase, def_map: CrateDefMap) -> CrateDefMap { |
821 | db: &impl DefDatabase, | ||
822 | def_map: CrateDefMap, | ||
823 | monitor: MacroStackMonitor, | ||
824 | ) -> (CrateDefMap, FxHashSet<MacroDefId>) { | ||
825 | let mut collector = DefCollector { | 877 | let mut collector = DefCollector { |
826 | db, | 878 | db, |
827 | def_map, | 879 | def_map, |
828 | glob_imports: FxHashMap::default(), | 880 | glob_imports: FxHashMap::default(), |
829 | unresolved_imports: Vec::new(), | 881 | unresolved_imports: Vec::new(), |
882 | resolved_imports: Vec::new(), | ||
830 | unexpanded_macros: Vec::new(), | 883 | unexpanded_macros: Vec::new(), |
884 | unexpanded_attribute_macros: Vec::new(), | ||
831 | mod_dirs: FxHashMap::default(), | 885 | mod_dirs: FxHashMap::default(), |
832 | macro_stack_monitor: monitor, | ||
833 | poison_macros: FxHashSet::default(), | ||
834 | cfg_options: &CfgOptions::default(), | 886 | cfg_options: &CfgOptions::default(), |
835 | }; | 887 | }; |
836 | collector.collect(); | 888 | collector.collect(); |
837 | (collector.def_map, collector.poison_macros) | 889 | collector.def_map |
838 | } | 890 | } |
839 | 891 | ||
840 | fn do_limited_resolve( | 892 | fn do_resolve(code: &str) -> CrateDefMap { |
841 | code: &str, | ||
842 | limit: u32, | ||
843 | poison_limit: u32, | ||
844 | ) -> (CrateDefMap, FxHashSet<MacroDefId>) { | ||
845 | let (db, _file_id) = TestDB::with_single_file(&code); | 893 | let (db, _file_id) = TestDB::with_single_file(&code); |
846 | let krate = db.test_crate(); | 894 | let krate = db.test_crate(); |
847 | 895 | ||
@@ -859,59 +907,18 @@ mod tests { | |||
859 | diagnostics: Vec::new(), | 907 | diagnostics: Vec::new(), |
860 | } | 908 | } |
861 | }; | 909 | }; |
862 | 910 | do_collect_defs(&db, def_map) | |
863 | let mut monitor = MacroStackMonitor::default(); | ||
864 | monitor.validator = Some(Box::new(move |count| { | ||
865 | assert!(count < limit); | ||
866 | count >= poison_limit | ||
867 | })); | ||
868 | |||
869 | do_collect_defs(&db, def_map, monitor) | ||
870 | } | 911 | } |
871 | 912 | ||
872 | #[test] | 913 | #[test] |
873 | fn test_macro_expand_limit_width() { | 914 | fn test_macro_expand_will_stop() { |
874 | do_limited_resolve( | 915 | do_resolve( |
875 | r#" | 916 | r#" |
876 | macro_rules! foo { | 917 | macro_rules! foo { |
877 | ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); } | 918 | ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); } |
878 | } | 919 | } |
879 | foo!(KABOOM); | 920 | foo!(KABOOM); |
880 | "#, | 921 | "#, |
881 | 16, | ||
882 | 1000, | ||
883 | ); | 922 | ); |
884 | } | 923 | } |
885 | |||
886 | #[test] | ||
887 | fn test_macro_expand_poisoned() { | ||
888 | let (_, poison_macros) = do_limited_resolve( | ||
889 | r#" | ||
890 | macro_rules! foo { | ||
891 | ($ty:ty) => { foo!($ty); } | ||
892 | } | ||
893 | foo!(KABOOM); | ||
894 | "#, | ||
895 | 100, | ||
896 | 16, | ||
897 | ); | ||
898 | |||
899 | assert_eq!(poison_macros.len(), 1); | ||
900 | } | ||
901 | |||
902 | #[test] | ||
903 | fn test_macro_expand_normal() { | ||
904 | let (_, poison_macros) = do_limited_resolve( | ||
905 | r#" | ||
906 | macro_rules! foo { | ||
907 | ($ident:ident) => { struct $ident {} } | ||
908 | } | ||
909 | foo!(Bar); | ||
910 | "#, | ||
911 | 16, | ||
912 | 16, | ||
913 | ); | ||
914 | |||
915 | assert_eq!(poison_macros.len(), 0); | ||
916 | } | ||
917 | } | 924 | } |
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs index b72c55bd1..695014c7b 100644 --- a/crates/ra_hir_def/src/nameres/path_resolution.rs +++ b/crates/ra_hir_def/src/nameres/path_resolution.rs | |||
@@ -10,16 +10,18 @@ | |||
10 | //! | 10 | //! |
11 | //! `ReachedFixedPoint` signals about this. | 11 | //! `ReachedFixedPoint` signals about this. |
12 | 12 | ||
13 | use std::iter::successors; | ||
14 | |||
13 | use hir_expand::name::Name; | 15 | use hir_expand::name::Name; |
14 | use ra_db::Edition; | 16 | use ra_db::Edition; |
15 | use test_utils::tested_by; | 17 | use test_utils::tested_by; |
16 | 18 | ||
17 | use crate::{ | 19 | use crate::{ |
18 | db::DefDatabase, | 20 | db::DefDatabase, |
19 | nameres::CrateDefMap, | 21 | nameres::{BuiltinShadowMode, CrateDefMap}, |
20 | path::{Path, PathKind}, | 22 | path::{ModPath, PathKind}, |
21 | per_ns::PerNs, | 23 | per_ns::PerNs, |
22 | AdtId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, | 24 | AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, |
23 | }; | 25 | }; |
24 | 26 | ||
25 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 27 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
@@ -39,19 +41,21 @@ pub(super) struct ResolvePathResult { | |||
39 | pub(super) resolved_def: PerNs, | 41 | pub(super) resolved_def: PerNs, |
40 | pub(super) segment_index: Option<usize>, | 42 | pub(super) segment_index: Option<usize>, |
41 | pub(super) reached_fixedpoint: ReachedFixedPoint, | 43 | pub(super) reached_fixedpoint: ReachedFixedPoint, |
44 | pub(super) krate: Option<CrateId>, | ||
42 | } | 45 | } |
43 | 46 | ||
44 | impl ResolvePathResult { | 47 | impl ResolvePathResult { |
45 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { | 48 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { |
46 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) | 49 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None) |
47 | } | 50 | } |
48 | 51 | ||
49 | fn with( | 52 | fn with( |
50 | resolved_def: PerNs, | 53 | resolved_def: PerNs, |
51 | reached_fixedpoint: ReachedFixedPoint, | 54 | reached_fixedpoint: ReachedFixedPoint, |
52 | segment_index: Option<usize>, | 55 | segment_index: Option<usize>, |
56 | krate: Option<CrateId>, | ||
53 | ) -> ResolvePathResult { | 57 | ) -> ResolvePathResult { |
54 | ResolvePathResult { resolved_def, reached_fixedpoint, segment_index } | 58 | ResolvePathResult { resolved_def, reached_fixedpoint, segment_index, krate } |
55 | } | 59 | } |
56 | } | 60 | } |
57 | 61 | ||
@@ -67,8 +71,18 @@ impl CrateDefMap { | |||
67 | db: &impl DefDatabase, | 71 | db: &impl DefDatabase, |
68 | mode: ResolveMode, | 72 | mode: ResolveMode, |
69 | original_module: LocalModuleId, | 73 | original_module: LocalModuleId, |
70 | path: &Path, | 74 | path: &ModPath, |
75 | shadow: BuiltinShadowMode, | ||
71 | ) -> ResolvePathResult { | 76 | ) -> ResolvePathResult { |
77 | // if it is not the last segment, we prefer the module to the builtin | ||
78 | let prefer_module = |index| { | ||
79 | if index == path.segments.len() - 1 { | ||
80 | shadow | ||
81 | } else { | ||
82 | BuiltinShadowMode::Module | ||
83 | } | ||
84 | }; | ||
85 | |||
72 | let mut segments = path.segments.iter().enumerate(); | 86 | let mut segments = path.segments.iter().enumerate(); |
73 | let mut curr_per_ns: PerNs = match path.kind { | 87 | let mut curr_per_ns: PerNs = match path.kind { |
74 | PathKind::DollarCrate(krate) => { | 88 | PathKind::DollarCrate(krate) => { |
@@ -85,9 +99,6 @@ impl CrateDefMap { | |||
85 | PathKind::Crate => { | 99 | PathKind::Crate => { |
86 | PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into()) | 100 | PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into()) |
87 | } | 101 | } |
88 | PathKind::Self_ => { | ||
89 | PerNs::types(ModuleId { krate: self.krate, local_id: original_module }.into()) | ||
90 | } | ||
91 | // plain import or absolute path in 2015: crate-relative with | 102 | // plain import or absolute path in 2015: crate-relative with |
92 | // fallback to extern prelude (with the simplification in | 103 | // fallback to extern prelude (with the simplification in |
93 | // rust-lang/rust#57745) | 104 | // rust-lang/rust#57745) |
@@ -96,24 +107,26 @@ impl CrateDefMap { | |||
96 | if self.edition == Edition::Edition2015 | 107 | if self.edition == Edition::Edition2015 |
97 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => | 108 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => |
98 | { | 109 | { |
99 | let segment = match segments.next() { | 110 | let (idx, segment) = match segments.next() { |
100 | Some((_, segment)) => segment, | 111 | Some((idx, segment)) => (idx, segment), |
101 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 112 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
102 | }; | 113 | }; |
103 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); | 114 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); |
104 | self.resolve_name_in_crate_root_or_extern_prelude(&segment.name) | 115 | self.resolve_name_in_crate_root_or_extern_prelude(&segment, prefer_module(idx)) |
105 | } | 116 | } |
106 | PathKind::Plain => { | 117 | PathKind::Plain => { |
107 | let segment = match segments.next() { | 118 | let (idx, segment) = match segments.next() { |
108 | Some((_, segment)) => segment, | 119 | Some((idx, segment)) => (idx, segment), |
109 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 120 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
110 | }; | 121 | }; |
111 | log::debug!("resolving {:?} in module", segment); | 122 | log::debug!("resolving {:?} in module", segment); |
112 | self.resolve_name_in_module(db, original_module, &segment.name) | 123 | self.resolve_name_in_module(db, original_module, &segment, prefer_module(idx)) |
113 | } | 124 | } |
114 | PathKind::Super => { | 125 | PathKind::Super(lvl) => { |
115 | if let Some(p) = self.modules[original_module].parent { | 126 | let m = successors(Some(original_module), |m| self.modules[*m].parent) |
116 | PerNs::types(ModuleId { krate: self.krate, local_id: p }.into()) | 127 | .nth(lvl as usize); |
128 | if let Some(local_id) = m { | ||
129 | PerNs::types(ModuleId { krate: self.krate, local_id }.into()) | ||
117 | } else { | 130 | } else { |
118 | log::debug!("super path in root module"); | 131 | log::debug!("super path in root module"); |
119 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | 132 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); |
@@ -125,18 +138,13 @@ impl CrateDefMap { | |||
125 | Some((_, segment)) => segment, | 138 | Some((_, segment)) => segment, |
126 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 139 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
127 | }; | 140 | }; |
128 | if let Some(def) = self.extern_prelude.get(&segment.name) { | 141 | if let Some(def) = self.extern_prelude.get(&segment) { |
129 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); | 142 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); |
130 | PerNs::types(*def) | 143 | PerNs::types(*def) |
131 | } else { | 144 | } else { |
132 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | 145 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude |
133 | } | 146 | } |
134 | } | 147 | } |
135 | PathKind::Type(_) => { | ||
136 | // This is handled in `infer::infer_path_expr` | ||
137 | // The result returned here does not matter | ||
138 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
139 | } | ||
140 | }; | 148 | }; |
141 | 149 | ||
142 | for (i, segment) in segments { | 150 | for (i, segment) in segments { |
@@ -156,32 +164,29 @@ impl CrateDefMap { | |||
156 | curr_per_ns = match curr { | 164 | curr_per_ns = match curr { |
157 | ModuleDefId::ModuleId(module) => { | 165 | ModuleDefId::ModuleId(module) => { |
158 | if module.krate != self.krate { | 166 | if module.krate != self.krate { |
159 | let path = | 167 | let path = ModPath { |
160 | Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; | 168 | segments: path.segments[i..].to_vec(), |
169 | kind: PathKind::Super(0), | ||
170 | }; | ||
161 | log::debug!("resolving {:?} in other crate", path); | 171 | log::debug!("resolving {:?} in other crate", path); |
162 | let defp_map = db.crate_def_map(module.krate); | 172 | let defp_map = db.crate_def_map(module.krate); |
163 | let (def, s) = defp_map.resolve_path(db, module.local_id, &path); | 173 | let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); |
164 | return ResolvePathResult::with( | 174 | return ResolvePathResult::with( |
165 | def, | 175 | def, |
166 | ReachedFixedPoint::Yes, | 176 | ReachedFixedPoint::Yes, |
167 | s.map(|s| s + i), | 177 | s.map(|s| s + i), |
178 | Some(module.krate), | ||
168 | ); | 179 | ); |
169 | } | 180 | } |
170 | 181 | ||
171 | // Since it is a qualified path here, it should not contains legacy macros | 182 | // Since it is a qualified path here, it should not contains legacy macros |
172 | match self[module.local_id].scope.get(&segment.name) { | 183 | self[module.local_id].scope.get(&segment, prefer_module(i)) |
173 | Some(res) => res.def, | ||
174 | _ => { | ||
175 | log::debug!("path segment {:?} not found", segment.name); | ||
176 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
177 | } | ||
178 | } | ||
179 | } | 184 | } |
180 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { | 185 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { |
181 | // enum variant | 186 | // enum variant |
182 | tested_by!(can_import_enum_variant); | 187 | tested_by!(can_import_enum_variant); |
183 | let enum_data = db.enum_data(e); | 188 | let enum_data = db.enum_data(e); |
184 | match enum_data.variant(&segment.name) { | 189 | match enum_data.variant(&segment) { |
185 | Some(local_id) => { | 190 | Some(local_id) => { |
186 | let variant = EnumVariantId { parent: e, local_id }; | 191 | let variant = EnumVariantId { parent: e, local_id }; |
187 | PerNs::both(variant.into(), variant.into()) | 192 | PerNs::both(variant.into(), variant.into()) |
@@ -191,6 +196,7 @@ impl CrateDefMap { | |||
191 | PerNs::types(e.into()), | 196 | PerNs::types(e.into()), |
192 | ReachedFixedPoint::Yes, | 197 | ReachedFixedPoint::Yes, |
193 | Some(i), | 198 | Some(i), |
199 | Some(self.krate), | ||
194 | ); | 200 | ); |
195 | } | 201 | } |
196 | } | 202 | } |
@@ -200,7 +206,7 @@ impl CrateDefMap { | |||
200 | // (`Struct::method`), or some other kind of associated item | 206 | // (`Struct::method`), or some other kind of associated item |
201 | log::debug!( | 207 | log::debug!( |
202 | "path segment {:?} resolved to non-module {:?}, but is not last", | 208 | "path segment {:?} resolved to non-module {:?}, but is not last", |
203 | segment.name, | 209 | segment, |
204 | curr, | 210 | curr, |
205 | ); | 211 | ); |
206 | 212 | ||
@@ -208,11 +214,13 @@ impl CrateDefMap { | |||
208 | PerNs::types(s), | 214 | PerNs::types(s), |
209 | ReachedFixedPoint::Yes, | 215 | ReachedFixedPoint::Yes, |
210 | Some(i), | 216 | Some(i), |
217 | Some(self.krate), | ||
211 | ); | 218 | ); |
212 | } | 219 | } |
213 | }; | 220 | }; |
214 | } | 221 | } |
215 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) | 222 | |
223 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate)) | ||
216 | } | 224 | } |
217 | 225 | ||
218 | fn resolve_name_in_module( | 226 | fn resolve_name_in_module( |
@@ -220,6 +228,7 @@ impl CrateDefMap { | |||
220 | db: &impl DefDatabase, | 228 | db: &impl DefDatabase, |
221 | module: LocalModuleId, | 229 | module: LocalModuleId, |
222 | name: &Name, | 230 | name: &Name, |
231 | shadow: BuiltinShadowMode, | ||
223 | ) -> PerNs { | 232 | ) -> PerNs { |
224 | // Resolve in: | 233 | // Resolve in: |
225 | // - legacy scope of macro | 234 | // - legacy scope of macro |
@@ -228,23 +237,31 @@ impl CrateDefMap { | |||
228 | // - std prelude | 237 | // - std prelude |
229 | let from_legacy_macro = | 238 | let from_legacy_macro = |
230 | self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); | 239 | self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); |
231 | let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def); | 240 | let from_scope = self[module].scope.get(name, shadow); |
232 | let from_extern_prelude = | 241 | let from_extern_prelude = |
233 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | 242 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); |
234 | let from_prelude = self.resolve_in_prelude(db, name); | 243 | let from_prelude = self.resolve_in_prelude(db, name, shadow); |
235 | 244 | ||
236 | from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) | 245 | from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) |
237 | } | 246 | } |
238 | 247 | ||
239 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { | 248 | fn resolve_name_in_crate_root_or_extern_prelude( |
240 | let from_crate_root = | 249 | &self, |
241 | self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def); | 250 | name: &Name, |
251 | shadow: BuiltinShadowMode, | ||
252 | ) -> PerNs { | ||
253 | let from_crate_root = self[self.root].scope.get(name, shadow); | ||
242 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); | 254 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); |
243 | 255 | ||
244 | from_crate_root.or(from_extern_prelude) | 256 | from_crate_root.or(from_extern_prelude) |
245 | } | 257 | } |
246 | 258 | ||
247 | fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs { | 259 | fn resolve_in_prelude( |
260 | &self, | ||
261 | db: &impl DefDatabase, | ||
262 | name: &Name, | ||
263 | shadow: BuiltinShadowMode, | ||
264 | ) -> PerNs { | ||
248 | if let Some(prelude) = self.prelude { | 265 | if let Some(prelude) = self.prelude { |
249 | let keep; | 266 | let keep; |
250 | let def_map = if prelude.krate == self.krate { | 267 | let def_map = if prelude.krate == self.krate { |
@@ -254,7 +271,7 @@ impl CrateDefMap { | |||
254 | keep = db.crate_def_map(prelude.krate); | 271 | keep = db.crate_def_map(prelude.krate); |
255 | &keep | 272 | &keep |
256 | }; | 273 | }; |
257 | def_map[prelude.local_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) | 274 | def_map[prelude.local_id].scope.get(name, shadow) |
258 | } else { | 275 | } else { |
259 | PerNs::none() | 276 | PerNs::none() |
260 | } | 277 | } |
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 6eb106094..73dc08745 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs | |||
@@ -10,21 +10,18 @@ use std::{ops::Index, sync::Arc}; | |||
10 | use hir_expand::{ | 10 | use hir_expand::{ |
11 | ast_id_map::AstIdMap, | 11 | ast_id_map::AstIdMap, |
12 | db::AstDatabase, | 12 | db::AstDatabase, |
13 | either::Either, | ||
14 | hygiene::Hygiene, | 13 | hygiene::Hygiene, |
15 | name::{AsName, Name}, | 14 | name::{AsName, Name}, |
16 | }; | 15 | }; |
17 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | 16 | use ra_arena::{impl_arena_id, Arena, RawId}; |
17 | use ra_prof::profile; | ||
18 | use ra_syntax::{ | 18 | use ra_syntax::{ |
19 | ast::{self, AttrsOwner, NameOwner}, | 19 | ast::{self, AttrsOwner, NameOwner}, |
20 | AstNode, AstPtr, | 20 | AstNode, |
21 | }; | 21 | }; |
22 | use test_utils::tested_by; | 22 | use test_utils::tested_by; |
23 | 23 | ||
24 | use crate::{ | 24 | use crate::{attr::Attrs, db::DefDatabase, path::ModPath, FileAstId, HirFileId, InFile}; |
25 | attr::Attrs, db::DefDatabase, path::Path, trace::Trace, FileAstId, HirFileId, LocalImportId, | ||
26 | Source, | ||
27 | }; | ||
28 | 25 | ||
29 | /// `RawItems` is a set of top-level items in a file (except for impls). | 26 | /// `RawItems` is a set of top-level items in a file (except for impls). |
30 | /// | 27 | /// |
@@ -33,7 +30,7 @@ use crate::{ | |||
33 | #[derive(Debug, Default, PartialEq, Eq)] | 30 | #[derive(Debug, Default, PartialEq, Eq)] |
34 | pub struct RawItems { | 31 | pub struct RawItems { |
35 | modules: Arena<Module, ModuleData>, | 32 | modules: Arena<Module, ModuleData>, |
36 | imports: Arena<LocalImportId, ImportData>, | 33 | imports: Arena<Import, ImportData>, |
37 | defs: Arena<Def, DefData>, | 34 | defs: Arena<Def, DefData>, |
38 | macros: Arena<Macro, MacroData>, | 35 | macros: Arena<Macro, MacroData>, |
39 | impls: Arena<Impl, ImplData>, | 36 | impls: Arena<Impl, ImplData>, |
@@ -41,35 +38,15 @@ pub struct RawItems { | |||
41 | items: Vec<RawItem>, | 38 | items: Vec<RawItem>, |
42 | } | 39 | } |
43 | 40 | ||
44 | #[derive(Debug, Default, PartialEq, Eq)] | ||
45 | pub struct ImportSourceMap { | ||
46 | map: ArenaMap<LocalImportId, ImportSourcePtr>, | ||
47 | } | ||
48 | |||
49 | type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>; | ||
50 | |||
51 | impl ImportSourceMap { | ||
52 | pub fn get(&self, import: LocalImportId) -> ImportSourcePtr { | ||
53 | self.map[import].clone() | ||
54 | } | ||
55 | } | ||
56 | |||
57 | impl RawItems { | 41 | impl RawItems { |
58 | pub(crate) fn raw_items_query( | 42 | pub(crate) fn raw_items_query( |
59 | db: &(impl DefDatabase + AstDatabase), | 43 | db: &(impl DefDatabase + AstDatabase), |
60 | file_id: HirFileId, | 44 | file_id: HirFileId, |
61 | ) -> Arc<RawItems> { | 45 | ) -> Arc<RawItems> { |
62 | db.raw_items_with_source_map(file_id).0 | 46 | let _p = profile("raw_items_query"); |
63 | } | ||
64 | |||
65 | pub(crate) fn raw_items_with_source_map_query( | ||
66 | db: &(impl DefDatabase + AstDatabase), | ||
67 | file_id: HirFileId, | ||
68 | ) -> (Arc<RawItems>, Arc<ImportSourceMap>) { | ||
69 | let mut collector = RawItemsCollector { | 47 | let mut collector = RawItemsCollector { |
70 | raw_items: RawItems::default(), | 48 | raw_items: RawItems::default(), |
71 | source_ast_id_map: db.ast_id_map(file_id), | 49 | source_ast_id_map: db.ast_id_map(file_id), |
72 | imports: Trace::new(), | ||
73 | file_id, | 50 | file_id, |
74 | hygiene: Hygiene::new(db, file_id), | 51 | hygiene: Hygiene::new(db, file_id), |
75 | }; | 52 | }; |
@@ -80,11 +57,8 @@ impl RawItems { | |||
80 | collector.process_module(None, item_list); | 57 | collector.process_module(None, item_list); |
81 | } | 58 | } |
82 | } | 59 | } |
83 | let mut raw_items = collector.raw_items; | 60 | let raw_items = collector.raw_items; |
84 | let (arena, map) = collector.imports.into_arena_and_map(); | 61 | Arc::new(raw_items) |
85 | raw_items.imports = arena; | ||
86 | let source_map = ImportSourceMap { map }; | ||
87 | (Arc::new(raw_items), Arc::new(source_map)) | ||
88 | } | 62 | } |
89 | 63 | ||
90 | pub(super) fn items(&self) -> &[RawItem] { | 64 | pub(super) fn items(&self) -> &[RawItem] { |
@@ -99,9 +73,9 @@ impl Index<Module> for RawItems { | |||
99 | } | 73 | } |
100 | } | 74 | } |
101 | 75 | ||
102 | impl Index<LocalImportId> for RawItems { | 76 | impl Index<Import> for RawItems { |
103 | type Output = ImportData; | 77 | type Output = ImportData; |
104 | fn index(&self, idx: LocalImportId) -> &ImportData { | 78 | fn index(&self, idx: Import) -> &ImportData { |
105 | &self.imports[idx] | 79 | &self.imports[idx] |
106 | } | 80 | } |
107 | } | 81 | } |
@@ -136,7 +110,7 @@ pub(super) struct RawItem { | |||
136 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 110 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
137 | pub(super) enum RawItemKind { | 111 | pub(super) enum RawItemKind { |
138 | Module(Module), | 112 | Module(Module), |
139 | Import(LocalImportId), | 113 | Import(Import), |
140 | Def(Def), | 114 | Def(Def), |
141 | Macro(Macro), | 115 | Macro(Macro), |
142 | Impl(Impl), | 116 | Impl(Impl), |
@@ -152,9 +126,13 @@ pub(super) enum ModuleData { | |||
152 | Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, | 126 | Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, |
153 | } | 127 | } |
154 | 128 | ||
129 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
130 | pub(crate) struct Import(RawId); | ||
131 | impl_arena_id!(Import); | ||
132 | |||
155 | #[derive(Debug, Clone, PartialEq, Eq)] | 133 | #[derive(Debug, Clone, PartialEq, Eq)] |
156 | pub struct ImportData { | 134 | pub struct ImportData { |
157 | pub(super) path: Path, | 135 | pub(super) path: ModPath, |
158 | pub(super) alias: Option<Name>, | 136 | pub(super) alias: Option<Name>, |
159 | pub(super) is_glob: bool, | 137 | pub(super) is_glob: bool, |
160 | pub(super) is_prelude: bool, | 138 | pub(super) is_prelude: bool, |
@@ -184,6 +162,21 @@ pub(super) enum DefKind { | |||
184 | TypeAlias(FileAstId<ast::TypeAliasDef>), | 162 | TypeAlias(FileAstId<ast::TypeAliasDef>), |
185 | } | 163 | } |
186 | 164 | ||
165 | impl DefKind { | ||
166 | pub fn ast_id(&self) -> FileAstId<ast::ModuleItem> { | ||
167 | match self { | ||
168 | DefKind::Function(it) => it.upcast(), | ||
169 | DefKind::Struct(it) => it.upcast(), | ||
170 | DefKind::Union(it) => it.upcast(), | ||
171 | DefKind::Enum(it) => it.upcast(), | ||
172 | DefKind::Const(it) => it.upcast(), | ||
173 | DefKind::Static(it) => it.upcast(), | ||
174 | DefKind::Trait(it) => it.upcast(), | ||
175 | DefKind::TypeAlias(it) => it.upcast(), | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
187 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 180 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
188 | pub(super) struct Macro(RawId); | 181 | pub(super) struct Macro(RawId); |
189 | impl_arena_id!(Macro); | 182 | impl_arena_id!(Macro); |
@@ -191,7 +184,7 @@ impl_arena_id!(Macro); | |||
191 | #[derive(Debug, PartialEq, Eq)] | 184 | #[derive(Debug, PartialEq, Eq)] |
192 | pub(super) struct MacroData { | 185 | pub(super) struct MacroData { |
193 | pub(super) ast_id: FileAstId<ast::MacroCall>, | 186 | pub(super) ast_id: FileAstId<ast::MacroCall>, |
194 | pub(super) path: Path, | 187 | pub(super) path: ModPath, |
195 | pub(super) name: Option<Name>, | 188 | pub(super) name: Option<Name>, |
196 | pub(super) export: bool, | 189 | pub(super) export: bool, |
197 | pub(super) builtin: bool, | 190 | pub(super) builtin: bool, |
@@ -208,7 +201,6 @@ pub(super) struct ImplData { | |||
208 | 201 | ||
209 | struct RawItemsCollector { | 202 | struct RawItemsCollector { |
210 | raw_items: RawItems, | 203 | raw_items: RawItems, |
211 | imports: Trace<LocalImportId, ImportData, ImportSourcePtr>, | ||
212 | source_ast_id_map: Arc<AstIdMap>, | 204 | source_ast_id_map: Arc<AstIdMap>, |
213 | file_id: HirFileId, | 205 | file_id: HirFileId, |
214 | hygiene: Hygiene, | 206 | hygiene: Hygiene, |
@@ -312,10 +304,10 @@ impl RawItemsCollector { | |||
312 | let attrs = self.parse_attrs(&use_item); | 304 | let attrs = self.parse_attrs(&use_item); |
313 | 305 | ||
314 | let mut buf = Vec::new(); | 306 | let mut buf = Vec::new(); |
315 | Path::expand_use_item( | 307 | ModPath::expand_use_item( |
316 | Source { value: use_item, file_id: self.file_id }, | 308 | InFile { value: use_item, file_id: self.file_id }, |
317 | &self.hygiene, | 309 | &self.hygiene, |
318 | |path, use_tree, is_glob, alias| { | 310 | |path, _use_tree, is_glob, alias| { |
319 | let import_data = ImportData { | 311 | let import_data = ImportData { |
320 | path, | 312 | path, |
321 | alias, | 313 | alias, |
@@ -324,11 +316,11 @@ impl RawItemsCollector { | |||
324 | is_extern_crate: false, | 316 | is_extern_crate: false, |
325 | is_macro_use: false, | 317 | is_macro_use: false, |
326 | }; | 318 | }; |
327 | buf.push((import_data, Either::A(AstPtr::new(use_tree)))); | 319 | buf.push(import_data); |
328 | }, | 320 | }, |
329 | ); | 321 | ); |
330 | for (import_data, ptr) in buf { | 322 | for import_data in buf { |
331 | self.push_import(current_module, attrs.clone(), import_data, ptr); | 323 | self.push_import(current_module, attrs.clone(), import_data); |
332 | } | 324 | } |
333 | } | 325 | } |
334 | 326 | ||
@@ -338,7 +330,7 @@ impl RawItemsCollector { | |||
338 | extern_crate: ast::ExternCrateItem, | 330 | extern_crate: ast::ExternCrateItem, |
339 | ) { | 331 | ) { |
340 | if let Some(name_ref) = extern_crate.name_ref() { | 332 | if let Some(name_ref) = extern_crate.name_ref() { |
341 | let path = Path::from_name_ref(&name_ref); | 333 | let path = ModPath::from_name_ref(&name_ref); |
342 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); | 334 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); |
343 | let attrs = self.parse_attrs(&extern_crate); | 335 | let attrs = self.parse_attrs(&extern_crate); |
344 | // FIXME: cfg_attr | 336 | // FIXME: cfg_attr |
@@ -351,18 +343,13 @@ impl RawItemsCollector { | |||
351 | is_extern_crate: true, | 343 | is_extern_crate: true, |
352 | is_macro_use, | 344 | is_macro_use, |
353 | }; | 345 | }; |
354 | self.push_import( | 346 | self.push_import(current_module, attrs, import_data); |
355 | current_module, | ||
356 | attrs, | ||
357 | import_data, | ||
358 | Either::B(AstPtr::new(&extern_crate)), | ||
359 | ); | ||
360 | } | 347 | } |
361 | } | 348 | } |
362 | 349 | ||
363 | fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { | 350 | fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { |
364 | let attrs = self.parse_attrs(&m); | 351 | let attrs = self.parse_attrs(&m); |
365 | let path = match m.path().and_then(|path| Path::from_src(path, &self.hygiene)) { | 352 | let path = match m.path().and_then(|path| ModPath::from_src(path, &self.hygiene)) { |
366 | Some(it) => it, | 353 | Some(it) => it, |
367 | _ => return, | 354 | _ => return, |
368 | }; | 355 | }; |
@@ -387,14 +374,8 @@ impl RawItemsCollector { | |||
387 | self.push_item(current_module, attrs, RawItemKind::Impl(imp)) | 374 | self.push_item(current_module, attrs, RawItemKind::Impl(imp)) |
388 | } | 375 | } |
389 | 376 | ||
390 | fn push_import( | 377 | fn push_import(&mut self, current_module: Option<Module>, attrs: Attrs, data: ImportData) { |
391 | &mut self, | 378 | let import = self.raw_items.imports.alloc(data); |
392 | current_module: Option<Module>, | ||
393 | attrs: Attrs, | ||
394 | data: ImportData, | ||
395 | source: ImportSourcePtr, | ||
396 | ) { | ||
397 | let import = self.imports.alloc(|| source, || data); | ||
398 | self.push_item(current_module, attrs, RawItemKind::Import(import)) | 379 | self.push_item(current_module, attrs, RawItemKind::Import(import)) |
399 | } | 380 | } |
400 | 381 | ||
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs index 87fcd617c..ff474b53b 100644 --- a/crates/ra_hir_def/src/nameres/tests.rs +++ b/crates/ra_hir_def/src/nameres/tests.rs | |||
@@ -32,27 +32,22 @@ fn render_crate_def_map(map: &CrateDefMap) -> String { | |||
32 | *buf += path; | 32 | *buf += path; |
33 | *buf += "\n"; | 33 | *buf += "\n"; |
34 | 34 | ||
35 | let mut entries = map.modules[module] | 35 | let mut entries = map.modules[module].scope.collect_resolutions(); |
36 | .scope | 36 | entries.sort_by_key(|(name, _)| name.clone()); |
37 | .items | 37 | |
38 | .iter() | 38 | for (name, def) in entries { |
39 | .map(|(name, res)| (name, res.def)) | ||
40 | .collect::<Vec<_>>(); | ||
41 | entries.sort_by_key(|(name, _)| *name); | ||
42 | |||
43 | for (name, res) in entries { | ||
44 | *buf += &format!("{}:", name); | 39 | *buf += &format!("{}:", name); |
45 | 40 | ||
46 | if res.types.is_some() { | 41 | if def.types.is_some() { |
47 | *buf += " t"; | 42 | *buf += " t"; |
48 | } | 43 | } |
49 | if res.values.is_some() { | 44 | if def.values.is_some() { |
50 | *buf += " v"; | 45 | *buf += " v"; |
51 | } | 46 | } |
52 | if res.macros.is_some() { | 47 | if def.macros.is_some() { |
53 | *buf += " m"; | 48 | *buf += " m"; |
54 | } | 49 | } |
55 | if res.is_none() { | 50 | if def.is_none() { |
56 | *buf += " _"; | 51 | *buf += " _"; |
57 | } | 52 | } |
58 | 53 | ||
@@ -558,3 +553,35 @@ fn cfg_test() { | |||
558 | â‹®Foo: t v | 553 | â‹®Foo: t v |
559 | "###); | 554 | "###); |
560 | } | 555 | } |
556 | |||
557 | #[test] | ||
558 | fn infer_multiple_namespace() { | ||
559 | let map = def_map( | ||
560 | r#" | ||
561 | //- /main.rs | ||
562 | mod a { | ||
563 | pub type T = (); | ||
564 | pub use crate::b::*; | ||
565 | } | ||
566 | |||
567 | use crate::a::T; | ||
568 | |||
569 | mod b { | ||
570 | pub const T: () = (); | ||
571 | } | ||
572 | "#, | ||
573 | ); | ||
574 | |||
575 | assert_snapshot!(map, @r###" | ||
576 | â‹®crate | ||
577 | â‹®T: t v | ||
578 | â‹®a: t | ||
579 | â‹®b: t | ||
580 | â‹® | ||
581 | â‹®crate::b | ||
582 | â‹®T: v | ||
583 | â‹® | ||
584 | â‹®crate::a | ||
585 | â‹®T: t v | ||
586 | "###); | ||
587 | } | ||
diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs index 5b03fe365..5e24cb94d 100644 --- a/crates/ra_hir_def/src/nameres/tests/globs.rs +++ b/crates/ra_hir_def/src/nameres/tests/globs.rs | |||
@@ -112,3 +112,24 @@ fn glob_enum() { | |||
112 | "### | 112 | "### |
113 | ); | 113 | ); |
114 | } | 114 | } |
115 | |||
116 | #[test] | ||
117 | fn glob_enum_group() { | ||
118 | covers!(glob_enum_group); | ||
119 | let map = def_map( | ||
120 | " | ||
121 | //- /lib.rs | ||
122 | enum Foo { | ||
123 | Bar, Baz | ||
124 | } | ||
125 | use self::Foo::{*}; | ||
126 | ", | ||
127 | ); | ||
128 | assert_snapshot!(map, @r###" | ||
129 | â‹®crate | ||
130 | â‹®Bar: t v | ||
131 | â‹®Baz: t v | ||
132 | â‹®Foo: t | ||
133 | "### | ||
134 | ); | ||
135 | } | ||
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs index 903a22771..ef2e9435c 100644 --- a/crates/ra_hir_def/src/nameres/tests/incremental.rs +++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs | |||
@@ -116,7 +116,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { | |||
116 | let events = db.log_executed(|| { | 116 | let events = db.log_executed(|| { |
117 | let crate_def_map = db.crate_def_map(krate); | 117 | let crate_def_map = db.crate_def_map(krate); |
118 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | 118 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); |
119 | assert_eq!(module_data.scope.items.len(), 1); | 119 | assert_eq!(module_data.scope.collect_resolutions().len(), 1); |
120 | }); | 120 | }); |
121 | assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) | 121 | assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) |
122 | } | 122 | } |
@@ -126,7 +126,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { | |||
126 | let events = db.log_executed(|| { | 126 | let events = db.log_executed(|| { |
127 | let crate_def_map = db.crate_def_map(krate); | 127 | let crate_def_map = db.crate_def_map(krate); |
128 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | 128 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); |
129 | assert_eq!(module_data.scope.items.len(), 1); | 129 | assert_eq!(module_data.scope.collect_resolutions().len(), 1); |
130 | }); | 130 | }); |
131 | assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) | 131 | assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) |
132 | } | 132 | } |
diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs index 704065633..d104f5993 100644 --- a/crates/ra_hir_def/src/nameres/tests/macros.rs +++ b/crates/ra_hir_def/src/nameres/tests/macros.rs | |||
@@ -600,3 +600,27 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() { | |||
600 | â‹®bar: t v | 600 | â‹®bar: t v |
601 | "###); | 601 | "###); |
602 | } | 602 | } |
603 | |||
604 | #[test] | ||
605 | fn expand_derive() { | ||
606 | let map = compute_crate_def_map( | ||
607 | " | ||
608 | //- /main.rs | ||
609 | #[derive(Clone)] | ||
610 | struct Foo; | ||
611 | ", | ||
612 | ); | ||
613 | assert_eq!(map.modules[map.root].scope.impls().len(), 1); | ||
614 | } | ||
615 | |||
616 | #[test] | ||
617 | fn expand_multiple_derive() { | ||
618 | let map = compute_crate_def_map( | ||
619 | " | ||
620 | //- /main.rs | ||
621 | #[derive(Copy, Clone)] | ||
622 | struct Foo; | ||
623 | ", | ||
624 | ); | ||
625 | assert_eq!(map.modules[map.root].scope.impls().len(), 2); | ||
626 | } | ||
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs index e11530062..e800cc68e 100644 --- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs | |||
@@ -668,7 +668,7 @@ fn unresolved_module_diagnostics() { | |||
668 | module: LocalModuleId( | 668 | module: LocalModuleId( |
669 | 0, | 669 | 0, |
670 | ), | 670 | ), |
671 | declaration: AstId { | 671 | declaration: InFile { |
672 | file_id: HirFileId( | 672 | file_id: HirFileId( |
673 | FileId( | 673 | FileId( |
674 | FileId( | 674 | FileId( |
@@ -676,7 +676,7 @@ fn unresolved_module_diagnostics() { | |||
676 | ), | 676 | ), |
677 | ), | 677 | ), |
678 | ), | 678 | ), |
679 | file_ast_id: FileAstId { | 679 | value: FileAstId { |
680 | raw: ErasedFileAstId( | 680 | raw: ErasedFileAstId( |
681 | 1, | 681 | 1, |
682 | ), | 682 | ), |
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 6810a26db..8e1294201 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -1,35 +1,97 @@ | |||
1 | //! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`. | 1 | //! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`. |
2 | mod lower; | ||
2 | 3 | ||
3 | use std::{iter, sync::Arc}; | 4 | use std::{iter, sync::Arc}; |
4 | 5 | ||
5 | use hir_expand::{ | 6 | use hir_expand::{ |
6 | either::Either, | ||
7 | hygiene::Hygiene, | 7 | hygiene::Hygiene, |
8 | name::{self, AsName, Name}, | 8 | name::{AsName, Name}, |
9 | }; | 9 | }; |
10 | use ra_db::CrateId; | 10 | use ra_db::CrateId; |
11 | use ra_syntax::{ | 11 | use ra_syntax::ast; |
12 | ast::{self, NameOwner, TypeAscriptionOwner}, | ||
13 | AstNode, | ||
14 | }; | ||
15 | 12 | ||
16 | use crate::{type_ref::TypeRef, Source}; | 13 | use crate::{type_ref::TypeRef, InFile}; |
17 | 14 | ||
18 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 15 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
19 | pub struct Path { | 16 | pub struct ModPath { |
20 | pub kind: PathKind, | 17 | pub kind: PathKind, |
21 | pub segments: Vec<PathSegment>, | 18 | pub segments: Vec<Name>, |
22 | } | 19 | } |
23 | 20 | ||
24 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 21 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
25 | pub struct PathSegment { | 22 | pub enum PathKind { |
26 | pub name: Name, | 23 | Plain, |
27 | pub args_and_bindings: Option<Arc<GenericArgs>>, | 24 | /// `self::` is `Super(0)` |
25 | Super(u8), | ||
26 | Crate, | ||
27 | /// Absolute path (::foo) | ||
28 | Abs, | ||
29 | /// `$crate` from macro expansion | ||
30 | DollarCrate(CrateId), | ||
31 | } | ||
32 | |||
33 | impl ModPath { | ||
34 | pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { | ||
35 | lower::lower_path(path, hygiene).map(|it| it.mod_path) | ||
36 | } | ||
37 | |||
38 | pub fn from_simple_segments( | ||
39 | kind: PathKind, | ||
40 | segments: impl IntoIterator<Item = Name>, | ||
41 | ) -> ModPath { | ||
42 | let segments = segments.into_iter().collect::<Vec<_>>(); | ||
43 | ModPath { kind, segments } | ||
44 | } | ||
45 | |||
46 | pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> ModPath { | ||
47 | name_ref.as_name().into() | ||
48 | } | ||
49 | |||
50 | /// Converts an `tt::Ident` into a single-identifier `Path`. | ||
51 | pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath { | ||
52 | ident.as_name().into() | ||
53 | } | ||
54 | |||
55 | /// Calls `cb` with all paths, represented by this use item. | ||
56 | pub(crate) fn expand_use_item( | ||
57 | item_src: InFile<ast::UseItem>, | ||
58 | hygiene: &Hygiene, | ||
59 | mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<Name>), | ||
60 | ) { | ||
61 | if let Some(tree) = item_src.value.use_tree() { | ||
62 | lower::lower_use_tree(None, tree, hygiene, &mut cb); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | pub fn is_ident(&self) -> bool { | ||
67 | self.kind == PathKind::Plain && self.segments.len() == 1 | ||
68 | } | ||
69 | |||
70 | pub fn is_self(&self) -> bool { | ||
71 | self.kind == PathKind::Super(0) && self.segments.is_empty() | ||
72 | } | ||
73 | |||
74 | /// If this path is a single identifier, like `foo`, return its name. | ||
75 | pub fn as_ident(&self) -> Option<&Name> { | ||
76 | if self.kind != PathKind::Plain || self.segments.len() > 1 { | ||
77 | return None; | ||
78 | } | ||
79 | self.segments.first() | ||
80 | } | ||
81 | } | ||
82 | |||
83 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
84 | pub struct Path { | ||
85 | /// Type based path like `<T>::foo`. | ||
86 | /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`. | ||
87 | type_anchor: Option<Box<TypeRef>>, | ||
88 | mod_path: ModPath, | ||
89 | /// Invariant: the same len as self.path.segments | ||
90 | generic_args: Vec<Option<Arc<GenericArgs>>>, | ||
28 | } | 91 | } |
29 | 92 | ||
30 | /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This | 93 | /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This |
31 | /// can (in the future) also include bindings of associated types, like in | 94 | /// also includes bindings of associated types, like in `Iterator<Item = Foo>`. |
32 | /// `Iterator<Item = Foo>`. | ||
33 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 95 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
34 | pub struct GenericArgs { | 96 | pub struct GenericArgs { |
35 | pub args: Vec<GenericArg>, | 97 | pub args: Vec<GenericArg>, |
@@ -50,234 +112,111 @@ pub enum GenericArg { | |||
50 | // or lifetime... | 112 | // or lifetime... |
51 | } | 113 | } |
52 | 114 | ||
53 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
54 | pub enum PathKind { | ||
55 | Plain, | ||
56 | Self_, | ||
57 | Super, | ||
58 | Crate, | ||
59 | // Absolute path | ||
60 | Abs, | ||
61 | // Type based path like `<T>::foo` | ||
62 | Type(Box<TypeRef>), | ||
63 | // `$crate` from macro expansion | ||
64 | DollarCrate(CrateId), | ||
65 | } | ||
66 | |||
67 | impl Path { | 115 | impl Path { |
68 | /// Calls `cb` with all paths, represented by this use item. | ||
69 | pub(crate) fn expand_use_item( | ||
70 | item_src: Source<ast::UseItem>, | ||
71 | hygiene: &Hygiene, | ||
72 | mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>), | ||
73 | ) { | ||
74 | if let Some(tree) = item_src.value.use_tree() { | ||
75 | expand_use_tree(None, tree, hygiene, &mut cb); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | pub(crate) fn from_simple_segments( | ||
80 | kind: PathKind, | ||
81 | segments: impl IntoIterator<Item = Name>, | ||
82 | ) -> Path { | ||
83 | Path { | ||
84 | kind, | ||
85 | segments: segments | ||
86 | .into_iter() | ||
87 | .map(|name| PathSegment { name, args_and_bindings: None }) | ||
88 | .collect(), | ||
89 | } | ||
90 | } | ||
91 | |||
92 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 116 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
93 | /// DEPRECATED: It does not handle `$crate` from macro call. | 117 | /// DEPRECATED: It does not handle `$crate` from macro call. |
94 | pub fn from_ast(path: ast::Path) -> Option<Path> { | 118 | pub fn from_ast(path: ast::Path) -> Option<Path> { |
95 | Path::from_src(path, &Hygiene::new_unhygienic()) | 119 | lower::lower_path(path, &Hygiene::new_unhygienic()) |
96 | } | 120 | } |
97 | 121 | ||
98 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 122 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
99 | /// It correctly handles `$crate` based path from macro call. | 123 | /// It correctly handles `$crate` based path from macro call. |
100 | pub fn from_src(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> { | 124 | pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> { |
101 | let mut kind = PathKind::Plain; | 125 | lower::lower_path(path, hygiene) |
102 | let mut segments = Vec::new(); | ||
103 | loop { | ||
104 | let segment = path.segment()?; | ||
105 | |||
106 | if segment.has_colon_colon() { | ||
107 | kind = PathKind::Abs; | ||
108 | } | ||
109 | |||
110 | match segment.kind()? { | ||
111 | ast::PathSegmentKind::Name(name_ref) => { | ||
112 | // FIXME: this should just return name | ||
113 | match hygiene.name_ref_to_name(name_ref) { | ||
114 | Either::A(name) => { | ||
115 | let args = segment | ||
116 | .type_arg_list() | ||
117 | .and_then(GenericArgs::from_ast) | ||
118 | .or_else(|| { | ||
119 | GenericArgs::from_fn_like_path_ast( | ||
120 | segment.param_list(), | ||
121 | segment.ret_type(), | ||
122 | ) | ||
123 | }) | ||
124 | .map(Arc::new); | ||
125 | let segment = PathSegment { name, args_and_bindings: args }; | ||
126 | segments.push(segment); | ||
127 | } | ||
128 | Either::B(crate_id) => { | ||
129 | kind = PathKind::DollarCrate(crate_id); | ||
130 | break; | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { | ||
135 | assert!(path.qualifier().is_none()); // this can only occur at the first segment | ||
136 | |||
137 | let self_type = TypeRef::from_ast(type_ref?); | ||
138 | |||
139 | match trait_ref { | ||
140 | // <T>::foo | ||
141 | None => { | ||
142 | kind = PathKind::Type(Box::new(self_type)); | ||
143 | } | ||
144 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | ||
145 | Some(trait_ref) => { | ||
146 | let path = Path::from_src(trait_ref.path()?, hygiene)?; | ||
147 | kind = path.kind; | ||
148 | let mut prefix_segments = path.segments; | ||
149 | prefix_segments.reverse(); | ||
150 | segments.extend(prefix_segments); | ||
151 | // Insert the type reference (T in the above example) as Self parameter for the trait | ||
152 | let mut last_segment = segments.last_mut()?; | ||
153 | if last_segment.args_and_bindings.is_none() { | ||
154 | last_segment.args_and_bindings = | ||
155 | Some(Arc::new(GenericArgs::empty())); | ||
156 | }; | ||
157 | let args = last_segment.args_and_bindings.as_mut().unwrap(); | ||
158 | let mut args_inner = Arc::make_mut(args); | ||
159 | args_inner.has_self_type = true; | ||
160 | args_inner.args.insert(0, GenericArg::Type(self_type)); | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | ast::PathSegmentKind::CrateKw => { | ||
165 | kind = PathKind::Crate; | ||
166 | break; | ||
167 | } | ||
168 | ast::PathSegmentKind::SelfKw => { | ||
169 | kind = PathKind::Self_; | ||
170 | break; | ||
171 | } | ||
172 | ast::PathSegmentKind::SuperKw => { | ||
173 | kind = PathKind::Super; | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | path = match qualifier(&path) { | ||
178 | Some(it) => it, | ||
179 | None => break, | ||
180 | }; | ||
181 | } | ||
182 | segments.reverse(); | ||
183 | return Some(Path { kind, segments }); | ||
184 | |||
185 | fn qualifier(path: &ast::Path) -> Option<ast::Path> { | ||
186 | if let Some(q) = path.qualifier() { | ||
187 | return Some(q); | ||
188 | } | ||
189 | // FIXME: this bottom up traversal is not too precise. | ||
190 | // Should we handle do a top-down analysis, recording results? | ||
191 | let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; | ||
192 | let use_tree = use_tree_list.parent_use_tree(); | ||
193 | use_tree.path() | ||
194 | } | ||
195 | } | 126 | } |
196 | 127 | ||
197 | /// Converts an `ast::NameRef` into a single-identifier `Path`. | 128 | /// Converts an `ast::NameRef` into a single-identifier `Path`. |
198 | pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path { | 129 | pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path { |
199 | name_ref.as_name().into() | 130 | Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] } |
200 | } | 131 | } |
201 | 132 | ||
202 | /// `true` is this path is a single identifier, like `foo` | 133 | pub fn kind(&self) -> &PathKind { |
203 | pub fn is_ident(&self) -> bool { | 134 | &self.mod_path.kind |
204 | self.kind == PathKind::Plain && self.segments.len() == 1 | ||
205 | } | 135 | } |
206 | 136 | ||
207 | /// `true` if this path is just a standalone `self` | 137 | pub fn type_anchor(&self) -> Option<&TypeRef> { |
208 | pub fn is_self(&self) -> bool { | 138 | self.type_anchor.as_deref() |
209 | self.kind == PathKind::Self_ && self.segments.is_empty() | ||
210 | } | 139 | } |
211 | 140 | ||
212 | /// If this path is a single identifier, like `foo`, return its name. | 141 | pub fn segments(&self) -> PathSegments<'_> { |
213 | pub fn as_ident(&self) -> Option<&Name> { | 142 | PathSegments { |
214 | if self.kind != PathKind::Plain || self.segments.len() > 1 { | 143 | segments: self.mod_path.segments.as_slice(), |
215 | return None; | 144 | generic_args: self.generic_args.as_slice(), |
216 | } | 145 | } |
217 | self.segments.first().map(|s| &s.name) | ||
218 | } | 146 | } |
219 | 147 | ||
220 | pub fn expand_macro_expr(&self) -> Option<Name> { | 148 | pub fn mod_path(&self) -> &ModPath { |
221 | self.as_ident().and_then(|name| Some(name.clone())) | 149 | &self.mod_path |
222 | } | 150 | } |
223 | 151 | ||
224 | pub fn is_type_relative(&self) -> bool { | 152 | pub fn qualifier(&self) -> Option<Path> { |
225 | match self.kind { | 153 | if self.mod_path.is_ident() { |
226 | PathKind::Type(_) => true, | 154 | return None; |
227 | _ => false, | ||
228 | } | 155 | } |
156 | let res = Path { | ||
157 | type_anchor: self.type_anchor.clone(), | ||
158 | mod_path: ModPath { | ||
159 | kind: self.mod_path.kind.clone(), | ||
160 | segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(), | ||
161 | }, | ||
162 | generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(), | ||
163 | }; | ||
164 | Some(res) | ||
229 | } | 165 | } |
230 | } | 166 | } |
231 | 167 | ||
232 | impl GenericArgs { | 168 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
233 | pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> { | 169 | pub struct PathSegment<'a> { |
234 | let mut args = Vec::new(); | 170 | pub name: &'a Name, |
235 | for type_arg in node.type_args() { | 171 | pub args_and_bindings: Option<&'a GenericArgs>, |
236 | let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); | 172 | } |
237 | args.push(GenericArg::Type(type_ref)); | 173 | |
238 | } | 174 | pub struct PathSegments<'a> { |
239 | // lifetimes ignored for now | 175 | segments: &'a [Name], |
240 | let mut bindings = Vec::new(); | 176 | generic_args: &'a [Option<Arc<GenericArgs>>], |
241 | for assoc_type_arg in node.assoc_type_args() { | 177 | } |
242 | if let Some(name_ref) = assoc_type_arg.name_ref() { | 178 | |
243 | let name = name_ref.as_name(); | 179 | impl<'a> PathSegments<'a> { |
244 | let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref()); | 180 | pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] }; |
245 | bindings.push((name, type_ref)); | 181 | pub fn is_empty(&self) -> bool { |
246 | } | 182 | self.len() == 0 |
247 | } | 183 | } |
248 | if args.is_empty() && bindings.is_empty() { | 184 | pub fn len(&self) -> usize { |
249 | None | 185 | self.segments.len() |
250 | } else { | 186 | } |
251 | Some(GenericArgs { args, has_self_type: false, bindings }) | 187 | pub fn first(&self) -> Option<PathSegment<'a>> { |
252 | } | 188 | self.get(0) |
189 | } | ||
190 | pub fn last(&self) -> Option<PathSegment<'a>> { | ||
191 | self.get(self.len().checked_sub(1)?) | ||
192 | } | ||
193 | pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> { | ||
194 | assert_eq!(self.segments.len(), self.generic_args.len()); | ||
195 | let res = PathSegment { | ||
196 | name: self.segments.get(idx)?, | ||
197 | args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it), | ||
198 | }; | ||
199 | Some(res) | ||
200 | } | ||
201 | pub fn skip(&self, len: usize) -> PathSegments<'a> { | ||
202 | assert_eq!(self.segments.len(), self.generic_args.len()); | ||
203 | PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] } | ||
204 | } | ||
205 | pub fn take(&self, len: usize) -> PathSegments<'a> { | ||
206 | assert_eq!(self.segments.len(), self.generic_args.len()); | ||
207 | PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] } | ||
208 | } | ||
209 | pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> { | ||
210 | self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment { | ||
211 | name, | ||
212 | args_and_bindings: args.as_ref().map(|it| &**it), | ||
213 | }) | ||
253 | } | 214 | } |
215 | } | ||
254 | 216 | ||
255 | /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) | 217 | impl GenericArgs { |
256 | /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). | 218 | pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> { |
257 | pub(crate) fn from_fn_like_path_ast( | 219 | lower::lower_generic_args(node) |
258 | params: Option<ast::ParamList>, | ||
259 | ret_type: Option<ast::RetType>, | ||
260 | ) -> Option<GenericArgs> { | ||
261 | let mut args = Vec::new(); | ||
262 | let mut bindings = Vec::new(); | ||
263 | if let Some(params) = params { | ||
264 | let mut param_types = Vec::new(); | ||
265 | for param in params.params() { | ||
266 | let type_ref = TypeRef::from_ast_opt(param.ascribed_type()); | ||
267 | param_types.push(type_ref); | ||
268 | } | ||
269 | let arg = GenericArg::Type(TypeRef::Tuple(param_types)); | ||
270 | args.push(arg); | ||
271 | } | ||
272 | if let Some(ret_type) = ret_type { | ||
273 | let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); | ||
274 | bindings.push((name::OUTPUT_TYPE, type_ref)) | ||
275 | } | ||
276 | if args.is_empty() && bindings.is_empty() { | ||
277 | None | ||
278 | } else { | ||
279 | Some(GenericArgs { args, has_self_type: false, bindings }) | ||
280 | } | ||
281 | } | 220 | } |
282 | 221 | ||
283 | pub(crate) fn empty() -> GenericArgs { | 222 | pub(crate) fn empty() -> GenericArgs { |
@@ -287,137 +226,51 @@ impl GenericArgs { | |||
287 | 226 | ||
288 | impl From<Name> for Path { | 227 | impl From<Name> for Path { |
289 | fn from(name: Name) -> Path { | 228 | fn from(name: Name) -> Path { |
290 | Path::from_simple_segments(PathKind::Plain, iter::once(name)) | 229 | Path { |
230 | type_anchor: None, | ||
231 | mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)), | ||
232 | generic_args: vec![None], | ||
233 | } | ||
291 | } | 234 | } |
292 | } | 235 | } |
293 | 236 | ||
294 | fn expand_use_tree( | 237 | impl From<Name> for ModPath { |
295 | prefix: Option<Path>, | 238 | fn from(name: Name) -> ModPath { |
296 | tree: ast::UseTree, | 239 | ModPath::from_simple_segments(PathKind::Plain, iter::once(name)) |
297 | hygiene: &Hygiene, | ||
298 | cb: &mut dyn FnMut(Path, &ast::UseTree, bool, Option<Name>), | ||
299 | ) { | ||
300 | if let Some(use_tree_list) = tree.use_tree_list() { | ||
301 | let prefix = match tree.path() { | ||
302 | // E.g. use something::{{{inner}}}; | ||
303 | None => prefix, | ||
304 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | ||
305 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) | ||
306 | Some(path) => match convert_path(prefix, path, hygiene) { | ||
307 | Some(it) => Some(it), | ||
308 | None => return, // FIXME: report errors somewhere | ||
309 | }, | ||
310 | }; | ||
311 | for child_tree in use_tree_list.use_trees() { | ||
312 | expand_use_tree(prefix.clone(), child_tree, hygiene, cb); | ||
313 | } | ||
314 | } else { | ||
315 | let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); | ||
316 | if let Some(ast_path) = tree.path() { | ||
317 | // Handle self in a path. | ||
318 | // E.g. `use something::{self, <...>}` | ||
319 | if ast_path.qualifier().is_none() { | ||
320 | if let Some(segment) = ast_path.segment() { | ||
321 | if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { | ||
322 | if let Some(prefix) = prefix { | ||
323 | cb(prefix, &tree, false, alias); | ||
324 | return; | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | } | ||
329 | if let Some(path) = convert_path(prefix, ast_path, hygiene) { | ||
330 | let is_glob = tree.has_star(); | ||
331 | cb(path, &tree, is_glob, alias) | ||
332 | } | ||
333 | // FIXME: report errors somewhere | ||
334 | // We get here if we do | ||
335 | } | ||
336 | } | 240 | } |
337 | } | 241 | } |
338 | 242 | ||
339 | fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Option<Path> { | 243 | pub use hir_expand::name as __name; |
340 | let prefix = if let Some(qual) = path.qualifier() { | 244 | |
341 | Some(convert_path(prefix, qual, hygiene)?) | 245 | #[macro_export] |
342 | } else { | 246 | macro_rules! __known_path { |
343 | prefix | 247 | (std::iter::IntoIterator) => {}; |
344 | }; | 248 | (std::result::Result) => {}; |
345 | 249 | (std::ops::Range) => {}; | |
346 | let segment = path.segment()?; | 250 | (std::ops::RangeFrom) => {}; |
347 | let res = match segment.kind()? { | 251 | (std::ops::RangeFull) => {}; |
348 | ast::PathSegmentKind::Name(name_ref) => { | 252 | (std::ops::RangeTo) => {}; |
349 | match hygiene.name_ref_to_name(name_ref) { | 253 | (std::ops::RangeToInclusive) => {}; |
350 | Either::A(name) => { | 254 | (std::ops::RangeInclusive) => {}; |
351 | // no type args in use | 255 | (std::boxed::Box) => {}; |
352 | let mut res = prefix.unwrap_or_else(|| Path { | 256 | (std::future::Future) => {}; |
353 | kind: PathKind::Plain, | 257 | (std::ops::Try) => {}; |
354 | segments: Vec::with_capacity(1), | 258 | (std::ops::Neg) => {}; |
355 | }); | 259 | (std::ops::Not) => {}; |
356 | res.segments.push(PathSegment { | 260 | (std::ops::Index) => {}; |
357 | name, | 261 | ($path:path) => { |
358 | args_and_bindings: None, // no type args in use | 262 | compile_error!("Please register your known path in the path module") |
359 | }); | ||
360 | res | ||
361 | } | ||
362 | Either::B(crate_id) => { | ||
363 | return Some(Path::from_simple_segments( | ||
364 | PathKind::DollarCrate(crate_id), | ||
365 | iter::empty(), | ||
366 | )) | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | ast::PathSegmentKind::CrateKw => { | ||
371 | if prefix.is_some() { | ||
372 | return None; | ||
373 | } | ||
374 | Path::from_simple_segments(PathKind::Crate, iter::empty()) | ||
375 | } | ||
376 | ast::PathSegmentKind::SelfKw => { | ||
377 | if prefix.is_some() { | ||
378 | return None; | ||
379 | } | ||
380 | Path::from_simple_segments(PathKind::Self_, iter::empty()) | ||
381 | } | ||
382 | ast::PathSegmentKind::SuperKw => { | ||
383 | if prefix.is_some() { | ||
384 | return None; | ||
385 | } | ||
386 | Path::from_simple_segments(PathKind::Super, iter::empty()) | ||
387 | } | ||
388 | ast::PathSegmentKind::Type { .. } => { | ||
389 | // not allowed in imports | ||
390 | return None; | ||
391 | } | ||
392 | }; | 263 | }; |
393 | Some(res) | ||
394 | } | 264 | } |
395 | 265 | ||
396 | pub mod known { | 266 | #[macro_export] |
397 | use hir_expand::name; | 267 | macro_rules! __path { |
398 | 268 | ($start:ident $(:: $seg:ident)*) => ({ | |
399 | use super::{Path, PathKind}; | 269 | $crate::__known_path!($start $(:: $seg)*); |
400 | 270 | $crate::path::ModPath::from_simple_segments($crate::path::PathKind::Abs, vec![ | |
401 | pub fn std_iter_into_iterator() -> Path { | 271 | $crate::path::__name![$start], $($crate::path::__name![$seg],)* |
402 | Path::from_simple_segments( | 272 | ]) |
403 | PathKind::Abs, | 273 | }); |
404 | vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE], | ||
405 | ) | ||
406 | } | ||
407 | |||
408 | pub fn std_ops_try() -> Path { | ||
409 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE]) | ||
410 | } | ||
411 | |||
412 | pub fn std_result_result() -> Path { | ||
413 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE]) | ||
414 | } | ||
415 | |||
416 | pub fn std_future_future() -> Path { | ||
417 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE]) | ||
418 | } | ||
419 | |||
420 | pub fn std_boxed_box() -> Path { | ||
421 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE]) | ||
422 | } | ||
423 | } | 274 | } |
275 | |||
276 | pub use crate::__path as path; | ||
diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs new file mode 100644 index 000000000..62aafd508 --- /dev/null +++ b/crates/ra_hir_def/src/path/lower.rs | |||
@@ -0,0 +1,178 @@ | |||
1 | //! Transforms syntax into `Path` objects, ideally with accounting for hygiene | ||
2 | |||
3 | mod lower_use; | ||
4 | |||
5 | use std::sync::Arc; | ||
6 | |||
7 | use either::Either; | ||
8 | use hir_expand::{ | ||
9 | hygiene::Hygiene, | ||
10 | name::{name, AsName}, | ||
11 | }; | ||
12 | use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner}; | ||
13 | |||
14 | use crate::{ | ||
15 | path::{GenericArg, GenericArgs, ModPath, Path, PathKind}, | ||
16 | type_ref::TypeRef, | ||
17 | }; | ||
18 | |||
19 | pub(super) use lower_use::lower_use_tree; | ||
20 | |||
21 | /// Converts an `ast::Path` to `Path`. Works with use trees. | ||
22 | /// It correctly handles `$crate` based path from macro call. | ||
23 | pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> { | ||
24 | let mut kind = PathKind::Plain; | ||
25 | let mut type_anchor = None; | ||
26 | let mut segments = Vec::new(); | ||
27 | let mut generic_args = Vec::new(); | ||
28 | loop { | ||
29 | let segment = path.segment()?; | ||
30 | |||
31 | if segment.has_colon_colon() { | ||
32 | kind = PathKind::Abs; | ||
33 | } | ||
34 | |||
35 | match segment.kind()? { | ||
36 | ast::PathSegmentKind::Name(name_ref) => { | ||
37 | // FIXME: this should just return name | ||
38 | match hygiene.name_ref_to_name(name_ref) { | ||
39 | Either::Left(name) => { | ||
40 | let args = segment | ||
41 | .type_arg_list() | ||
42 | .and_then(lower_generic_args) | ||
43 | .or_else(|| { | ||
44 | lower_generic_args_from_fn_path( | ||
45 | segment.param_list(), | ||
46 | segment.ret_type(), | ||
47 | ) | ||
48 | }) | ||
49 | .map(Arc::new); | ||
50 | segments.push(name); | ||
51 | generic_args.push(args) | ||
52 | } | ||
53 | Either::Right(crate_id) => { | ||
54 | kind = PathKind::DollarCrate(crate_id); | ||
55 | break; | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { | ||
60 | assert!(path.qualifier().is_none()); // this can only occur at the first segment | ||
61 | |||
62 | let self_type = TypeRef::from_ast(type_ref?); | ||
63 | |||
64 | match trait_ref { | ||
65 | // <T>::foo | ||
66 | None => { | ||
67 | type_anchor = Some(Box::new(self_type)); | ||
68 | kind = PathKind::Plain; | ||
69 | } | ||
70 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | ||
71 | Some(trait_ref) => { | ||
72 | let path = Path::from_src(trait_ref.path()?, hygiene)?; | ||
73 | kind = path.mod_path.kind; | ||
74 | |||
75 | let mut prefix_segments = path.mod_path.segments; | ||
76 | prefix_segments.reverse(); | ||
77 | segments.extend(prefix_segments); | ||
78 | |||
79 | let mut prefix_args = path.generic_args; | ||
80 | prefix_args.reverse(); | ||
81 | generic_args.extend(prefix_args); | ||
82 | |||
83 | // Insert the type reference (T in the above example) as Self parameter for the trait | ||
84 | let last_segment = generic_args.last_mut()?; | ||
85 | if last_segment.is_none() { | ||
86 | *last_segment = Some(Arc::new(GenericArgs::empty())); | ||
87 | }; | ||
88 | let args = last_segment.as_mut().unwrap(); | ||
89 | let mut args_inner = Arc::make_mut(args); | ||
90 | args_inner.has_self_type = true; | ||
91 | args_inner.args.insert(0, GenericArg::Type(self_type)); | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | ast::PathSegmentKind::CrateKw => { | ||
96 | kind = PathKind::Crate; | ||
97 | break; | ||
98 | } | ||
99 | ast::PathSegmentKind::SelfKw => { | ||
100 | kind = PathKind::Super(0); | ||
101 | break; | ||
102 | } | ||
103 | ast::PathSegmentKind::SuperKw => { | ||
104 | kind = PathKind::Super(1); | ||
105 | break; | ||
106 | } | ||
107 | } | ||
108 | path = match qualifier(&path) { | ||
109 | Some(it) => it, | ||
110 | None => break, | ||
111 | }; | ||
112 | } | ||
113 | segments.reverse(); | ||
114 | generic_args.reverse(); | ||
115 | let mod_path = ModPath { kind, segments }; | ||
116 | return Some(Path { type_anchor, mod_path, generic_args }); | ||
117 | |||
118 | fn qualifier(path: &ast::Path) -> Option<ast::Path> { | ||
119 | if let Some(q) = path.qualifier() { | ||
120 | return Some(q); | ||
121 | } | ||
122 | // FIXME: this bottom up traversal is not too precise. | ||
123 | // Should we handle do a top-down analysis, recording results? | ||
124 | let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; | ||
125 | let use_tree = use_tree_list.parent_use_tree(); | ||
126 | use_tree.path() | ||
127 | } | ||
128 | } | ||
129 | |||
130 | pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs> { | ||
131 | let mut args = Vec::new(); | ||
132 | for type_arg in node.type_args() { | ||
133 | let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); | ||
134 | args.push(GenericArg::Type(type_ref)); | ||
135 | } | ||
136 | // lifetimes ignored for now | ||
137 | let mut bindings = Vec::new(); | ||
138 | for assoc_type_arg in node.assoc_type_args() { | ||
139 | if let Some(name_ref) = assoc_type_arg.name_ref() { | ||
140 | let name = name_ref.as_name(); | ||
141 | let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref()); | ||
142 | bindings.push((name, type_ref)); | ||
143 | } | ||
144 | } | ||
145 | if args.is_empty() && bindings.is_empty() { | ||
146 | None | ||
147 | } else { | ||
148 | Some(GenericArgs { args, has_self_type: false, bindings }) | ||
149 | } | ||
150 | } | ||
151 | |||
152 | /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) | ||
153 | /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). | ||
154 | fn lower_generic_args_from_fn_path( | ||
155 | params: Option<ast::ParamList>, | ||
156 | ret_type: Option<ast::RetType>, | ||
157 | ) -> Option<GenericArgs> { | ||
158 | let mut args = Vec::new(); | ||
159 | let mut bindings = Vec::new(); | ||
160 | if let Some(params) = params { | ||
161 | let mut param_types = Vec::new(); | ||
162 | for param in params.params() { | ||
163 | let type_ref = TypeRef::from_ast_opt(param.ascribed_type()); | ||
164 | param_types.push(type_ref); | ||
165 | } | ||
166 | let arg = GenericArg::Type(TypeRef::Tuple(param_types)); | ||
167 | args.push(arg); | ||
168 | } | ||
169 | if let Some(ret_type) = ret_type { | ||
170 | let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); | ||
171 | bindings.push((name![Output], type_ref)) | ||
172 | } | ||
173 | if args.is_empty() && bindings.is_empty() { | ||
174 | None | ||
175 | } else { | ||
176 | Some(GenericArgs { args, has_self_type: false, bindings }) | ||
177 | } | ||
178 | } | ||
diff --git a/crates/ra_hir_def/src/path/lower/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs new file mode 100644 index 000000000..3218eaf0a --- /dev/null +++ b/crates/ra_hir_def/src/path/lower/lower_use.rs | |||
@@ -0,0 +1,118 @@ | |||
1 | //! Lowers a single complex use like `use foo::{bar, baz};` into a list of paths like | ||
2 | //! `foo::bar`, `foo::baz`; | ||
3 | |||
4 | use std::iter; | ||
5 | |||
6 | use either::Either; | ||
7 | use hir_expand::{ | ||
8 | hygiene::Hygiene, | ||
9 | name::{AsName, Name}, | ||
10 | }; | ||
11 | use ra_syntax::ast::{self, NameOwner}; | ||
12 | use test_utils::tested_by; | ||
13 | |||
14 | use crate::path::{ModPath, PathKind}; | ||
15 | |||
16 | pub(crate) fn lower_use_tree( | ||
17 | prefix: Option<ModPath>, | ||
18 | tree: ast::UseTree, | ||
19 | hygiene: &Hygiene, | ||
20 | cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, Option<Name>), | ||
21 | ) { | ||
22 | if let Some(use_tree_list) = tree.use_tree_list() { | ||
23 | let prefix = match tree.path() { | ||
24 | // E.g. use something::{{{inner}}}; | ||
25 | None => prefix, | ||
26 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | ||
27 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) | ||
28 | Some(path) => match convert_path(prefix, path, hygiene) { | ||
29 | Some(it) => Some(it), | ||
30 | None => return, // FIXME: report errors somewhere | ||
31 | }, | ||
32 | }; | ||
33 | for child_tree in use_tree_list.use_trees() { | ||
34 | lower_use_tree(prefix.clone(), child_tree, hygiene, cb); | ||
35 | } | ||
36 | } else { | ||
37 | let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); | ||
38 | let is_glob = tree.has_star(); | ||
39 | if let Some(ast_path) = tree.path() { | ||
40 | // Handle self in a path. | ||
41 | // E.g. `use something::{self, <...>}` | ||
42 | if ast_path.qualifier().is_none() { | ||
43 | if let Some(segment) = ast_path.segment() { | ||
44 | if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { | ||
45 | if let Some(prefix) = prefix { | ||
46 | cb(prefix, &tree, false, alias); | ||
47 | return; | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | if let Some(path) = convert_path(prefix, ast_path, hygiene) { | ||
53 | cb(path, &tree, is_glob, alias) | ||
54 | } | ||
55 | // FIXME: report errors somewhere | ||
56 | // We get here if we do | ||
57 | } else if is_glob { | ||
58 | tested_by!(glob_enum_group); | ||
59 | if let Some(prefix) = prefix { | ||
60 | cb(prefix, &tree, is_glob, None) | ||
61 | } | ||
62 | } | ||
63 | } | ||
64 | } | ||
65 | |||
66 | fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { | ||
67 | let prefix = if let Some(qual) = path.qualifier() { | ||
68 | Some(convert_path(prefix, qual, hygiene)?) | ||
69 | } else { | ||
70 | prefix | ||
71 | }; | ||
72 | |||
73 | let segment = path.segment()?; | ||
74 | let res = match segment.kind()? { | ||
75 | ast::PathSegmentKind::Name(name_ref) => { | ||
76 | match hygiene.name_ref_to_name(name_ref) { | ||
77 | Either::Left(name) => { | ||
78 | // no type args in use | ||
79 | let mut res = prefix.unwrap_or_else(|| ModPath { | ||
80 | kind: PathKind::Plain, | ||
81 | segments: Vec::with_capacity(1), | ||
82 | }); | ||
83 | res.segments.push(name); | ||
84 | res | ||
85 | } | ||
86 | Either::Right(crate_id) => { | ||
87 | return Some(ModPath::from_simple_segments( | ||
88 | PathKind::DollarCrate(crate_id), | ||
89 | iter::empty(), | ||
90 | )) | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | ast::PathSegmentKind::CrateKw => { | ||
95 | if prefix.is_some() { | ||
96 | return None; | ||
97 | } | ||
98 | ModPath::from_simple_segments(PathKind::Crate, iter::empty()) | ||
99 | } | ||
100 | ast::PathSegmentKind::SelfKw => { | ||
101 | if prefix.is_some() { | ||
102 | return None; | ||
103 | } | ||
104 | ModPath::from_simple_segments(PathKind::Super(0), iter::empty()) | ||
105 | } | ||
106 | ast::PathSegmentKind::SuperKw => { | ||
107 | if prefix.is_some() { | ||
108 | return None; | ||
109 | } | ||
110 | ModPath::from_simple_segments(PathKind::Super(1), iter::empty()) | ||
111 | } | ||
112 | ast::PathSegmentKind::Type { .. } => { | ||
113 | // not allowed in imports | ||
114 | return None; | ||
115 | } | ||
116 | }; | ||
117 | Some(res) | ||
118 | } | ||
diff --git a/crates/ra_hir_def/src/per_ns.rs b/crates/ra_hir_def/src/per_ns.rs index 00e866bf9..3a5105028 100644 --- a/crates/ra_hir_def/src/per_ns.rs +++ b/crates/ra_hir_def/src/per_ns.rs | |||
@@ -11,8 +11,6 @@ use crate::ModuleDefId; | |||
11 | pub struct PerNs { | 11 | pub struct PerNs { |
12 | pub types: Option<ModuleDefId>, | 12 | pub types: Option<ModuleDefId>, |
13 | pub values: Option<ModuleDefId>, | 13 | pub values: Option<ModuleDefId>, |
14 | /// Since macros has different type, many methods simply ignore it. | ||
15 | /// We can only use special method like `get_macros` to access it. | ||
16 | pub macros: Option<MacroDefId>, | 14 | pub macros: Option<MacroDefId>, |
17 | } | 15 | } |
18 | 16 | ||
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index 0847f6dcf..cf3c33d78 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use hir_expand::{ | 4 | use hir_expand::{ |
5 | name::{self, Name}, | 5 | name::{name, Name}, |
6 | MacroDefId, | 6 | MacroDefId, |
7 | }; | 7 | }; |
8 | use ra_db::CrateId; | 8 | use ra_db::CrateId; |
@@ -10,20 +10,23 @@ use rustc_hash::FxHashSet; | |||
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | body::scope::{ExprScopes, ScopeId}, | 12 | body::scope::{ExprScopes, ScopeId}, |
13 | body::Body, | ||
13 | builtin_type::BuiltinType, | 14 | builtin_type::BuiltinType, |
14 | db::DefDatabase, | 15 | db::DefDatabase, |
15 | expr::{ExprId, PatId}, | 16 | expr::{ExprId, PatId}, |
16 | generics::GenericParams, | 17 | generics::GenericParams, |
18 | item_scope::BuiltinShadowMode, | ||
17 | nameres::CrateDefMap, | 19 | nameres::CrateDefMap, |
18 | path::{Path, PathKind}, | 20 | path::{ModPath, PathKind}, |
19 | per_ns::PerNs, | 21 | per_ns::PerNs, |
20 | AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, | 22 | AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, |
21 | GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, | 23 | FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, |
22 | StructId, TraitId, TypeAliasId, | 24 | StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId, |
23 | }; | 25 | }; |
24 | 26 | ||
25 | #[derive(Debug, Clone, Default)] | 27 | #[derive(Debug, Clone, Default)] |
26 | pub struct Resolver { | 28 | pub struct Resolver { |
29 | // FIXME: all usages generally call `.rev`, so maybe reverse once in consturciton? | ||
27 | scopes: Vec<Scope>, | 30 | scopes: Vec<Scope>, |
28 | } | 31 | } |
29 | 32 | ||
@@ -53,12 +56,14 @@ enum Scope { | |||
53 | AdtScope(AdtId), | 56 | AdtScope(AdtId), |
54 | /// Local bindings | 57 | /// Local bindings |
55 | ExprScope(ExprScope), | 58 | ExprScope(ExprScope), |
59 | /// Temporary hack to support local items. | ||
60 | LocalItemsScope(Arc<Body>), | ||
56 | } | 61 | } |
57 | 62 | ||
58 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 63 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
59 | pub enum TypeNs { | 64 | pub enum TypeNs { |
60 | SelfType(ImplId), | 65 | SelfType(ImplId), |
61 | GenericParam(u32), | 66 | GenericParam(TypeParamId), |
62 | AdtId(AdtId), | 67 | AdtId(AdtId), |
63 | AdtSelfType(AdtId), | 68 | AdtSelfType(AdtId), |
64 | // Yup, enum variants are added to the types ns, but any usage of variant as | 69 | // Yup, enum variants are added to the types ns, but any usage of variant as |
@@ -90,8 +95,8 @@ pub enum ValueNs { | |||
90 | 95 | ||
91 | impl Resolver { | 96 | impl Resolver { |
92 | /// Resolve known trait from std, like `std::futures::Future` | 97 | /// Resolve known trait from std, like `std::futures::Future` |
93 | pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &Path) -> Option<TraitId> { | 98 | pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &ModPath) -> Option<TraitId> { |
94 | let res = self.resolve_module_path(db, path).take_types()?; | 99 | let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; |
95 | match res { | 100 | match res { |
96 | ModuleDefId::TraitId(it) => Some(it), | 101 | ModuleDefId::TraitId(it) => Some(it), |
97 | _ => None, | 102 | _ => None, |
@@ -99,8 +104,8 @@ impl Resolver { | |||
99 | } | 104 | } |
100 | 105 | ||
101 | /// Resolve known struct from std, like `std::boxed::Box` | 106 | /// Resolve known struct from std, like `std::boxed::Box` |
102 | pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &Path) -> Option<StructId> { | 107 | pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &ModPath) -> Option<StructId> { |
103 | let res = self.resolve_module_path(db, path).take_types()?; | 108 | let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; |
104 | match res { | 109 | match res { |
105 | ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it), | 110 | ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it), |
106 | _ => None, | 111 | _ => None, |
@@ -108,87 +113,116 @@ impl Resolver { | |||
108 | } | 113 | } |
109 | 114 | ||
110 | /// Resolve known enum from std, like `std::result::Result` | 115 | /// Resolve known enum from std, like `std::result::Result` |
111 | pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &Path) -> Option<EnumId> { | 116 | pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &ModPath) -> Option<EnumId> { |
112 | let res = self.resolve_module_path(db, path).take_types()?; | 117 | let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?; |
113 | match res { | 118 | match res { |
114 | ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it), | 119 | ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it), |
115 | _ => None, | 120 | _ => None, |
116 | } | 121 | } |
117 | } | 122 | } |
118 | 123 | ||
119 | /// pub only for source-binder | 124 | fn resolve_module_path( |
120 | pub fn resolve_module_path(&self, db: &impl DefDatabase, path: &Path) -> PerNs { | 125 | &self, |
126 | db: &impl DefDatabase, | ||
127 | path: &ModPath, | ||
128 | shadow: BuiltinShadowMode, | ||
129 | ) -> PerNs { | ||
121 | let (item_map, module) = match self.module() { | 130 | let (item_map, module) = match self.module() { |
122 | Some(it) => it, | 131 | Some(it) => it, |
123 | None => return PerNs::none(), | 132 | None => return PerNs::none(), |
124 | }; | 133 | }; |
125 | let (module_res, segment_index) = item_map.resolve_path(db, module, path); | 134 | let (module_res, segment_index) = item_map.resolve_path(db, module, &path, shadow); |
126 | if segment_index.is_some() { | 135 | if segment_index.is_some() { |
127 | return PerNs::none(); | 136 | return PerNs::none(); |
128 | } | 137 | } |
129 | module_res | 138 | module_res |
130 | } | 139 | } |
131 | 140 | ||
141 | pub fn resolve_module_path_in_items(&self, db: &impl DefDatabase, path: &ModPath) -> PerNs { | ||
142 | self.resolve_module_path(db, path, BuiltinShadowMode::Module) | ||
143 | } | ||
144 | |||
132 | pub fn resolve_path_in_type_ns( | 145 | pub fn resolve_path_in_type_ns( |
133 | &self, | 146 | &self, |
134 | db: &impl DefDatabase, | 147 | db: &impl DefDatabase, |
135 | path: &Path, | 148 | path: &ModPath, |
136 | ) -> Option<(TypeNs, Option<usize>)> { | 149 | ) -> Option<(TypeNs, Option<usize>)> { |
137 | if path.is_type_relative() { | 150 | let first_name = path.segments.first()?; |
138 | return None; | ||
139 | } | ||
140 | let first_name = &path.segments.first()?.name; | ||
141 | let skip_to_mod = path.kind != PathKind::Plain; | 151 | let skip_to_mod = path.kind != PathKind::Plain; |
142 | for scope in self.scopes.iter().rev() { | 152 | for scope in self.scopes.iter().rev() { |
143 | match scope { | 153 | match scope { |
144 | Scope::ExprScope(_) => continue, | 154 | Scope::ExprScope(_) => continue, |
145 | Scope::GenericParams { .. } | Scope::ImplBlockScope(_) if skip_to_mod => continue, | 155 | Scope::GenericParams { .. } |
156 | | Scope::ImplBlockScope(_) | ||
157 | | Scope::LocalItemsScope(_) | ||
158 | if skip_to_mod => | ||
159 | { | ||
160 | continue | ||
161 | } | ||
146 | 162 | ||
147 | Scope::GenericParams { params, .. } => { | 163 | Scope::GenericParams { params, def } => { |
148 | if let Some(param) = params.find_by_name(first_name) { | 164 | if let Some(local_id) = params.find_by_name(first_name) { |
149 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; | 165 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; |
150 | return Some((TypeNs::GenericParam(param.idx), idx)); | 166 | return Some(( |
167 | TypeNs::GenericParam(TypeParamId { local_id, parent: *def }), | ||
168 | idx, | ||
169 | )); | ||
151 | } | 170 | } |
152 | } | 171 | } |
153 | Scope::ImplBlockScope(impl_) => { | 172 | Scope::ImplBlockScope(impl_) => { |
154 | if first_name == &name::SELF_TYPE { | 173 | if first_name == &name![Self] { |
155 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; | 174 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; |
156 | return Some((TypeNs::SelfType(*impl_), idx)); | 175 | return Some((TypeNs::SelfType(*impl_), idx)); |
157 | } | 176 | } |
158 | } | 177 | } |
159 | Scope::AdtScope(adt) => { | 178 | Scope::AdtScope(adt) => { |
160 | if first_name == &name::SELF_TYPE { | 179 | if first_name == &name![Self] { |
161 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; | 180 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; |
162 | return Some((TypeNs::AdtSelfType(*adt), idx)); | 181 | return Some((TypeNs::AdtSelfType(*adt), idx)); |
163 | } | 182 | } |
164 | } | 183 | } |
165 | Scope::ModuleScope(m) => { | 184 | Scope::ModuleScope(m) => { |
166 | let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); | 185 | let (module_def, idx) = m.crate_def_map.resolve_path( |
167 | let res = match module_def.take_types()? { | 186 | db, |
168 | ModuleDefId::AdtId(it) => TypeNs::AdtId(it), | 187 | m.module_id, |
169 | ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it), | 188 | &path, |
170 | 189 | BuiltinShadowMode::Other, | |
171 | ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), | 190 | ); |
172 | ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), | 191 | let res = to_type_ns(module_def)?; |
173 | |||
174 | ModuleDefId::TraitId(it) => TypeNs::TraitId(it), | ||
175 | |||
176 | ModuleDefId::FunctionId(_) | ||
177 | | ModuleDefId::ConstId(_) | ||
178 | | ModuleDefId::StaticId(_) | ||
179 | | ModuleDefId::ModuleId(_) => return None, | ||
180 | }; | ||
181 | return Some((res, idx)); | 192 | return Some((res, idx)); |
182 | } | 193 | } |
194 | Scope::LocalItemsScope(body) => { | ||
195 | let def = body.item_scope.get(first_name, BuiltinShadowMode::Other); | ||
196 | if let Some(res) = to_type_ns(def) { | ||
197 | return Some((res, None)); | ||
198 | } | ||
199 | } | ||
183 | } | 200 | } |
184 | } | 201 | } |
185 | None | 202 | return None; |
203 | fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> { | ||
204 | let res = match per_ns.take_types()? { | ||
205 | ModuleDefId::AdtId(it) => TypeNs::AdtId(it), | ||
206 | ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it), | ||
207 | |||
208 | ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), | ||
209 | ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), | ||
210 | |||
211 | ModuleDefId::TraitId(it) => TypeNs::TraitId(it), | ||
212 | |||
213 | ModuleDefId::FunctionId(_) | ||
214 | | ModuleDefId::ConstId(_) | ||
215 | | ModuleDefId::StaticId(_) | ||
216 | | ModuleDefId::ModuleId(_) => return None, | ||
217 | }; | ||
218 | Some(res) | ||
219 | } | ||
186 | } | 220 | } |
187 | 221 | ||
188 | pub fn resolve_path_in_type_ns_fully( | 222 | pub fn resolve_path_in_type_ns_fully( |
189 | &self, | 223 | &self, |
190 | db: &impl DefDatabase, | 224 | db: &impl DefDatabase, |
191 | path: &Path, | 225 | path: &ModPath, |
192 | ) -> Option<TypeNs> { | 226 | ) -> Option<TypeNs> { |
193 | let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?; | 227 | let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?; |
194 | if unresolved.is_some() { | 228 | if unresolved.is_some() { |
@@ -197,17 +231,14 @@ impl Resolver { | |||
197 | Some(res) | 231 | Some(res) |
198 | } | 232 | } |
199 | 233 | ||
200 | pub fn resolve_path_in_value_ns<'p>( | 234 | pub fn resolve_path_in_value_ns( |
201 | &self, | 235 | &self, |
202 | db: &impl DefDatabase, | 236 | db: &impl DefDatabase, |
203 | path: &'p Path, | 237 | path: &ModPath, |
204 | ) -> Option<ResolveValueResult> { | 238 | ) -> Option<ResolveValueResult> { |
205 | if path.is_type_relative() { | ||
206 | return None; | ||
207 | } | ||
208 | let n_segments = path.segments.len(); | 239 | let n_segments = path.segments.len(); |
209 | let tmp = name::SELF_PARAM; | 240 | let tmp = name![self]; |
210 | let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; | 241 | let first_name = if path.is_self() { &tmp } else { &path.segments.first()? }; |
211 | let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); | 242 | let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); |
212 | for scope in self.scopes.iter().rev() { | 243 | for scope in self.scopes.iter().rev() { |
213 | match scope { | 244 | match scope { |
@@ -215,6 +246,7 @@ impl Resolver { | |||
215 | | Scope::ExprScope(_) | 246 | | Scope::ExprScope(_) |
216 | | Scope::GenericParams { .. } | 247 | | Scope::GenericParams { .. } |
217 | | Scope::ImplBlockScope(_) | 248 | | Scope::ImplBlockScope(_) |
249 | | Scope::LocalItemsScope(_) | ||
218 | if skip_to_mod => | 250 | if skip_to_mod => |
219 | { | 251 | { |
220 | continue | 252 | continue |
@@ -233,22 +265,22 @@ impl Resolver { | |||
233 | } | 265 | } |
234 | Scope::ExprScope(_) => continue, | 266 | Scope::ExprScope(_) => continue, |
235 | 267 | ||
236 | Scope::GenericParams { params, .. } if n_segments > 1 => { | 268 | Scope::GenericParams { params, def } if n_segments > 1 => { |
237 | if let Some(param) = params.find_by_name(first_name) { | 269 | if let Some(local_id) = params.find_by_name(first_name) { |
238 | let ty = TypeNs::GenericParam(param.idx); | 270 | let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def }); |
239 | return Some(ResolveValueResult::Partial(ty, 1)); | 271 | return Some(ResolveValueResult::Partial(ty, 1)); |
240 | } | 272 | } |
241 | } | 273 | } |
242 | Scope::GenericParams { .. } => continue, | 274 | Scope::GenericParams { .. } => continue, |
243 | 275 | ||
244 | Scope::ImplBlockScope(impl_) if n_segments > 1 => { | 276 | Scope::ImplBlockScope(impl_) if n_segments > 1 => { |
245 | if first_name == &name::SELF_TYPE { | 277 | if first_name == &name![Self] { |
246 | let ty = TypeNs::SelfType(*impl_); | 278 | let ty = TypeNs::SelfType(*impl_); |
247 | return Some(ResolveValueResult::Partial(ty, 1)); | 279 | return Some(ResolveValueResult::Partial(ty, 1)); |
248 | } | 280 | } |
249 | } | 281 | } |
250 | Scope::AdtScope(adt) if n_segments > 1 => { | 282 | Scope::AdtScope(adt) if n_segments > 1 => { |
251 | if first_name == &name::SELF_TYPE { | 283 | if first_name == &name![Self] { |
252 | let ty = TypeNs::AdtSelfType(*adt); | 284 | let ty = TypeNs::AdtSelfType(*adt); |
253 | return Some(ResolveValueResult::Partial(ty, 1)); | 285 | return Some(ResolveValueResult::Partial(ty, 1)); |
254 | } | 286 | } |
@@ -256,23 +288,15 @@ impl Resolver { | |||
256 | Scope::ImplBlockScope(_) | Scope::AdtScope(_) => continue, | 288 | Scope::ImplBlockScope(_) | Scope::AdtScope(_) => continue, |
257 | 289 | ||
258 | Scope::ModuleScope(m) => { | 290 | Scope::ModuleScope(m) => { |
259 | let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); | 291 | let (module_def, idx) = m.crate_def_map.resolve_path( |
292 | db, | ||
293 | m.module_id, | ||
294 | &path, | ||
295 | BuiltinShadowMode::Other, | ||
296 | ); | ||
260 | return match idx { | 297 | return match idx { |
261 | None => { | 298 | None => { |
262 | let value = match module_def.take_values()? { | 299 | let value = to_value_ns(module_def)?; |
263 | ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it), | ||
264 | ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it), | ||
265 | ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it), | ||
266 | ModuleDefId::ConstId(it) => ValueNs::ConstId(it), | ||
267 | ModuleDefId::StaticId(it) => ValueNs::StaticId(it), | ||
268 | |||
269 | ModuleDefId::AdtId(AdtId::EnumId(_)) | ||
270 | | ModuleDefId::AdtId(AdtId::UnionId(_)) | ||
271 | | ModuleDefId::TraitId(_) | ||
272 | | ModuleDefId::TypeAliasId(_) | ||
273 | | ModuleDefId::BuiltinType(_) | ||
274 | | ModuleDefId::ModuleId(_) => return None, | ||
275 | }; | ||
276 | Some(ResolveValueResult::ValueNs(value)) | 300 | Some(ResolveValueResult::ValueNs(value)) |
277 | } | 301 | } |
278 | Some(idx) => { | 302 | Some(idx) => { |
@@ -292,15 +316,39 @@ impl Resolver { | |||
292 | } | 316 | } |
293 | }; | 317 | }; |
294 | } | 318 | } |
319 | Scope::LocalItemsScope(body) => { | ||
320 | let def = body.item_scope.get(first_name, BuiltinShadowMode::Other); | ||
321 | if let Some(res) = to_value_ns(def) { | ||
322 | return Some(ResolveValueResult::ValueNs(res)); | ||
323 | } | ||
324 | } | ||
295 | } | 325 | } |
296 | } | 326 | } |
297 | None | 327 | return None; |
328 | |||
329 | fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> { | ||
330 | let res = match per_ns.take_values()? { | ||
331 | ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it), | ||
332 | ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it), | ||
333 | ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it), | ||
334 | ModuleDefId::ConstId(it) => ValueNs::ConstId(it), | ||
335 | ModuleDefId::StaticId(it) => ValueNs::StaticId(it), | ||
336 | |||
337 | ModuleDefId::AdtId(AdtId::EnumId(_)) | ||
338 | | ModuleDefId::AdtId(AdtId::UnionId(_)) | ||
339 | | ModuleDefId::TraitId(_) | ||
340 | | ModuleDefId::TypeAliasId(_) | ||
341 | | ModuleDefId::BuiltinType(_) | ||
342 | | ModuleDefId::ModuleId(_) => return None, | ||
343 | }; | ||
344 | Some(res) | ||
345 | } | ||
298 | } | 346 | } |
299 | 347 | ||
300 | pub fn resolve_path_in_value_ns_fully( | 348 | pub fn resolve_path_in_value_ns_fully( |
301 | &self, | 349 | &self, |
302 | db: &impl DefDatabase, | 350 | db: &impl DefDatabase, |
303 | path: &Path, | 351 | path: &ModPath, |
304 | ) -> Option<ValueNs> { | 352 | ) -> Option<ValueNs> { |
305 | match self.resolve_path_in_value_ns(db, path)? { | 353 | match self.resolve_path_in_value_ns(db, path)? { |
306 | ResolveValueResult::ValueNs(it) => Some(it), | 354 | ResolveValueResult::ValueNs(it) => Some(it), |
@@ -308,9 +356,13 @@ impl Resolver { | |||
308 | } | 356 | } |
309 | } | 357 | } |
310 | 358 | ||
311 | pub fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> { | 359 | pub fn resolve_path_as_macro( |
360 | &self, | ||
361 | db: &impl DefDatabase, | ||
362 | path: &ModPath, | ||
363 | ) -> Option<MacroDefId> { | ||
312 | let (item_map, module) = self.module()?; | 364 | let (item_map, module) = self.module()?; |
313 | item_map.resolve_path(db, module, path).0.take_macros() | 365 | item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() |
314 | } | 366 | } |
315 | 367 | ||
316 | pub fn process_all_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) { | 368 | pub fn process_all_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) { |
@@ -350,6 +402,7 @@ impl Resolver { | |||
350 | ) -> impl Iterator<Item = &'a crate::generics::WherePredicate> + 'a { | 402 | ) -> impl Iterator<Item = &'a crate::generics::WherePredicate> + 'a { |
351 | self.scopes | 403 | self.scopes |
352 | .iter() | 404 | .iter() |
405 | .rev() | ||
353 | .filter_map(|scope| match scope { | 406 | .filter_map(|scope| match scope { |
354 | Scope::GenericParams { params, .. } => Some(params), | 407 | Scope::GenericParams { params, .. } => Some(params), |
355 | _ => None, | 408 | _ => None, |
@@ -358,14 +411,14 @@ impl Resolver { | |||
358 | } | 411 | } |
359 | 412 | ||
360 | pub fn generic_def(&self) -> Option<GenericDefId> { | 413 | pub fn generic_def(&self) -> Option<GenericDefId> { |
361 | self.scopes.iter().find_map(|scope| match scope { | 414 | self.scopes.iter().rev().find_map(|scope| match scope { |
362 | Scope::GenericParams { def, .. } => Some(*def), | 415 | Scope::GenericParams { def, .. } => Some(*def), |
363 | _ => None, | 416 | _ => None, |
364 | }) | 417 | }) |
365 | } | 418 | } |
366 | 419 | ||
367 | pub fn body_owner(&self) -> Option<DefWithBodyId> { | 420 | pub fn body_owner(&self) -> Option<DefWithBodyId> { |
368 | self.scopes.iter().find_map(|scope| match scope { | 421 | self.scopes.iter().rev().find_map(|scope| match scope { |
369 | Scope::ExprScope(it) => Some(it.owner), | 422 | Scope::ExprScope(it) => Some(it.owner), |
370 | _ => None, | 423 | _ => None, |
371 | }) | 424 | }) |
@@ -376,7 +429,7 @@ pub enum ScopeDef { | |||
376 | PerNs(PerNs), | 429 | PerNs(PerNs), |
377 | ImplSelfType(ImplId), | 430 | ImplSelfType(ImplId), |
378 | AdtSelfType(AdtId), | 431 | AdtSelfType(AdtId), |
379 | GenericParam(u32), | 432 | GenericParam(TypeParamId), |
380 | Local(PatId), | 433 | Local(PatId), |
381 | } | 434 | } |
382 | 435 | ||
@@ -391,8 +444,8 @@ impl Scope { | |||
391 | // def: m.module.into(), | 444 | // def: m.module.into(), |
392 | // }), | 445 | // }), |
393 | // ); | 446 | // ); |
394 | m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| { | 447 | m.crate_def_map[m.module_id].scope.entries().for_each(|(name, def)| { |
395 | f(name.clone(), ScopeDef::PerNs(res.def)); | 448 | f(name.clone(), ScopeDef::PerNs(def)); |
396 | }); | 449 | }); |
397 | m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { | 450 | m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { |
398 | f(name.clone(), ScopeDef::PerNs(PerNs::macros(macro_))); | 451 | f(name.clone(), ScopeDef::PerNs(PerNs::macros(macro_))); |
@@ -402,21 +455,29 @@ impl Scope { | |||
402 | }); | 455 | }); |
403 | if let Some(prelude) = m.crate_def_map.prelude { | 456 | if let Some(prelude) = m.crate_def_map.prelude { |
404 | let prelude_def_map = db.crate_def_map(prelude.krate); | 457 | let prelude_def_map = db.crate_def_map(prelude.krate); |
405 | prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, res)| { | 458 | prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| { |
406 | f(name.clone(), ScopeDef::PerNs(res.def)); | 459 | f(name.clone(), ScopeDef::PerNs(def)); |
407 | }); | 460 | }); |
408 | } | 461 | } |
409 | } | 462 | } |
410 | Scope::GenericParams { params, .. } => { | 463 | Scope::LocalItemsScope(body) => { |
411 | for param in params.params.iter() { | 464 | body.item_scope.entries_without_primitives().for_each(|(name, def)| { |
412 | f(param.name.clone(), ScopeDef::GenericParam(param.idx)) | 465 | f(name.clone(), ScopeDef::PerNs(def)); |
466 | }) | ||
467 | } | ||
468 | Scope::GenericParams { params, def } => { | ||
469 | for (local_id, param) in params.types.iter() { | ||
470 | f( | ||
471 | param.name.clone(), | ||
472 | ScopeDef::GenericParam(TypeParamId { local_id, parent: *def }), | ||
473 | ) | ||
413 | } | 474 | } |
414 | } | 475 | } |
415 | Scope::ImplBlockScope(i) => { | 476 | Scope::ImplBlockScope(i) => { |
416 | f(name::SELF_TYPE, ScopeDef::ImplSelfType((*i).into())); | 477 | f(name![Self], ScopeDef::ImplSelfType((*i).into())); |
417 | } | 478 | } |
418 | Scope::AdtScope(i) => { | 479 | Scope::AdtScope(i) => { |
419 | f(name::SELF_TYPE, ScopeDef::AdtSelfType((*i).into())); | 480 | f(name![Self], ScopeDef::AdtSelfType((*i).into())); |
420 | } | 481 | } |
421 | Scope::ExprScope(scope) => { | 482 | Scope::ExprScope(scope) => { |
422 | scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { | 483 | scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { |
@@ -439,6 +500,7 @@ pub fn resolver_for_scope( | |||
439 | scope_id: Option<ScopeId>, | 500 | scope_id: Option<ScopeId>, |
440 | ) -> Resolver { | 501 | ) -> Resolver { |
441 | let mut r = owner.resolver(db); | 502 | let mut r = owner.resolver(db); |
503 | r = r.push_local_items_scope(db.body(owner)); | ||
442 | let scopes = db.expr_scopes(owner); | 504 | let scopes = db.expr_scopes(owner); |
443 | let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); | 505 | let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); |
444 | for scope in scope_chain.into_iter().rev() { | 506 | for scope in scope_chain.into_iter().rev() { |
@@ -455,7 +517,7 @@ impl Resolver { | |||
455 | 517 | ||
456 | fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver { | 518 | fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver { |
457 | let params = db.generic_params(def); | 519 | let params = db.generic_params(def); |
458 | if params.params.is_empty() { | 520 | if params.types.is_empty() { |
459 | self | 521 | self |
460 | } else { | 522 | } else { |
461 | self.push_scope(Scope::GenericParams { def, params }) | 523 | self.push_scope(Scope::GenericParams { def, params }) |
@@ -474,6 +536,10 @@ impl Resolver { | |||
474 | self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id })) | 536 | self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id })) |
475 | } | 537 | } |
476 | 538 | ||
539 | fn push_local_items_scope(self, body: Arc<Body>) -> Resolver { | ||
540 | self.push_scope(Scope::LocalItemsScope(body)) | ||
541 | } | ||
542 | |||
477 | fn push_expr_scope( | 543 | fn push_expr_scope( |
478 | self, | 544 | self, |
479 | owner: DefWithBodyId, | 545 | owner: DefWithBodyId, |
@@ -498,7 +564,7 @@ impl HasResolver for ModuleId { | |||
498 | 564 | ||
499 | impl HasResolver for TraitId { | 565 | impl HasResolver for TraitId { |
500 | fn resolver(self, db: &impl DefDatabase) -> Resolver { | 566 | fn resolver(self, db: &impl DefDatabase) -> Resolver { |
501 | self.module(db).resolver(db).push_generic_params_scope(db, self.into()) | 567 | self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) |
502 | } | 568 | } |
503 | } | 569 | } |
504 | 570 | ||
@@ -518,16 +584,6 @@ impl HasResolver for FunctionId { | |||
518 | } | 584 | } |
519 | } | 585 | } |
520 | 586 | ||
521 | impl HasResolver for DefWithBodyId { | ||
522 | fn resolver(self, db: &impl DefDatabase) -> Resolver { | ||
523 | match self { | ||
524 | DefWithBodyId::ConstId(c) => c.resolver(db), | ||
525 | DefWithBodyId::FunctionId(f) => f.resolver(db), | ||
526 | DefWithBodyId::StaticId(s) => s.resolver(db), | ||
527 | } | ||
528 | } | ||
529 | } | ||
530 | |||
531 | impl HasResolver for ConstId { | 587 | impl HasResolver for ConstId { |
532 | fn resolver(self, db: &impl DefDatabase) -> Resolver { | 588 | fn resolver(self, db: &impl DefDatabase) -> Resolver { |
533 | self.lookup(db).container.resolver(db) | 589 | self.lookup(db).container.resolver(db) |
@@ -546,12 +602,41 @@ impl HasResolver for TypeAliasId { | |||
546 | } | 602 | } |
547 | } | 603 | } |
548 | 604 | ||
605 | impl HasResolver for ImplId { | ||
606 | fn resolver(self, db: &impl DefDatabase) -> Resolver { | ||
607 | self.lookup(db) | ||
608 | .container | ||
609 | .resolver(db) | ||
610 | .push_generic_params_scope(db, self.into()) | ||
611 | .push_impl_block_scope(self) | ||
612 | } | ||
613 | } | ||
614 | |||
615 | impl HasResolver for DefWithBodyId { | ||
616 | fn resolver(self, db: &impl DefDatabase) -> Resolver { | ||
617 | match self { | ||
618 | DefWithBodyId::ConstId(c) => c.resolver(db), | ||
619 | DefWithBodyId::FunctionId(f) => f.resolver(db), | ||
620 | DefWithBodyId::StaticId(s) => s.resolver(db), | ||
621 | } | ||
622 | } | ||
623 | } | ||
624 | |||
549 | impl HasResolver for ContainerId { | 625 | impl HasResolver for ContainerId { |
550 | fn resolver(self, db: &impl DefDatabase) -> Resolver { | 626 | fn resolver(self, db: &impl DefDatabase) -> Resolver { |
551 | match self { | 627 | match self { |
552 | ContainerId::TraitId(it) => it.resolver(db), | ||
553 | ContainerId::ImplId(it) => it.resolver(db), | ||
554 | ContainerId::ModuleId(it) => it.resolver(db), | 628 | ContainerId::ModuleId(it) => it.resolver(db), |
629 | ContainerId::DefWithBodyId(it) => it.resolver(db), | ||
630 | } | ||
631 | } | ||
632 | } | ||
633 | |||
634 | impl HasResolver for AssocContainerId { | ||
635 | fn resolver(self, db: &impl DefDatabase) -> Resolver { | ||
636 | match self { | ||
637 | AssocContainerId::ContainerId(it) => it.resolver(db), | ||
638 | AssocContainerId::TraitId(it) => it.resolver(db), | ||
639 | AssocContainerId::ImplId(it) => it.resolver(db), | ||
555 | } | 640 | } |
556 | } | 641 | } |
557 | } | 642 | } |
@@ -570,11 +655,12 @@ impl HasResolver for GenericDefId { | |||
570 | } | 655 | } |
571 | } | 656 | } |
572 | 657 | ||
573 | impl HasResolver for ImplId { | 658 | impl HasResolver for VariantId { |
574 | fn resolver(self, db: &impl DefDatabase) -> Resolver { | 659 | fn resolver(self, db: &impl DefDatabase) -> Resolver { |
575 | self.module(db) | 660 | match self { |
576 | .resolver(db) | 661 | VariantId::EnumVariantId(it) => it.parent.resolver(db), |
577 | .push_generic_params_scope(db, self.into()) | 662 | VariantId::StructId(it) => it.resolver(db), |
578 | .push_impl_block_scope(self) | 663 | VariantId::UnionId(it) => it.resolver(db), |
664 | } | ||
579 | } | 665 | } |
580 | } | 666 | } |
diff --git a/crates/ra_hir_def/src/src.rs b/crates/ra_hir_def/src/src.rs new file mode 100644 index 000000000..499375b80 --- /dev/null +++ b/crates/ra_hir_def/src/src.rs | |||
@@ -0,0 +1,36 @@ | |||
1 | //! Utilities for mapping between hir IDs and the surface syntax. | ||
2 | |||
3 | use hir_expand::InFile; | ||
4 | use ra_arena::map::ArenaMap; | ||
5 | use ra_syntax::AstNode; | ||
6 | |||
7 | use crate::{db::DefDatabase, AssocItemLoc, ItemLoc}; | ||
8 | |||
9 | pub trait HasSource { | ||
10 | type Value; | ||
11 | fn source(&self, db: &impl DefDatabase) -> InFile<Self::Value>; | ||
12 | } | ||
13 | |||
14 | impl<N: AstNode> HasSource for AssocItemLoc<N> { | ||
15 | type Value = N; | ||
16 | |||
17 | fn source(&self, db: &impl DefDatabase) -> InFile<N> { | ||
18 | let node = self.ast_id.to_node(db); | ||
19 | InFile::new(self.ast_id.file_id, node) | ||
20 | } | ||
21 | } | ||
22 | |||
23 | impl<N: AstNode> HasSource for ItemLoc<N> { | ||
24 | type Value = N; | ||
25 | |||
26 | fn source(&self, db: &impl DefDatabase) -> InFile<N> { | ||
27 | let node = self.ast_id.to_node(db); | ||
28 | InFile::new(self.ast_id.file_id, node) | ||
29 | } | ||
30 | } | ||
31 | |||
32 | pub trait HasChildSource { | ||
33 | type ChildId; | ||
34 | type Value; | ||
35 | fn child_source(&self, db: &impl DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>>; | ||
36 | } | ||
diff --git a/crates/ra_hir_def/src/trace.rs b/crates/ra_hir_def/src/trace.rs index 2bcd707bc..9769e88df 100644 --- a/crates/ra_hir_def/src/trace.rs +++ b/crates/ra_hir_def/src/trace.rs | |||
@@ -18,10 +18,6 @@ pub(crate) struct Trace<ID: ArenaId, T, V> { | |||
18 | } | 18 | } |
19 | 19 | ||
20 | impl<ID: ra_arena::ArenaId + Copy, T, V> Trace<ID, T, V> { | 20 | impl<ID: ra_arena::ArenaId + Copy, T, V> Trace<ID, T, V> { |
21 | pub(crate) fn new() -> Trace<ID, T, V> { | ||
22 | Trace { arena: Some(Arena::default()), map: Some(ArenaMap::default()), len: 0 } | ||
23 | } | ||
24 | |||
25 | pub(crate) fn new_for_arena() -> Trace<ID, T, V> { | 21 | pub(crate) fn new_for_arena() -> Trace<ID, T, V> { |
26 | Trace { arena: Some(Arena::default()), map: None, len: 0 } | 22 | Trace { arena: Some(Arena::default()), map: None, len: 0 } |
27 | } | 23 | } |
@@ -52,8 +48,4 @@ impl<ID: ra_arena::ArenaId + Copy, T, V> Trace<ID, T, V> { | |||
52 | pub(crate) fn into_map(mut self) -> ArenaMap<ID, V> { | 48 | pub(crate) fn into_map(mut self) -> ArenaMap<ID, V> { |
53 | self.map.take().unwrap() | 49 | self.map.take().unwrap() |
54 | } | 50 | } |
55 | |||
56 | pub(crate) fn into_arena_and_map(mut self) -> (Arena<ID, T>, ArenaMap<ID, V>) { | ||
57 | (self.arena.take().unwrap(), self.map.take().unwrap()) | ||
58 | } | ||
59 | } | 51 | } |