diff options
Diffstat (limited to 'crates/ra_hir_def/src')
43 files changed, 0 insertions, 15242 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs deleted file mode 100644 index 6cb56a1cd..000000000 --- a/crates/ra_hir_def/src/adt.rs +++ /dev/null | |||
@@ -1,295 +0,0 @@ | |||
1 | //! Defines hir-level representation of structs, enums and unions | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use either::Either; | ||
6 | use hir_expand::{ | ||
7 | name::{AsName, Name}, | ||
8 | InFile, | ||
9 | }; | ||
10 | use ra_arena::{map::ArenaMap, Arena}; | ||
11 | use ra_syntax::ast::{self, NameOwner, VisibilityOwner}; | ||
12 | |||
13 | use crate::{ | ||
14 | body::{CfgExpander, LowerCtx}, | ||
15 | db::DefDatabase, | ||
16 | item_tree::{Field, Fields, ItemTree}, | ||
17 | src::HasChildSource, | ||
18 | src::HasSource, | ||
19 | trace::Trace, | ||
20 | type_ref::TypeRef, | ||
21 | visibility::RawVisibility, | ||
22 | EnumId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, | ||
23 | VariantId, | ||
24 | }; | ||
25 | use ra_cfg::CfgOptions; | ||
26 | |||
27 | /// Note that we use `StructData` for unions as well! | ||
28 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
29 | pub struct StructData { | ||
30 | pub name: Name, | ||
31 | pub variant_data: Arc<VariantData>, | ||
32 | } | ||
33 | |||
34 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
35 | pub struct EnumData { | ||
36 | pub name: Name, | ||
37 | pub variants: Arena<EnumVariantData>, | ||
38 | } | ||
39 | |||
40 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
41 | pub struct EnumVariantData { | ||
42 | pub name: Name, | ||
43 | pub variant_data: Arc<VariantData>, | ||
44 | } | ||
45 | |||
46 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
47 | pub enum VariantData { | ||
48 | Record(Arena<FieldData>), | ||
49 | Tuple(Arena<FieldData>), | ||
50 | Unit, | ||
51 | } | ||
52 | |||
53 | /// A single field of an enum variant or struct | ||
54 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
55 | pub struct FieldData { | ||
56 | pub name: Name, | ||
57 | pub type_ref: TypeRef, | ||
58 | pub visibility: RawVisibility, | ||
59 | } | ||
60 | |||
61 | impl StructData { | ||
62 | pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { | ||
63 | let loc = id.lookup(db); | ||
64 | let item_tree = db.item_tree(loc.id.file_id); | ||
65 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); | ||
66 | |||
67 | let strukt = &item_tree[loc.id.value]; | ||
68 | let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields); | ||
69 | |||
70 | Arc::new(StructData { name: strukt.name.clone(), variant_data: Arc::new(variant_data) }) | ||
71 | } | ||
72 | pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { | ||
73 | let loc = id.lookup(db); | ||
74 | let item_tree = db.item_tree(loc.id.file_id); | ||
75 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); | ||
76 | |||
77 | let union = &item_tree[loc.id.value]; | ||
78 | let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields); | ||
79 | |||
80 | Arc::new(StructData { name: union.name.clone(), variant_data: Arc::new(variant_data) }) | ||
81 | } | ||
82 | } | ||
83 | |||
84 | impl EnumData { | ||
85 | pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> { | ||
86 | let loc = e.lookup(db); | ||
87 | let item_tree = db.item_tree(loc.id.file_id); | ||
88 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); | ||
89 | |||
90 | let enum_ = &item_tree[loc.id.value]; | ||
91 | let mut variants = Arena::new(); | ||
92 | for var_id in enum_.variants.clone() { | ||
93 | if item_tree.attrs(var_id.into()).is_cfg_enabled(&cfg_options) { | ||
94 | let var = &item_tree[var_id]; | ||
95 | let var_data = lower_fields(&item_tree, &cfg_options, &var.fields); | ||
96 | |||
97 | variants.alloc(EnumVariantData { | ||
98 | name: var.name.clone(), | ||
99 | variant_data: Arc::new(var_data), | ||
100 | }); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | Arc::new(EnumData { name: enum_.name.clone(), variants }) | ||
105 | } | ||
106 | |||
107 | pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> { | ||
108 | let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?; | ||
109 | Some(id) | ||
110 | } | ||
111 | } | ||
112 | |||
113 | impl HasChildSource for EnumId { | ||
114 | type ChildId = LocalEnumVariantId; | ||
115 | type Value = ast::Variant; | ||
116 | fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { | ||
117 | let src = self.lookup(db).source(db); | ||
118 | let mut trace = Trace::new_for_map(); | ||
119 | lower_enum(db, &mut trace, &src, self.lookup(db).container.module(db)); | ||
120 | src.with_value(trace.into_map()) | ||
121 | } | ||
122 | } | ||
123 | |||
124 | fn lower_enum( | ||
125 | db: &dyn DefDatabase, | ||
126 | trace: &mut Trace<EnumVariantData, ast::Variant>, | ||
127 | ast: &InFile<ast::Enum>, | ||
128 | module_id: ModuleId, | ||
129 | ) { | ||
130 | let expander = CfgExpander::new(db, ast.file_id, module_id.krate); | ||
131 | let variants = ast | ||
132 | .value | ||
133 | .variant_list() | ||
134 | .into_iter() | ||
135 | .flat_map(|it| it.variants()) | ||
136 | .filter(|var| expander.is_cfg_enabled(var)); | ||
137 | for var in variants { | ||
138 | trace.alloc( | ||
139 | || var.clone(), | ||
140 | || EnumVariantData { | ||
141 | name: var.name().map_or_else(Name::missing, |it| it.as_name()), | ||
142 | variant_data: Arc::new(VariantData::new(db, ast.with_value(var.kind()), module_id)), | ||
143 | }, | ||
144 | ); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | impl VariantData { | ||
149 | fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self { | ||
150 | let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate); | ||
151 | let mut trace = Trace::new_for_arena(); | ||
152 | match lower_struct(db, &mut expander, &mut trace, &flavor) { | ||
153 | StructKind::Tuple => VariantData::Tuple(trace.into_arena()), | ||
154 | StructKind::Record => VariantData::Record(trace.into_arena()), | ||
155 | StructKind::Unit => VariantData::Unit, | ||
156 | } | ||
157 | } | ||
158 | |||
159 | pub fn fields(&self) -> &Arena<FieldData> { | ||
160 | const EMPTY: &Arena<FieldData> = &Arena::new(); | ||
161 | match &self { | ||
162 | VariantData::Record(fields) | VariantData::Tuple(fields) => fields, | ||
163 | _ => EMPTY, | ||
164 | } | ||
165 | } | ||
166 | |||
167 | pub fn field(&self, name: &Name) -> Option<LocalFieldId> { | ||
168 | self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None }) | ||
169 | } | ||
170 | |||
171 | pub fn kind(&self) -> StructKind { | ||
172 | match self { | ||
173 | VariantData::Record(_) => StructKind::Record, | ||
174 | VariantData::Tuple(_) => StructKind::Tuple, | ||
175 | VariantData::Unit => StructKind::Unit, | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | impl HasChildSource for VariantId { | ||
181 | type ChildId = LocalFieldId; | ||
182 | type Value = Either<ast::TupleField, ast::RecordField>; | ||
183 | |||
184 | fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { | ||
185 | let (src, module_id) = match self { | ||
186 | VariantId::EnumVariantId(it) => { | ||
187 | // I don't really like the fact that we call into parent source | ||
188 | // here, this might add to more queries then necessary. | ||
189 | let src = it.parent.child_source(db); | ||
190 | (src.map(|map| map[it.local_id].kind()), it.parent.lookup(db).container.module(db)) | ||
191 | } | ||
192 | VariantId::StructId(it) => { | ||
193 | (it.lookup(db).source(db).map(|it| it.kind()), it.lookup(db).container.module(db)) | ||
194 | } | ||
195 | VariantId::UnionId(it) => ( | ||
196 | it.lookup(db).source(db).map(|it| { | ||
197 | it.record_field_list() | ||
198 | .map(ast::StructKind::Record) | ||
199 | .unwrap_or(ast::StructKind::Unit) | ||
200 | }), | ||
201 | it.lookup(db).container.module(db), | ||
202 | ), | ||
203 | }; | ||
204 | let mut expander = CfgExpander::new(db, src.file_id, module_id.krate); | ||
205 | let mut trace = Trace::new_for_map(); | ||
206 | lower_struct(db, &mut expander, &mut trace, &src); | ||
207 | src.with_value(trace.into_map()) | ||
208 | } | ||
209 | } | ||
210 | |||
211 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
212 | pub enum StructKind { | ||
213 | Tuple, | ||
214 | Record, | ||
215 | Unit, | ||
216 | } | ||
217 | |||
218 | fn lower_struct( | ||
219 | db: &dyn DefDatabase, | ||
220 | expander: &mut CfgExpander, | ||
221 | trace: &mut Trace<FieldData, Either<ast::TupleField, ast::RecordField>>, | ||
222 | ast: &InFile<ast::StructKind>, | ||
223 | ) -> StructKind { | ||
224 | let ctx = LowerCtx::new(db, ast.file_id); | ||
225 | |||
226 | match &ast.value { | ||
227 | ast::StructKind::Tuple(fl) => { | ||
228 | for (i, fd) in fl.fields().enumerate() { | ||
229 | if !expander.is_cfg_enabled(&fd) { | ||
230 | continue; | ||
231 | } | ||
232 | |||
233 | trace.alloc( | ||
234 | || Either::Left(fd.clone()), | ||
235 | || FieldData { | ||
236 | name: Name::new_tuple_field(i), | ||
237 | type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()), | ||
238 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), | ||
239 | }, | ||
240 | ); | ||
241 | } | ||
242 | StructKind::Tuple | ||
243 | } | ||
244 | ast::StructKind::Record(fl) => { | ||
245 | for fd in fl.fields() { | ||
246 | if !expander.is_cfg_enabled(&fd) { | ||
247 | continue; | ||
248 | } | ||
249 | |||
250 | trace.alloc( | ||
251 | || Either::Right(fd.clone()), | ||
252 | || FieldData { | ||
253 | name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), | ||
254 | type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()), | ||
255 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), | ||
256 | }, | ||
257 | ); | ||
258 | } | ||
259 | StructKind::Record | ||
260 | } | ||
261 | ast::StructKind::Unit => StructKind::Unit, | ||
262 | } | ||
263 | } | ||
264 | |||
265 | fn lower_fields(item_tree: &ItemTree, cfg_options: &CfgOptions, fields: &Fields) -> VariantData { | ||
266 | match fields { | ||
267 | Fields::Record(flds) => { | ||
268 | let mut arena = Arena::new(); | ||
269 | for field_id in flds.clone() { | ||
270 | if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) { | ||
271 | arena.alloc(lower_field(item_tree, &item_tree[field_id])); | ||
272 | } | ||
273 | } | ||
274 | VariantData::Record(arena) | ||
275 | } | ||
276 | Fields::Tuple(flds) => { | ||
277 | let mut arena = Arena::new(); | ||
278 | for field_id in flds.clone() { | ||
279 | if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) { | ||
280 | arena.alloc(lower_field(item_tree, &item_tree[field_id])); | ||
281 | } | ||
282 | } | ||
283 | VariantData::Tuple(arena) | ||
284 | } | ||
285 | Fields::Unit => VariantData::Unit, | ||
286 | } | ||
287 | } | ||
288 | |||
289 | fn lower_field(item_tree: &ItemTree, field: &Field) -> FieldData { | ||
290 | FieldData { | ||
291 | name: field.name.clone(), | ||
292 | type_ref: field.type_ref.clone(), | ||
293 | visibility: item_tree[field.visibility].clone(), | ||
294 | } | ||
295 | } | ||
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs deleted file mode 100644 index 050832ce0..000000000 --- a/crates/ra_hir_def/src/attr.rs +++ /dev/null | |||
@@ -1,212 +0,0 @@ | |||
1 | //! A higher level attributes based on TokenTree, with also some shortcuts. | ||
2 | |||
3 | use std::{ops, sync::Arc}; | ||
4 | |||
5 | use either::Either; | ||
6 | use hir_expand::{hygiene::Hygiene, AstId, InFile}; | ||
7 | use mbe::ast_to_token_tree; | ||
8 | use ra_cfg::{CfgExpr, CfgOptions}; | ||
9 | use ra_syntax::{ | ||
10 | ast::{self, AstNode, AttrsOwner}, | ||
11 | SmolStr, | ||
12 | }; | ||
13 | use tt::Subtree; | ||
14 | |||
15 | use crate::{ | ||
16 | db::DefDatabase, | ||
17 | item_tree::{ItemTreeId, ItemTreeNode}, | ||
18 | nameres::ModuleSource, | ||
19 | path::ModPath, | ||
20 | src::HasChildSource, | ||
21 | AdtId, AttrDefId, Lookup, | ||
22 | }; | ||
23 | |||
24 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | ||
25 | pub struct Attrs { | ||
26 | entries: Option<Arc<[Attr]>>, | ||
27 | } | ||
28 | |||
29 | impl ops::Deref for Attrs { | ||
30 | type Target = [Attr]; | ||
31 | |||
32 | fn deref(&self) -> &[Attr] { | ||
33 | match &self.entries { | ||
34 | Some(it) => &*it, | ||
35 | None => &[], | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | impl Attrs { | ||
41 | pub const EMPTY: Attrs = Attrs { entries: None }; | ||
42 | |||
43 | pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { | ||
44 | match def { | ||
45 | AttrDefId::ModuleId(module) => { | ||
46 | let def_map = db.crate_def_map(module.krate); | ||
47 | let mod_data = &def_map[module.local_id]; | ||
48 | match mod_data.declaration_source(db) { | ||
49 | Some(it) => { | ||
50 | Attrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner)) | ||
51 | } | ||
52 | None => Attrs::from_attrs_owner( | ||
53 | db, | ||
54 | mod_data.definition_source(db).as_ref().map(|src| match src { | ||
55 | ModuleSource::SourceFile(file) => file as &dyn AttrsOwner, | ||
56 | ModuleSource::Module(module) => module as &dyn AttrsOwner, | ||
57 | }), | ||
58 | ), | ||
59 | } | ||
60 | } | ||
61 | AttrDefId::FieldId(it) => { | ||
62 | let src = it.parent.child_source(db); | ||
63 | match &src.value[it.local_id] { | ||
64 | Either::Left(_tuple) => Attrs::default(), | ||
65 | Either::Right(record) => Attrs::from_attrs_owner(db, src.with_value(record)), | ||
66 | } | ||
67 | } | ||
68 | AttrDefId::EnumVariantId(var_id) => { | ||
69 | let src = var_id.parent.child_source(db); | ||
70 | let src = src.as_ref().map(|it| &it[var_id.local_id]); | ||
71 | Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) | ||
72 | } | ||
73 | AttrDefId::AdtId(it) => match it { | ||
74 | AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
75 | AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
76 | AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
77 | }, | ||
78 | AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
79 | AttrDefId::MacroDefId(it) => { | ||
80 | it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) | ||
81 | } | ||
82 | AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
83 | AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
84 | AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
85 | AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
86 | AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
87 | } | ||
88 | } | ||
89 | |||
90 | pub fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs { | ||
91 | let hygiene = Hygiene::new(db.upcast(), owner.file_id); | ||
92 | Attrs::new(owner.value, &hygiene) | ||
93 | } | ||
94 | |||
95 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs { | ||
96 | let docs = ast::CommentIter::from_syntax_node(owner.syntax()).doc_comment_text().map( | ||
97 | |docs_text| Attr { | ||
98 | input: Some(AttrInput::Literal(SmolStr::new(docs_text))), | ||
99 | path: ModPath::from(hir_expand::name!(doc)), | ||
100 | }, | ||
101 | ); | ||
102 | let mut attrs = owner.attrs().peekable(); | ||
103 | let entries = if attrs.peek().is_none() { | ||
104 | // Avoid heap allocation | ||
105 | None | ||
106 | } else { | ||
107 | Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).chain(docs).collect()) | ||
108 | }; | ||
109 | Attrs { entries } | ||
110 | } | ||
111 | |||
112 | pub fn merge(&self, other: Attrs) -> Attrs { | ||
113 | match (&self.entries, &other.entries) { | ||
114 | (None, None) => Attrs { entries: None }, | ||
115 | (Some(entries), None) | (None, Some(entries)) => { | ||
116 | Attrs { entries: Some(entries.clone()) } | ||
117 | } | ||
118 | (Some(a), Some(b)) => { | ||
119 | Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) } | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
124 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { | ||
125 | AttrQuery { attrs: self, key } | ||
126 | } | ||
127 | |||
128 | pub fn cfg(&self) -> impl Iterator<Item = CfgExpr> + '_ { | ||
129 | // FIXME: handle cfg_attr :-) | ||
130 | self.by_key("cfg").tt_values().map(CfgExpr::parse) | ||
131 | } | ||
132 | pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { | ||
133 | self.cfg().all(|cfg| cfg_options.check(&cfg) != Some(false)) | ||
134 | } | ||
135 | } | ||
136 | |||
137 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
138 | pub struct Attr { | ||
139 | pub(crate) path: ModPath, | ||
140 | pub(crate) input: Option<AttrInput>, | ||
141 | } | ||
142 | |||
143 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
144 | pub enum AttrInput { | ||
145 | /// `#[attr = "string"]` | ||
146 | Literal(SmolStr), | ||
147 | /// `#[attr(subtree)]` | ||
148 | TokenTree(Subtree), | ||
149 | } | ||
150 | |||
151 | impl Attr { | ||
152 | fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { | ||
153 | let path = ModPath::from_src(ast.path()?, hygiene)?; | ||
154 | let input = if let Some(lit) = ast.literal() { | ||
155 | // FIXME: escape? raw string? | ||
156 | let value = lit.syntax().first_token()?.text().trim_matches('"').into(); | ||
157 | Some(AttrInput::Literal(value)) | ||
158 | } else if let Some(tt) = ast.token_tree() { | ||
159 | Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0)) | ||
160 | } else { | ||
161 | None | ||
162 | }; | ||
163 | Some(Attr { path, input }) | ||
164 | } | ||
165 | } | ||
166 | |||
167 | #[derive(Debug, Clone, Copy)] | ||
168 | pub struct AttrQuery<'a> { | ||
169 | attrs: &'a Attrs, | ||
170 | key: &'static str, | ||
171 | } | ||
172 | |||
173 | impl<'a> AttrQuery<'a> { | ||
174 | pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> { | ||
175 | self.attrs().filter_map(|attr| match attr.input.as_ref()? { | ||
176 | AttrInput::TokenTree(it) => Some(it), | ||
177 | _ => None, | ||
178 | }) | ||
179 | } | ||
180 | |||
181 | pub fn string_value(self) -> Option<&'a SmolStr> { | ||
182 | self.attrs().find_map(|attr| match attr.input.as_ref()? { | ||
183 | AttrInput::Literal(it) => Some(it), | ||
184 | _ => None, | ||
185 | }) | ||
186 | } | ||
187 | |||
188 | pub fn exists(self) -> bool { | ||
189 | self.attrs().next().is_some() | ||
190 | } | ||
191 | |||
192 | fn attrs(self) -> impl Iterator<Item = &'a Attr> { | ||
193 | let key = self.key; | ||
194 | self.attrs | ||
195 | .iter() | ||
196 | .filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_string() == key)) | ||
197 | } | ||
198 | } | ||
199 | |||
200 | fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> Attrs | ||
201 | where | ||
202 | N: ast::AttrsOwner, | ||
203 | { | ||
204 | let src = InFile::new(src.file_id, src.to_node(db.upcast())); | ||
205 | Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) | ||
206 | } | ||
207 | |||
208 | fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs { | ||
209 | let tree = db.item_tree(id.file_id); | ||
210 | let mod_item = N::id_to_mod_item(id.value); | ||
211 | tree.attrs(mod_item.into()).clone() | ||
212 | } | ||
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs deleted file mode 100644 index d5f18b920..000000000 --- a/crates/ra_hir_def/src/body.rs +++ /dev/null | |||
@@ -1,361 +0,0 @@ | |||
1 | //! Defines `Body`: a lowered representation of bodies of functions, statics and | ||
2 | //! consts. | ||
3 | mod lower; | ||
4 | pub mod scope; | ||
5 | |||
6 | use std::{mem, ops::Index, sync::Arc}; | ||
7 | |||
8 | use drop_bomb::DropBomb; | ||
9 | use either::Either; | ||
10 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId}; | ||
11 | use ra_arena::{map::ArenaMap, Arena}; | ||
12 | use ra_cfg::CfgOptions; | ||
13 | use ra_db::CrateId; | ||
14 | use ra_prof::profile; | ||
15 | use ra_syntax::{ast, AstNode, AstPtr}; | ||
16 | use rustc_hash::FxHashMap; | ||
17 | use test_utils::mark; | ||
18 | |||
19 | pub(crate) use lower::LowerCtx; | ||
20 | |||
21 | use crate::{ | ||
22 | attr::Attrs, | ||
23 | db::DefDatabase, | ||
24 | expr::{Expr, ExprId, Pat, PatId}, | ||
25 | item_scope::BuiltinShadowMode, | ||
26 | item_scope::ItemScope, | ||
27 | nameres::CrateDefMap, | ||
28 | path::{ModPath, Path}, | ||
29 | src::HasSource, | ||
30 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, | ||
31 | }; | ||
32 | |||
33 | /// A subset of Expander that only deals with cfg attributes. We only need it to | ||
34 | /// avoid cyclic queries in crate def map during enum processing. | ||
35 | pub(crate) struct CfgExpander { | ||
36 | cfg_options: CfgOptions, | ||
37 | hygiene: Hygiene, | ||
38 | } | ||
39 | |||
40 | pub(crate) struct Expander { | ||
41 | cfg_expander: CfgExpander, | ||
42 | crate_def_map: Arc<CrateDefMap>, | ||
43 | current_file_id: HirFileId, | ||
44 | ast_id_map: Arc<AstIdMap>, | ||
45 | module: ModuleId, | ||
46 | recursion_limit: usize, | ||
47 | } | ||
48 | |||
49 | #[cfg(test)] | ||
50 | const EXPANSION_RECURSION_LIMIT: usize = 32; | ||
51 | |||
52 | #[cfg(not(test))] | ||
53 | const EXPANSION_RECURSION_LIMIT: usize = 128; | ||
54 | |||
55 | impl CfgExpander { | ||
56 | pub(crate) fn new( | ||
57 | db: &dyn DefDatabase, | ||
58 | current_file_id: HirFileId, | ||
59 | krate: CrateId, | ||
60 | ) -> CfgExpander { | ||
61 | let hygiene = Hygiene::new(db.upcast(), current_file_id); | ||
62 | let cfg_options = db.crate_graph()[krate].cfg_options.clone(); | ||
63 | CfgExpander { cfg_options, hygiene } | ||
64 | } | ||
65 | |||
66 | pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs { | ||
67 | Attrs::new(owner, &self.hygiene) | ||
68 | } | ||
69 | |||
70 | pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool { | ||
71 | let attrs = self.parse_attrs(owner); | ||
72 | attrs.is_cfg_enabled(&self.cfg_options) | ||
73 | } | ||
74 | } | ||
75 | |||
76 | impl Expander { | ||
77 | pub(crate) fn new( | ||
78 | db: &dyn DefDatabase, | ||
79 | current_file_id: HirFileId, | ||
80 | module: ModuleId, | ||
81 | ) -> Expander { | ||
82 | let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); | ||
83 | let crate_def_map = db.crate_def_map(module.krate); | ||
84 | let ast_id_map = db.ast_id_map(current_file_id); | ||
85 | Expander { | ||
86 | cfg_expander, | ||
87 | crate_def_map, | ||
88 | current_file_id, | ||
89 | ast_id_map, | ||
90 | module, | ||
91 | recursion_limit: 0, | ||
92 | } | ||
93 | } | ||
94 | |||
95 | pub(crate) fn enter_expand<T: ast::AstNode>( | ||
96 | &mut self, | ||
97 | db: &dyn DefDatabase, | ||
98 | local_scope: Option<&ItemScope>, | ||
99 | macro_call: ast::MacroCall, | ||
100 | ) -> Option<(Mark, T)> { | ||
101 | self.recursion_limit += 1; | ||
102 | if self.recursion_limit > EXPANSION_RECURSION_LIMIT { | ||
103 | mark::hit!(your_stack_belongs_to_me); | ||
104 | return None; | ||
105 | } | ||
106 | |||
107 | let macro_call = InFile::new(self.current_file_id, ¯o_call); | ||
108 | |||
109 | if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, |path| { | ||
110 | if let Some(local_scope) = local_scope { | ||
111 | if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { | ||
112 | return Some(def); | ||
113 | } | ||
114 | } | ||
115 | self.resolve_path_as_macro(db, &path) | ||
116 | }) { | ||
117 | let file_id = call_id.as_file(); | ||
118 | if let Some(node) = db.parse_or_expand(file_id) { | ||
119 | if let Some(expr) = T::cast(node) { | ||
120 | log::debug!("macro expansion {:#?}", expr.syntax()); | ||
121 | |||
122 | let mark = Mark { | ||
123 | file_id: self.current_file_id, | ||
124 | ast_id_map: mem::take(&mut self.ast_id_map), | ||
125 | bomb: DropBomb::new("expansion mark dropped"), | ||
126 | }; | ||
127 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); | ||
128 | self.current_file_id = file_id; | ||
129 | self.ast_id_map = db.ast_id_map(file_id); | ||
130 | return Some((mark, expr)); | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | // FIXME: Instead of just dropping the error from expansion | ||
136 | // report it | ||
137 | None | ||
138 | } | ||
139 | |||
140 | pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { | ||
141 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); | ||
142 | self.current_file_id = mark.file_id; | ||
143 | self.ast_id_map = mem::take(&mut mark.ast_id_map); | ||
144 | self.recursion_limit -= 1; | ||
145 | mark.bomb.defuse(); | ||
146 | } | ||
147 | |||
148 | pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> { | ||
149 | InFile { file_id: self.current_file_id, value } | ||
150 | } | ||
151 | |||
152 | pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool { | ||
153 | self.cfg_expander.is_cfg_enabled(owner) | ||
154 | } | ||
155 | |||
156 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { | ||
157 | Path::from_src(path, &self.cfg_expander.hygiene) | ||
158 | } | ||
159 | |||
160 | fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { | ||
161 | self.crate_def_map | ||
162 | .resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other) | ||
163 | .0 | ||
164 | .take_macros() | ||
165 | } | ||
166 | |||
167 | fn ast_id<N: AstNode>(&self, item: &N) -> AstId<N> { | ||
168 | let file_local_id = self.ast_id_map.ast_id(item); | ||
169 | AstId::new(self.current_file_id, file_local_id) | ||
170 | } | ||
171 | } | ||
172 | |||
173 | pub(crate) struct Mark { | ||
174 | file_id: HirFileId, | ||
175 | ast_id_map: Arc<AstIdMap>, | ||
176 | bomb: DropBomb, | ||
177 | } | ||
178 | |||
179 | /// The body of an item (function, const etc.). | ||
180 | #[derive(Debug, Eq, PartialEq)] | ||
181 | pub struct Body { | ||
182 | pub exprs: Arena<Expr>, | ||
183 | pub pats: Arena<Pat>, | ||
184 | /// The patterns for the function's parameters. While the parameter types are | ||
185 | /// part of the function signature, the patterns are not (they don't change | ||
186 | /// the external type of the function). | ||
187 | /// | ||
188 | /// If this `Body` is for the body of a constant, this will just be | ||
189 | /// empty. | ||
190 | pub params: Vec<PatId>, | ||
191 | /// The `ExprId` of the actual body expression. | ||
192 | pub body_expr: ExprId, | ||
193 | pub item_scope: ItemScope, | ||
194 | } | ||
195 | |||
196 | pub type ExprPtr = AstPtr<ast::Expr>; | ||
197 | pub type ExprSource = InFile<ExprPtr>; | ||
198 | |||
199 | pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | ||
200 | pub type PatSource = InFile<PatPtr>; | ||
201 | |||
202 | /// An item body together with the mapping from syntax nodes to HIR expression | ||
203 | /// IDs. This is needed to go from e.g. a position in a file to the HIR | ||
204 | /// expression containing it; but for type inference etc., we want to operate on | ||
205 | /// a structure that is agnostic to the actual positions of expressions in the | ||
206 | /// file, so that we don't recompute types whenever some whitespace is typed. | ||
207 | /// | ||
208 | /// One complication here is that, due to macro expansion, a single `Body` might | ||
209 | /// be spread across several files. So, for each ExprId and PatId, we record | ||
210 | /// both the HirFileId and the position inside the file. However, we only store | ||
211 | /// AST -> ExprId mapping for non-macro files, as it is not clear how to handle | ||
212 | /// this properly for macros. | ||
213 | #[derive(Default, Debug, Eq, PartialEq)] | ||
214 | pub struct BodySourceMap { | ||
215 | expr_map: FxHashMap<ExprSource, ExprId>, | ||
216 | expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, | ||
217 | pat_map: FxHashMap<PatSource, PatId>, | ||
218 | pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, | ||
219 | field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordExprField>>>, | ||
220 | expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, | ||
221 | } | ||
222 | |||
223 | #[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] | ||
224 | pub struct SyntheticSyntax; | ||
225 | |||
226 | impl Body { | ||
227 | pub(crate) fn body_with_source_map_query( | ||
228 | db: &dyn DefDatabase, | ||
229 | def: DefWithBodyId, | ||
230 | ) -> (Arc<Body>, Arc<BodySourceMap>) { | ||
231 | let _p = profile("body_with_source_map_query"); | ||
232 | let mut params = None; | ||
233 | |||
234 | let (file_id, module, body) = match def { | ||
235 | DefWithBodyId::FunctionId(f) => { | ||
236 | let f = f.lookup(db); | ||
237 | let src = f.source(db); | ||
238 | params = src.value.param_list(); | ||
239 | (src.file_id, f.module(db), src.value.body().map(ast::Expr::from)) | ||
240 | } | ||
241 | DefWithBodyId::ConstId(c) => { | ||
242 | let c = c.lookup(db); | ||
243 | let src = c.source(db); | ||
244 | (src.file_id, c.module(db), src.value.body()) | ||
245 | } | ||
246 | DefWithBodyId::StaticId(s) => { | ||
247 | let s = s.lookup(db); | ||
248 | let src = s.source(db); | ||
249 | (src.file_id, s.module(db), src.value.body()) | ||
250 | } | ||
251 | }; | ||
252 | let expander = Expander::new(db, file_id, module); | ||
253 | let (body, source_map) = Body::new(db, def, expander, params, body); | ||
254 | (Arc::new(body), Arc::new(source_map)) | ||
255 | } | ||
256 | |||
257 | pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<Body> { | ||
258 | db.body_with_source_map(def).0 | ||
259 | } | ||
260 | |||
261 | fn new( | ||
262 | db: &dyn DefDatabase, | ||
263 | def: DefWithBodyId, | ||
264 | expander: Expander, | ||
265 | params: Option<ast::ParamList>, | ||
266 | body: Option<ast::Expr>, | ||
267 | ) -> (Body, BodySourceMap) { | ||
268 | lower::lower(db, def, expander, params, body) | ||
269 | } | ||
270 | } | ||
271 | |||
272 | impl Index<ExprId> for Body { | ||
273 | type Output = Expr; | ||
274 | |||
275 | fn index(&self, expr: ExprId) -> &Expr { | ||
276 | &self.exprs[expr] | ||
277 | } | ||
278 | } | ||
279 | |||
280 | impl Index<PatId> for Body { | ||
281 | type Output = Pat; | ||
282 | |||
283 | fn index(&self, pat: PatId) -> &Pat { | ||
284 | &self.pats[pat] | ||
285 | } | ||
286 | } | ||
287 | |||
288 | impl BodySourceMap { | ||
289 | pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { | ||
290 | self.expr_map_back[expr].clone() | ||
291 | } | ||
292 | |||
293 | pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> { | ||
294 | let src = node.map(|it| AstPtr::new(it)); | ||
295 | self.expr_map.get(&src).cloned() | ||
296 | } | ||
297 | |||
298 | pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId> { | ||
299 | let src = node.map(|it| AstPtr::new(it)); | ||
300 | self.expansions.get(&src).cloned() | ||
301 | } | ||
302 | |||
303 | pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> { | ||
304 | self.pat_map_back[pat].clone() | ||
305 | } | ||
306 | |||
307 | pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> { | ||
308 | let src = node.map(|it| Either::Left(AstPtr::new(it))); | ||
309 | self.pat_map.get(&src).cloned() | ||
310 | } | ||
311 | |||
312 | pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> { | ||
313 | let src = node.map(|it| Either::Right(AstPtr::new(it))); | ||
314 | self.pat_map.get(&src).cloned() | ||
315 | } | ||
316 | |||
317 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordExprField>> { | ||
318 | self.field_map[&(expr, field)].clone() | ||
319 | } | ||
320 | } | ||
321 | |||
322 | #[cfg(test)] | ||
323 | mod tests { | ||
324 | use ra_db::{fixture::WithFixture, SourceDatabase}; | ||
325 | use test_utils::mark; | ||
326 | |||
327 | use crate::ModuleDefId; | ||
328 | |||
329 | use super::*; | ||
330 | |||
331 | fn lower(ra_fixture: &str) -> Arc<Body> { | ||
332 | let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture); | ||
333 | |||
334 | let krate = db.crate_graph().iter().next().unwrap(); | ||
335 | let def_map = db.crate_def_map(krate); | ||
336 | let module = def_map.modules_for_file(file_id).next().unwrap(); | ||
337 | let module = &def_map[module]; | ||
338 | let fn_def = match module.scope.declarations().next().unwrap() { | ||
339 | ModuleDefId::FunctionId(it) => it, | ||
340 | _ => panic!(), | ||
341 | }; | ||
342 | |||
343 | db.body(fn_def.into()) | ||
344 | } | ||
345 | |||
346 | #[test] | ||
347 | fn your_stack_belongs_to_me() { | ||
348 | mark::check!(your_stack_belongs_to_me); | ||
349 | lower( | ||
350 | " | ||
351 | macro_rules! n_nuple { | ||
352 | ($e:tt) => (); | ||
353 | ($($rest:tt)*) => {{ | ||
354 | (n_nuple!($($rest)*)None,) | ||
355 | }}; | ||
356 | } | ||
357 | fn main() { n_nuple!(1,2,3); } | ||
358 | ", | ||
359 | ); | ||
360 | } | ||
361 | } | ||
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs deleted file mode 100644 index 827ced4ad..000000000 --- a/crates/ra_hir_def/src/body/lower.rs +++ /dev/null | |||
@@ -1,916 +0,0 @@ | |||
1 | //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` | ||
2 | //! representation. | ||
3 | |||
4 | use either::Either; | ||
5 | use hir_expand::{ | ||
6 | hygiene::Hygiene, | ||
7 | name::{name, AsName, Name}, | ||
8 | HirFileId, MacroDefId, MacroDefKind, | ||
9 | }; | ||
10 | use ra_arena::Arena; | ||
11 | use ra_syntax::{ | ||
12 | ast::{ | ||
13 | self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner, | ||
14 | SlicePatComponents, | ||
15 | }, | ||
16 | AstNode, AstPtr, | ||
17 | }; | ||
18 | use test_utils::mark; | ||
19 | |||
20 | use crate::{ | ||
21 | adt::StructKind, | ||
22 | body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax}, | ||
23 | builtin_type::{BuiltinFloat, BuiltinInt}, | ||
24 | db::DefDatabase, | ||
25 | expr::{ | ||
26 | dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, | ||
27 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, | ||
28 | }, | ||
29 | item_scope::BuiltinShadowMode, | ||
30 | item_tree::{ItemTree, ItemTreeId, ItemTreeNode}, | ||
31 | path::{GenericArgs, Path}, | ||
32 | type_ref::{Mutability, Rawness, TypeRef}, | ||
33 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, | ||
34 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, | ||
35 | }; | ||
36 | |||
37 | use super::{ExprSource, PatSource}; | ||
38 | use ast::AstChildren; | ||
39 | use rustc_hash::FxHashMap; | ||
40 | use std::{any::type_name, sync::Arc}; | ||
41 | |||
42 | pub(crate) struct LowerCtx { | ||
43 | hygiene: Hygiene, | ||
44 | } | ||
45 | |||
46 | impl LowerCtx { | ||
47 | pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { | ||
48 | LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) } | ||
49 | } | ||
50 | pub fn with_hygiene(hygiene: &Hygiene) -> Self { | ||
51 | LowerCtx { hygiene: hygiene.clone() } | ||
52 | } | ||
53 | |||
54 | pub fn lower_path(&self, ast: ast::Path) -> Option<Path> { | ||
55 | Path::from_src(ast, &self.hygiene) | ||
56 | } | ||
57 | } | ||
58 | |||
59 | pub(super) fn lower( | ||
60 | db: &dyn DefDatabase, | ||
61 | def: DefWithBodyId, | ||
62 | expander: Expander, | ||
63 | params: Option<ast::ParamList>, | ||
64 | body: Option<ast::Expr>, | ||
65 | ) -> (Body, BodySourceMap) { | ||
66 | let item_tree = db.item_tree(expander.current_file_id); | ||
67 | ExprCollector { | ||
68 | db, | ||
69 | def, | ||
70 | source_map: BodySourceMap::default(), | ||
71 | body: Body { | ||
72 | exprs: Arena::default(), | ||
73 | pats: Arena::default(), | ||
74 | params: Vec::new(), | ||
75 | body_expr: dummy_expr_id(), | ||
76 | item_scope: Default::default(), | ||
77 | }, | ||
78 | item_trees: { | ||
79 | let mut map = FxHashMap::default(); | ||
80 | map.insert(expander.current_file_id, item_tree); | ||
81 | map | ||
82 | }, | ||
83 | expander, | ||
84 | } | ||
85 | .collect(params, body) | ||
86 | } | ||
87 | |||
88 | struct ExprCollector<'a> { | ||
89 | db: &'a dyn DefDatabase, | ||
90 | def: DefWithBodyId, | ||
91 | expander: Expander, | ||
92 | body: Body, | ||
93 | source_map: BodySourceMap, | ||
94 | |||
95 | item_trees: FxHashMap<HirFileId, Arc<ItemTree>>, | ||
96 | } | ||
97 | |||
98 | impl ExprCollector<'_> { | ||
99 | fn collect( | ||
100 | mut self, | ||
101 | param_list: Option<ast::ParamList>, | ||
102 | body: Option<ast::Expr>, | ||
103 | ) -> (Body, BodySourceMap) { | ||
104 | if let Some(param_list) = param_list { | ||
105 | if let Some(self_param) = param_list.self_param() { | ||
106 | let ptr = AstPtr::new(&self_param); | ||
107 | let param_pat = self.alloc_pat( | ||
108 | Pat::Bind { | ||
109 | name: name![self], | ||
110 | mode: BindingAnnotation::Unannotated, | ||
111 | subpat: None, | ||
112 | }, | ||
113 | Either::Right(ptr), | ||
114 | ); | ||
115 | self.body.params.push(param_pat); | ||
116 | } | ||
117 | |||
118 | for param in param_list.params() { | ||
119 | let pat = match param.pat() { | ||
120 | None => continue, | ||
121 | Some(pat) => pat, | ||
122 | }; | ||
123 | let param_pat = self.collect_pat(pat); | ||
124 | self.body.params.push(param_pat); | ||
125 | } | ||
126 | }; | ||
127 | |||
128 | self.body.body_expr = self.collect_expr_opt(body); | ||
129 | (self.body, self.source_map) | ||
130 | } | ||
131 | |||
132 | fn ctx(&self) -> LowerCtx { | ||
133 | LowerCtx::new(self.db, self.expander.current_file_id) | ||
134 | } | ||
135 | |||
136 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { | ||
137 | let src = self.expander.to_source(ptr); | ||
138 | let id = self.make_expr(expr, Ok(src.clone())); | ||
139 | self.source_map.expr_map.insert(src, id); | ||
140 | id | ||
141 | } | ||
142 | // desugared exprs don't have ptr, that's wrong and should be fixed | ||
143 | // somehow. | ||
144 | fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { | ||
145 | self.make_expr(expr, Err(SyntheticSyntax)) | ||
146 | } | ||
147 | fn empty_block(&mut self) -> ExprId { | ||
148 | self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None, label: None }) | ||
149 | } | ||
150 | fn missing_expr(&mut self) -> ExprId { | ||
151 | self.alloc_expr_desugared(Expr::Missing) | ||
152 | } | ||
153 | fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) -> ExprId { | ||
154 | let id = self.body.exprs.alloc(expr); | ||
155 | self.source_map.expr_map_back.insert(id, src); | ||
156 | id | ||
157 | } | ||
158 | |||
159 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { | ||
160 | let src = self.expander.to_source(ptr); | ||
161 | let id = self.make_pat(pat, Ok(src.clone())); | ||
162 | self.source_map.pat_map.insert(src, id); | ||
163 | id | ||
164 | } | ||
165 | fn missing_pat(&mut self) -> PatId { | ||
166 | self.make_pat(Pat::Missing, Err(SyntheticSyntax)) | ||
167 | } | ||
168 | fn make_pat(&mut self, pat: Pat, src: Result<PatSource, SyntheticSyntax>) -> PatId { | ||
169 | let id = self.body.pats.alloc(pat); | ||
170 | self.source_map.pat_map_back.insert(id, src); | ||
171 | id | ||
172 | } | ||
173 | |||
174 | fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { | ||
175 | let syntax_ptr = AstPtr::new(&expr); | ||
176 | if !self.expander.is_cfg_enabled(&expr) { | ||
177 | return self.missing_expr(); | ||
178 | } | ||
179 | |||
180 | match expr { | ||
181 | ast::Expr::IfExpr(e) => { | ||
182 | let then_branch = self.collect_block_opt(e.then_branch()); | ||
183 | |||
184 | let else_branch = e.else_branch().map(|b| match b { | ||
185 | ast::ElseBranch::Block(it) => self.collect_block(it), | ||
186 | ast::ElseBranch::IfExpr(elif) => { | ||
187 | let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap(); | ||
188 | self.collect_expr(expr) | ||
189 | } | ||
190 | }); | ||
191 | |||
192 | let condition = match e.condition() { | ||
193 | None => self.missing_expr(), | ||
194 | Some(condition) => match condition.pat() { | ||
195 | None => self.collect_expr_opt(condition.expr()), | ||
196 | // if let -- desugar to match | ||
197 | Some(pat) => { | ||
198 | let pat = self.collect_pat(pat); | ||
199 | let match_expr = self.collect_expr_opt(condition.expr()); | ||
200 | let placeholder_pat = self.missing_pat(); | ||
201 | let arms = vec![ | ||
202 | MatchArm { pat, expr: then_branch, guard: None }, | ||
203 | MatchArm { | ||
204 | pat: placeholder_pat, | ||
205 | expr: else_branch.unwrap_or_else(|| self.empty_block()), | ||
206 | guard: None, | ||
207 | }, | ||
208 | ]; | ||
209 | return self | ||
210 | .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr); | ||
211 | } | ||
212 | }, | ||
213 | }; | ||
214 | |||
215 | self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) | ||
216 | } | ||
217 | ast::Expr::EffectExpr(e) => match e.effect() { | ||
218 | ast::Effect::Try(_) => { | ||
219 | let body = self.collect_block_opt(e.block_expr()); | ||
220 | self.alloc_expr(Expr::TryBlock { body }, syntax_ptr) | ||
221 | } | ||
222 | ast::Effect::Unsafe(_) => { | ||
223 | let body = self.collect_block_opt(e.block_expr()); | ||
224 | self.alloc_expr(Expr::Unsafe { body }, syntax_ptr) | ||
225 | } | ||
226 | // FIXME: we need to record these effects somewhere... | ||
227 | ast::Effect::Async(_) | ast::Effect::Label(_) => { | ||
228 | self.collect_block_opt(e.block_expr()) | ||
229 | } | ||
230 | }, | ||
231 | ast::Expr::BlockExpr(e) => self.collect_block(e), | ||
232 | ast::Expr::LoopExpr(e) => { | ||
233 | let body = self.collect_block_opt(e.loop_body()); | ||
234 | self.alloc_expr( | ||
235 | Expr::Loop { | ||
236 | body, | ||
237 | label: e | ||
238 | .label() | ||
239 | .and_then(|l| l.lifetime_token()) | ||
240 | .map(|l| Name::new_lifetime(&l)), | ||
241 | }, | ||
242 | syntax_ptr, | ||
243 | ) | ||
244 | } | ||
245 | ast::Expr::WhileExpr(e) => { | ||
246 | let body = self.collect_block_opt(e.loop_body()); | ||
247 | |||
248 | let condition = match e.condition() { | ||
249 | None => self.missing_expr(), | ||
250 | Some(condition) => match condition.pat() { | ||
251 | None => self.collect_expr_opt(condition.expr()), | ||
252 | // if let -- desugar to match | ||
253 | Some(pat) => { | ||
254 | mark::hit!(infer_resolve_while_let); | ||
255 | let pat = self.collect_pat(pat); | ||
256 | let match_expr = self.collect_expr_opt(condition.expr()); | ||
257 | let placeholder_pat = self.missing_pat(); | ||
258 | let break_ = | ||
259 | self.alloc_expr_desugared(Expr::Break { expr: None, label: None }); | ||
260 | let arms = vec![ | ||
261 | MatchArm { pat, expr: body, guard: None }, | ||
262 | MatchArm { pat: placeholder_pat, expr: break_, guard: None }, | ||
263 | ]; | ||
264 | let match_expr = | ||
265 | self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); | ||
266 | return self.alloc_expr( | ||
267 | Expr::Loop { | ||
268 | body: match_expr, | ||
269 | label: e | ||
270 | .label() | ||
271 | .and_then(|l| l.lifetime_token()) | ||
272 | .map(|l| Name::new_lifetime(&l)), | ||
273 | }, | ||
274 | syntax_ptr, | ||
275 | ); | ||
276 | } | ||
277 | }, | ||
278 | }; | ||
279 | |||
280 | self.alloc_expr( | ||
281 | Expr::While { | ||
282 | condition, | ||
283 | body, | ||
284 | label: e | ||
285 | .label() | ||
286 | .and_then(|l| l.lifetime_token()) | ||
287 | .map(|l| Name::new_lifetime(&l)), | ||
288 | }, | ||
289 | syntax_ptr, | ||
290 | ) | ||
291 | } | ||
292 | ast::Expr::ForExpr(e) => { | ||
293 | let iterable = self.collect_expr_opt(e.iterable()); | ||
294 | let pat = self.collect_pat_opt(e.pat()); | ||
295 | let body = self.collect_block_opt(e.loop_body()); | ||
296 | self.alloc_expr( | ||
297 | Expr::For { | ||
298 | iterable, | ||
299 | pat, | ||
300 | body, | ||
301 | label: e | ||
302 | .label() | ||
303 | .and_then(|l| l.lifetime_token()) | ||
304 | .map(|l| Name::new_lifetime(&l)), | ||
305 | }, | ||
306 | syntax_ptr, | ||
307 | ) | ||
308 | } | ||
309 | ast::Expr::CallExpr(e) => { | ||
310 | let callee = self.collect_expr_opt(e.expr()); | ||
311 | let args = if let Some(arg_list) = e.arg_list() { | ||
312 | arg_list.args().map(|e| self.collect_expr(e)).collect() | ||
313 | } else { | ||
314 | Vec::new() | ||
315 | }; | ||
316 | self.alloc_expr(Expr::Call { callee, args }, syntax_ptr) | ||
317 | } | ||
318 | ast::Expr::MethodCallExpr(e) => { | ||
319 | let receiver = self.collect_expr_opt(e.expr()); | ||
320 | let args = if let Some(arg_list) = e.arg_list() { | ||
321 | arg_list.args().map(|e| self.collect_expr(e)).collect() | ||
322 | } else { | ||
323 | Vec::new() | ||
324 | }; | ||
325 | let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); | ||
326 | let generic_args = | ||
327 | e.type_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); | ||
328 | self.alloc_expr( | ||
329 | Expr::MethodCall { receiver, method_name, args, generic_args }, | ||
330 | syntax_ptr, | ||
331 | ) | ||
332 | } | ||
333 | ast::Expr::MatchExpr(e) => { | ||
334 | let expr = self.collect_expr_opt(e.expr()); | ||
335 | let arms = if let Some(match_arm_list) = e.match_arm_list() { | ||
336 | match_arm_list | ||
337 | .arms() | ||
338 | .map(|arm| MatchArm { | ||
339 | pat: self.collect_pat_opt(arm.pat()), | ||
340 | expr: self.collect_expr_opt(arm.expr()), | ||
341 | guard: arm | ||
342 | .guard() | ||
343 | .and_then(|guard| guard.expr()) | ||
344 | .map(|e| self.collect_expr(e)), | ||
345 | }) | ||
346 | .collect() | ||
347 | } else { | ||
348 | Vec::new() | ||
349 | }; | ||
350 | self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) | ||
351 | } | ||
352 | ast::Expr::PathExpr(e) => { | ||
353 | let path = e | ||
354 | .path() | ||
355 | .and_then(|path| self.expander.parse_path(path)) | ||
356 | .map(Expr::Path) | ||
357 | .unwrap_or(Expr::Missing); | ||
358 | self.alloc_expr(path, syntax_ptr) | ||
359 | } | ||
360 | ast::Expr::ContinueExpr(e) => self.alloc_expr( | ||
361 | Expr::Continue { label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) }, | ||
362 | syntax_ptr, | ||
363 | ), | ||
364 | ast::Expr::BreakExpr(e) => { | ||
365 | let expr = e.expr().map(|e| self.collect_expr(e)); | ||
366 | self.alloc_expr( | ||
367 | Expr::Break { expr, label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) }, | ||
368 | syntax_ptr, | ||
369 | ) | ||
370 | } | ||
371 | ast::Expr::ParenExpr(e) => { | ||
372 | let inner = self.collect_expr_opt(e.expr()); | ||
373 | // make the paren expr point to the inner expression as well | ||
374 | let src = self.expander.to_source(syntax_ptr); | ||
375 | self.source_map.expr_map.insert(src, inner); | ||
376 | inner | ||
377 | } | ||
378 | ast::Expr::ReturnExpr(e) => { | ||
379 | let expr = e.expr().map(|e| self.collect_expr(e)); | ||
380 | self.alloc_expr(Expr::Return { expr }, syntax_ptr) | ||
381 | } | ||
382 | ast::Expr::RecordExpr(e) => { | ||
383 | let path = e.path().and_then(|path| self.expander.parse_path(path)); | ||
384 | let mut field_ptrs = Vec::new(); | ||
385 | let record_lit = if let Some(nfl) = e.record_expr_field_list() { | ||
386 | let fields = nfl | ||
387 | .fields() | ||
388 | .inspect(|field| field_ptrs.push(AstPtr::new(field))) | ||
389 | .filter_map(|field| { | ||
390 | if !self.expander.is_cfg_enabled(&field) { | ||
391 | return None; | ||
392 | } | ||
393 | let name = field.field_name()?.as_name(); | ||
394 | |||
395 | Some(RecordLitField { | ||
396 | name, | ||
397 | expr: match field.expr() { | ||
398 | Some(e) => self.collect_expr(e), | ||
399 | None => self.missing_expr(), | ||
400 | }, | ||
401 | }) | ||
402 | }) | ||
403 | .collect(); | ||
404 | let spread = nfl.spread().map(|s| self.collect_expr(s)); | ||
405 | Expr::RecordLit { path, fields, spread } | ||
406 | } else { | ||
407 | Expr::RecordLit { path, fields: Vec::new(), spread: None } | ||
408 | }; | ||
409 | |||
410 | let res = self.alloc_expr(record_lit, syntax_ptr); | ||
411 | for (i, ptr) in field_ptrs.into_iter().enumerate() { | ||
412 | let src = self.expander.to_source(ptr); | ||
413 | self.source_map.field_map.insert((res, i), src); | ||
414 | } | ||
415 | res | ||
416 | } | ||
417 | ast::Expr::FieldExpr(e) => { | ||
418 | let expr = self.collect_expr_opt(e.expr()); | ||
419 | let name = match e.field_access() { | ||
420 | Some(kind) => kind.as_name(), | ||
421 | _ => Name::missing(), | ||
422 | }; | ||
423 | self.alloc_expr(Expr::Field { expr, name }, syntax_ptr) | ||
424 | } | ||
425 | ast::Expr::AwaitExpr(e) => { | ||
426 | let expr = self.collect_expr_opt(e.expr()); | ||
427 | self.alloc_expr(Expr::Await { expr }, syntax_ptr) | ||
428 | } | ||
429 | ast::Expr::TryExpr(e) => { | ||
430 | let expr = self.collect_expr_opt(e.expr()); | ||
431 | self.alloc_expr(Expr::Try { expr }, syntax_ptr) | ||
432 | } | ||
433 | ast::Expr::CastExpr(e) => { | ||
434 | let expr = self.collect_expr_opt(e.expr()); | ||
435 | let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty()); | ||
436 | self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) | ||
437 | } | ||
438 | ast::Expr::RefExpr(e) => { | ||
439 | let expr = self.collect_expr_opt(e.expr()); | ||
440 | let raw_tok = e.raw_token().is_some(); | ||
441 | let mutability = if raw_tok { | ||
442 | if e.mut_token().is_some() { | ||
443 | Mutability::Mut | ||
444 | } else if e.const_token().is_some() { | ||
445 | Mutability::Shared | ||
446 | } else { | ||
447 | unreachable!("parser only remaps to raw_token() if matching mutability token follows") | ||
448 | } | ||
449 | } else { | ||
450 | Mutability::from_mutable(e.mut_token().is_some()) | ||
451 | }; | ||
452 | let rawness = Rawness::from_raw(raw_tok); | ||
453 | self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr) | ||
454 | } | ||
455 | ast::Expr::PrefixExpr(e) => { | ||
456 | let expr = self.collect_expr_opt(e.expr()); | ||
457 | if let Some(op) = e.op_kind() { | ||
458 | self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr) | ||
459 | } else { | ||
460 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
461 | } | ||
462 | } | ||
463 | ast::Expr::LambdaExpr(e) => { | ||
464 | let mut args = Vec::new(); | ||
465 | let mut arg_types = Vec::new(); | ||
466 | if let Some(pl) = e.param_list() { | ||
467 | for param in pl.params() { | ||
468 | let pat = self.collect_pat_opt(param.pat()); | ||
469 | let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); | ||
470 | args.push(pat); | ||
471 | arg_types.push(type_ref); | ||
472 | } | ||
473 | } | ||
474 | let ret_type = | ||
475 | e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it)); | ||
476 | let body = self.collect_expr_opt(e.body()); | ||
477 | self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) | ||
478 | } | ||
479 | ast::Expr::BinExpr(e) => { | ||
480 | let lhs = self.collect_expr_opt(e.lhs()); | ||
481 | let rhs = self.collect_expr_opt(e.rhs()); | ||
482 | let op = e.op_kind().map(BinaryOp::from); | ||
483 | self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr) | ||
484 | } | ||
485 | ast::Expr::TupleExpr(e) => { | ||
486 | let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect(); | ||
487 | self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr) | ||
488 | } | ||
489 | ast::Expr::BoxExpr(e) => { | ||
490 | let expr = self.collect_expr_opt(e.expr()); | ||
491 | self.alloc_expr(Expr::Box { expr }, syntax_ptr) | ||
492 | } | ||
493 | |||
494 | ast::Expr::ArrayExpr(e) => { | ||
495 | let kind = e.kind(); | ||
496 | |||
497 | match kind { | ||
498 | ArrayExprKind::ElementList(e) => { | ||
499 | let exprs = e.map(|expr| self.collect_expr(expr)).collect(); | ||
500 | self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr) | ||
501 | } | ||
502 | ArrayExprKind::Repeat { initializer, repeat } => { | ||
503 | let initializer = self.collect_expr_opt(initializer); | ||
504 | let repeat = self.collect_expr_opt(repeat); | ||
505 | self.alloc_expr( | ||
506 | Expr::Array(Array::Repeat { initializer, repeat }), | ||
507 | syntax_ptr, | ||
508 | ) | ||
509 | } | ||
510 | } | ||
511 | } | ||
512 | |||
513 | ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr), | ||
514 | ast::Expr::IndexExpr(e) => { | ||
515 | let base = self.collect_expr_opt(e.base()); | ||
516 | let index = self.collect_expr_opt(e.index()); | ||
517 | self.alloc_expr(Expr::Index { base, index }, syntax_ptr) | ||
518 | } | ||
519 | ast::Expr::RangeExpr(e) => { | ||
520 | let lhs = e.start().map(|lhs| self.collect_expr(lhs)); | ||
521 | let rhs = e.end().map(|rhs| self.collect_expr(rhs)); | ||
522 | match e.op_kind() { | ||
523 | Some(range_type) => { | ||
524 | self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr) | ||
525 | } | ||
526 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
527 | } | ||
528 | } | ||
529 | ast::Expr::MacroCall(e) => { | ||
530 | if let Some(name) = e.is_macro_rules().map(|it| it.as_name()) { | ||
531 | let mac = MacroDefId { | ||
532 | krate: Some(self.expander.module.krate), | ||
533 | ast_id: Some(self.expander.ast_id(&e)), | ||
534 | kind: MacroDefKind::Declarative, | ||
535 | local_inner: false, | ||
536 | }; | ||
537 | self.body.item_scope.define_legacy_macro(name, mac); | ||
538 | |||
539 | // FIXME: do we still need to allocate this as missing ? | ||
540 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
541 | } else { | ||
542 | let macro_call = self.expander.to_source(AstPtr::new(&e)); | ||
543 | match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) { | ||
544 | Some((mark, expansion)) => { | ||
545 | self.source_map | ||
546 | .expansions | ||
547 | .insert(macro_call, self.expander.current_file_id); | ||
548 | |||
549 | let item_tree = self.db.item_tree(self.expander.current_file_id); | ||
550 | self.item_trees.insert(self.expander.current_file_id, item_tree); | ||
551 | let id = self.collect_expr(expansion); | ||
552 | self.expander.exit(self.db, mark); | ||
553 | id | ||
554 | } | ||
555 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | |||
560 | // FIXME implement HIR for these: | ||
561 | ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
562 | } | ||
563 | } | ||
564 | |||
565 | fn find_inner_item<N: ItemTreeNode>(&self, ast: &N::Source) -> Option<ItemTreeId<N>> { | ||
566 | let id = self.expander.ast_id(ast); | ||
567 | let tree = &self.item_trees[&id.file_id]; | ||
568 | |||
569 | // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes | ||
570 | |||
571 | // Root file (non-macro). | ||
572 | let item_tree_id = tree | ||
573 | .all_inner_items() | ||
574 | .chain(tree.top_level_items().iter().copied()) | ||
575 | .filter_map(|mod_item| mod_item.downcast::<N>()) | ||
576 | .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value.upcast()) | ||
577 | .or_else(|| { | ||
578 | log::debug!( | ||
579 | "couldn't find inner {} item for {:?} (AST: `{}` - {:?})", | ||
580 | type_name::<N>(), | ||
581 | id, | ||
582 | ast.syntax(), | ||
583 | ast.syntax(), | ||
584 | ); | ||
585 | None | ||
586 | })?; | ||
587 | |||
588 | Some(ItemTreeId::new(id.file_id, item_tree_id)) | ||
589 | } | ||
590 | |||
591 | fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { | ||
592 | if let Some(expr) = expr { | ||
593 | self.collect_expr(expr) | ||
594 | } else { | ||
595 | self.missing_expr() | ||
596 | } | ||
597 | } | ||
598 | |||
599 | fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { | ||
600 | let syntax_node_ptr = AstPtr::new(&block.clone().into()); | ||
601 | self.collect_block_items(&block); | ||
602 | let statements = block | ||
603 | .statements() | ||
604 | .map(|s| match s { | ||
605 | ast::Stmt::LetStmt(stmt) => { | ||
606 | let pat = self.collect_pat_opt(stmt.pat()); | ||
607 | let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); | ||
608 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); | ||
609 | Statement::Let { pat, type_ref, initializer } | ||
610 | } | ||
611 | ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())), | ||
612 | }) | ||
613 | .collect(); | ||
614 | let tail = block.expr().map(|e| self.collect_expr(e)); | ||
615 | let label = block.label().and_then(|l| l.lifetime_token()).map(|t| Name::new_lifetime(&t)); | ||
616 | self.alloc_expr(Expr::Block { statements, tail, label }, syntax_node_ptr) | ||
617 | } | ||
618 | |||
619 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { | ||
620 | let container = ContainerId::DefWithBodyId(self.def); | ||
621 | |||
622 | let items = block | ||
623 | .items() | ||
624 | .filter_map(|item| { | ||
625 | let (def, name): (ModuleDefId, Option<ast::Name>) = match item { | ||
626 | ast::Item::Fn(def) => { | ||
627 | let id = self.find_inner_item(&def)?; | ||
628 | ( | ||
629 | FunctionLoc { container: container.into(), id }.intern(self.db).into(), | ||
630 | def.name(), | ||
631 | ) | ||
632 | } | ||
633 | ast::Item::TypeAlias(def) => { | ||
634 | let id = self.find_inner_item(&def)?; | ||
635 | ( | ||
636 | TypeAliasLoc { container: container.into(), id }.intern(self.db).into(), | ||
637 | def.name(), | ||
638 | ) | ||
639 | } | ||
640 | ast::Item::Const(def) => { | ||
641 | let id = self.find_inner_item(&def)?; | ||
642 | ( | ||
643 | ConstLoc { container: container.into(), id }.intern(self.db).into(), | ||
644 | def.name(), | ||
645 | ) | ||
646 | } | ||
647 | ast::Item::Static(def) => { | ||
648 | let id = self.find_inner_item(&def)?; | ||
649 | (StaticLoc { container, id }.intern(self.db).into(), def.name()) | ||
650 | } | ||
651 | ast::Item::Struct(def) => { | ||
652 | let id = self.find_inner_item(&def)?; | ||
653 | (StructLoc { container, id }.intern(self.db).into(), def.name()) | ||
654 | } | ||
655 | ast::Item::Enum(def) => { | ||
656 | let id = self.find_inner_item(&def)?; | ||
657 | (EnumLoc { container, id }.intern(self.db).into(), def.name()) | ||
658 | } | ||
659 | ast::Item::Union(def) => { | ||
660 | let id = self.find_inner_item(&def)?; | ||
661 | (UnionLoc { container, id }.intern(self.db).into(), def.name()) | ||
662 | } | ||
663 | ast::Item::Trait(def) => { | ||
664 | let id = self.find_inner_item(&def)?; | ||
665 | (TraitLoc { container, id }.intern(self.db).into(), def.name()) | ||
666 | } | ||
667 | ast::Item::ExternBlock(_) => return None, // FIXME: collect from extern blocks | ||
668 | ast::Item::Impl(_) | ||
669 | | ast::Item::Use(_) | ||
670 | | ast::Item::ExternCrate(_) | ||
671 | | ast::Item::Module(_) | ||
672 | | ast::Item::MacroCall(_) => return None, | ||
673 | }; | ||
674 | |||
675 | Some((def, name)) | ||
676 | }) | ||
677 | .collect::<Vec<_>>(); | ||
678 | |||
679 | for (def, name) in items { | ||
680 | self.body.item_scope.define_def(def); | ||
681 | if let Some(name) = name { | ||
682 | let vis = crate::visibility::Visibility::Public; // FIXME determine correctly | ||
683 | let has_constructor = match def { | ||
684 | ModuleDefId::AdtId(AdtId::StructId(s)) => { | ||
685 | self.db.struct_data(s).variant_data.kind() != StructKind::Record | ||
686 | } | ||
687 | _ => true, | ||
688 | }; | ||
689 | self.body.item_scope.push_res( | ||
690 | name.as_name(), | ||
691 | crate::per_ns::PerNs::from_def(def, vis, has_constructor), | ||
692 | ); | ||
693 | } | ||
694 | } | ||
695 | } | ||
696 | |||
697 | fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId { | ||
698 | if let Some(block) = expr { | ||
699 | self.collect_block(block) | ||
700 | } else { | ||
701 | self.missing_expr() | ||
702 | } | ||
703 | } | ||
704 | |||
705 | fn collect_pat(&mut self, pat: ast::Pat) -> PatId { | ||
706 | let pattern = match &pat { | ||
707 | ast::Pat::BindPat(bp) => { | ||
708 | let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); | ||
709 | let annotation = | ||
710 | BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some()); | ||
711 | let subpat = bp.pat().map(|subpat| self.collect_pat(subpat)); | ||
712 | if annotation == BindingAnnotation::Unannotated && subpat.is_none() { | ||
713 | // This could also be a single-segment path pattern. To | ||
714 | // decide that, we need to try resolving the name. | ||
715 | let (resolved, _) = self.expander.crate_def_map.resolve_path( | ||
716 | self.db, | ||
717 | self.expander.module.local_id, | ||
718 | &name.clone().into(), | ||
719 | BuiltinShadowMode::Other, | ||
720 | ); | ||
721 | match resolved.take_values() { | ||
722 | Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()), | ||
723 | Some(ModuleDefId::EnumVariantId(_)) => { | ||
724 | // this is only really valid for unit variants, but | ||
725 | // shadowing other enum variants with a pattern is | ||
726 | // an error anyway | ||
727 | Pat::Path(name.into()) | ||
728 | } | ||
729 | Some(ModuleDefId::AdtId(AdtId::StructId(s))) | ||
730 | if self.db.struct_data(s).variant_data.kind() != StructKind::Record => | ||
731 | { | ||
732 | // Funnily enough, record structs *can* be shadowed | ||
733 | // by pattern bindings (but unit or tuple structs | ||
734 | // can't). | ||
735 | Pat::Path(name.into()) | ||
736 | } | ||
737 | // shadowing statics is an error as well, so we just ignore that case here | ||
738 | _ => Pat::Bind { name, mode: annotation, subpat }, | ||
739 | } | ||
740 | } else { | ||
741 | Pat::Bind { name, mode: annotation, subpat } | ||
742 | } | ||
743 | } | ||
744 | ast::Pat::TupleStructPat(p) => { | ||
745 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | ||
746 | let (args, ellipsis) = self.collect_tuple_pat(p.args()); | ||
747 | Pat::TupleStruct { path, args, ellipsis } | ||
748 | } | ||
749 | ast::Pat::RefPat(p) => { | ||
750 | let pat = self.collect_pat_opt(p.pat()); | ||
751 | let mutability = Mutability::from_mutable(p.mut_token().is_some()); | ||
752 | Pat::Ref { pat, mutability } | ||
753 | } | ||
754 | ast::Pat::PathPat(p) => { | ||
755 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | ||
756 | path.map(Pat::Path).unwrap_or(Pat::Missing) | ||
757 | } | ||
758 | ast::Pat::OrPat(p) => { | ||
759 | let pats = p.pats().map(|p| self.collect_pat(p)).collect(); | ||
760 | Pat::Or(pats) | ||
761 | } | ||
762 | ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()), | ||
763 | ast::Pat::TuplePat(p) => { | ||
764 | let (args, ellipsis) = self.collect_tuple_pat(p.args()); | ||
765 | Pat::Tuple { args, ellipsis } | ||
766 | } | ||
767 | ast::Pat::PlaceholderPat(_) => Pat::Wild, | ||
768 | ast::Pat::RecordPat(p) => { | ||
769 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | ||
770 | let record_field_pat_list = | ||
771 | p.record_field_pat_list().expect("every struct should have a field list"); | ||
772 | let mut fields: Vec<_> = record_field_pat_list | ||
773 | .bind_pats() | ||
774 | .filter_map(|bind_pat| { | ||
775 | let ast_pat = | ||
776 | ast::Pat::cast(bind_pat.syntax().clone()).expect("bind pat is a pat"); | ||
777 | let pat = self.collect_pat(ast_pat); | ||
778 | let name = bind_pat.name()?.as_name(); | ||
779 | Some(RecordFieldPat { name, pat }) | ||
780 | }) | ||
781 | .collect(); | ||
782 | let iter = record_field_pat_list.record_field_pats().filter_map(|f| { | ||
783 | let ast_pat = f.pat()?; | ||
784 | let pat = self.collect_pat(ast_pat); | ||
785 | let name = f.field_name()?.as_name(); | ||
786 | Some(RecordFieldPat { name, pat }) | ||
787 | }); | ||
788 | fields.extend(iter); | ||
789 | |||
790 | let ellipsis = record_field_pat_list.dotdot_token().is_some(); | ||
791 | |||
792 | Pat::Record { path, args: fields, ellipsis } | ||
793 | } | ||
794 | ast::Pat::SlicePat(p) => { | ||
795 | let SlicePatComponents { prefix, slice, suffix } = p.components(); | ||
796 | |||
797 | // FIXME properly handle `DotDotPat` | ||
798 | Pat::Slice { | ||
799 | prefix: prefix.into_iter().map(|p| self.collect_pat(p)).collect(), | ||
800 | slice: slice.map(|p| self.collect_pat(p)), | ||
801 | suffix: suffix.into_iter().map(|p| self.collect_pat(p)).collect(), | ||
802 | } | ||
803 | } | ||
804 | ast::Pat::LiteralPat(lit) => { | ||
805 | if let Some(ast_lit) = lit.literal() { | ||
806 | let expr = Expr::Literal(ast_lit.kind().into()); | ||
807 | let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit)); | ||
808 | let expr_id = self.alloc_expr(expr, expr_ptr); | ||
809 | Pat::Lit(expr_id) | ||
810 | } else { | ||
811 | Pat::Missing | ||
812 | } | ||
813 | } | ||
814 | ast::Pat::DotDotPat(_) => { | ||
815 | // `DotDotPat` requires special handling and should not be mapped | ||
816 | // to a Pat. Here we are using `Pat::Missing` as a fallback for | ||
817 | // when `DotDotPat` is mapped to `Pat`, which can easily happen | ||
818 | // when the source code being analyzed has a malformed pattern | ||
819 | // which includes `..` in a place where it isn't valid. | ||
820 | |||
821 | Pat::Missing | ||
822 | } | ||
823 | // FIXME: implement | ||
824 | ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, | ||
825 | }; | ||
826 | let ptr = AstPtr::new(&pat); | ||
827 | self.alloc_pat(pattern, Either::Left(ptr)) | ||
828 | } | ||
829 | |||
830 | fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId { | ||
831 | if let Some(pat) = pat { | ||
832 | self.collect_pat(pat) | ||
833 | } else { | ||
834 | self.missing_pat() | ||
835 | } | ||
836 | } | ||
837 | |||
838 | fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Vec<PatId>, Option<usize>) { | ||
839 | // Find the location of the `..`, if there is one. Note that we do not | ||
840 | // consider the possiblity of there being multiple `..` here. | ||
841 | let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::DotDotPat(_))); | ||
842 | // We want to skip the `..` pattern here, since we account for it above. | ||
843 | let args = args | ||
844 | .filter(|p| !matches!(p, ast::Pat::DotDotPat(_))) | ||
845 | .map(|p| self.collect_pat(p)) | ||
846 | .collect(); | ||
847 | |||
848 | (args, ellipsis) | ||
849 | } | ||
850 | } | ||
851 | |||
852 | impl From<ast::BinOp> for BinaryOp { | ||
853 | fn from(ast_op: ast::BinOp) -> Self { | ||
854 | match ast_op { | ||
855 | ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or), | ||
856 | ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And), | ||
857 | ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }), | ||
858 | ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }), | ||
859 | ast::BinOp::LesserEqualTest => { | ||
860 | BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false }) | ||
861 | } | ||
862 | ast::BinOp::GreaterEqualTest => { | ||
863 | BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false }) | ||
864 | } | ||
865 | ast::BinOp::LesserTest => { | ||
866 | BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true }) | ||
867 | } | ||
868 | ast::BinOp::GreaterTest => { | ||
869 | BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true }) | ||
870 | } | ||
871 | ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add), | ||
872 | ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul), | ||
873 | ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub), | ||
874 | ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div), | ||
875 | ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem), | ||
876 | ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl), | ||
877 | ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr), | ||
878 | ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor), | ||
879 | ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr), | ||
880 | ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd), | ||
881 | ast::BinOp::Assignment => BinaryOp::Assignment { op: None }, | ||
882 | ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) }, | ||
883 | ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) }, | ||
884 | ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) }, | ||
885 | ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) }, | ||
886 | ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) }, | ||
887 | ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) }, | ||
888 | ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) }, | ||
889 | ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) }, | ||
890 | ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) }, | ||
891 | ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) }, | ||
892 | } | ||
893 | } | ||
894 | } | ||
895 | |||
896 | impl From<ast::LiteralKind> for Literal { | ||
897 | fn from(ast_lit_kind: ast::LiteralKind) -> Self { | ||
898 | match ast_lit_kind { | ||
899 | LiteralKind::IntNumber { suffix } => { | ||
900 | let known_name = suffix.and_then(|it| BuiltinInt::from_suffix(&it)); | ||
901 | |||
902 | Literal::Int(Default::default(), known_name) | ||
903 | } | ||
904 | LiteralKind::FloatNumber { suffix } => { | ||
905 | let known_name = suffix.and_then(|it| BuiltinFloat::from_suffix(&it)); | ||
906 | |||
907 | Literal::Float(Default::default(), known_name) | ||
908 | } | ||
909 | LiteralKind::ByteString => Literal::ByteString(Default::default()), | ||
910 | LiteralKind::String => Literal::String(Default::default()), | ||
911 | LiteralKind::Byte => Literal::Int(Default::default(), Some(BuiltinInt::U8)), | ||
912 | LiteralKind::Bool(val) => Literal::Bool(val), | ||
913 | LiteralKind::Char => Literal::Char(Default::default()), | ||
914 | } | ||
915 | } | ||
916 | } | ||
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs deleted file mode 100644 index 99e876683..000000000 --- a/crates/ra_hir_def/src/body/scope.rs +++ /dev/null | |||
@@ -1,456 +0,0 @@ | |||
1 | //! Name resolution for expressions. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use hir_expand::name::Name; | ||
5 | use ra_arena::{Arena, Idx}; | ||
6 | use rustc_hash::FxHashMap; | ||
7 | |||
8 | use crate::{ | ||
9 | body::Body, | ||
10 | db::DefDatabase, | ||
11 | expr::{Expr, ExprId, Pat, PatId, Statement}, | ||
12 | DefWithBodyId, | ||
13 | }; | ||
14 | |||
15 | pub type ScopeId = Idx<ScopeData>; | ||
16 | |||
17 | #[derive(Debug, PartialEq, Eq)] | ||
18 | pub struct ExprScopes { | ||
19 | scopes: Arena<ScopeData>, | ||
20 | scope_by_expr: FxHashMap<ExprId, ScopeId>, | ||
21 | } | ||
22 | |||
23 | #[derive(Debug, PartialEq, Eq)] | ||
24 | pub struct ScopeEntry { | ||
25 | name: Name, | ||
26 | pat: PatId, | ||
27 | } | ||
28 | |||
29 | impl ScopeEntry { | ||
30 | pub fn name(&self) -> &Name { | ||
31 | &self.name | ||
32 | } | ||
33 | |||
34 | pub fn pat(&self) -> PatId { | ||
35 | self.pat | ||
36 | } | ||
37 | } | ||
38 | |||
39 | #[derive(Debug, PartialEq, Eq)] | ||
40 | pub struct ScopeData { | ||
41 | parent: Option<ScopeId>, | ||
42 | entries: Vec<ScopeEntry>, | ||
43 | } | ||
44 | |||
45 | impl ExprScopes { | ||
46 | pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> { | ||
47 | let body = db.body(def); | ||
48 | Arc::new(ExprScopes::new(&*body)) | ||
49 | } | ||
50 | |||
51 | fn new(body: &Body) -> ExprScopes { | ||
52 | let mut scopes = | ||
53 | ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() }; | ||
54 | let root = scopes.root_scope(); | ||
55 | scopes.add_params_bindings(body, root, &body.params); | ||
56 | compute_expr_scopes(body.body_expr, body, &mut scopes, root); | ||
57 | scopes | ||
58 | } | ||
59 | |||
60 | pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { | ||
61 | &self.scopes[scope].entries | ||
62 | } | ||
63 | |||
64 | pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ { | ||
65 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) | ||
66 | } | ||
67 | |||
68 | pub fn resolve_name_in_scope(&self, scope: ScopeId, name: &Name) -> Option<&ScopeEntry> { | ||
69 | self.scope_chain(Some(scope)) | ||
70 | .find_map(|scope| self.entries(scope).iter().find(|it| it.name == *name)) | ||
71 | } | ||
72 | |||
73 | pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { | ||
74 | self.scope_by_expr.get(&expr).copied() | ||
75 | } | ||
76 | |||
77 | pub fn scope_by_expr(&self) -> &FxHashMap<ExprId, ScopeId> { | ||
78 | &self.scope_by_expr | ||
79 | } | ||
80 | |||
81 | fn root_scope(&mut self) -> ScopeId { | ||
82 | self.scopes.alloc(ScopeData { parent: None, entries: vec![] }) | ||
83 | } | ||
84 | |||
85 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { | ||
86 | self.scopes.alloc(ScopeData { parent: Some(parent), entries: vec![] }) | ||
87 | } | ||
88 | |||
89 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { | ||
90 | let pattern = &body[pat]; | ||
91 | if let Pat::Bind { name, .. } = pattern { | ||
92 | let entry = ScopeEntry { name: name.clone(), pat }; | ||
93 | self.scopes[scope].entries.push(entry); | ||
94 | } | ||
95 | |||
96 | pattern.walk_child_pats(|pat| self.add_bindings(body, scope, pat)); | ||
97 | } | ||
98 | |||
99 | fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) { | ||
100 | params.iter().for_each(|pat| self.add_bindings(body, scope, *pat)); | ||
101 | } | ||
102 | |||
103 | fn set_scope(&mut self, node: ExprId, scope: ScopeId) { | ||
104 | self.scope_by_expr.insert(node, scope); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | fn compute_block_scopes( | ||
109 | statements: &[Statement], | ||
110 | tail: Option<ExprId>, | ||
111 | body: &Body, | ||
112 | scopes: &mut ExprScopes, | ||
113 | mut scope: ScopeId, | ||
114 | ) { | ||
115 | for stmt in statements { | ||
116 | match stmt { | ||
117 | Statement::Let { pat, initializer, .. } => { | ||
118 | if let Some(expr) = initializer { | ||
119 | scopes.set_scope(*expr, scope); | ||
120 | compute_expr_scopes(*expr, body, scopes, scope); | ||
121 | } | ||
122 | scope = scopes.new_scope(scope); | ||
123 | scopes.add_bindings(body, scope, *pat); | ||
124 | } | ||
125 | Statement::Expr(expr) => { | ||
126 | scopes.set_scope(*expr, scope); | ||
127 | compute_expr_scopes(*expr, body, scopes, scope); | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | if let Some(expr) = tail { | ||
132 | compute_expr_scopes(expr, body, scopes, scope); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { | ||
137 | scopes.set_scope(expr, scope); | ||
138 | match &body[expr] { | ||
139 | Expr::Block { statements, tail, .. } => { | ||
140 | compute_block_scopes(&statements, *tail, body, scopes, scope); | ||
141 | } | ||
142 | Expr::For { iterable, pat, body: body_expr, .. } => { | ||
143 | compute_expr_scopes(*iterable, body, scopes, scope); | ||
144 | let scope = scopes.new_scope(scope); | ||
145 | scopes.add_bindings(body, scope, *pat); | ||
146 | compute_expr_scopes(*body_expr, body, scopes, scope); | ||
147 | } | ||
148 | Expr::Lambda { args, body: body_expr, .. } => { | ||
149 | let scope = scopes.new_scope(scope); | ||
150 | scopes.add_params_bindings(body, scope, &args); | ||
151 | compute_expr_scopes(*body_expr, body, scopes, scope); | ||
152 | } | ||
153 | Expr::Match { expr, arms } => { | ||
154 | compute_expr_scopes(*expr, body, scopes, scope); | ||
155 | for arm in arms { | ||
156 | let scope = scopes.new_scope(scope); | ||
157 | scopes.add_bindings(body, scope, arm.pat); | ||
158 | if let Some(guard) = arm.guard { | ||
159 | scopes.set_scope(guard, scope); | ||
160 | compute_expr_scopes(guard, body, scopes, scope); | ||
161 | } | ||
162 | scopes.set_scope(arm.expr, scope); | ||
163 | compute_expr_scopes(arm.expr, body, scopes, scope); | ||
164 | } | ||
165 | } | ||
166 | e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), | ||
167 | }; | ||
168 | } | ||
169 | |||
170 | #[cfg(test)] | ||
171 | mod tests { | ||
172 | use hir_expand::{name::AsName, InFile}; | ||
173 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase}; | ||
174 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; | ||
175 | use test_utils::{assert_eq_text, extract_offset, mark}; | ||
176 | |||
177 | use crate::{db::DefDatabase, test_db::TestDB, FunctionId, ModuleDefId}; | ||
178 | |||
179 | fn find_function(db: &TestDB, file_id: FileId) -> FunctionId { | ||
180 | let krate = db.test_crate(); | ||
181 | let crate_def_map = db.crate_def_map(krate); | ||
182 | |||
183 | let module = crate_def_map.modules_for_file(file_id).next().unwrap(); | ||
184 | let (_, def) = crate_def_map[module].scope.entries().next().unwrap(); | ||
185 | match def.take_values().unwrap() { | ||
186 | ModuleDefId::FunctionId(it) => it, | ||
187 | _ => panic!(), | ||
188 | } | ||
189 | } | ||
190 | |||
191 | fn do_check(ra_fixture: &str, expected: &[&str]) { | ||
192 | let (offset, code) = extract_offset(ra_fixture); | ||
193 | let code = { | ||
194 | let mut buf = String::new(); | ||
195 | let off: usize = offset.into(); | ||
196 | buf.push_str(&code[..off]); | ||
197 | buf.push_str("<|>marker"); | ||
198 | buf.push_str(&code[off..]); | ||
199 | buf | ||
200 | }; | ||
201 | |||
202 | let (db, position) = TestDB::with_position(&code); | ||
203 | let file_id = position.file_id; | ||
204 | let offset = position.offset; | ||
205 | |||
206 | let file_syntax = db.parse(file_id).syntax_node(); | ||
207 | let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap(); | ||
208 | let function = find_function(&db, file_id); | ||
209 | |||
210 | let scopes = db.expr_scopes(function.into()); | ||
211 | let (_body, source_map) = db.body_with_source_map(function.into()); | ||
212 | |||
213 | let expr_id = source_map | ||
214 | .node_expr(InFile { file_id: file_id.into(), value: &marker.into() }) | ||
215 | .unwrap(); | ||
216 | let scope = scopes.scope_for(expr_id); | ||
217 | |||
218 | let actual = scopes | ||
219 | .scope_chain(scope) | ||
220 | .flat_map(|scope| scopes.entries(scope)) | ||
221 | .map(|it| it.name().to_string()) | ||
222 | .collect::<Vec<_>>() | ||
223 | .join("\n"); | ||
224 | let expected = expected.join("\n"); | ||
225 | assert_eq_text!(&expected, &actual); | ||
226 | } | ||
227 | |||
228 | #[test] | ||
229 | fn test_lambda_scope() { | ||
230 | do_check( | ||
231 | r" | ||
232 | fn quux(foo: i32) { | ||
233 | let f = |bar, baz: i32| { | ||
234 | <|> | ||
235 | }; | ||
236 | }", | ||
237 | &["bar", "baz", "foo"], | ||
238 | ); | ||
239 | } | ||
240 | |||
241 | #[test] | ||
242 | fn test_call_scope() { | ||
243 | do_check( | ||
244 | r" | ||
245 | fn quux() { | ||
246 | f(|x| <|> ); | ||
247 | }", | ||
248 | &["x"], | ||
249 | ); | ||
250 | } | ||
251 | |||
252 | #[test] | ||
253 | fn test_method_call_scope() { | ||
254 | do_check( | ||
255 | r" | ||
256 | fn quux() { | ||
257 | z.f(|x| <|> ); | ||
258 | }", | ||
259 | &["x"], | ||
260 | ); | ||
261 | } | ||
262 | |||
263 | #[test] | ||
264 | fn test_loop_scope() { | ||
265 | do_check( | ||
266 | r" | ||
267 | fn quux() { | ||
268 | loop { | ||
269 | let x = (); | ||
270 | <|> | ||
271 | }; | ||
272 | }", | ||
273 | &["x"], | ||
274 | ); | ||
275 | } | ||
276 | |||
277 | #[test] | ||
278 | fn test_match() { | ||
279 | do_check( | ||
280 | r" | ||
281 | fn quux() { | ||
282 | match () { | ||
283 | Some(x) => { | ||
284 | <|> | ||
285 | } | ||
286 | }; | ||
287 | }", | ||
288 | &["x"], | ||
289 | ); | ||
290 | } | ||
291 | |||
292 | #[test] | ||
293 | fn test_shadow_variable() { | ||
294 | do_check( | ||
295 | r" | ||
296 | fn foo(x: String) { | ||
297 | let x : &str = &x<|>; | ||
298 | }", | ||
299 | &["x"], | ||
300 | ); | ||
301 | } | ||
302 | |||
303 | #[test] | ||
304 | fn test_bindings_after_at() { | ||
305 | do_check( | ||
306 | r" | ||
307 | fn foo() { | ||
308 | match Some(()) { | ||
309 | opt @ Some(unit) => { | ||
310 | <|> | ||
311 | } | ||
312 | _ => {} | ||
313 | } | ||
314 | } | ||
315 | ", | ||
316 | &["opt", "unit"], | ||
317 | ); | ||
318 | } | ||
319 | |||
320 | #[test] | ||
321 | fn macro_inner_item() { | ||
322 | do_check( | ||
323 | r" | ||
324 | macro_rules! mac { | ||
325 | () => {{ | ||
326 | fn inner() {} | ||
327 | inner(); | ||
328 | }}; | ||
329 | } | ||
330 | |||
331 | fn foo() { | ||
332 | mac!(); | ||
333 | <|> | ||
334 | } | ||
335 | ", | ||
336 | &[], | ||
337 | ); | ||
338 | } | ||
339 | |||
340 | #[test] | ||
341 | fn broken_inner_item() { | ||
342 | do_check( | ||
343 | r" | ||
344 | fn foo() { | ||
345 | trait {} | ||
346 | <|> | ||
347 | } | ||
348 | ", | ||
349 | &[], | ||
350 | ); | ||
351 | } | ||
352 | |||
353 | fn do_check_local_name(ra_fixture: &str, expected_offset: u32) { | ||
354 | let (db, position) = TestDB::with_position(ra_fixture); | ||
355 | let file_id = position.file_id; | ||
356 | let offset = position.offset; | ||
357 | |||
358 | let file = db.parse(file_id).ok().unwrap(); | ||
359 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) | ||
360 | .expect("failed to find a name at the target offset"); | ||
361 | let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset).unwrap(); | ||
362 | |||
363 | let function = find_function(&db, file_id); | ||
364 | |||
365 | let scopes = db.expr_scopes(function.into()); | ||
366 | let (_body, source_map) = db.body_with_source_map(function.into()); | ||
367 | |||
368 | let expr_scope = { | ||
369 | let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap(); | ||
370 | let expr_id = | ||
371 | source_map.node_expr(InFile { file_id: file_id.into(), value: &expr_ast }).unwrap(); | ||
372 | scopes.scope_for(expr_id).unwrap() | ||
373 | }; | ||
374 | |||
375 | let resolved = scopes.resolve_name_in_scope(expr_scope, &name_ref.as_name()).unwrap(); | ||
376 | let pat_src = source_map.pat_syntax(resolved.pat()).unwrap(); | ||
377 | |||
378 | let local_name = pat_src.value.either( | ||
379 | |it| it.syntax_node_ptr().to_node(file.syntax()), | ||
380 | |it| it.syntax_node_ptr().to_node(file.syntax()), | ||
381 | ); | ||
382 | assert_eq!(local_name.text_range(), expected_name.syntax().text_range()); | ||
383 | } | ||
384 | |||
385 | #[test] | ||
386 | fn test_resolve_local_name() { | ||
387 | do_check_local_name( | ||
388 | r#" | ||
389 | fn foo(x: i32, y: u32) { | ||
390 | { | ||
391 | let z = x * 2; | ||
392 | } | ||
393 | { | ||
394 | let t = x<|> * 3; | ||
395 | } | ||
396 | } | ||
397 | "#, | ||
398 | 7, | ||
399 | ); | ||
400 | } | ||
401 | |||
402 | #[test] | ||
403 | fn test_resolve_local_name_declaration() { | ||
404 | do_check_local_name( | ||
405 | r#" | ||
406 | fn foo(x: String) { | ||
407 | let x : &str = &x<|>; | ||
408 | } | ||
409 | "#, | ||
410 | 7, | ||
411 | ); | ||
412 | } | ||
413 | |||
414 | #[test] | ||
415 | fn test_resolve_local_name_shadow() { | ||
416 | do_check_local_name( | ||
417 | r" | ||
418 | fn foo(x: String) { | ||
419 | let x : &str = &x; | ||
420 | x<|> | ||
421 | } | ||
422 | ", | ||
423 | 28, | ||
424 | ); | ||
425 | } | ||
426 | |||
427 | #[test] | ||
428 | fn ref_patterns_contribute_bindings() { | ||
429 | do_check_local_name( | ||
430 | r" | ||
431 | fn foo() { | ||
432 | if let Some(&from) = bar() { | ||
433 | from<|>; | ||
434 | } | ||
435 | } | ||
436 | ", | ||
437 | 28, | ||
438 | ); | ||
439 | } | ||
440 | |||
441 | #[test] | ||
442 | fn while_let_desugaring() { | ||
443 | mark::check!(infer_resolve_while_let); | ||
444 | do_check_local_name( | ||
445 | r#" | ||
446 | fn test() { | ||
447 | let foo: Option<f32> = None; | ||
448 | while let Option::Some(spam) = foo { | ||
449 | spam<|> | ||
450 | } | ||
451 | } | ||
452 | "#, | ||
453 | 75, | ||
454 | ); | ||
455 | } | ||
456 | } | ||
diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs deleted file mode 100644 index 0f872b5c0..000000000 --- a/crates/ra_hir_def/src/builtin_type.rs +++ /dev/null | |||
@@ -1,166 +0,0 @@ | |||
1 | //! This module defines built-in types. | ||
2 | //! | ||
3 | //! A peculiarity of built-in types is that they are always available and are | ||
4 | //! not associated with any particular crate. | ||
5 | |||
6 | use std::fmt; | ||
7 | |||
8 | use hir_expand::name::{name, AsName, Name}; | ||
9 | |||
10 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
11 | pub enum Signedness { | ||
12 | Signed, | ||
13 | Unsigned, | ||
14 | } | ||
15 | |||
16 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
17 | pub enum IntBitness { | ||
18 | Xsize, | ||
19 | X8, | ||
20 | X16, | ||
21 | X32, | ||
22 | X64, | ||
23 | X128, | ||
24 | } | ||
25 | |||
26 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
27 | pub enum FloatBitness { | ||
28 | X32, | ||
29 | X64, | ||
30 | } | ||
31 | |||
32 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
33 | pub struct BuiltinInt { | ||
34 | pub signedness: Signedness, | ||
35 | pub bitness: IntBitness, | ||
36 | } | ||
37 | |||
38 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
39 | pub struct BuiltinFloat { | ||
40 | pub bitness: FloatBitness, | ||
41 | } | ||
42 | |||
43 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
44 | pub enum BuiltinType { | ||
45 | Char, | ||
46 | Bool, | ||
47 | Str, | ||
48 | Int(BuiltinInt), | ||
49 | Float(BuiltinFloat), | ||
50 | } | ||
51 | |||
52 | impl BuiltinType { | ||
53 | #[rustfmt::skip] | ||
54 | pub const ALL: &'static [(Name, BuiltinType)] = &[ | ||
55 | (name![char], BuiltinType::Char), | ||
56 | (name![bool], BuiltinType::Bool), | ||
57 | (name![str], BuiltinType::Str), | ||
58 | |||
59 | (name![isize], BuiltinType::Int(BuiltinInt::ISIZE)), | ||
60 | (name![i8], BuiltinType::Int(BuiltinInt::I8)), | ||
61 | (name![i16], BuiltinType::Int(BuiltinInt::I16)), | ||
62 | (name![i32], BuiltinType::Int(BuiltinInt::I32)), | ||
63 | (name![i64], BuiltinType::Int(BuiltinInt::I64)), | ||
64 | (name![i128], BuiltinType::Int(BuiltinInt::I128)), | ||
65 | |||
66 | (name![usize], BuiltinType::Int(BuiltinInt::USIZE)), | ||
67 | (name![u8], BuiltinType::Int(BuiltinInt::U8)), | ||
68 | (name![u16], BuiltinType::Int(BuiltinInt::U16)), | ||
69 | (name![u32], BuiltinType::Int(BuiltinInt::U32)), | ||
70 | (name![u64], BuiltinType::Int(BuiltinInt::U64)), | ||
71 | (name![u128], BuiltinType::Int(BuiltinInt::U128)), | ||
72 | |||
73 | (name![f32], BuiltinType::Float(BuiltinFloat::F32)), | ||
74 | (name![f64], BuiltinType::Float(BuiltinFloat::F64)), | ||
75 | ]; | ||
76 | } | ||
77 | |||
78 | impl AsName for BuiltinType { | ||
79 | fn as_name(&self) -> Name { | ||
80 | match self { | ||
81 | BuiltinType::Char => name![char], | ||
82 | BuiltinType::Bool => name![bool], | ||
83 | BuiltinType::Str => name![str], | ||
84 | BuiltinType::Int(BuiltinInt { signedness, bitness }) => match (signedness, bitness) { | ||
85 | (Signedness::Signed, IntBitness::Xsize) => name![isize], | ||
86 | (Signedness::Signed, IntBitness::X8) => name![i8], | ||
87 | (Signedness::Signed, IntBitness::X16) => name![i16], | ||
88 | (Signedness::Signed, IntBitness::X32) => name![i32], | ||
89 | (Signedness::Signed, IntBitness::X64) => name![i64], | ||
90 | (Signedness::Signed, IntBitness::X128) => name![i128], | ||
91 | |||
92 | (Signedness::Unsigned, IntBitness::Xsize) => name![usize], | ||
93 | (Signedness::Unsigned, IntBitness::X8) => name![u8], | ||
94 | (Signedness::Unsigned, IntBitness::X16) => name![u16], | ||
95 | (Signedness::Unsigned, IntBitness::X32) => name![u32], | ||
96 | (Signedness::Unsigned, IntBitness::X64) => name![u64], | ||
97 | (Signedness::Unsigned, IntBitness::X128) => name![u128], | ||
98 | }, | ||
99 | BuiltinType::Float(BuiltinFloat { bitness }) => match bitness { | ||
100 | FloatBitness::X32 => name![f32], | ||
101 | FloatBitness::X64 => name![f64], | ||
102 | }, | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | |||
107 | impl fmt::Display for BuiltinType { | ||
108 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
109 | let type_name = self.as_name(); | ||
110 | type_name.fmt(f) | ||
111 | } | ||
112 | } | ||
113 | |||
114 | #[rustfmt::skip] | ||
115 | impl BuiltinInt { | ||
116 | pub const ISIZE: BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::Xsize }; | ||
117 | pub const I8 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X8 }; | ||
118 | pub const I16 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X16 }; | ||
119 | pub const I32 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X32 }; | ||
120 | pub const I64 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X64 }; | ||
121 | pub const I128 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X128 }; | ||
122 | |||
123 | pub const USIZE: BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize }; | ||
124 | pub const U8 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X8 }; | ||
125 | pub const U16 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X16 }; | ||
126 | pub const U32 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X32 }; | ||
127 | pub const U64 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X64 }; | ||
128 | pub const U128 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X128 }; | ||
129 | |||
130 | |||
131 | pub fn from_suffix(suffix: &str) -> Option<BuiltinInt> { | ||
132 | let res = match suffix { | ||
133 | "isize" => Self::ISIZE, | ||
134 | "i8" => Self::I8, | ||
135 | "i16" => Self::I16, | ||
136 | "i32" => Self::I32, | ||
137 | "i64" => Self::I64, | ||
138 | "i128" => Self::I128, | ||
139 | |||
140 | "usize" => Self::USIZE, | ||
141 | "u8" => Self::U8, | ||
142 | "u16" => Self::U16, | ||
143 | "u32" => Self::U32, | ||
144 | "u64" => Self::U64, | ||
145 | "u128" => Self::U128, | ||
146 | |||
147 | _ => return None, | ||
148 | }; | ||
149 | Some(res) | ||
150 | } | ||
151 | } | ||
152 | |||
153 | #[rustfmt::skip] | ||
154 | impl BuiltinFloat { | ||
155 | pub const F32: BuiltinFloat = BuiltinFloat { bitness: FloatBitness::X32 }; | ||
156 | pub const F64: BuiltinFloat = BuiltinFloat { bitness: FloatBitness::X64 }; | ||
157 | |||
158 | pub fn from_suffix(suffix: &str) -> Option<BuiltinFloat> { | ||
159 | let res = match suffix { | ||
160 | "f32" => BuiltinFloat::F32, | ||
161 | "f64" => BuiltinFloat::F64, | ||
162 | _ => return None, | ||
163 | }; | ||
164 | Some(res) | ||
165 | } | ||
166 | } | ||
diff --git a/crates/ra_hir_def/src/child_by_source.rs b/crates/ra_hir_def/src/child_by_source.rs deleted file mode 100644 index dcb00a1d9..000000000 --- a/crates/ra_hir_def/src/child_by_source.rs +++ /dev/null | |||
@@ -1,177 +0,0 @@ | |||
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, FieldId, ImplId, Lookup, ModuleDefId, | ||
16 | ModuleId, TraitId, VariantId, | ||
17 | }; | ||
18 | |||
19 | pub trait ChildBySource { | ||
20 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap; | ||
21 | } | ||
22 | |||
23 | impl ChildBySource for TraitId { | ||
24 | fn child_by_source(&self, db: &dyn 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: &dyn 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: &dyn 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: &dyn 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: &dyn 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: &dyn 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: &dyn 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 = FieldId { 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: &dyn 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::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: &dyn 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 deleted file mode 100644 index 88a8ef9bf..000000000 --- a/crates/ra_hir_def/src/data.rs +++ /dev/null | |||
@@ -1,279 +0,0 @@ | |||
1 | //! Contains basic data about various HIR declarations. | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use hir_expand::{name::Name, InFile}; | ||
6 | use ra_prof::profile; | ||
7 | use ra_syntax::ast; | ||
8 | |||
9 | use crate::{ | ||
10 | attr::Attrs, | ||
11 | body::Expander, | ||
12 | db::DefDatabase, | ||
13 | item_tree::{AssocItem, ItemTreeId, ModItem}, | ||
14 | type_ref::{TypeBound, TypeRef}, | ||
15 | visibility::RawVisibility, | ||
16 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, | ||
17 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | ||
18 | }; | ||
19 | |||
20 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
21 | pub struct FunctionData { | ||
22 | pub name: Name, | ||
23 | pub params: Vec<TypeRef>, | ||
24 | pub ret_type: TypeRef, | ||
25 | pub attrs: Attrs, | ||
26 | /// True if the first param is `self`. This is relevant to decide whether this | ||
27 | /// can be called as a method. | ||
28 | pub has_self_param: bool, | ||
29 | pub is_unsafe: bool, | ||
30 | pub is_varargs: bool, | ||
31 | pub visibility: RawVisibility, | ||
32 | } | ||
33 | |||
34 | impl FunctionData { | ||
35 | pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> { | ||
36 | let loc = func.lookup(db); | ||
37 | let item_tree = db.item_tree(loc.id.file_id); | ||
38 | let func = &item_tree[loc.id.value]; | ||
39 | |||
40 | Arc::new(FunctionData { | ||
41 | name: func.name.clone(), | ||
42 | params: func.params.to_vec(), | ||
43 | ret_type: func.ret_type.clone(), | ||
44 | attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(), | ||
45 | has_self_param: func.has_self_param, | ||
46 | is_unsafe: func.is_unsafe, | ||
47 | is_varargs: func.is_varargs, | ||
48 | visibility: item_tree[func.visibility].clone(), | ||
49 | }) | ||
50 | } | ||
51 | } | ||
52 | |||
53 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
54 | pub struct TypeAliasData { | ||
55 | pub name: Name, | ||
56 | pub type_ref: Option<TypeRef>, | ||
57 | pub visibility: RawVisibility, | ||
58 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). | ||
59 | pub bounds: Vec<TypeBound>, | ||
60 | } | ||
61 | |||
62 | impl TypeAliasData { | ||
63 | pub(crate) fn type_alias_data_query( | ||
64 | db: &dyn DefDatabase, | ||
65 | typ: TypeAliasId, | ||
66 | ) -> Arc<TypeAliasData> { | ||
67 | let loc = typ.lookup(db); | ||
68 | let item_tree = db.item_tree(loc.id.file_id); | ||
69 | let typ = &item_tree[loc.id.value]; | ||
70 | |||
71 | Arc::new(TypeAliasData { | ||
72 | name: typ.name.clone(), | ||
73 | type_ref: typ.type_ref.clone(), | ||
74 | visibility: item_tree[typ.visibility].clone(), | ||
75 | bounds: typ.bounds.to_vec(), | ||
76 | }) | ||
77 | } | ||
78 | } | ||
79 | |||
80 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
81 | pub struct TraitData { | ||
82 | pub name: Name, | ||
83 | pub items: Vec<(Name, AssocItemId)>, | ||
84 | pub auto: bool, | ||
85 | } | ||
86 | |||
87 | impl TraitData { | ||
88 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { | ||
89 | let tr_loc = tr.lookup(db); | ||
90 | let item_tree = db.item_tree(tr_loc.id.file_id); | ||
91 | let tr_def = &item_tree[tr_loc.id.value]; | ||
92 | let name = tr_def.name.clone(); | ||
93 | let auto = tr_def.auto; | ||
94 | let module_id = tr_loc.container.module(db); | ||
95 | let container = AssocContainerId::TraitId(tr); | ||
96 | let mut expander = Expander::new(db, tr_loc.id.file_id, module_id); | ||
97 | |||
98 | let items = collect_items( | ||
99 | db, | ||
100 | module_id, | ||
101 | &mut expander, | ||
102 | tr_def.items.iter().copied(), | ||
103 | tr_loc.id.file_id, | ||
104 | container, | ||
105 | 100, | ||
106 | ); | ||
107 | |||
108 | Arc::new(TraitData { name, items, auto }) | ||
109 | } | ||
110 | |||
111 | pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { | ||
112 | self.items.iter().filter_map(|(_name, item)| match item { | ||
113 | AssocItemId::TypeAliasId(t) => Some(*t), | ||
114 | _ => None, | ||
115 | }) | ||
116 | } | ||
117 | |||
118 | pub fn associated_type_by_name(&self, name: &Name) -> Option<TypeAliasId> { | ||
119 | self.items.iter().find_map(|(item_name, item)| match item { | ||
120 | AssocItemId::TypeAliasId(t) if item_name == name => Some(*t), | ||
121 | _ => None, | ||
122 | }) | ||
123 | } | ||
124 | } | ||
125 | |||
126 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
127 | pub struct ImplData { | ||
128 | pub target_trait: Option<TypeRef>, | ||
129 | pub target_type: TypeRef, | ||
130 | pub items: Vec<AssocItemId>, | ||
131 | pub is_negative: bool, | ||
132 | } | ||
133 | |||
134 | impl ImplData { | ||
135 | pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { | ||
136 | let _p = profile("impl_data_query"); | ||
137 | let impl_loc = id.lookup(db); | ||
138 | |||
139 | let item_tree = db.item_tree(impl_loc.id.file_id); | ||
140 | let impl_def = &item_tree[impl_loc.id.value]; | ||
141 | let target_trait = impl_def.target_trait.clone(); | ||
142 | let target_type = impl_def.target_type.clone(); | ||
143 | let is_negative = impl_def.is_negative; | ||
144 | let module_id = impl_loc.container.module(db); | ||
145 | let container = AssocContainerId::ImplId(id); | ||
146 | let mut expander = Expander::new(db, impl_loc.id.file_id, module_id); | ||
147 | |||
148 | let items = collect_items( | ||
149 | db, | ||
150 | module_id, | ||
151 | &mut expander, | ||
152 | impl_def.items.iter().copied(), | ||
153 | impl_loc.id.file_id, | ||
154 | container, | ||
155 | 100, | ||
156 | ); | ||
157 | let items = items.into_iter().map(|(_, item)| item).collect(); | ||
158 | |||
159 | Arc::new(ImplData { target_trait, target_type, items, is_negative }) | ||
160 | } | ||
161 | } | ||
162 | |||
163 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
164 | pub struct ConstData { | ||
165 | /// const _: () = (); | ||
166 | pub name: Option<Name>, | ||
167 | pub type_ref: TypeRef, | ||
168 | pub visibility: RawVisibility, | ||
169 | } | ||
170 | |||
171 | impl ConstData { | ||
172 | pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> { | ||
173 | let loc = konst.lookup(db); | ||
174 | let item_tree = db.item_tree(loc.id.file_id); | ||
175 | let konst = &item_tree[loc.id.value]; | ||
176 | |||
177 | Arc::new(ConstData { | ||
178 | name: konst.name.clone(), | ||
179 | type_ref: konst.type_ref.clone(), | ||
180 | visibility: item_tree[konst.visibility].clone(), | ||
181 | }) | ||
182 | } | ||
183 | } | ||
184 | |||
185 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
186 | pub struct StaticData { | ||
187 | pub name: Option<Name>, | ||
188 | pub type_ref: TypeRef, | ||
189 | pub visibility: RawVisibility, | ||
190 | pub mutable: bool, | ||
191 | } | ||
192 | |||
193 | impl StaticData { | ||
194 | pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> { | ||
195 | let node = konst.lookup(db); | ||
196 | let item_tree = db.item_tree(node.id.file_id); | ||
197 | let statik = &item_tree[node.id.value]; | ||
198 | |||
199 | Arc::new(StaticData { | ||
200 | name: Some(statik.name.clone()), | ||
201 | type_ref: statik.type_ref.clone(), | ||
202 | visibility: item_tree[statik.visibility].clone(), | ||
203 | mutable: statik.mutable, | ||
204 | }) | ||
205 | } | ||
206 | } | ||
207 | |||
208 | fn collect_items( | ||
209 | db: &dyn DefDatabase, | ||
210 | module: ModuleId, | ||
211 | expander: &mut Expander, | ||
212 | assoc_items: impl Iterator<Item = AssocItem>, | ||
213 | file_id: crate::HirFileId, | ||
214 | container: AssocContainerId, | ||
215 | limit: usize, | ||
216 | ) -> Vec<(Name, AssocItemId)> { | ||
217 | if limit == 0 { | ||
218 | return Vec::new(); | ||
219 | } | ||
220 | |||
221 | let item_tree = db.item_tree(file_id); | ||
222 | let cfg_options = db.crate_graph()[module.krate].cfg_options.clone(); | ||
223 | |||
224 | let mut items = Vec::new(); | ||
225 | for item in assoc_items { | ||
226 | match item { | ||
227 | AssocItem::Function(id) => { | ||
228 | let item = &item_tree[id]; | ||
229 | let attrs = item_tree.attrs(ModItem::from(id).into()); | ||
230 | if !attrs.is_cfg_enabled(&cfg_options) { | ||
231 | continue; | ||
232 | } | ||
233 | let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
234 | items.push((item.name.clone(), def.into())); | ||
235 | } | ||
236 | // FIXME: cfg? | ||
237 | AssocItem::Const(id) => { | ||
238 | let item = &item_tree[id]; | ||
239 | let name = match item.name.clone() { | ||
240 | Some(name) => name, | ||
241 | None => continue, | ||
242 | }; | ||
243 | let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
244 | items.push((name, def.into())); | ||
245 | } | ||
246 | AssocItem::TypeAlias(id) => { | ||
247 | let item = &item_tree[id]; | ||
248 | let def = TypeAliasLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
249 | items.push((item.name.clone(), def.into())); | ||
250 | } | ||
251 | AssocItem::MacroCall(call) => { | ||
252 | let call = &item_tree[call]; | ||
253 | let ast_id_map = db.ast_id_map(file_id); | ||
254 | let root = db.parse_or_expand(file_id).unwrap(); | ||
255 | let call = ast_id_map.get(call.ast_id).to_node(&root); | ||
256 | |||
257 | if let Some((mark, mac)) = expander.enter_expand(db, None, call) { | ||
258 | let src: InFile<ast::MacroItems> = expander.to_source(mac); | ||
259 | let item_tree = db.item_tree(src.file_id); | ||
260 | let iter = | ||
261 | item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item); | ||
262 | items.extend(collect_items( | ||
263 | db, | ||
264 | module, | ||
265 | expander, | ||
266 | iter, | ||
267 | src.file_id, | ||
268 | container, | ||
269 | limit - 1, | ||
270 | )); | ||
271 | |||
272 | expander.exit(db, mark); | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | |||
278 | items | ||
279 | } | ||
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs deleted file mode 100644 index 9c3ede2d7..000000000 --- a/crates/ra_hir_def/src/db.rs +++ /dev/null | |||
@@ -1,121 +0,0 @@ | |||
1 | //! Defines database & queries for name resolution. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use hir_expand::{db::AstDatabase, HirFileId}; | ||
5 | use ra_db::{salsa, CrateId, SourceDatabase, Upcast}; | ||
6 | use ra_prof::profile; | ||
7 | use ra_syntax::SmolStr; | ||
8 | |||
9 | use crate::{ | ||
10 | adt::{EnumData, StructData}, | ||
11 | attr::Attrs, | ||
12 | body::{scope::ExprScopes, Body, BodySourceMap}, | ||
13 | data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData}, | ||
14 | docs::Documentation, | ||
15 | generics::GenericParams, | ||
16 | import_map::ImportMap, | ||
17 | item_tree::ItemTree, | ||
18 | lang_item::{LangItemTarget, LangItems}, | ||
19 | nameres::CrateDefMap, | ||
20 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, | ||
21 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, | ||
22 | TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, | ||
23 | }; | ||
24 | |||
25 | #[salsa::query_group(InternDatabaseStorage)] | ||
26 | pub trait InternDatabase: SourceDatabase { | ||
27 | #[salsa::interned] | ||
28 | fn intern_function(&self, loc: FunctionLoc) -> FunctionId; | ||
29 | #[salsa::interned] | ||
30 | fn intern_struct(&self, loc: StructLoc) -> StructId; | ||
31 | #[salsa::interned] | ||
32 | fn intern_union(&self, loc: UnionLoc) -> UnionId; | ||
33 | #[salsa::interned] | ||
34 | fn intern_enum(&self, loc: EnumLoc) -> EnumId; | ||
35 | #[salsa::interned] | ||
36 | fn intern_const(&self, loc: ConstLoc) -> ConstId; | ||
37 | #[salsa::interned] | ||
38 | fn intern_static(&self, loc: StaticLoc) -> StaticId; | ||
39 | #[salsa::interned] | ||
40 | fn intern_trait(&self, loc: TraitLoc) -> TraitId; | ||
41 | #[salsa::interned] | ||
42 | fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; | ||
43 | #[salsa::interned] | ||
44 | fn intern_impl(&self, loc: ImplLoc) -> ImplId; | ||
45 | } | ||
46 | |||
47 | #[salsa::query_group(DefDatabaseStorage)] | ||
48 | pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | ||
49 | #[salsa::invoke(ItemTree::item_tree_query)] | ||
50 | fn item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>; | ||
51 | |||
52 | #[salsa::invoke(crate_def_map_wait)] | ||
53 | #[salsa::transparent] | ||
54 | fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>; | ||
55 | |||
56 | #[salsa::invoke(CrateDefMap::crate_def_map_query)] | ||
57 | fn crate_def_map_query(&self, krate: CrateId) -> Arc<CrateDefMap>; | ||
58 | |||
59 | #[salsa::invoke(StructData::struct_data_query)] | ||
60 | fn struct_data(&self, id: StructId) -> Arc<StructData>; | ||
61 | #[salsa::invoke(StructData::union_data_query)] | ||
62 | fn union_data(&self, id: UnionId) -> Arc<StructData>; | ||
63 | |||
64 | #[salsa::invoke(EnumData::enum_data_query)] | ||
65 | fn enum_data(&self, e: EnumId) -> Arc<EnumData>; | ||
66 | |||
67 | #[salsa::invoke(ImplData::impl_data_query)] | ||
68 | fn impl_data(&self, e: ImplId) -> Arc<ImplData>; | ||
69 | |||
70 | #[salsa::invoke(TraitData::trait_data_query)] | ||
71 | fn trait_data(&self, e: TraitId) -> Arc<TraitData>; | ||
72 | |||
73 | #[salsa::invoke(TypeAliasData::type_alias_data_query)] | ||
74 | fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>; | ||
75 | |||
76 | #[salsa::invoke(FunctionData::fn_data_query)] | ||
77 | fn function_data(&self, func: FunctionId) -> Arc<FunctionData>; | ||
78 | |||
79 | #[salsa::invoke(ConstData::const_data_query)] | ||
80 | fn const_data(&self, konst: ConstId) -> Arc<ConstData>; | ||
81 | |||
82 | #[salsa::invoke(StaticData::static_data_query)] | ||
83 | fn static_data(&self, konst: StaticId) -> Arc<StaticData>; | ||
84 | |||
85 | #[salsa::invoke(Body::body_with_source_map_query)] | ||
86 | fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>); | ||
87 | |||
88 | #[salsa::invoke(Body::body_query)] | ||
89 | fn body(&self, def: DefWithBodyId) -> Arc<Body>; | ||
90 | |||
91 | #[salsa::invoke(ExprScopes::expr_scopes_query)] | ||
92 | fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>; | ||
93 | |||
94 | #[salsa::invoke(GenericParams::generic_params_query)] | ||
95 | fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; | ||
96 | |||
97 | #[salsa::invoke(Attrs::attrs_query)] | ||
98 | fn attrs(&self, def: AttrDefId) -> Attrs; | ||
99 | |||
100 | #[salsa::invoke(LangItems::module_lang_items_query)] | ||
101 | fn module_lang_items(&self, module: ModuleId) -> Option<Arc<LangItems>>; | ||
102 | |||
103 | #[salsa::invoke(LangItems::crate_lang_items_query)] | ||
104 | fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>; | ||
105 | |||
106 | #[salsa::invoke(LangItems::lang_item_query)] | ||
107 | fn lang_item(&self, start_crate: CrateId, item: SmolStr) -> Option<LangItemTarget>; | ||
108 | |||
109 | // FIXME(https://github.com/rust-analyzer/rust-analyzer/issues/2148#issuecomment-550519102) | ||
110 | // Remove this query completely, in favor of `Attrs::docs` method | ||
111 | #[salsa::invoke(Documentation::documentation_query)] | ||
112 | fn documentation(&self, def: AttrDefId) -> Option<Documentation>; | ||
113 | |||
114 | #[salsa::invoke(ImportMap::import_map_query)] | ||
115 | fn import_map(&self, krate: CrateId) -> Arc<ImportMap>; | ||
116 | } | ||
117 | |||
118 | fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { | ||
119 | let _p = profile("crate_def_map:wait"); | ||
120 | db.crate_def_map_query(krate) | ||
121 | } | ||
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs deleted file mode 100644 index 30db48f86..000000000 --- a/crates/ra_hir_def/src/diagnostics.rs +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | //! Diagnostics produced by `hir_def`. | ||
2 | |||
3 | use std::any::Any; | ||
4 | |||
5 | use hir_expand::diagnostics::Diagnostic; | ||
6 | use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; | ||
7 | |||
8 | use hir_expand::{HirFileId, InFile}; | ||
9 | |||
10 | #[derive(Debug)] | ||
11 | pub struct UnresolvedModule { | ||
12 | pub file: HirFileId, | ||
13 | pub decl: AstPtr<ast::Module>, | ||
14 | pub candidate: String, | ||
15 | } | ||
16 | |||
17 | impl Diagnostic for UnresolvedModule { | ||
18 | fn message(&self) -> String { | ||
19 | "unresolved module".to_string() | ||
20 | } | ||
21 | fn source(&self) -> InFile<SyntaxNodePtr> { | ||
22 | InFile::new(self.file, self.decl.clone().into()) | ||
23 | } | ||
24 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
25 | self | ||
26 | } | ||
27 | } | ||
diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs deleted file mode 100644 index 2630b3d89..000000000 --- a/crates/ra_hir_def/src/docs.rs +++ /dev/null | |||
@@ -1,121 +0,0 @@ | |||
1 | //! Defines hir documentation. | ||
2 | //! | ||
3 | //! This really shouldn't exist, instead, we should deshugar doc comments into attributes, see | ||
4 | //! https://github.com/rust-analyzer/rust-analyzer/issues/2148#issuecomment-550519102 | ||
5 | |||
6 | use std::sync::Arc; | ||
7 | |||
8 | use either::Either; | ||
9 | use ra_syntax::ast; | ||
10 | |||
11 | use crate::{ | ||
12 | db::DefDatabase, | ||
13 | src::{HasChildSource, HasSource}, | ||
14 | AdtId, AttrDefId, Lookup, | ||
15 | }; | ||
16 | |||
17 | /// Holds documentation | ||
18 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
19 | pub struct Documentation(Arc<str>); | ||
20 | |||
21 | impl Into<String> for Documentation { | ||
22 | fn into(self) -> String { | ||
23 | self.as_str().to_owned() | ||
24 | } | ||
25 | } | ||
26 | |||
27 | impl Documentation { | ||
28 | fn new(s: &str) -> Documentation { | ||
29 | Documentation(s.into()) | ||
30 | } | ||
31 | |||
32 | pub fn from_ast<N>(node: &N) -> Option<Documentation> | ||
33 | where | ||
34 | N: ast::DocCommentsOwner + ast::AttrsOwner, | ||
35 | { | ||
36 | docs_from_ast(node) | ||
37 | } | ||
38 | |||
39 | pub fn as_str(&self) -> &str { | ||
40 | &*self.0 | ||
41 | } | ||
42 | |||
43 | pub(crate) fn documentation_query( | ||
44 | db: &dyn DefDatabase, | ||
45 | def: AttrDefId, | ||
46 | ) -> Option<Documentation> { | ||
47 | match def { | ||
48 | AttrDefId::ModuleId(module) => { | ||
49 | let def_map = db.crate_def_map(module.krate); | ||
50 | let src = def_map[module.local_id].declaration_source(db)?; | ||
51 | docs_from_ast(&src.value) | ||
52 | } | ||
53 | AttrDefId::FieldId(it) => { | ||
54 | let src = it.parent.child_source(db); | ||
55 | match &src.value[it.local_id] { | ||
56 | Either::Left(_tuple) => None, | ||
57 | Either::Right(record) => docs_from_ast(record), | ||
58 | } | ||
59 | } | ||
60 | AttrDefId::AdtId(it) => match it { | ||
61 | AdtId::StructId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
62 | AdtId::EnumId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
63 | AdtId::UnionId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
64 | }, | ||
65 | AttrDefId::EnumVariantId(it) => { | ||
66 | let src = it.parent.child_source(db); | ||
67 | docs_from_ast(&src.value[it.local_id]) | ||
68 | } | ||
69 | AttrDefId::TraitId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
70 | AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id?.to_node(db.upcast())), | ||
71 | AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
72 | AttrDefId::StaticId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
73 | AttrDefId::FunctionId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
74 | AttrDefId::TypeAliasId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
75 | AttrDefId::ImplId(_) => None, | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | |||
80 | pub(crate) fn docs_from_ast<N>(node: &N) -> Option<Documentation> | ||
81 | where | ||
82 | N: ast::DocCommentsOwner + ast::AttrsOwner, | ||
83 | { | ||
84 | let doc_comment_text = node.doc_comment_text(); | ||
85 | let doc_attr_text = expand_doc_attrs(node); | ||
86 | let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text); | ||
87 | docs.map(|it| Documentation::new(&it)) | ||
88 | } | ||
89 | |||
90 | fn merge_doc_comments_and_attrs( | ||
91 | doc_comment_text: Option<String>, | ||
92 | doc_attr_text: Option<String>, | ||
93 | ) -> Option<String> { | ||
94 | match (doc_comment_text, doc_attr_text) { | ||
95 | (Some(mut comment_text), Some(attr_text)) => { | ||
96 | comment_text.push_str("\n\n"); | ||
97 | comment_text.push_str(&attr_text); | ||
98 | Some(comment_text) | ||
99 | } | ||
100 | (Some(comment_text), None) => Some(comment_text), | ||
101 | (None, Some(attr_text)) => Some(attr_text), | ||
102 | (None, None) => None, | ||
103 | } | ||
104 | } | ||
105 | |||
106 | fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option<String> { | ||
107 | let mut docs = String::new(); | ||
108 | for attr in owner.attrs() { | ||
109 | if let Some(("doc", value)) = | ||
110 | attr.as_simple_key_value().as_ref().map(|(k, v)| (k.as_str(), v.as_str())) | ||
111 | { | ||
112 | docs.push_str(value); | ||
113 | docs.push_str("\n\n"); | ||
114 | } | ||
115 | } | ||
116 | if docs.is_empty() { | ||
117 | None | ||
118 | } else { | ||
119 | Some(docs.trim_end_matches("\n\n").to_owned()) | ||
120 | } | ||
121 | } | ||
diff --git a/crates/ra_hir_def/src/dyn_map.rs b/crates/ra_hir_def/src/dyn_map.rs deleted file mode 100644 index 6f269d7b0..000000000 --- a/crates/ra_hir_def/src/dyn_map.rs +++ /dev/null | |||
@@ -1,108 +0,0 @@ | |||
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 deleted file mode 100644 index e41cfc16b..000000000 --- a/crates/ra_hir_def/src/expr.rs +++ /dev/null | |||
@@ -1,420 +0,0 @@ | |||
1 | //! This module describes hir-level representation of expressions. | ||
2 | //! | ||
3 | //! This representaion is: | ||
4 | //! | ||
5 | //! 1. Identity-based. Each expression has an `id`, so we can distinguish | ||
6 | //! between different `1` in `1 + 1`. | ||
7 | //! 2. Independent of syntax. Though syntactic provenance information can be | ||
8 | //! attached separately via id-based side map. | ||
9 | //! 3. Unresolved. Paths are stored as sequences of names, and not as defs the | ||
10 | //! names refer to. | ||
11 | //! 4. Desugared. There's no `if let`. | ||
12 | //! | ||
13 | //! See also a neighboring `body` module. | ||
14 | |||
15 | use hir_expand::name::Name; | ||
16 | use ra_arena::{Idx, RawId}; | ||
17 | use ra_syntax::ast::RangeOp; | ||
18 | |||
19 | use crate::{ | ||
20 | builtin_type::{BuiltinFloat, BuiltinInt}, | ||
21 | path::{GenericArgs, Path}, | ||
22 | type_ref::{Mutability, Rawness, TypeRef}, | ||
23 | }; | ||
24 | |||
25 | pub type ExprId = Idx<Expr>; | ||
26 | pub(crate) fn dummy_expr_id() -> ExprId { | ||
27 | ExprId::from_raw(RawId::from(!0)) | ||
28 | } | ||
29 | |||
30 | pub type PatId = Idx<Pat>; | ||
31 | |||
32 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
33 | pub enum Literal { | ||
34 | String(String), | ||
35 | ByteString(Vec<u8>), | ||
36 | Char(char), | ||
37 | Bool(bool), | ||
38 | Int(u64, Option<BuiltinInt>), | ||
39 | Float(u64, Option<BuiltinFloat>), // FIXME: f64 is not Eq | ||
40 | } | ||
41 | |||
42 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
43 | pub enum Expr { | ||
44 | /// This is produced if the syntax tree does not have a required expression piece. | ||
45 | Missing, | ||
46 | Path(Path), | ||
47 | If { | ||
48 | condition: ExprId, | ||
49 | then_branch: ExprId, | ||
50 | else_branch: Option<ExprId>, | ||
51 | }, | ||
52 | Block { | ||
53 | statements: Vec<Statement>, | ||
54 | tail: Option<ExprId>, | ||
55 | label: Option<Name>, | ||
56 | }, | ||
57 | Loop { | ||
58 | body: ExprId, | ||
59 | label: Option<Name>, | ||
60 | }, | ||
61 | While { | ||
62 | condition: ExprId, | ||
63 | body: ExprId, | ||
64 | label: Option<Name>, | ||
65 | }, | ||
66 | For { | ||
67 | iterable: ExprId, | ||
68 | pat: PatId, | ||
69 | body: ExprId, | ||
70 | label: Option<Name>, | ||
71 | }, | ||
72 | Call { | ||
73 | callee: ExprId, | ||
74 | args: Vec<ExprId>, | ||
75 | }, | ||
76 | MethodCall { | ||
77 | receiver: ExprId, | ||
78 | method_name: Name, | ||
79 | args: Vec<ExprId>, | ||
80 | generic_args: Option<GenericArgs>, | ||
81 | }, | ||
82 | Match { | ||
83 | expr: ExprId, | ||
84 | arms: Vec<MatchArm>, | ||
85 | }, | ||
86 | Continue { | ||
87 | label: Option<Name>, | ||
88 | }, | ||
89 | Break { | ||
90 | expr: Option<ExprId>, | ||
91 | label: Option<Name>, | ||
92 | }, | ||
93 | Return { | ||
94 | expr: Option<ExprId>, | ||
95 | }, | ||
96 | RecordLit { | ||
97 | path: Option<Path>, | ||
98 | fields: Vec<RecordLitField>, | ||
99 | spread: Option<ExprId>, | ||
100 | }, | ||
101 | Field { | ||
102 | expr: ExprId, | ||
103 | name: Name, | ||
104 | }, | ||
105 | Await { | ||
106 | expr: ExprId, | ||
107 | }, | ||
108 | Try { | ||
109 | expr: ExprId, | ||
110 | }, | ||
111 | TryBlock { | ||
112 | body: ExprId, | ||
113 | }, | ||
114 | Cast { | ||
115 | expr: ExprId, | ||
116 | type_ref: TypeRef, | ||
117 | }, | ||
118 | Ref { | ||
119 | expr: ExprId, | ||
120 | rawness: Rawness, | ||
121 | mutability: Mutability, | ||
122 | }, | ||
123 | Box { | ||
124 | expr: ExprId, | ||
125 | }, | ||
126 | UnaryOp { | ||
127 | expr: ExprId, | ||
128 | op: UnaryOp, | ||
129 | }, | ||
130 | BinaryOp { | ||
131 | lhs: ExprId, | ||
132 | rhs: ExprId, | ||
133 | op: Option<BinaryOp>, | ||
134 | }, | ||
135 | Range { | ||
136 | lhs: Option<ExprId>, | ||
137 | rhs: Option<ExprId>, | ||
138 | range_type: RangeOp, | ||
139 | }, | ||
140 | Index { | ||
141 | base: ExprId, | ||
142 | index: ExprId, | ||
143 | }, | ||
144 | Lambda { | ||
145 | args: Vec<PatId>, | ||
146 | arg_types: Vec<Option<TypeRef>>, | ||
147 | ret_type: Option<TypeRef>, | ||
148 | body: ExprId, | ||
149 | }, | ||
150 | Tuple { | ||
151 | exprs: Vec<ExprId>, | ||
152 | }, | ||
153 | Unsafe { | ||
154 | body: ExprId, | ||
155 | }, | ||
156 | Array(Array), | ||
157 | Literal(Literal), | ||
158 | } | ||
159 | |||
160 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
161 | pub enum BinaryOp { | ||
162 | LogicOp(LogicOp), | ||
163 | ArithOp(ArithOp), | ||
164 | CmpOp(CmpOp), | ||
165 | Assignment { op: Option<ArithOp> }, | ||
166 | } | ||
167 | |||
168 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
169 | pub enum LogicOp { | ||
170 | And, | ||
171 | Or, | ||
172 | } | ||
173 | |||
174 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
175 | pub enum CmpOp { | ||
176 | Eq { negated: bool }, | ||
177 | Ord { ordering: Ordering, strict: bool }, | ||
178 | } | ||
179 | |||
180 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
181 | pub enum Ordering { | ||
182 | Less, | ||
183 | Greater, | ||
184 | } | ||
185 | |||
186 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
187 | pub enum ArithOp { | ||
188 | Add, | ||
189 | Mul, | ||
190 | Sub, | ||
191 | Div, | ||
192 | Rem, | ||
193 | Shl, | ||
194 | Shr, | ||
195 | BitXor, | ||
196 | BitOr, | ||
197 | BitAnd, | ||
198 | } | ||
199 | |||
200 | pub use ra_syntax::ast::PrefixOp as UnaryOp; | ||
201 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
202 | pub enum Array { | ||
203 | ElementList(Vec<ExprId>), | ||
204 | Repeat { initializer: ExprId, repeat: ExprId }, | ||
205 | } | ||
206 | |||
207 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
208 | pub struct MatchArm { | ||
209 | pub pat: PatId, | ||
210 | pub guard: Option<ExprId>, | ||
211 | pub expr: ExprId, | ||
212 | } | ||
213 | |||
214 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
215 | pub struct RecordLitField { | ||
216 | pub name: Name, | ||
217 | pub expr: ExprId, | ||
218 | } | ||
219 | |||
220 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
221 | pub enum Statement { | ||
222 | Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> }, | ||
223 | Expr(ExprId), | ||
224 | } | ||
225 | |||
226 | impl Expr { | ||
227 | pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) { | ||
228 | match self { | ||
229 | Expr::Missing => {} | ||
230 | Expr::Path(_) => {} | ||
231 | Expr::If { condition, then_branch, else_branch } => { | ||
232 | f(*condition); | ||
233 | f(*then_branch); | ||
234 | if let Some(else_branch) = else_branch { | ||
235 | f(*else_branch); | ||
236 | } | ||
237 | } | ||
238 | Expr::Block { statements, tail, .. } => { | ||
239 | for stmt in statements { | ||
240 | match stmt { | ||
241 | Statement::Let { initializer, .. } => { | ||
242 | if let Some(expr) = initializer { | ||
243 | f(*expr); | ||
244 | } | ||
245 | } | ||
246 | Statement::Expr(e) => f(*e), | ||
247 | } | ||
248 | } | ||
249 | if let Some(expr) = tail { | ||
250 | f(*expr); | ||
251 | } | ||
252 | } | ||
253 | Expr::TryBlock { body } | Expr::Unsafe { body } => f(*body), | ||
254 | Expr::Loop { body, .. } => f(*body), | ||
255 | Expr::While { condition, body, .. } => { | ||
256 | f(*condition); | ||
257 | f(*body); | ||
258 | } | ||
259 | Expr::For { iterable, body, .. } => { | ||
260 | f(*iterable); | ||
261 | f(*body); | ||
262 | } | ||
263 | Expr::Call { callee, args } => { | ||
264 | f(*callee); | ||
265 | for arg in args { | ||
266 | f(*arg); | ||
267 | } | ||
268 | } | ||
269 | Expr::MethodCall { receiver, args, .. } => { | ||
270 | f(*receiver); | ||
271 | for arg in args { | ||
272 | f(*arg); | ||
273 | } | ||
274 | } | ||
275 | Expr::Match { expr, arms } => { | ||
276 | f(*expr); | ||
277 | for arm in arms { | ||
278 | f(arm.expr); | ||
279 | } | ||
280 | } | ||
281 | Expr::Continue { .. } => {} | ||
282 | Expr::Break { expr, .. } | Expr::Return { expr } => { | ||
283 | if let Some(expr) = expr { | ||
284 | f(*expr); | ||
285 | } | ||
286 | } | ||
287 | Expr::RecordLit { fields, spread, .. } => { | ||
288 | for field in fields { | ||
289 | f(field.expr); | ||
290 | } | ||
291 | if let Some(expr) = spread { | ||
292 | f(*expr); | ||
293 | } | ||
294 | } | ||
295 | Expr::Lambda { body, .. } => { | ||
296 | f(*body); | ||
297 | } | ||
298 | Expr::BinaryOp { lhs, rhs, .. } => { | ||
299 | f(*lhs); | ||
300 | f(*rhs); | ||
301 | } | ||
302 | Expr::Range { lhs, rhs, .. } => { | ||
303 | if let Some(lhs) = rhs { | ||
304 | f(*lhs); | ||
305 | } | ||
306 | if let Some(rhs) = lhs { | ||
307 | f(*rhs); | ||
308 | } | ||
309 | } | ||
310 | Expr::Index { base, index } => { | ||
311 | f(*base); | ||
312 | f(*index); | ||
313 | } | ||
314 | Expr::Field { expr, .. } | ||
315 | | Expr::Await { expr } | ||
316 | | Expr::Try { expr } | ||
317 | | Expr::Cast { expr, .. } | ||
318 | | Expr::Ref { expr, .. } | ||
319 | | Expr::UnaryOp { expr, .. } | ||
320 | | Expr::Box { expr } => { | ||
321 | f(*expr); | ||
322 | } | ||
323 | Expr::Tuple { exprs } => { | ||
324 | for expr in exprs { | ||
325 | f(*expr); | ||
326 | } | ||
327 | } | ||
328 | Expr::Array(a) => match a { | ||
329 | Array::ElementList(exprs) => { | ||
330 | for expr in exprs { | ||
331 | f(*expr); | ||
332 | } | ||
333 | } | ||
334 | Array::Repeat { initializer, repeat } => { | ||
335 | f(*initializer); | ||
336 | f(*repeat) | ||
337 | } | ||
338 | }, | ||
339 | Expr::Literal(_) => {} | ||
340 | } | ||
341 | } | ||
342 | } | ||
343 | |||
344 | /// Explicit binding annotations given in the HIR for a binding. Note | ||
345 | /// that this is not the final binding *mode* that we infer after type | ||
346 | /// inference. | ||
347 | #[derive(Clone, PartialEq, Eq, Debug, Copy)] | ||
348 | pub enum BindingAnnotation { | ||
349 | /// No binding annotation given: this means that the final binding mode | ||
350 | /// will depend on whether we have skipped through a `&` reference | ||
351 | /// when matching. For example, the `x` in `Some(x)` will have binding | ||
352 | /// mode `None`; if you do `let Some(x) = &Some(22)`, it will | ||
353 | /// ultimately be inferred to be by-reference. | ||
354 | Unannotated, | ||
355 | |||
356 | /// Annotated with `mut x` -- could be either ref or not, similar to `None`. | ||
357 | Mutable, | ||
358 | |||
359 | /// Annotated as `ref`, like `ref x` | ||
360 | Ref, | ||
361 | |||
362 | /// Annotated as `ref mut x`. | ||
363 | RefMut, | ||
364 | } | ||
365 | |||
366 | impl BindingAnnotation { | ||
367 | pub fn new(is_mutable: bool, is_ref: bool) -> Self { | ||
368 | match (is_mutable, is_ref) { | ||
369 | (true, true) => BindingAnnotation::RefMut, | ||
370 | (false, true) => BindingAnnotation::Ref, | ||
371 | (true, false) => BindingAnnotation::Mutable, | ||
372 | (false, false) => BindingAnnotation::Unannotated, | ||
373 | } | ||
374 | } | ||
375 | } | ||
376 | |||
377 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
378 | pub struct RecordFieldPat { | ||
379 | pub name: Name, | ||
380 | pub pat: PatId, | ||
381 | } | ||
382 | |||
383 | /// Close relative to rustc's hir::PatKind | ||
384 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
385 | pub enum Pat { | ||
386 | Missing, | ||
387 | Wild, | ||
388 | Tuple { args: Vec<PatId>, ellipsis: Option<usize> }, | ||
389 | Or(Vec<PatId>), | ||
390 | Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool }, | ||
391 | Range { start: ExprId, end: ExprId }, | ||
392 | Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> }, | ||
393 | Path(Path), | ||
394 | Lit(ExprId), | ||
395 | Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, | ||
396 | TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, | ||
397 | Ref { pat: PatId, mutability: Mutability }, | ||
398 | } | ||
399 | |||
400 | impl Pat { | ||
401 | pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { | ||
402 | match self { | ||
403 | Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {} | ||
404 | Pat::Bind { subpat, .. } => { | ||
405 | subpat.iter().copied().for_each(f); | ||
406 | } | ||
407 | Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => { | ||
408 | args.iter().copied().for_each(f); | ||
409 | } | ||
410 | Pat::Ref { pat, .. } => f(*pat), | ||
411 | Pat::Slice { prefix, slice, suffix } => { | ||
412 | let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter()); | ||
413 | total_iter.copied().for_each(f); | ||
414 | } | ||
415 | Pat::Record { args, .. } => { | ||
416 | args.iter().map(|f| f.pat).for_each(f); | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | } | ||
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs deleted file mode 100644 index 06701a830..000000000 --- a/crates/ra_hir_def/src/find_path.rs +++ /dev/null | |||
@@ -1,691 +0,0 @@ | |||
1 | //! An algorithm to find a path to refer to a certain item. | ||
2 | |||
3 | use hir_expand::name::{known, AsName, Name}; | ||
4 | use ra_prof::profile; | ||
5 | use rustc_hash::FxHashSet; | ||
6 | use test_utils::mark; | ||
7 | |||
8 | use crate::{ | ||
9 | db::DefDatabase, | ||
10 | item_scope::ItemInNs, | ||
11 | path::{ModPath, PathKind}, | ||
12 | visibility::Visibility, | ||
13 | ModuleDefId, ModuleId, | ||
14 | }; | ||
15 | |||
16 | // FIXME: handle local items | ||
17 | |||
18 | /// Find a path that can be used to refer to a certain item. This can depend on | ||
19 | /// *from where* you're referring to the item, hence the `from` parameter. | ||
20 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | ||
21 | let _p = profile("find_path"); | ||
22 | find_path_inner(db, item, from, MAX_PATH_LEN) | ||
23 | } | ||
24 | |||
25 | const MAX_PATH_LEN: usize = 15; | ||
26 | |||
27 | impl ModPath { | ||
28 | fn starts_with_std(&self) -> bool { | ||
29 | self.segments.first() == Some(&known::std) | ||
30 | } | ||
31 | |||
32 | // When std library is present, paths starting with `std::` | ||
33 | // should be preferred over paths starting with `core::` and `alloc::` | ||
34 | fn can_start_with_std(&self) -> bool { | ||
35 | let first_segment = self.segments.first(); | ||
36 | first_segment == Some(&known::alloc) || first_segment == Some(&known::core) | ||
37 | } | ||
38 | } | ||
39 | |||
40 | fn find_path_inner( | ||
41 | db: &dyn DefDatabase, | ||
42 | item: ItemInNs, | ||
43 | from: ModuleId, | ||
44 | max_len: usize, | ||
45 | ) -> Option<ModPath> { | ||
46 | if max_len == 0 { | ||
47 | return None; | ||
48 | } | ||
49 | |||
50 | // Base cases: | ||
51 | |||
52 | // - if the item is already in scope, return the name under which it is | ||
53 | let def_map = db.crate_def_map(from.krate); | ||
54 | let from_scope: &crate::item_scope::ItemScope = &def_map.modules[from.local_id].scope; | ||
55 | if let Some((name, _)) = from_scope.name_of(item) { | ||
56 | return Some(ModPath::from_segments(PathKind::Plain, vec![name.clone()])); | ||
57 | } | ||
58 | |||
59 | // - if the item is the crate root, return `crate` | ||
60 | if item | ||
61 | == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { | ||
62 | krate: from.krate, | ||
63 | local_id: def_map.root, | ||
64 | })) | ||
65 | { | ||
66 | return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); | ||
67 | } | ||
68 | |||
69 | // - if the item is the module we're in, use `self` | ||
70 | if item == ItemInNs::Types(from.into()) { | ||
71 | return Some(ModPath::from_segments(PathKind::Super(0), Vec::new())); | ||
72 | } | ||
73 | |||
74 | // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) | ||
75 | if let Some(parent_id) = def_map.modules[from.local_id].parent { | ||
76 | if item | ||
77 | == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { | ||
78 | krate: from.krate, | ||
79 | local_id: parent_id, | ||
80 | })) | ||
81 | { | ||
82 | return Some(ModPath::from_segments(PathKind::Super(1), Vec::new())); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | // - if the item is the crate root of a dependency crate, return the name from the extern prelude | ||
87 | for (name, def_id) in &def_map.extern_prelude { | ||
88 | if item == ItemInNs::Types(*def_id) { | ||
89 | return Some(ModPath::from_segments(PathKind::Plain, vec![name.clone()])); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | // - if the item is in the prelude, return the name from there | ||
94 | if let Some(prelude_module) = def_map.prelude { | ||
95 | let prelude_def_map = db.crate_def_map(prelude_module.krate); | ||
96 | let prelude_scope: &crate::item_scope::ItemScope = | ||
97 | &prelude_def_map.modules[prelude_module.local_id].scope; | ||
98 | if let Some((name, vis)) = prelude_scope.name_of(item) { | ||
99 | if vis.is_visible_from(db, from) { | ||
100 | return Some(ModPath::from_segments(PathKind::Plain, vec![name.clone()])); | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | |||
105 | // - if the item is a builtin, it's in scope | ||
106 | if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item { | ||
107 | return Some(ModPath::from_segments(PathKind::Plain, vec![builtin.as_name()])); | ||
108 | } | ||
109 | |||
110 | // Recursive case: | ||
111 | // - if the item is an enum variant, refer to it via the enum | ||
112 | if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() { | ||
113 | if let Some(mut path) = find_path(db, ItemInNs::Types(variant.parent.into()), from) { | ||
114 | let data = db.enum_data(variant.parent); | ||
115 | path.segments.push(data.variants[variant.local_id].name.clone()); | ||
116 | return Some(path); | ||
117 | } | ||
118 | // If this doesn't work, it seems we have no way of referring to the | ||
119 | // enum; that's very weird, but there might still be a reexport of the | ||
120 | // variant somewhere | ||
121 | } | ||
122 | |||
123 | // - otherwise, look for modules containing (reexporting) it and import it from one of those | ||
124 | |||
125 | let crate_root = ModuleId { local_id: def_map.root, krate: from.krate }; | ||
126 | let crate_attrs = db.attrs(crate_root.into()); | ||
127 | let prefer_no_std = crate_attrs.by_key("no_std").exists(); | ||
128 | let mut best_path = None; | ||
129 | let mut best_path_len = max_len; | ||
130 | |||
131 | if item.krate(db) == Some(from.krate) { | ||
132 | // Item was defined in the same crate that wants to import it. It cannot be found in any | ||
133 | // dependency in this case. | ||
134 | |||
135 | let local_imports = find_local_import_locations(db, item, from); | ||
136 | for (module_id, name) in local_imports { | ||
137 | if let Some(mut path) = find_path_inner( | ||
138 | db, | ||
139 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), | ||
140 | from, | ||
141 | best_path_len - 1, | ||
142 | ) { | ||
143 | path.segments.push(name); | ||
144 | |||
145 | let new_path = if let Some(best_path) = best_path { | ||
146 | select_best_path(best_path, path, prefer_no_std) | ||
147 | } else { | ||
148 | path | ||
149 | }; | ||
150 | best_path_len = new_path.len(); | ||
151 | best_path = Some(new_path); | ||
152 | } | ||
153 | } | ||
154 | } else { | ||