aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src')
-rw-r--r--crates/ra_hir_def/src/adt.rs295
-rw-r--r--crates/ra_hir_def/src/attr.rs212
-rw-r--r--crates/ra_hir_def/src/body.rs361
-rw-r--r--crates/ra_hir_def/src/body/lower.rs931
-rw-r--r--crates/ra_hir_def/src/body/scope.rs456
-rw-r--r--crates/ra_hir_def/src/builtin_type.rs166
-rw-r--r--crates/ra_hir_def/src/child_by_source.rs177
-rw-r--r--crates/ra_hir_def/src/data.rs279
-rw-r--r--crates/ra_hir_def/src/db.rs121
-rw-r--r--crates/ra_hir_def/src/diagnostics.rs27
-rw-r--r--crates/ra_hir_def/src/docs.rs121
-rw-r--r--crates/ra_hir_def/src/dyn_map.rs108
-rw-r--r--crates/ra_hir_def/src/expr.rs420
-rw-r--r--crates/ra_hir_def/src/find_path.rs691
-rw-r--r--crates/ra_hir_def/src/generics.rs340
-rw-r--r--crates/ra_hir_def/src/import_map.rs745
-rw-r--r--crates/ra_hir_def/src/item_scope.rs341
-rw-r--r--crates/ra_hir_def/src/item_tree.rs754
-rw-r--r--crates/ra_hir_def/src/item_tree/lower.rs705
-rw-r--r--crates/ra_hir_def/src/item_tree/tests.rs439
-rw-r--r--crates/ra_hir_def/src/keys.rs58
-rw-r--r--crates/ra_hir_def/src/lang_item.rs175
-rw-r--r--crates/ra_hir_def/src/lib.rs541
-rw-r--r--crates/ra_hir_def/src/nameres.rs327
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs1279
-rw-r--r--crates/ra_hir_def/src/nameres/mod_resolution.rs139
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs330
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs690
-rw-r--r--crates/ra_hir_def/src/nameres/tests/globs.rs338
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs101
-rw-r--r--crates/ra_hir_def/src/nameres/tests/macros.rs669
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs796
-rw-r--r--crates/ra_hir_def/src/nameres/tests/primitives.rs23
-rw-r--r--crates/ra_hir_def/src/path.rs351
-rw-r--r--crates/ra_hir_def/src/path/lower.rs215
-rw-r--r--crates/ra_hir_def/src/path/lower/lower_use.rs120
-rw-r--r--crates/ra_hir_def/src/per_ns.rs95
-rw-r--r--crates/ra_hir_def/src/resolver.rs713
-rw-r--r--crates/ra_hir_def/src/src.rs43
-rw-r--r--crates/ra_hir_def/src/test_db.rs101
-rw-r--r--crates/ra_hir_def/src/trace.rs51
-rw-r--r--crates/ra_hir_def/src/type_ref.rs245
-rw-r--r--crates/ra_hir_def/src/visibility.rs171
43 files changed, 0 insertions, 15260 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
3use std::sync::Arc;
4
5use either::Either;
6use hir_expand::{
7 name::{AsName, Name},
8 InFile,
9};
10use ra_arena::{map::ArenaMap, Arena};
11use ra_syntax::ast::{self, NameOwner, VisibilityOwner};
12
13use 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};
25use ra_cfg::CfgOptions;
26
27/// Note that we use `StructData` for unions as well!
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct StructData {
30 pub name: Name,
31 pub variant_data: Arc<VariantData>,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct EnumData {
36 pub name: Name,
37 pub variants: Arena<EnumVariantData>,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
41pub struct EnumVariantData {
42 pub name: Name,
43 pub variant_data: Arc<VariantData>,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub 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)]
55pub struct FieldData {
56 pub name: Name,
57 pub type_ref: TypeRef,
58 pub visibility: RawVisibility,
59}
60
61impl 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
84impl 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
113impl 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
124fn 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
148impl 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
180impl 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)]
212pub enum StructKind {
213 Tuple,
214 Record,
215 Unit,
216}
217
218fn 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
265fn 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
289fn 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
3use std::{ops, sync::Arc};
4
5use either::Either;
6use hir_expand::{hygiene::Hygiene, AstId, InFile};
7use mbe::ast_to_token_tree;
8use ra_cfg::{CfgExpr, CfgOptions};
9use ra_syntax::{
10 ast::{self, AstNode, AttrsOwner},
11 SmolStr,
12};
13use tt::Subtree;
14
15use 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)]
25pub struct Attrs {
26 entries: Option<Arc<[Attr]>>,
27}
28
29impl 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
40impl 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)]
138pub struct Attr {
139 pub(crate) path: ModPath,
140 pub(crate) input: Option<AttrInput>,
141}
142
143#[derive(Debug, Clone, PartialEq, Eq)]
144pub enum AttrInput {
145 /// `#[attr = "string"]`
146 Literal(SmolStr),
147 /// `#[attr(subtree)]`
148 TokenTree(Subtree),
149}
150
151impl 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)]
168pub struct AttrQuery<'a> {
169 attrs: &'a Attrs,
170 key: &'static str,
171}
172
173impl<'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
200fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> Attrs
201where
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
208fn 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.
3mod lower;
4pub mod scope;
5
6use std::{mem, ops::Index, sync::Arc};
7
8use drop_bomb::DropBomb;
9use either::Either;
10use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId};
11use ra_arena::{map::ArenaMap, Arena};
12use ra_cfg::CfgOptions;
13use ra_db::CrateId;
14use ra_prof::profile;
15use ra_syntax::{ast, AstNode, AstPtr};
16use rustc_hash::FxHashMap;
17use test_utils::mark;
18
19pub(crate) use lower::LowerCtx;
20
21use 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.
35pub(crate) struct CfgExpander {
36 cfg_options: CfgOptions,
37 hygiene: Hygiene,
38}
39
40pub(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)]
50const EXPANSION_RECURSION_LIMIT: usize = 32;
51
52#[cfg(not(test))]
53const EXPANSION_RECURSION_LIMIT: usize = 128;
54
55impl 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
76impl 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, &macro_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
173pub(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)]
181pub 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
196pub type ExprPtr = AstPtr<ast::Expr>;
197pub type ExprSource = InFile<ExprPtr>;
198
199pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
200pub 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)]
214pub 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)]
224pub struct SyntheticSyntax;
225
226impl 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
272impl Index<ExprId> for Body {
273 type Output = Expr;
274
275 fn index(&self, expr: ExprId) -> &Expr {
276 &self.exprs[expr]
277 }
278}
279
280impl Index<PatId> for Body {
281 type Output = Pat;
282
283 fn index(&self, pat: PatId) -> &Pat {
284 &self.pats[pat]
285 }
286}
287
288impl 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)]
323mod 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 "
351macro_rules! n_nuple {
352 ($e:tt) => ();
353 ($($rest:tt)*) => {{
354 (n_nuple!($($rest)*)None,)
355 }};
356}
357fn 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 f5c37edb3..000000000
--- a/crates/ra_hir_def/src/body/lower.rs
+++ /dev/null
@@ -1,931 +0,0 @@
1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2//! representation.
3
4use std::{any::type_name, sync::Arc};
5
6use either::Either;
7use hir_expand::{
8 hygiene::Hygiene,
9 name::{name, AsName, Name},
10 HirFileId, MacroDefId, MacroDefKind,
11};
12use ra_arena::Arena;
13use ra_syntax::{
14 ast::{
15 self, ArgListOwner, ArrayExprKind, AstChildren, LiteralKind, LoopBodyOwner, NameOwner,
16 SlicePatComponents,
17 },
18 AstNode, AstPtr,
19};
20use rustc_hash::FxHashMap;
21use test_utils::mark;
22
23use crate::{
24 adt::StructKind,
25 body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax},
26 builtin_type::{BuiltinFloat, BuiltinInt},
27 db::DefDatabase,
28 expr::{
29 dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal,
30 LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
31 },
32 item_scope::BuiltinShadowMode,
33 item_tree::{ItemTree, ItemTreeId, ItemTreeNode},
34 path::{GenericArgs, Path},
35 type_ref::{Mutability, Rawness, TypeRef},
36 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId,
37 StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
38};
39
40use super::{ExprSource, PatSource};
41
42pub(crate) struct LowerCtx {
43 hygiene: Hygiene,
44}
45
46impl 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
59pub(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
88struct 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
98impl 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::Label(label) => match e.block_expr() {
228 Some(block) => {
229 let res = self.collect_block(block);
230 match &mut self.body.exprs[res] {
231 Expr::Block { label: block_label, .. } => {
232 *block_label =
233 label.lifetime_token().map(|t| Name::new_lifetime(&t))
234 }
235 _ => unreachable!(),
236 }
237 res
238 }
239 None => self.missing_expr(),
240 },
241 // FIXME: we need to record these effects somewhere...
242 ast::Effect::Async(_) => self.collect_block_opt(e.block_expr()),
243 },
244 ast::Expr::BlockExpr(e) => self.collect_block(e),
245 ast::Expr::LoopExpr(e) => {
246 let body = self.collect_block_opt(e.loop_body());
247 self.alloc_expr(
248 Expr::Loop {
249 body,
250 label: e
251 .label()
252 .and_then(|l| l.lifetime_token())
253 .map(|l| Name::new_lifetime(&l)),
254 },
255 syntax_ptr,
256 )
257 }
258 ast::Expr::WhileExpr(e) => {
259 let body = self.collect_block_opt(e.loop_body());
260
261 let condition = match e.condition() {
262 None => self.missing_expr(),
263 Some(condition) => match condition.pat() {
264 None => self.collect_expr_opt(condition.expr()),
265 // if let -- desugar to match
266 Some(pat) => {
267 mark::hit!(infer_resolve_while_let);
268 let pat = self.collect_pat(pat);
269 let match_expr = self.collect_expr_opt(condition.expr());
270 let placeholder_pat = self.missing_pat();
271 let break_ =
272 self.alloc_expr_desugared(Expr::Break { expr: None, label: None });
273 let arms = vec![
274 MatchArm { pat, expr: body, guard: None },
275 MatchArm { pat: placeholder_pat, expr: break_, guard: None },
276 ];
277 let match_expr =
278 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
279 return self.alloc_expr(
280 Expr::Loop {
281 body: match_expr,
282 label: e
283 .label()
284 .and_then(|l| l.lifetime_token())
285 .map(|l| Name::new_lifetime(&l)),
286 },
287 syntax_ptr,
288 );
289 }
290 },
291 };
292
293 self.alloc_expr(
294 Expr::While {
295 condition,
296 body,
297 label: e
298 .label()
299 .and_then(|l| l.lifetime_token())
300 .map(|l| Name::new_lifetime(&l)),
301 },
302 syntax_ptr,
303 )
304 }
305 ast::Expr::ForExpr(e) => {
306 let iterable = self.collect_expr_opt(e.iterable());
307 let pat = self.collect_pat_opt(e.pat());
308 let body = self.collect_block_opt(e.loop_body());
309 self.alloc_expr(
310 Expr::For {
311 iterable,
312 pat,
313 body,
314 label: e
315 .label()
316 .and_then(|l| l.lifetime_token())
317 .map(|l| Name::new_lifetime(&l)),
318 },
319 syntax_ptr,
320 )
321 }
322 ast::Expr::CallExpr(e) => {
323 let callee = self.collect_expr_opt(e.expr());
324 let args = if let Some(arg_list) = e.arg_list() {
325 arg_list.args().map(|e| self.collect_expr(e)).collect()
326 } else {
327 Vec::new()
328 };
329 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
330 }
331 ast::Expr::MethodCallExpr(e) => {
332 let receiver = self.collect_expr_opt(e.expr());
333 let args = if let Some(arg_list) = e.arg_list() {
334 arg_list.args().map(|e| self.collect_expr(e)).collect()
335 } else {
336 Vec::new()
337 };
338 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
339 let generic_args =
340 e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it));
341 self.alloc_expr(
342 Expr::MethodCall { receiver, method_name, args, generic_args },
343 syntax_ptr,
344 )
345 }
346 ast::Expr::MatchExpr(e) => {
347 let expr = self.collect_expr_opt(e.expr());
348 let arms = if let Some(match_arm_list) = e.match_arm_list() {
349 match_arm_list
350 .arms()
351 .map(|arm| MatchArm {
352 pat: self.collect_pat_opt(arm.pat()),
353 expr: self.collect_expr_opt(arm.expr()),
354 guard: arm
355 .guard()
356 .and_then(|guard| guard.expr())
357 .map(|e| self.collect_expr(e)),
358 })
359 .collect()
360 } else {
361 Vec::new()
362 };
363 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
364 }
365 ast::Expr::PathExpr(e) => {
366 let path = e
367 .path()
368 .and_then(|path| self.expander.parse_path(path))
369 .map(Expr::Path)
370 .unwrap_or(Expr::Missing);
371 self.alloc_expr(path, syntax_ptr)
372 }
373 ast::Expr::ContinueExpr(e) => self.alloc_expr(
374 Expr::Continue { label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) },
375 syntax_ptr,
376 ),
377 ast::Expr::BreakExpr(e) => {
378 let expr = e.expr().map(|e| self.collect_expr(e));
379 self.alloc_expr(
380 Expr::Break { expr, label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) },
381 syntax_ptr,
382 )
383 }
384 ast::Expr::ParenExpr(e) => {
385 let inner = self.collect_expr_opt(e.expr());
386 // make the paren expr point to the inner expression as well
387 let src = self.expander.to_source(syntax_ptr);
388 self.source_map.expr_map.insert(src, inner);
389 inner
390 }
391 ast::Expr::ReturnExpr(e) => {
392 let expr = e.expr().map(|e| self.collect_expr(e));
393 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
394 }
395 ast::Expr::RecordExpr(e) => {
396 let path = e.path().and_then(|path| self.expander.parse_path(path));
397 let mut field_ptrs = Vec::new();
398 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
399 let fields = nfl
400 .fields()
401 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
402 .filter_map(|field| {
403 if !self.expander.is_cfg_enabled(&field) {
404 return None;
405 }
406 let name = field.field_name()?.as_name();
407
408 Some(RecordLitField {
409 name,
410 expr: match field.expr() {
411 Some(e) => self.collect_expr(e),
412 None => self.missing_expr(),
413 },
414 })
415 })
416 .collect();
417 let spread = nfl.spread().map(|s| self.collect_expr(s));
418 Expr::RecordLit { path, fields, spread }
419 } else {
420 Expr::RecordLit { path, fields: Vec::new(), spread: None }
421 };
422
423 let res = self.alloc_expr(record_lit, syntax_ptr);
424 for (i, ptr) in field_ptrs.into_iter().enumerate() {
425 let src = self.expander.to_source(ptr);
426 self.source_map.field_map.insert((res, i), src);
427 }
428 res
429 }
430 ast::Expr::FieldExpr(e) => {
431 let expr = self.collect_expr_opt(e.expr());
432 let name = match e.field_access() {
433 Some(kind) => kind.as_name(),
434 _ => Name::missing(),
435 };
436 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
437 }
438 ast::Expr::AwaitExpr(e) => {
439 let expr = self.collect_expr_opt(e.expr());
440 self.alloc_expr(Expr::Await { expr }, syntax_ptr)
441 }
442 ast::Expr::TryExpr(e) => {
443 let expr = self.collect_expr_opt(e.expr());
444 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
445 }
446 ast::Expr::CastExpr(e) => {
447 let expr = self.collect_expr_opt(e.expr());
448 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty());
449 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
450 }
451 ast::Expr::RefExpr(e) => {
452 let expr = self.collect_expr_opt(e.expr());
453 let raw_tok = e.raw_token().is_some();
454 let mutability = if raw_tok {
455 if e.mut_token().is_some() {
456 Mutability::Mut
457 } else if e.const_token().is_some() {
458 Mutability::Shared
459 } else {
460 unreachable!("parser only remaps to raw_token() if matching mutability token follows")
461 }
462 } else {
463 Mutability::from_mutable(e.mut_token().is_some())
464 };
465 let rawness = Rawness::from_raw(raw_tok);
466 self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
467 }
468 ast::Expr::PrefixExpr(e) => {
469 let expr = self.collect_expr_opt(e.expr());
470 if let Some(op) = e.op_kind() {
471 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
472 } else {
473 self.alloc_expr(Expr::Missing, syntax_ptr)
474 }
475 }
476 ast::Expr::ClosureExpr(e) => {
477 let mut args = Vec::new();
478 let mut arg_types = Vec::new();
479 if let Some(pl) = e.param_list() {
480 for param in pl.params() {
481 let pat = self.collect_pat_opt(param.pat());
482 let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
483 args.push(pat);
484 arg_types.push(type_ref);
485 }
486 }
487 let ret_type =
488 e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it));
489 let body = self.collect_expr_opt(e.body());
490 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
491 }
492 ast::Expr::BinExpr(e) => {
493 let lhs = self.collect_expr_opt(e.lhs());
494 let rhs = self.collect_expr_opt(e.rhs());
495 let op = e.op_kind().map(BinaryOp::from);
496 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
497 }
498 ast::Expr::TupleExpr(e) => {
499 let exprs = e.fields().map(|expr| self.collect_expr(expr)).collect();
500 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
501 }
502 ast::Expr::BoxExpr(e) => {
503 let expr = self.collect_expr_opt(e.expr());
504 self.alloc_expr(Expr::Box { expr }, syntax_ptr)
505 }
506
507 ast::Expr::ArrayExpr(e) => {
508 let kind = e.kind();
509
510 match kind {
511 ArrayExprKind::ElementList(e) => {
512 let exprs = e.map(|expr| self.collect_expr(expr)).collect();
513 self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr)
514 }
515 ArrayExprKind::Repeat { initializer, repeat } => {
516 let initializer = self.collect_expr_opt(initializer);
517 let repeat = self.collect_expr_opt(repeat);
518 self.alloc_expr(
519 Expr::Array(Array::Repeat { initializer, repeat }),
520 syntax_ptr,
521 )
522 }
523 }
524 }
525
526 ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),
527 ast::Expr::IndexExpr(e) => {
528 let base = self.collect_expr_opt(e.base());
529 let index = self.collect_expr_opt(e.index());
530 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
531 }
532 ast::Expr::RangeExpr(e) => {
533 let lhs = e.start().map(|lhs| self.collect_expr(lhs));
534 let rhs = e.end().map(|rhs| self.collect_expr(rhs));
535 match e.op_kind() {
536 Some(range_type) => {
537 self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
538 }
539 None => self.alloc_expr(Expr::Missing, syntax_ptr),
540 }
541 }
542 ast::Expr::MacroCall(e) => {
543 if let Some(name) = e.is_macro_rules().map(|it| it.as_name()) {
544 let mac = MacroDefId {
545 krate: Some(self.expander.module.krate),
546 ast_id: Some(self.expander.ast_id(&e)),
547 kind: MacroDefKind::Declarative,
548 local_inner: false,
549 };
550 self.body.item_scope.define_legacy_macro(name, mac);
551
552 // FIXME: do we still need to allocate this as missing ?
553 self.alloc_expr(Expr::Missing, syntax_ptr)
554 } else {
555 let macro_call = self.expander.to_source(AstPtr::new(&e));
556 match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) {
557 Some((mark, expansion)) => {
558 self.source_map
559 .expansions
560 .insert(macro_call, self.expander.current_file_id);
561
562 let item_tree = self.db.item_tree(self.expander.current_file_id);
563 self.item_trees.insert(self.expander.current_file_id, item_tree);
564 let id = self.collect_expr(expansion);
565 self.expander.exit(self.db, mark);
566 id
567 }
568 None => self.alloc_expr(Expr::Missing, syntax_ptr),
569 }
570 }
571 }
572 }
573 }
574
575 fn find_inner_item<N: ItemTreeNode>(&self, ast: &N::Source) -> Option<ItemTreeId<N>> {
576 let id = self.expander.ast_id(ast);
577 let tree = &self.item_trees[&id.file_id];
578
579 // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes
580
581 // Root file (non-macro).
582 let item_tree_id = tree
583 .all_inner_items()
584 .chain(tree.top_level_items().iter().copied())
585 .filter_map(|mod_item| mod_item.downcast::<N>())
586 .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value.upcast())
587 .or_else(|| {
588 log::debug!(
589 "couldn't find inner {} item for {:?} (AST: `{}` - {:?})",
590 type_name::<N>(),
591 id,
592 ast.syntax(),
593 ast.syntax(),
594 );
595 None
596 })?;
597
598 Some(ItemTreeId::new(id.file_id, item_tree_id))
599 }
600
601 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
602 if let Some(expr) = expr {
603 self.collect_expr(expr)
604 } else {
605 self.missing_expr()
606 }
607 }
608
609 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
610 let syntax_node_ptr = AstPtr::new(&block.clone().into());
611 self.collect_block_items(&block);
612 let statements = block
613 .statements()
614 .filter_map(|s| {
615 let stmt = match s {
616 ast::Stmt::LetStmt(stmt) => {
617 let pat = self.collect_pat_opt(stmt.pat());
618 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
619 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
620 Statement::Let { pat, type_ref, initializer }
621 }
622 ast::Stmt::ExprStmt(stmt) => {
623 Statement::Expr(self.collect_expr_opt(stmt.expr()))
624 }
625 ast::Stmt::Item(_) => return None,
626 };
627 Some(stmt)
628 })
629 .collect();
630 let tail = block.expr().map(|e| self.collect_expr(e));
631 self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr)
632 }
633
634 fn collect_block_items(&mut self, block: &ast::BlockExpr) {
635 let container = ContainerId::DefWithBodyId(self.def);
636
637 let items = block
638 .statements()
639 .filter_map(|stmt| match stmt {
640 ast::Stmt::Item(it) => Some(it),
641 ast::Stmt::LetStmt(_) | ast::Stmt::ExprStmt(_) => None,
642 })
643 .filter_map(|item| {
644 let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
645 ast::Item::Fn(def) => {
646 let id = self.find_inner_item(&def)?;
647 (
648 FunctionLoc { container: container.into(), id }.intern(self.db).into(),
649 def.name(),
650 )
651 }
652 ast::Item::TypeAlias(def) => {
653 let id = self.find_inner_item(&def)?;
654 (
655 TypeAliasLoc { container: container.into(), id }.intern(self.db).into(),
656 def.name(),
657 )
658 }
659 ast::Item::Const(def) => {
660 let id = self.find_inner_item(&def)?;
661 (
662 ConstLoc { container: container.into(), id }.intern(self.db).into(),
663 def.name(),
664 )
665 }
666 ast::Item::Static(def) => {
667 let id = self.find_inner_item(&def)?;
668 (StaticLoc { container, id }.intern(self.db).into(), def.name())
669 }
670 ast::Item::Struct(def) => {
671 let id = self.find_inner_item(&def)?;
672 (StructLoc { container, id }.intern(self.db).into(), def.name())
673 }
674 ast::Item::Enum(def) => {
675 let id = self.find_inner_item(&def)?;
676 (EnumLoc { container, id }.intern(self.db).into(), def.name())
677 }
678 ast::Item::Union(def) => {
679 let id = self.find_inner_item(&def)?;
680 (UnionLoc { container, id }.intern(self.db).into(), def.name())
681 }
682 ast::Item::Trait(def) => {
683 let id = self.find_inner_item(&def)?;
684 (TraitLoc { container, id }.intern(self.db).into(), def.name())
685 }
686 ast::Item::ExternBlock(_) => return None, // FIXME: collect from extern blocks
687 ast::Item::Impl(_)
688 | ast::Item::Use(_)
689 | ast::Item::ExternCrate(_)
690 | ast::Item::Module(_)
691 | ast::Item::MacroCall(_) => return None,
692 };
693
694 Some((def, name))
695 })
696 .collect::<Vec<_>>();
697
698 for (def, name) in items {
699 self.body.item_scope.define_def(def);
700 if let Some(name) = name {
701 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
702 let has_constructor = match def {
703 ModuleDefId::AdtId(AdtId::StructId(s)) => {
704 self.db.struct_data(s).variant_data.kind() != StructKind::Record
705 }
706 _ => true,
707 };
708 self.body.item_scope.push_res(
709 name.as_name(),
710 crate::per_ns::PerNs::from_def(def, vis, has_constructor),
711 );
712 }
713 }
714 }
715
716 fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
717 if let Some(block) = expr {
718 self.collect_block(block)
719 } else {
720 self.missing_expr()
721 }
722 }
723
724 fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
725 let pattern = match &pat {
726 ast::Pat::IdentPat(bp) => {
727 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
728 let annotation =
729 BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
730 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
731 if annotation == BindingAnnotation::Unannotated && subpat.is_none() {
732 // This could also be a single-segment path pattern. To
733 // decide that, we need to try resolving the name.
734 let (resolved, _) = self.expander.crate_def_map.resolve_path(
735 self.db,
736 self.expander.module.local_id,
737 &name.clone().into(),
738 BuiltinShadowMode::Other,
739 );
740 match resolved.take_values() {
741 Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()),
742 Some(ModuleDefId::EnumVariantId(_)) => {
743 // this is only really valid for unit variants, but
744 // shadowing other enum variants with a pattern is
745 // an error anyway
746 Pat::Path(name.into())
747 }
748 Some(ModuleDefId::AdtId(AdtId::StructId(s)))
749 if self.db.struct_data(s).variant_data.kind() != StructKind::Record =>
750 {
751 // Funnily enough, record structs *can* be shadowed
752 // by pattern bindings (but unit or tuple structs
753 // can't).
754 Pat::Path(name.into())
755 }
756 // shadowing statics is an error as well, so we just ignore that case here
757 _ => Pat::Bind { name, mode: annotation, subpat },
758 }
759 } else {
760 Pat::Bind { name, mode: annotation, subpat }
761 }
762 }
763 ast::Pat::TupleStructPat(p) => {
764 let path = p.path().and_then(|path| self.expander.parse_path(path));
765 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
766 Pat::TupleStruct { path, args, ellipsis }
767 }
768 ast::Pat::RefPat(p) => {
769 let pat = self.collect_pat_opt(p.pat());
770 let mutability = Mutability::from_mutable(p.mut_token().is_some());
771 Pat::Ref { pat, mutability }
772 }
773 ast::Pat::PathPat(p) => {
774 let path = p.path().and_then(|path| self.expander.parse_path(path));
775 path.map(Pat::Path).unwrap_or(Pat::Missing)
776 }
777 ast::Pat::OrPat(p) => {
778 let pats = p.pats().map(|p| self.collect_pat(p)).collect();
779 Pat::Or(pats)
780 }
781 ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()),
782 ast::Pat::TuplePat(p) => {
783 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
784 Pat::Tuple { args, ellipsis }
785 }
786 ast::Pat::WildcardPat(_) => Pat::Wild,
787 ast::Pat::RecordPat(p) => {
788 let path = p.path().and_then(|path| self.expander.parse_path(path));
789 let args: Vec<_> = p
790 .record_pat_field_list()
791 .expect("every struct should have a field list")
792 .fields()
793 .filter_map(|f| {
794 let ast_pat = f.pat()?;
795 let pat = self.collect_pat(ast_pat);
796 let name = f.field_name()?.as_name();
797 Some(RecordFieldPat { name, pat })
798 })
799 .collect();
800
801 let ellipsis = p
802 .record_pat_field_list()
803 .expect("every struct should have a field list")
804 .dotdot_token()
805 .is_some();
806
807 Pat::Record { path, args, ellipsis }
808 }
809 ast::Pat::SlicePat(p) => {
810 let SlicePatComponents { prefix, slice, suffix } = p.components();
811
812 // FIXME properly handle `RestPat`
813 Pat::Slice {
814 prefix: prefix.into_iter().map(|p| self.collect_pat(p)).collect(),
815 slice: slice.map(|p| self.collect_pat(p)),
816 suffix: suffix.into_iter().map(|p| self.collect_pat(p)).collect(),
817 }
818 }
819 ast::Pat::LiteralPat(lit) => {
820 if let Some(ast_lit) = lit.literal() {
821 let expr = Expr::Literal(ast_lit.kind().into());
822 let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
823 let expr_id = self.alloc_expr(expr, expr_ptr);
824 Pat::Lit(expr_id)
825 } else {
826 Pat::Missing
827 }
828 }
829 ast::Pat::RestPat(_) => {
830 // `RestPat` requires special handling and should not be mapped
831 // to a Pat. Here we are using `Pat::Missing` as a fallback for
832 // when `RestPat` is mapped to `Pat`, which can easily happen
833 // when the source code being analyzed has a malformed pattern
834 // which includes `..` in a place where it isn't valid.
835
836 Pat::Missing
837 }
838 // FIXME: implement
839 ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
840 };
841 let ptr = AstPtr::new(&pat);
842 self.alloc_pat(pattern, Either::Left(ptr))
843 }
844
845 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
846 if let Some(pat) = pat {
847 self.collect_pat(pat)
848 } else {
849 self.missing_pat()
850 }
851 }
852
853 fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Vec<PatId>, Option<usize>) {
854 // Find the location of the `..`, if there is one. Note that we do not
855 // consider the possiblity of there being multiple `..` here.
856 let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_)));
857 // We want to skip the `..` pattern here, since we account for it above.
858 let args = args
859 .filter(|p| !matches!(p, ast::Pat::RestPat(_)))
860 .map(|p| self.collect_pat(p))
861 .collect();
862
863 (args, ellipsis)
864 }
865}
866
867impl From<ast::BinOp> for BinaryOp {
868 fn from(ast_op: ast::BinOp) -> Self {
869 match ast_op {
870 ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
871 ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
872 ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
873 ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
874 ast::BinOp::LesserEqualTest => {
875 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
876 }
877 ast::BinOp::GreaterEqualTest => {
878 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
879 }
880 ast::BinOp::LesserTest => {
881 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
882 }
883 ast::BinOp::GreaterTest => {
884 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
885 }
886 ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
887 ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
888 ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
889 ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
890 ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
891 ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
892 ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
893 ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
894 ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
895 ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
896 ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
897 ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
898 ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
899 ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
900 ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
901 ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
902 ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
903 ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
904 ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
905 ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
906 ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
907 }
908 }
909}
910
911impl From<ast::LiteralKind> for Literal {
912 fn from(ast_lit_kind: ast::LiteralKind) -> Self {
913 match ast_lit_kind {
914 LiteralKind::IntNumber { suffix } => {
915 let known_name = suffix.and_then(|it| BuiltinInt::from_suffix(&it));
916
917 Literal::Int(Default::default(), known_name)
918 }
919 LiteralKind::FloatNumber { suffix } => {
920 let known_name = suffix.and_then(|it| BuiltinFloat::from_suffix(&it));
921
922 Literal::Float(Default::default(), known_name)
923 }
924 LiteralKind::ByteString => Literal::ByteString(Default::default()),
925 LiteralKind::String => Literal::String(Default::default()),
926 LiteralKind::Byte => Literal::Int(Default::default(), Some(BuiltinInt::U8)),
927 LiteralKind::Bool(val) => Literal::Bool(val),
928 LiteralKind::Char => Literal::Char(Default::default()),
929 }
930 }
931}
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.
2use std::sync::Arc;
3
4use hir_expand::name::Name;
5use ra_arena::{Arena, Idx};
6use rustc_hash::FxHashMap;
7
8use crate::{
9 body::Body,
10 db::DefDatabase,
11 expr::{Expr, ExprId, Pat, PatId, Statement},
12 DefWithBodyId,
13};
14
15pub type ScopeId = Idx<ScopeData>;
16
17#[derive(Debug, PartialEq, Eq)]
18pub struct ExprScopes {
19 scopes: Arena<ScopeData>,
20 scope_by_expr: FxHashMap<ExprId, ScopeId>,
21}
22
23#[derive(Debug, PartialEq, Eq)]
24pub struct ScopeEntry {
25 name: Name,
26 pat: PatId,
27}
28
29impl 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)]
40pub struct ScopeData {
41 parent: Option<ScopeId>,
42 entries: Vec<ScopeEntry>,
43}
44
45impl 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
108fn 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
136fn 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)]
171mod 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"
307fn 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#"
389fn 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#"
406fn 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"
418fn 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"
431fn 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#"
446fn 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
6use std::fmt;
7
8use hir_expand::name::{name, AsName, Name};
9
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
11pub enum Signedness {
12 Signed,
13 Unsigned,
14}
15
16#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
17pub enum IntBitness {
18 Xsize,
19 X8,
20 X16,
21 X32,
22 X64,
23 X128,
24}
25
26#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
27pub enum FloatBitness {
28 X32,
29 X64,
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33pub struct BuiltinInt {
34 pub signedness: Signedness,
35 pub bitness: IntBitness,
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
39pub struct BuiltinFloat {
40 pub bitness: FloatBitness,
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44pub enum BuiltinType {
45 Char,
46 Bool,
47 Str,
48 Int(BuiltinInt),
49 Float(BuiltinFloat),
50}
51
52impl 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
78impl 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
107impl 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]
115impl 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]
154impl 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
7use either::Either;
8
9use 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
19pub trait ChildBySource {
20 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap;
21}
22
23impl 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
49impl 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
75impl 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
83impl 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
136impl 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
157impl 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
172impl 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
3use std::sync::Arc;
4
5use hir_expand::{name::Name, InFile};
6use ra_prof::profile;
7use ra_syntax::ast;
8
9use 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)]
21pub 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
34impl 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)]
54pub 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
62impl 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)]
81pub struct TraitData {
82 pub name: Name,
83 pub items: Vec<(Name, AssocItemId)>,
84 pub auto: bool,
85}
86
87impl 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)]
127pub 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
134impl 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)]
164pub struct ConstData {
165 /// const _: () = ();
166 pub name: Option<Name>,
167 pub type_ref: TypeRef,
168 pub visibility: RawVisibility,
169}
170
171impl 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)]
186pub struct StaticData {
187 pub name: Option<Name>,
188 pub type_ref: TypeRef,
189 pub visibility: RawVisibility,
190 pub mutable: bool,
191}
192
193impl 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
208fn 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.
2use std::sync::Arc;
3
4use hir_expand::{db::AstDatabase, HirFileId};
5use ra_db::{salsa, CrateId, SourceDatabase, Upcast};
6use ra_prof::profile;
7use ra_syntax::SmolStr;
8
9use 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)]
26pub 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)]
48pub 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
118fn 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
3use std::any::Any;
4
5use hir_expand::diagnostics::Diagnostic;
6use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
7
8use hir_expand::{HirFileId, InFile};
9
10#[derive(Debug)]
11pub struct UnresolvedModule {
12 pub file: HirFileId,
13 pub decl: AstPtr<ast::Module>,
14 pub candidate: String,
15}
16
17impl 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
6use std::sync::Arc;
7
8use either::Either;
9use ra_syntax::ast;
10
11use crate::{
12 db::DefDatabase,
13 src::{HasChildSource, HasSource},
14 AdtId, AttrDefId, Lookup,
15};
16
17/// Holds documentation
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Documentation(Arc<str>);
20
21impl Into<String> for Documentation {
22 fn into(self) -> String {
23 self.as_str().to_owned()
24 }
25}
26
27impl 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
80pub(crate) fn docs_from_ast<N>(node: &N) -> Option<Documentation>
81where
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
90fn 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
106fn 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.
24use std::{
25 hash::Hash,
26 marker::PhantomData,
27 ops::{Index, IndexMut},
28};
29
30use anymap::Map;
31use rustc_hash::FxHashMap;
32
33pub struct Key<K, V, P = (K, V)> {
34 _phantom: PhantomData<(K, V, P)>,
35}
36
37impl<K, V, P> Key<K, V, P> {
38 pub(crate) const fn new() -> Key<K, V, P> {
39 Key { _phantom: PhantomData }
40 }
41}
42
43impl<K, V, P> Copy for Key<K, V, P> {}
44
45impl<K, V, P> Clone for Key<K, V, P> {
46 fn clone(&self) -> Key<K, V, P> {
47 *self
48 }
49}
50
51pub 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
59impl<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
70pub struct DynMap {
71 pub(crate) map: Map,
72}
73
74impl Default for DynMap {
75 fn default() -> Self {
76 DynMap { map: Map::new() }
77 }
78}
79
80#[repr(transparent)]
81pub struct KeyMap<KEY> {
82 map: DynMap,
83 _phantom: PhantomData<KEY>,
84}
85
86impl<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
95impl<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
103impl<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
15use hir_expand::name::Name;
16use ra_arena::{Idx, RawId};
17use ra_syntax::ast::RangeOp;
18
19use crate::{
20 builtin_type::{BuiltinFloat, BuiltinInt},
21 path::{GenericArgs, Path},
22 type_ref::{Mutability, Rawness, TypeRef},
23};
24
25pub type ExprId = Idx<Expr>;
26pub(crate) fn dummy_expr_id() -> ExprId {
27 ExprId::from_raw(RawId::from(!0))
28}
29
30pub type PatId = Idx<Pat>;
31
32#[derive(Debug, Clone, Eq, PartialEq)]
33pub 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)]
43pub 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)]
161pub 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)]
169pub enum LogicOp {
170 And,
171 Or,
172}
173
174#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
175pub enum CmpOp {
176 Eq { negated: bool },
177 Ord { ordering: Ordering, strict: bool },
178}
179
180#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
181pub enum Ordering {
182 Less,
183 Greater,
184}
185
186#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
187pub enum ArithOp {
188 Add,
189 Mul,
190 Sub,
191 Div,
192 Rem,
193 Shl,
194 Shr,
195 BitXor,
196 BitOr,
197 BitAnd,
198}
199
200pub use ra_syntax::ast::PrefixOp as UnaryOp;
201#[derive(Debug, Clone, Eq, PartialEq)]
202pub enum Array {
203 ElementList(Vec<ExprId>),
204 Repeat { initializer: ExprId, repeat: ExprId },
205}
206
207#[derive(Debug, Clone, Eq, PartialEq)]
208pub struct MatchArm {
209 pub pat: PatId,
210 pub guard: Option<ExprId>,
211 pub expr: ExprId,
212}
213
214#[derive(Debug, Clone, Eq, PartialEq)]
215pub struct RecordLitField {
216 pub name: Name,
217 pub expr: ExprId,
218}
219
220#[derive(Debug, Clone, Eq, PartialEq)]
221pub enum Statement {
222 Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> },
223 Expr(ExprId),
224}
225
226impl 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)]
348pub 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
366impl 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)]
378pub 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)]
385pub 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
400impl 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
3use hir_expand::name::{known, AsName, Name};
4use ra_prof::profile;
5use rustc_hash::FxHashSet;
6use test_utils::mark;
7
8use 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.
20pub 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
25const MAX_PATH_LEN: usize = 15;
26
27impl 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
40fn 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 {
155 // Item was defined in some upstream crate. This means that it must be exported from one,
156 // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
157 // that wants to import it here, but we always prefer to use the external path here.
158
159 let crate_graph = db.crate_graph();
160 let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| {
161 let import_map = db.import_map(dep.crate_id);
162 import_map.import_info_for(item).and_then(|info| {
163 // Determine best path for containing module and append last segment from `info`.
164 let mut path = find_path_inner(
165 db,
166 ItemInNs::Types(ModuleDefId::ModuleId(info.container)),
167 from,
168 best_path_len - 1,
169 )?;
170 path.segments.push(info.path.segments.last().unwrap().clone());
171 Some(path)
172 })
173 });
174
175 for path in extern_paths {
176 let new_path = if let Some(best_path) = best_path {
177 select_best_path(best_path, path, prefer_no_std)
178 } else {
179 path
180 };
181 best_path = Some(new_path);
182 }
183 }
184
185 best_path
186}
187
188fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath {
189 if old_path.starts_with_std() && new_path.can_start_with_std() {
190 if prefer_no_std {
191 mark::hit!(prefer_no_std_paths);
192 new_path
193 } else {
194 mark::hit!(prefer_std_paths);
195 old_path
196 }
197 } else if new_path.starts_with_std() && old_path.can_start_with_std() {
198 if prefer_no_std {
199 mark::hit!(prefer_no_std_paths);
200 old_path
201 } else {
202 mark::hit!(prefer_std_paths);
203 new_path
204 }
205 } else if new_path.len() < old_path.len() {
206 new_path
207 } else {
208 old_path
209 }
210}
211
212/// Finds locations in `from.krate` from which `item` can be imported by `from`.
213fn find_local_import_locations(
214 db: &dyn DefDatabase,
215 item: ItemInNs,
216 from: ModuleId,
217) -> Vec<(ModuleId, Name)> {
218 let _p = profile("find_local_import_locations");
219
220 // `from` can import anything below `from` with visibility of at least `from`, and anything
221 // above `from` with any visibility. That means we do not need to descend into private siblings
222 // of `from` (and similar).
223
224 let def_map = db.crate_def_map(from.krate);
225
226 // Compute the initial worklist. We start with all direct child modules of `from` as well as all
227 // of its (recursive) parent modules.
228 let data = &def_map.modules[from.local_id];
229 let mut worklist = data
230 .children
231 .values()
232 .map(|child| ModuleId { krate: from.krate, local_id: *child })
233 .collect::<Vec<_>>();
234 let mut parent = data.parent;
235 while let Some(p) = parent {
236 worklist.push(ModuleId { krate: from.krate, local_id: p });
237 parent = def_map.modules[p].parent;
238 }
239
240 let mut seen: FxHashSet<_> = FxHashSet::default();
241
242 let mut locations = Vec::new();
243 while let Some(module) = worklist.pop() {
244 if !seen.insert(module) {
245 continue; // already processed this module
246 }
247
248 let ext_def_map;
249 let data = if module.krate == from.krate {
250 &def_map[module.local_id]
251 } else {
252 // The crate might reexport a module defined in another crate.
253 ext_def_map = db.crate_def_map(module.krate);
254 &ext_def_map[module.local_id]
255 };
256
257 if let Some((name, vis)) = data.scope.name_of(item) {
258 if vis.is_visible_from(db, from) {
259 let is_private = if let Visibility::Module(private_to) = vis {
260 private_to.local_id == module.local_id
261 } else {
262 false
263 };
264 let is_original_def = if let Some(module_def_id) = item.as_module_def_id() {
265 data.scope.declarations().any(|it| it == module_def_id)
266 } else {
267 false
268 };
269
270 // Ignore private imports. these could be used if we are
271 // in a submodule of this module, but that's usually not
272 // what the user wants; and if this module can import
273 // the item and we're a submodule of it, so can we.
274 // Also this keeps the cached data smaller.
275 if !is_private || is_original_def {
276 locations.push((module, name.clone()));
277 }
278 }
279 }
280
281 // Descend into all modules visible from `from`.
282 for (_, per_ns) in data.scope.entries() {
283 if let Some((ModuleDefId::ModuleId(module), vis)) = per_ns.take_types_vis() {
284 if vis.is_visible_from(db, from) {
285 worklist.push(module);
286 }
287 }
288 }
289 }
290
291 locations
292}
293
294#[cfg(test)]
295mod tests {
296 use hir_expand::hygiene::Hygiene;
297 use ra_db::fixture::WithFixture;
298 use ra_syntax::ast::AstNode;
299 use test_utils::mark;
300
301 use crate::test_db::TestDB;
302
303 use super::*;
304
305 /// `code` needs to contain a cursor marker; checks that `find_path` for the
306 /// item the `path` refers to returns that same path when called from the
307 /// module the cursor is in.
308 fn check_found_path(ra_fixture: &str, path: &str) {
309 let (db, pos) = TestDB::with_position(ra_fixture);
310 let module = db.module_for_file(pos.file_id);
311 let parsed_path_file = ra_syntax::SourceFile::parse(&format!("use {};", path));
312 let ast_path = parsed_path_file
313 .syntax_node()
314 .descendants()
315 .find_map(ra_syntax::ast::Path::cast)
316 .unwrap();
317 let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap();
318
319 let crate_def_map = db.crate_def_map(module.krate);
320 let resolved = crate_def_map
321 .resolve_path(
322 &db,
323 module.local_id,
324 &mod_path,
325 crate::item_scope::BuiltinShadowMode::Module,
326 )
327 .0
328 .take_types()
329 .unwrap();
330
331 let found_path = find_path(&db, ItemInNs::Types(resolved), module);
332
333 assert_eq!(found_path, Some(mod_path));
334 }
335
336 #[test]
337 fn same_module() {
338 let code = r#"
339 //- /main.rs
340 struct S;
341 <|>
342 "#;
343 check_found_path(code, "S");
344 }
345
346 #[test]
347 fn enum_variant() {
348 let code = r#"
349 //- /main.rs
350 enum E { A }
351 <|>
352 "#;
353 check_found_path(code, "E::A");
354 }
355
356 #[test]
357 fn sub_module() {
358 let code = r#"
359 //- /main.rs
360 mod foo {
361 pub struct S;
362 }
363 <|>
364 "#;
365 check_found_path(code, "foo::S");
366 }
367
368 #[test]
369 fn super_module() {
370 let code = r#"
371 //- /main.rs
372 mod foo;
373 //- /foo.rs
374 mod bar;
375 struct S;
376 //- /foo/bar.rs
377 <|>
378 "#;
379 check_found_path(code, "super::S");
380 }
381
382 #[test]
383 fn self_module() {
384 let code = r#"
385 //- /main.rs
386 mod foo;
387 //- /foo.rs
388 <|>
389 "#;
390 check_found_path(code, "self");
391 }
392
393 #[test]
394 fn crate_root() {
395 let code = r#"
396 //- /main.rs
397 mod foo;
398 //- /foo.rs
399 <|>
400 "#;
401 check_found_path(code, "crate");
402 }
403
404 #[test]
405 fn same_crate() {
406 let code = r#"
407 //- /main.rs
408 mod foo;
409 struct S;
410 //- /foo.rs
411 <|>
412 "#;
413 check_found_path(code, "crate::S");
414 }
415
416 #[test]
417 fn different_crate() {
418 let code = r#"
419 //- /main.rs crate:main deps:std
420 <|>
421 //- /std.rs crate:std
422 pub struct S;
423 "#;
424 check_found_path(code, "std::S");
425 }
426
427 #[test]
428 fn different_crate_renamed() {
429 let code = r#"
430 //- /main.rs crate:main deps:std
431 extern crate std as std_renamed;
432 <|>
433 //- /std.rs crate:std
434 pub struct S;
435 "#;
436 check_found_path(code, "std_renamed::S");
437 }
438
439 #[test]
440 fn partially_imported() {
441 // Tests that short paths are used even for external items, when parts of the path are
442 // already in scope.
443 check_found_path(
444 r#"
445 //- /main.rs crate:main deps:ra_syntax
446
447 use ra_syntax::ast;
448 <|>
449
450 //- /lib.rs crate:ra_syntax
451 pub mod ast {
452 pub enum ModuleItem {
453 A, B, C,
454 }
455 }
456 "#,
457 "ast::ModuleItem",
458 );
459
460 check_found_path(
461 r#"
462 //- /main.rs crate:main deps:ra_syntax
463
464 <|>
465
466 //- /lib.rs crate:ra_syntax
467 pub mod ast {
468 pub enum ModuleItem {
469 A, B, C,
470 }
471 }
472 "#,
473 "ra_syntax::ast::ModuleItem",
474 );
475 }
476
477 #[test]
478 fn same_crate_reexport() {
479 let code = r#"
480 //- /main.rs
481 mod bar {
482 mod foo { pub(super) struct S; }
483 pub(crate) use foo::*;
484 }
485 <|>
486 "#;
487 check_found_path(code, "bar::S");
488 }
489
490 #[test]
491 fn same_crate_reexport_rename() {
492 let code = r#"
493 //- /main.rs
494 mod bar {
495 mod foo { pub(super) struct S; }
496 pub(crate) use foo::S as U;
497 }
498 <|>
499 "#;
500 check_found_path(code, "bar::U");
501 }
502
503 #[test]
504 fn different_crate_reexport() {
505 let code = r#"
506 //- /main.rs crate:main deps:std
507 <|>
508 //- /std.rs crate:std deps:core
509 pub use core::S;
510 //- /core.rs crate:core
511 pub struct S;
512 "#;
513 check_found_path(code, "std::S");
514 }
515
516 #[test]
517 fn prelude() {
518 let code = r#"
519 //- /main.rs crate:main deps:std
520 <|>
521 //- /std.rs crate:std
522 pub mod prelude { pub struct S; }
523 #[prelude_import]
524 pub use prelude::*;
525 "#;
526 check_found_path(code, "S");
527 }
528
529 #[test]
530 fn enum_variant_from_prelude() {
531 let code = r#"
532 //- /main.rs crate:main deps:std
533 <|>
534 //- /std.rs crate:std
535 pub mod prelude {
536 pub enum Option<T> { Some(T), None }
537 pub use Option::*;
538 }
539 #[prelude_import]
540 pub use prelude::*;
541 "#;
542 check_found_path(code, "None");
543 check_found_path(code, "Some");
544 }
545
546 #[test]
547 fn shortest_path() {
548 let code = r#"
549 //- /main.rs
550 pub mod foo;
551 pub mod baz;
552 struct S;
553 <|>
554 //- /foo.rs
555 pub mod bar { pub struct S; }
556 //- /baz.rs
557 pub use crate::foo::bar::S;
558 "#;
559 check_found_path(code, "baz::S");
560 }
561
562 #[test]
563 fn discount_private_imports() {
564 let code = r#"
565 //- /main.rs
566 mod foo;
567 pub mod bar { pub struct S; }
568 use bar::S;
569 //- /foo.rs
570 <|>
571 "#;
572 // crate::S would be shorter, but using private imports seems wrong
573 check_found_path(code, "crate::bar::S");
574 }
575
576 #[test]
577 fn import_cycle() {
578 let code = r#"
579 //- /main.rs
580 pub mod foo;
581 pub mod bar;
582 pub mod baz;
583 //- /bar.rs
584 <|>
585 //- /foo.rs
586 pub use super::baz;
587 pub struct S;
588 //- /baz.rs
589 pub use super::foo;
590 "#;
591 check_found_path(code, "crate::foo::S");
592 }
593
594 #[test]
595 fn prefer_std_paths_over_alloc() {
596 mark::check!(prefer_std_paths);
597 let code = r#"
598 //- /main.rs crate:main deps:alloc,std
599 <|>
600
601 //- /std.rs crate:std deps:alloc
602 pub mod sync {
603 pub use alloc::sync::Arc;
604 }
605
606 //- /zzz.rs crate:alloc
607 pub mod sync {
608 pub struct Arc;
609 }
610 "#;
611 check_found_path(code, "std::sync::Arc");
612 }
613
614 #[test]
615 fn prefer_core_paths_over_std() {
616 mark::check!(prefer_no_std_paths);
617 let code = r#"
618 //- /main.rs crate:main deps:core,std
619 #![no_std]
620
621 <|>
622
623 //- /std.rs crate:std deps:core
624
625 pub mod fmt {
626 pub use core::fmt::Error;
627 }
628
629 //- /zzz.rs crate:core
630
631 pub mod fmt {
632 pub struct Error;
633 }
634 "#;
635 check_found_path(code, "core::fmt::Error");
636 }
637
638 #[test]
639 fn prefer_alloc_paths_over_std() {
640 let code = r#"
641 //- /main.rs crate:main deps:alloc,std
642 #![no_std]
643
644 <|>
645
646 //- /std.rs crate:std deps:alloc
647
648 pub mod sync {
649 pub use alloc::sync::Arc;
650 }
651
652 //- /zzz.rs crate:alloc
653
654 pub mod sync {
655 pub struct Arc;
656 }
657 "#;
658 check_found_path(code, "alloc::sync::Arc");
659 }
660
661 #[test]
662 fn prefer_shorter_paths_if_not_alloc() {
663 let code = r#"
664 //- /main.rs crate:main deps:megaalloc,std
665 <|>
666
667 //- /std.rs crate:std deps:megaalloc
668 pub mod sync {
669 pub use megaalloc::sync::Arc;
670 }
671
672 //- /zzz.rs crate:megaalloc
673 pub struct Arc;
674 "#;
675 check_found_path(code, "megaalloc::Arc");
676 }
677
678 #[test]
679 fn builtins_are_in_scope() {
680 let code = r#"
681 //- /main.rs
682 <|>
683
684 pub mod primitive {
685 pub use u8;
686 }
687 "#;
688 check_found_path(code, "u8");
689 check_found_path(code, "u16");
690 }
691}
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
deleted file mode 100644
index 699ba9c92..000000000
--- a/crates/ra_hir_def/src/generics.rs
+++ /dev/null
@@ -1,340 +0,0 @@
1//! Many kinds of items or constructs can have generic parameters: functions,
2//! structs, impls, traits, etc. This module provides a common HIR for these
3//! generic parameters. See also the `Generics` type and the `generics_of` query
4//! in rustc.
5use std::sync::Arc;
6
7use either::Either;
8use hir_expand::{
9 name::{name, AsName, Name},
10 InFile,
11};
12use ra_arena::{map::ArenaMap, Arena};
13use ra_db::FileId;
14use ra_prof::profile;
15use ra_syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner};
16
17use crate::{
18 body::LowerCtx,
19 child_by_source::ChildBySource,
20 db::DefDatabase,
21 dyn_map::DynMap,
22 keys,
23 src::HasChildSource,
24 src::HasSource,
25 type_ref::{TypeBound, TypeRef},
26 AdtId, GenericDefId, LocalTypeParamId, Lookup, TypeParamId,
27};
28
29/// Data about a generic parameter (to a function, struct, impl, ...).
30#[derive(Clone, PartialEq, Eq, Debug)]
31pub struct TypeParamData {
32 pub name: Option<Name>,
33 pub default: Option<TypeRef>,
34 pub provenance: TypeParamProvenance,
35}
36
37#[derive(Copy, Clone, PartialEq, Eq, Debug)]
38pub enum TypeParamProvenance {
39 TypeParamList,
40 TraitSelf,
41 ArgumentImplTrait,
42}
43
44/// Data about the generic parameters of a function, struct, impl, etc.
45#[derive(Clone, PartialEq, Eq, Debug, Default)]
46pub struct GenericParams {
47 pub types: Arena<TypeParamData>,
48 // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>,
49 pub where_predicates: Vec<WherePredicate>,
50}
51
52/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
53/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
54/// It might still result in multiple actual predicates though, because of
55/// associated type bindings like `Iterator<Item = u32>`.
56#[derive(Clone, PartialEq, Eq, Debug)]
57pub struct WherePredicate {
58 pub target: WherePredicateTarget,
59 pub bound: TypeBound,
60}
61
62#[derive(Clone, PartialEq, Eq, Debug)]
63pub enum WherePredicateTarget {
64 TypeRef(TypeRef),
65 /// For desugared where predicates that can directly refer to a type param.
66 TypeParam(LocalTypeParamId),
67}
68
69type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>;
70
71impl GenericParams {
72 pub(crate) fn generic_params_query(
73 db: &dyn DefDatabase,
74 def: GenericDefId,
75 ) -> Arc<GenericParams> {
76 let _p = profile("generic_params_query");
77
78 let generics = match def {
79 GenericDefId::FunctionId(id) => {
80 let id = id.lookup(db).id;
81 let tree = db.item_tree(id.file_id);
82 let item = &tree[id.value];
83 tree[item.generic_params].clone()
84 }
85 GenericDefId::AdtId(AdtId::StructId(id)) => {
86 let id = id.lookup(db).id;
87 let tree = db.item_tree(id.file_id);
88 let item = &tree[id.value];
89 tree[item.generic_params].clone()
90 }
91 GenericDefId::AdtId(AdtId::EnumId(id)) => {
92 let id = id.lookup(db).id;
93 let tree = db.item_tree(id.file_id);
94 let item = &tree[id.value];
95 tree[item.generic_params].clone()
96 }
97 GenericDefId::AdtId(AdtId::UnionId(id)) => {
98 let id = id.lookup(db).id;
99 let tree = db.item_tree(id.file_id);
100 let item = &tree[id.value];
101 tree[item.generic_params].clone()
102 }
103 GenericDefId::TraitId(id) => {
104 let id = id.lookup(db).id;
105 let tree = db.item_tree(id.file_id);
106 let item = &tree[id.value];
107 tree[item.generic_params].clone()
108 }
109 GenericDefId::TypeAliasId(id) => {
110 let id = id.lookup(db).id;
111 let tree = db.item_tree(id.file_id);
112 let item = &tree[id.value];
113 tree[item.generic_params].clone()
114 }
115 GenericDefId::ImplId(id) => {
116 let id = id.lookup(db).id;
117 let tree = db.item_tree(id.file_id);
118 let item = &tree[id.value];
119 tree[item.generic_params].clone()
120 }
121 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(),
122 };
123 Arc::new(generics)
124 }
125
126 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
127 let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() };
128 let mut sm = ArenaMap::default();
129
130 // FIXME: add `: Sized` bound for everything except for `Self` in traits
131 let file_id = match def {
132 GenericDefId::FunctionId(it) => {
133 let src = it.lookup(db).source(db);
134 let lower_ctx = LowerCtx::new(db, src.file_id);
135 generics.fill(&lower_ctx, &mut sm, &src.value);
136 // lower `impl Trait` in arguments
137 let data = db.function_data(it);
138 for param in &data.params {
139 generics.fill_implicit_impl_trait_args(param);
140 }
141 src.file_id
142 }
143 GenericDefId::AdtId(AdtId::StructId(it)) => {
144 let src = it.lookup(db).source(db);
145 let lower_ctx = LowerCtx::new(db, src.file_id);
146 generics.fill(&lower_ctx, &mut sm, &src.value);
147 src.file_id
148 }
149 GenericDefId::AdtId(AdtId::UnionId(it)) => {
150 let src = it.lookup(db).source(db);
151 let lower_ctx = LowerCtx::new(db, src.file_id);
152 generics.fill(&lower_ctx, &mut sm, &src.value);
153 src.file_id
154 }
155 GenericDefId::AdtId(AdtId::EnumId(it)) => {
156 let src = it.lookup(db).source(db);
157 let lower_ctx = LowerCtx::new(db, src.file_id);
158 generics.fill(&lower_ctx, &mut sm, &src.value);
159 src.file_id
160 }
161 GenericDefId::TraitId(it) => {
162 let src = it.lookup(db).source(db);
163 let lower_ctx = LowerCtx::new(db, src.file_id);
164
165 // traits get the Self type as an implicit first type parameter
166 let self_param_id = generics.types.alloc(TypeParamData {
167 name: Some(name![Self]),
168 default: None,
169 provenance: TypeParamProvenance::TraitSelf,
170 });
171 sm.insert(self_param_id, Either::Left(src.value.clone()));
172 // add super traits as bounds on Self
173 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
174 let self_param = TypeRef::Path(name![Self].into());
175 generics.fill_bounds(&lower_ctx, &src.value, self_param);
176
177 generics.fill(&lower_ctx, &mut sm, &src.value);
178 src.file_id
179 }
180 GenericDefId::TypeAliasId(it) => {
181 let src = it.lookup(db).source(db);
182 let lower_ctx = LowerCtx::new(db, src.file_id);
183
184 generics.fill(&lower_ctx, &mut sm, &src.value);
185 src.file_id
186 }
187 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
188 // type-parameter, but rather is a type-alias for impl's target
189 // type, so this is handled by the resolver.
190 GenericDefId::ImplId(it) => {
191 let src = it.lookup(db).source(db);
192 let lower_ctx = LowerCtx::new(db, src.file_id);
193
194 generics.fill(&lower_ctx, &mut sm, &src.value);
195 src.file_id
196 }
197 // We won't be using this ID anyway
198 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(),
199 };
200
201 (generics, InFile::new(file_id, sm))
202 }
203
204 pub(crate) fn fill(
205 &mut self,
206 lower_ctx: &LowerCtx,
207 sm: &mut SourceMap,
208 node: &dyn GenericParamsOwner,
209 ) {
210 if let Some(params) = node.generic_param_list() {
211 self.fill_params(lower_ctx, sm, params)
212 }
213 if let Some(where_clause) = node.where_clause() {
214 self.fill_where_predicates(lower_ctx, where_clause);
215 }
216 }
217
218 pub(crate) fn fill_bounds(
219 &mut self,
220 lower_ctx: &LowerCtx,
221 node: &dyn ast::TypeBoundsOwner,
222 type_ref: TypeRef,
223 ) {
224 for bound in
225 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
226 {
227 self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone());
228 }
229 }
230
231 fn fill_params(
232 &mut self,
233 lower_ctx: &LowerCtx,
234 sm: &mut SourceMap,
235 params: ast::GenericParamList,
236 ) {
237 for type_param in params.type_params() {
238 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
239 // FIXME: Use `Path::from_src`
240 let default = type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it));
241 let param = TypeParamData {
242 name: Some(name.clone()),
243 default,
244 provenance: TypeParamProvenance::TypeParamList,
245 };
246 let param_id = self.types.alloc(param);
247 sm.insert(param_id, Either::Right(type_param.clone()));
248
249 let type_ref = TypeRef::Path(name.into());
250 self.fill_bounds(&lower_ctx, &type_param, type_ref);
251 }
252 }
253
254 fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) {
255 for pred in where_clause.predicates() {
256 let type_ref = match pred.ty() {
257 Some(type_ref) => type_ref,
258 None => continue,
259 };
260 let type_ref = TypeRef::from_ast(lower_ctx, type_ref);
261 for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
262 self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone());
263 }
264 }
265 }
266
267 fn add_where_predicate_from_bound(
268 &mut self,
269 lower_ctx: &LowerCtx,
270 bound: ast::TypeBound,
271 type_ref: TypeRef,
272 ) {
273 if bound.question_mark_token().is_some() {
274 // FIXME: remove this bound
275 return;
276 }
277 let bound = TypeBound::from_ast(lower_ctx, bound);
278 self.where_predicates
279 .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound });
280 }
281
282 pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) {
283 type_ref.walk(&mut |type_ref| {
284 if let TypeRef::ImplTrait(bounds) = type_ref {
285 let param = TypeParamData {
286 name: None,
287 default: None,
288 provenance: TypeParamProvenance::ArgumentImplTrait,
289 };
290 let param_id = self.types.alloc(param);
291 for bound in bounds {
292 self.where_predicates.push(WherePredicate {
293 target: WherePredicateTarget::TypeParam(param_id),
294 bound: bound.clone(),
295 });
296 }
297 }
298 });
299 }
300
301 pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
302 self.types
303 .iter()
304 .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None })
305 }
306
307 pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> {
308 self.types.iter().find_map(|(id, p)| {
309 if p.provenance == TypeParamProvenance::TraitSelf {
310 Some(id)
311 } else {
312 None
313 }
314 })
315 }
316}
317
318impl HasChildSource for GenericDefId {
319 type ChildId = LocalTypeParamId;
320 type Value = Either<ast::Trait, ast::TypeParam>;
321 fn child_source(&self, db: &dyn DefDatabase) -> InFile<SourceMap> {
322 let (_, sm) = GenericParams::new(db, *self);
323 sm
324 }
325}
326
327impl ChildBySource for GenericDefId {
328 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
329 let mut res = DynMap::default();
330 let arena_map = self.child_source(db);
331 let arena_map = arena_map.as_ref();
332 for (local_id, src) in arena_map.value.iter() {
333 let id = TypeParamId { parent: *self, local_id };
334 if let Either::Right(type_param) = src {
335 res[keys::TYPE_PARAM].insert(arena_map.with_value(type_param.clone()), id)
336 }
337 }
338 res
339 }
340}
diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs
deleted file mode 100644
index 9e4c30b1a..000000000
--- a/crates/ra_hir_def/src/import_map.rs
+++ /dev/null
@@ -1,745 +0,0 @@
1//! A map of all publicly exported items in a crate.
2
3use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc};
4
5use fst::{self, Streamer};
6use indexmap::{map::Entry, IndexMap};
7use ra_db::CrateId;
8use ra_syntax::SmolStr;
9use rustc_hash::{FxHashMap, FxHasher};
10use smallvec::SmallVec;
11
12use crate::{
13 db::DefDatabase,
14 item_scope::ItemInNs,
15 path::{ModPath, PathKind},
16 visibility::Visibility,
17 AssocItemId, ModuleDefId, ModuleId, TraitId,
18};
19
20type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>;
21
22/// Item import details stored in the `ImportMap`.
23#[derive(Debug, Clone, Eq, PartialEq)]
24pub struct ImportInfo {
25 /// A path that can be used to import the item, relative to the crate's root.
26 pub path: ModPath,
27 /// The module containing this item.
28 pub container: ModuleId,
29}
30
31/// A map from publicly exported items to the path needed to import/name them from a downstream
32/// crate.
33///
34/// Reexports of items are taken into account, ie. if something is exported under multiple
35/// names, the one with the shortest import path will be used.
36///
37/// Note that all paths are relative to the containing crate's root, so the crate name still needs
38/// to be prepended to the `ModPath` before the path is valid.
39#[derive(Default)]
40pub struct ImportMap {
41 map: FxIndexMap<ItemInNs, ImportInfo>,
42
43 /// List of keys stored in `map`, sorted lexicographically by their `ModPath`. Indexed by the
44 /// values returned by running `fst`.
45 ///
46 /// Since a path can refer to multiple items due to namespacing, we store all items with the
47 /// same path right after each other. This allows us to find all items after the FST gives us
48 /// the index of the first one.
49 importables: Vec<ItemInNs>,
50 fst: fst::Map<Vec<u8>>,
51
52 /// Maps names of associated items to the item's ID. Only includes items whose defining trait is
53 /// exported.
54 assoc_map: FxHashMap<SmolStr, SmallVec<[AssocItemId; 1]>>,
55}
56
57impl ImportMap {
58 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
59 let _p = ra_prof::profile("import_map_query");
60 let def_map = db.crate_def_map(krate);
61 let mut import_map = Self::default();
62
63 // We look only into modules that are public(ly reexported), starting with the crate root.
64 let empty = ModPath { kind: PathKind::Plain, segments: vec![] };
65 let root = ModuleId { krate, local_id: def_map.root };
66 let mut worklist = vec![(root, empty)];
67 while let Some((module, mod_path)) = worklist.pop() {
68 let ext_def_map;
69 let mod_data = if module.krate == krate {
70 &def_map[module.local_id]
71 } else {
72 // The crate might reexport a module defined in another crate.
73 ext_def_map = db.crate_def_map(module.krate);
74 &ext_def_map[module.local_id]
75 };
76
77 let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| {
78 let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public);
79 if per_ns.is_none() {
80 None
81 } else {
82 Some((name, per_ns))
83 }
84 });
85
86 for (name, per_ns) in visible_items {
87 let mk_path = || {
88 let mut path = mod_path.clone();
89 path.segments.push(name.clone());
90 path
91 };
92
93 for item in per_ns.iter_items() {
94 let path = mk_path();
95 match import_map.map.entry(item) {
96 Entry::Vacant(entry) => {
97 entry.insert(ImportInfo { path, container: module });
98 }
99 Entry::Occupied(mut entry) => {
100 // If the new path is shorter, prefer that one.
101 if path.len() < entry.get().path.len() {
102 *entry.get_mut() = ImportInfo { path, container: module };
103 } else {
104 continue;
105 }
106 }
107 }
108
109 // If we've just added a path to a module, descend into it. We might traverse
110 // modules multiple times, but only if the new path to it is shorter than the
111 // first (else we `continue` above).
112 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
113 worklist.push((mod_id, mk_path()));
114 }
115
116 // If we've added a path to a trait, add the trait's methods to the method map.
117 if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
118 import_map.collect_trait_methods(db, tr);
119 }
120 }
121 }
122 }
123
124 let mut importables = import_map.map.iter().collect::<Vec<_>>();
125
126 importables.sort_by(cmp);
127
128 // Build the FST, taking care not to insert duplicate values.
129
130 let mut builder = fst::MapBuilder::memory();
131 let mut last_batch_start = 0;
132
133 for idx in 0..importables.len() {
134 if let Some(next_item) = importables.get(idx + 1) {
135 if cmp(&importables[last_batch_start], next_item) == Ordering::Equal {
136 continue;
137 }
138 }
139
140 let start = last_batch_start;
141 last_batch_start = idx + 1;
142
143 let key = fst_path(&importables[start].1.path);
144
145 builder.insert(key, start as u64).unwrap();
146 }
147
148 import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap();
149 import_map.importables = importables.iter().map(|(item, _)| **item).collect();
150
151 Arc::new(import_map)
152 }
153
154 /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root.
155 pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> {
156 Some(&self.map.get(&item)?.path)
157 }
158
159 pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> {
160 self.map.get(&item)
161 }
162
163 fn collect_trait_methods(&mut self, db: &dyn DefDatabase, tr: TraitId) {
164 let data = db.trait_data(tr);
165 for (name, item) in data.items.iter() {
166 self.assoc_map.entry(name.to_string().into()).or_default().push(*item);
167 }
168 }
169}
170
171impl PartialEq for ImportMap {
172 fn eq(&self, other: &Self) -> bool {
173 // `fst` and `importables` are built from `map`, so we don't need to compare them.
174 self.map == other.map
175 }
176}
177
178impl Eq for ImportMap {}
179
180impl fmt::Debug for ImportMap {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 let mut importable_paths: Vec<_> = self
183 .map
184 .iter()
185 .map(|(item, info)| {
186 let ns = match item {
187 ItemInNs::Types(_) => "t",
188 ItemInNs::Values(_) => "v",
189 ItemInNs::Macros(_) => "m",
190 };
191 format!("- {} ({})", info.path, ns)
192 })
193 .collect();
194
195 importable_paths.sort();
196 f.write_str(&importable_paths.join("\n"))
197 }
198}
199
200fn fst_path(path: &ModPath) -> String {
201 let mut s = path.to_string();
202 s.make_ascii_lowercase();
203 s
204}
205
206fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering {
207 let lhs_str = fst_path(&lhs.path);
208 let rhs_str = fst_path(&rhs.path);
209 lhs_str.cmp(&rhs_str)
210}
211
212#[derive(Debug)]
213pub struct Query {
214 query: String,
215 lowercased: String,
216 anchor_end: bool,
217 case_sensitive: bool,
218 limit: usize,
219}
220
221impl Query {
222 pub fn new(query: &str) -> Self {
223 Self {
224 lowercased: query.to_lowercase(),
225 query: query.to_string(),
226 anchor_end: false,
227 case_sensitive: false,
228 limit: usize::max_value(),
229 }
230 }
231
232 /// Only returns items whose paths end with the (case-insensitive) query string as their last
233 /// segment.
234 pub fn anchor_end(self) -> Self {
235 Self { anchor_end: true, ..self }
236 }
237
238 /// Limits the returned number of items to `limit`.
239 pub fn limit(self, limit: usize) -> Self {
240 Self { limit, ..self }
241 }
242
243 /// Respect casing of the query string when matching.
244 pub fn case_sensitive(self) -> Self {
245 Self { case_sensitive: true, ..self }
246 }
247}
248
249/// Searches dependencies of `krate` for an importable path matching `query`.
250///
251/// This returns a list of items that could be imported from dependencies of `krate`.
252pub fn search_dependencies<'a>(
253 db: &'a dyn DefDatabase,
254 krate: CrateId,
255 query: Query,
256) -> Vec<ItemInNs> {
257 let _p = ra_prof::profile("search_dependencies").detail(|| format!("{:?}", query));
258
259 let graph = db.crate_graph();
260 let import_maps: Vec<_> =
261 graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect();
262
263 let automaton = fst::automaton::Subsequence::new(&query.lowercased);
264
265 let mut op = fst::map::OpBuilder::new();
266 for map in &import_maps {
267 op = op.add(map.fst.search(&automaton));
268 }
269
270 let mut stream = op.union();
271 let mut res = Vec::new();
272 while let Some((_, indexed_values)) = stream.next() {
273 for indexed_value in indexed_values {
274 let import_map = &import_maps[indexed_value.index];
275 let importables = &import_map.importables[indexed_value.value as usize..];
276
277 // Path shared by the importable items in this group.
278 let path = &import_map.map[&importables[0]].path;
279
280 if query.anchor_end {
281 // Last segment must match query.
282 let last = path.segments.last().unwrap().to_string();
283 if last.to_lowercase() != query.lowercased {
284 continue;
285 }
286 }
287
288 // Add the items from this `ModPath` group. Those are all subsequent items in
289 // `importables` whose paths match `path`.
290 let iter = importables.iter().copied().take_while(|item| {
291 let item_path = &import_map.map[item].path;
292 fst_path(item_path) == fst_path(path)
293 });
294
295 if query.case_sensitive {
296 // FIXME: This does not do a subsequence match.
297 res.extend(iter.filter(|item| {
298 let item_path = &import_map.map[item].path;
299 item_path.to_string().contains(&query.query)
300 }));
301 } else {
302 res.extend(iter);
303 }
304
305 if res.len() >= query.limit {
306 res.truncate(query.limit);
307 return res;
308 }
309 }
310 }
311
312 // Add all exported associated items whose names match the query (exactly).
313 for map in &import_maps {
314 if let Some(v) = map.assoc_map.get(&*query.query) {
315 res.extend(v.iter().map(|&assoc| {
316 ItemInNs::Types(match assoc {
317 AssocItemId::FunctionId(it) => it.into(),
318 AssocItemId::ConstId(it) => it.into(),
319 AssocItemId::TypeAliasId(it) => it.into(),
320 })
321 }));
322 }
323 }
324
325 res
326}
327
328#[cfg(test)]
329mod tests {
330 use expect::{expect, Expect};
331 use ra_db::{fixture::WithFixture, SourceDatabase, Upcast};
332
333 use crate::{test_db::TestDB, AssocContainerId, Lookup};
334
335 use super::*;
336
337 fn check_search(ra_fixture: &str, krate_name: &str, query: Query, expect: Expect) {
338 let db = TestDB::with_files(ra_fixture);
339 let crate_graph = db.crate_graph();
340 let krate = crate_graph
341 .iter()
342 .find(|krate| {
343 crate_graph[*krate].display_name.as_ref().map(|n| n.to_string())
344 == Some(krate_name.to_string())
345 })
346 .unwrap();
347
348 let actual = search_dependencies(db.upcast(), krate, query)
349 .into_iter()
350 .filter_map(|item| {
351 let mark = match item {
352 ItemInNs::Types(_) => "t",
353 ItemInNs::Values(_) => "v",
354 ItemInNs::Macros(_) => "m",
355 };
356 let item = assoc_to_trait(&db, item);
357 item.krate(db.upcast()).map(|krate| {
358 let map = db.import_map(krate);
359 let path = map.path_of(item).unwrap();
360 format!(
361 "{}::{} ({})\n",
362 crate_graph[krate].display_name.as_ref().unwrap(),
363 path,
364 mark
365 )
366 })
367 })
368 .collect::<String>();
369 expect.assert_eq(&actual)
370 }
371
372 fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> ItemInNs {
373 let assoc: AssocItemId = match item {
374 ItemInNs::Types(it) | ItemInNs::Values(it) => match it {
375 ModuleDefId::TypeAliasId(it) => it.into(),
376 ModuleDefId::FunctionId(it) => it.into(),
377 ModuleDefId::ConstId(it) => it.into(),
378 _ => return item,
379 },
380 _ => return item,
381 };
382
383 let container = match assoc {
384 AssocItemId::FunctionId(it) => it.lookup(db).container,
385 AssocItemId::ConstId(it) => it.lookup(db).container,
386 AssocItemId::TypeAliasId(it) => it.lookup(db).container,
387 };
388
389 match container {
390 AssocContainerId::TraitId(it) => ItemInNs::Types(it.into()),
391 _ => item,
392 }
393 }
394
395 fn check(ra_fixture: &str, expect: Expect) {
396 let db = TestDB::with_files(ra_fixture);
397 let crate_graph = db.crate_graph();
398
399 let actual = crate_graph
400 .iter()
401 .filter_map(|krate| {
402 let cdata = &crate_graph[krate];
403 let name = cdata.display_name.as_ref()?;
404
405 let map = db.import_map(krate);
406
407 Some(format!("{}:\n{:?}\n", name, map))
408 })
409 .collect::<String>();
410
411 expect.assert_eq(&actual)
412 }
413
414 #[test]
415 fn smoke() {
416 check(
417 r"
418 //- /main.rs crate:main deps:lib
419
420 mod private {
421 pub use lib::Pub;
422 pub struct InPrivateModule;
423 }
424
425 pub mod publ1 {
426 use lib::Pub;
427 }
428
429 pub mod real_pub {
430 pub use lib::Pub;
431 }
432 pub mod real_pu2 { // same path length as above
433 pub use lib::Pub;
434 }
435
436 //- /lib.rs crate:lib
437 pub struct Pub {}
438 pub struct Pub2; // t + v
439 struct Priv;
440 ",
441 expect![[r#"
442 main:
443 - publ1 (t)
444 - real_pu2 (t)
445 - real_pub (t)
446 - real_pub::Pub (t)
447 lib:
448 - Pub (t)
449 - Pub2 (t)
450 - Pub2 (v)
451 "#]],
452 );
453 }
454
455 #[test]
456 fn prefers_shortest_path() {
457 check(
458 r"
459 //- /main.rs crate:main
460
461 pub mod sub {
462 pub mod subsub {
463 pub struct Def {}
464 }
465
466 pub use super::sub::subsub::Def;
467 }
468 ",
469 expect![[r#"
470 main:
471 - sub (t)
472 - sub::Def (t)
473 - sub::subsub (t)
474 "#]],
475 );
476 }
477
478 #[test]
479 fn type_reexport_cross_crate() {
480 // Reexports need to be visible from a crate, even if the original crate exports the item
481 // at a shorter path.
482 check(
483 r"
484 //- /main.rs crate:main deps:lib
485 pub mod m {
486 pub use lib::S;
487 }
488 //- /lib.rs crate:lib
489 pub struct S;
490 ",
491 expect![[r#"
492 main:
493 - m (t)
494 - m::S (t)
495 - m::S (v)
496 lib:
497 - S (t)
498 - S (v)
499 "#]],
500 );
501 }
502
503 #[test]
504 fn macro_reexport() {
505 check(
506 r"
507 //- /main.rs crate:main deps:lib
508 pub mod m {
509 pub use lib::pub_macro;
510 }
511 //- /lib.rs crate:lib
512 #[macro_export]
513 macro_rules! pub_macro {
514 () => {};
515 }
516 ",
517 expect![[r#"
518 main:
519 - m (t)
520 - m::pub_macro (m)
521 lib:
522 - pub_macro (m)
523 "#]],
524 );
525 }
526
527 #[test]
528 fn module_reexport() {
529 // Reexporting modules from a dependency adds all contents to the import map.
530 check(
531 r"
532 //- /main.rs crate:main deps:lib
533 pub use lib::module as reexported_module;
534 //- /lib.rs crate:lib
535 pub mod module {
536 pub struct S;
537 }
538 ",
539 expect![[r#"
540 main:
541 - reexported_module (t)
542 - reexported_module::S (t)
543 - reexported_module::S (v)
544 lib:
545 - module (t)
546 - module::S (t)
547 - module::S (v)
548 "#]],
549 );
550 }
551
552 #[test]
553 fn cyclic_module_reexport() {
554 // A cyclic reexport does not hang.
555 check(
556 r"
557 //- /lib.rs crate:lib
558 pub mod module {
559 pub struct S;
560 pub use super::sub::*;
561 }
562
563 pub mod sub {
564 pub use super::module;
565 }
566 ",
567 expect![[r#"
568 lib:
569 - module (t)
570 - module::S (t)
571 - module::S (v)
572 - sub (t)
573 "#]],
574 );
575 }
576
577 #[test]
578 fn private_macro() {
579 check(
580 r"
581 //- /lib.rs crate:lib
582 macro_rules! private_macro {
583 () => {};
584 }
585 ",
586 expect![[r#"
587 lib:
588
589 "#]],
590 );
591 }
592
593 #[test]
594 fn namespacing() {
595 check(
596 r"
597 //- /lib.rs crate:lib
598 pub struct Thing; // t + v
599 #[macro_export]
600 macro_rules! Thing { // m
601 () => {};
602 }
603 ",
604 expect![[r#"
605 lib:
606 - Thing (m)
607 - Thing (t)
608 - Thing (v)
609 "#]],
610 );
611
612 check(
613 r"
614 //- /lib.rs crate:lib
615 pub mod Thing {} // t
616 #[macro_export]
617 macro_rules! Thing { // m
618 () => {};
619 }
620 ",
621 expect![[r#"
622 lib:
623 - Thing (m)
624 - Thing (t)
625 "#]],
626 );
627 }
628
629 #[test]
630 fn search() {
631 let ra_fixture = r#"
632 //- /main.rs crate:main deps:dep
633 //- /dep.rs crate:dep deps:tdep
634 use tdep::fmt as fmt_dep;
635 pub mod fmt {
636 pub trait Display {
637 fn fmt();
638 }
639 }
640 #[macro_export]
641 macro_rules! Fmt {
642 () => {};
643 }
644 pub struct Fmt;
645
646 pub fn format() {}
647 pub fn no() {}
648
649 //- /tdep.rs crate:tdep
650 pub mod fmt {
651 pub struct NotImportableFromMain;
652 }
653 "#;
654
655 check_search(
656 ra_fixture,
657 "main",
658 Query::new("fmt"),
659 expect![[r#"
660 dep::fmt (t)
661 dep::Fmt (t)
662 dep::Fmt (v)
663 dep::Fmt (m)
664 dep::fmt::Display (t)
665 dep::format (v)
666 dep::fmt::Display (t)
667 "#]],
668 );
669
670 check_search(
671 ra_fixture,
672 "main",
673 Query::new("fmt").anchor_end(),
674 expect![[r#"
675 dep::fmt (t)
676 dep::Fmt (t)
677 dep::Fmt (v)
678 dep::Fmt (m)
679 dep::fmt::Display (t)
680 "#]],
681 );
682 }
683
684 #[test]
685 fn search_casing() {
686 let ra_fixture = r#"
687 //- /main.rs crate:main deps:dep
688 //- /dep.rs crate:dep
689
690 pub struct fmt;
691 pub struct FMT;
692 "#;
693
694 check_search(
695 ra_fixture,
696 "main",
697 Query::new("FMT"),
698 expect![[r#"
699 dep::fmt (t)
700 dep::fmt (v)
701 dep::FMT (t)
702 dep::FMT (v)
703 "#]],
704 );
705
706 check_search(
707 ra_fixture,
708 "main",
709 Query::new("FMT").case_sensitive(),
710 expect![[r#"
711 dep::FMT (t)
712 dep::FMT (v)
713 "#]],
714 );
715 }
716
717 #[test]
718 fn search_limit() {
719 check_search(
720 r#"
721 //- /main.rs crate:main deps:dep
722 //- /dep.rs crate:dep
723 pub mod fmt {
724 pub trait Display {
725 fn fmt();
726 }
727 }
728 #[macro_export]
729 macro_rules! Fmt {
730 () => {};
731 }
732 pub struct Fmt;
733
734 pub fn format() {}
735 pub fn no() {}
736 "#,
737 "main",
738 Query::new("").limit(2),
739 expect![[r#"
740 dep::fmt (t)
741 dep::Fmt (t)
742 "#]],
743 );
744 }
745}
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
deleted file mode 100644
index 8fee4b15e..000000000
--- a/crates/ra_hir_def/src/item_scope.rs
+++ /dev/null
@@ -1,341 +0,0 @@
1//! Describes items defined or visible (ie, imported) in a certain scope.
2//! This is shared between modules and blocks.
3
4use std::collections::hash_map::Entry;
5
6use hir_expand::name::Name;
7use once_cell::sync::Lazy;
8use ra_db::CrateId;
9use rustc_hash::{FxHashMap, FxHashSet};
10use test_utils::mark;
11
12use crate::{
13 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId,
14 LocalModuleId, Lookup, MacroDefId, ModuleDefId, TraitId,
15};
16
17#[derive(Copy, Clone)]
18pub(crate) enum ImportType {
19 Glob,
20 Named,
21}
22
23#[derive(Debug, Default)]
24pub struct PerNsGlobImports {
25 types: FxHashSet<(LocalModuleId, Name)>,
26 values: FxHashSet<(LocalModuleId, Name)>,
27 macros: FxHashSet<(LocalModuleId, Name)>,
28}
29
30#[derive(Debug, Default, PartialEq, Eq)]
31pub struct ItemScope {
32 types: FxHashMap<Name, (ModuleDefId, Visibility)>,
33 values: FxHashMap<Name, (ModuleDefId, Visibility)>,
34 macros: FxHashMap<Name, (MacroDefId, Visibility)>,
35 unresolved: FxHashSet<Name>,
36
37 defs: Vec<ModuleDefId>,
38 impls: Vec<ImplId>,
39 /// Traits imported via `use Trait as _;`.
40 unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
41 /// Macros visible in current module in legacy textual scope
42 ///
43 /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
44 /// If it yields no result, then it turns to module scoped `macros`.
45 /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
46 /// and only normal scoped `macros` will be searched in.
47 ///
48 /// Note that this automatically inherit macros defined textually before the definition of module itself.
49 ///
50 /// Module scoped macros will be inserted into `items` instead of here.
51 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
52 // be all resolved to the last one defined if shadowing happens.
53 legacy_macros: FxHashMap<Name, MacroDefId>,
54}
55
56pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
57 BuiltinType::ALL
58 .iter()
59 .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public)))
60 .collect()
61});
62
63/// Shadow mode for builtin type which can be shadowed by module.
64#[derive(Debug, Copy, Clone, PartialEq, Eq)]
65pub(crate) enum BuiltinShadowMode {
66 /// Prefer user-defined modules (or other types) over builtins.
67 Module,
68 /// Prefer builtins over user-defined modules (but not other types).
69 Other,
70}
71
72/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
73/// Other methods will only resolve values, types and module scoped macros only.
74impl ItemScope {
75 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
76 // FIXME: shadowing
77 let keys: FxHashSet<_> = self
78 .types
79 .keys()
80 .chain(self.values.keys())
81 .chain(self.macros.keys())
82 .chain(self.unresolved.iter())
83 .collect();
84
85 keys.into_iter().map(move |name| (name, self.get(name)))
86 }
87
88 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
89 self.defs.iter().copied()
90 }
91
92 pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
93 self.impls.iter().copied()
94 }
95
96 pub fn visibility_of(&self, def: ModuleDefId) -> Option<Visibility> {
97 self.name_of(ItemInNs::Types(def))
98 .or_else(|| self.name_of(ItemInNs::Values(def)))
99 .map(|(_, v)| v)
100 }
101
102 /// Iterate over all module scoped macros
103 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
104 self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
105 }
106
107 /// Iterate over all legacy textual scoped macros visible at the end of the module
108 pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
109 self.legacy_macros.iter().map(|(name, def)| (name, *def))
110 }
111
112 /// Get a name from current module scope, legacy macros are not included
113 pub(crate) fn get(&self, name: &Name) -> PerNs {
114 PerNs {
115 types: self.types.get(name).copied(),
116 values: self.values.get(name).copied(),
117 macros: self.macros.get(name).copied(),
118 }
119 }
120
121 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
122 for (name, per_ns) in self.entries() {
123 if let Some(vis) = item.match_with(per_ns) {
124 return Some((name, vis));
125 }
126 }
127 None
128 }
129
130 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
131 self.types
132 .values()
133 .filter_map(|(def, _)| match def {
134 ModuleDefId::TraitId(t) => Some(*t),
135 _ => None,
136 })
137 .chain(self.unnamed_trait_imports.keys().copied())
138 }
139
140 pub(crate) fn define_def(&mut self, def: ModuleDefId) {
141 self.defs.push(def)
142 }
143
144 pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
145 self.legacy_macros.get(name).copied()
146 }
147
148 pub(crate) fn define_impl(&mut self, imp: ImplId) {
149 self.impls.push(imp)
150 }
151
152 pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
153 self.legacy_macros.insert(name, mac);
154 }
155
156 pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
157 self.unnamed_trait_imports.get(&tr).copied()
158 }
159
160 pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
161 self.unnamed_trait_imports.insert(tr, vis);
162 }
163
164 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
165 let mut changed = false;
166
167 if let Some(types) = def.types {
168 self.types.entry(name.clone()).or_insert_with(|| {
169 changed = true;
170 types
171 });
172 }
173 if let Some(values) = def.values {
174 self.values.entry(name.clone()).or_insert_with(|| {
175 changed = true;
176 values
177 });
178 }
179 if let Some(macros) = def.macros {
180 self.macros.entry(name.clone()).or_insert_with(|| {
181 changed = true;
182 macros
183 });
184 }
185
186 if def.is_none() {
187 if self.unresolved.insert(name) {
188 changed = true;
189 }
190 }
191
192 changed
193 }
194
195 pub(crate) fn push_res_with_import(
196 &mut self,
197 glob_imports: &mut PerNsGlobImports,
198 lookup: (LocalModuleId, Name),
199 def: PerNs,
200 def_import_type: ImportType,
201 ) -> bool {
202 let mut changed = false;
203
204 macro_rules! check_changed {
205 (
206 $changed:ident,
207 ( $this:ident / $def:ident ) . $field:ident,
208 $glob_imports:ident [ $lookup:ident ],
209 $def_import_type:ident
210 ) => {{
211 let existing = $this.$field.entry($lookup.1.clone());
212 match (existing, $def.$field) {
213 (Entry::Vacant(entry), Some(_)) => {
214 match $def_import_type {
215 ImportType::Glob => {
216 $glob_imports.$field.insert($lookup.clone());
217 }
218 ImportType::Named => {
219 $glob_imports.$field.remove(&$lookup);
220 }
221 }
222
223 if let Some(fld) = $def.$field {
224 entry.insert(fld);
225 }
226 $changed = true;
227 }
228 (Entry::Occupied(mut entry), Some(_))
229 if $glob_imports.$field.contains(&$lookup)
230 && matches!($def_import_type, ImportType::Named) =>
231 {
232 mark::hit!(import_shadowed);
233 $glob_imports.$field.remove(&$lookup);
234 if let Some(fld) = $def.$field {
235 entry.insert(fld);
236 }
237 $changed = true;
238 }
239 _ => {}
240 }
241 }};
242 }
243
244 check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
245 check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
246 check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);
247
248 if def.is_none() {
249 if self.unresolved.insert(lookup.1) {
250 changed = true;
251 }
252 }
253
254 changed
255 }
256
257 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Option<Name>, PerNs)> + 'a {
258 self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
259 self.unnamed_trait_imports
260 .iter()
261 .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))),
262 )
263 }
264
265 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
266 self.legacy_macros.clone()
267 }
268}
269
270impl PerNs {
271 pub(crate) fn from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs {
272 match def {
273 ModuleDefId::ModuleId(_) => PerNs::types(def, v),
274 ModuleDefId::FunctionId(_) => PerNs::values(def, v),
275 ModuleDefId::AdtId(adt) => match adt {
276 AdtId::UnionId(_) => PerNs::types(def, v),
277 AdtId::EnumId(_) => PerNs::types(def, v),
278 AdtId::StructId(_) => {
279 if has_constructor {
280 PerNs::both(def, def, v)
281 } else {
282 PerNs::types(def, v)
283 }
284 }
285 },
286 ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v),
287 ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v),
288 ModuleDefId::TraitId(_) => PerNs::types(def, v),
289 ModuleDefId::TypeAliasId(_) => PerNs::types(def, v),
290 ModuleDefId::BuiltinType(_) => PerNs::types(def, v),
291 }
292 }
293}
294
295#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
296pub enum ItemInNs {
297 Types(ModuleDefId),
298 Values(ModuleDefId),
299 Macros(MacroDefId),
300}
301
302impl ItemInNs {
303 fn match_with(self, per_ns: PerNs) -> Option<Visibility> {
304 match self {
305 ItemInNs::Types(def) => {
306 per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
307 }
308 ItemInNs::Values(def) => {
309 per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
310 }
311 ItemInNs::Macros(def) => {
312 per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
313 }
314 }
315 }
316
317 pub fn as_module_def_id(self) -> Option<ModuleDefId> {
318 match self {
319 ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
320 ItemInNs::Macros(_) => None,
321 }
322 }
323
324 /// Returns the crate defining this item (or `None` if `self` is built-in).
325 pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
326 Some(match self {
327 ItemInNs::Types(did) | ItemInNs::Values(did) => match did {
328 ModuleDefId::ModuleId(id) => id.krate,
329 ModuleDefId::FunctionId(id) => id.lookup(db).module(db).krate,
330 ModuleDefId::AdtId(id) => id.module(db).krate,
331 ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db).krate,
332 ModuleDefId::ConstId(id) => id.lookup(db).container.module(db).krate,
333 ModuleDefId::StaticId(id) => id.lookup(db).container.module(db).krate,
334 ModuleDefId::TraitId(id) => id.lookup(db).container.module(db).krate,
335 ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate,
336 ModuleDefId::BuiltinType(_) => return None,
337 },
338 ItemInNs::Macros(id) => return id.krate,
339 })
340 }
341}
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs
deleted file mode 100644
index a67e75dac..000000000
--- a/crates/ra_hir_def/src/item_tree.rs
+++ /dev/null
@@ -1,754 +0,0 @@
1//! A simplified AST that only contains items.
2
3mod lower;
4#[cfg(test)]
5mod tests;
6
7use std::{
8 any::type_name,
9 fmt::{self, Debug},
10 hash::{Hash, Hasher},
11 marker::PhantomData,
12 ops::{Index, Range},
13 sync::Arc,
14};
15
16use ast::{AstNode, AttrsOwner, NameOwner, StructKind};
17use either::Either;
18use hir_expand::{
19 ast_id_map::FileAstId,
20 hygiene::Hygiene,
21 name::{name, AsName, Name},
22 HirFileId, InFile,
23};
24use ra_arena::{Arena, Idx, RawId};
25use ra_syntax::{ast, match_ast};
26use rustc_hash::FxHashMap;
27use smallvec::SmallVec;
28use test_utils::mark;
29
30use crate::{
31 attr::Attrs,
32 db::DefDatabase,
33 generics::GenericParams,
34 path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
35 type_ref::{Mutability, TypeBound, TypeRef},
36 visibility::RawVisibility,
37};
38
39#[derive(Copy, Clone, Eq, PartialEq)]
40pub struct RawVisibilityId(u32);
41
42impl RawVisibilityId {
43 pub const PUB: Self = RawVisibilityId(u32::max_value());
44 pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1);
45 pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2);
46}
47
48impl fmt::Debug for RawVisibilityId {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 let mut f = f.debug_tuple("RawVisibilityId");
51 match *self {
52 Self::PUB => f.field(&"pub"),
53 Self::PRIV => f.field(&"pub(self)"),
54 Self::PUB_CRATE => f.field(&"pub(crate)"),
55 _ => f.field(&self.0),
56 };
57 f.finish()
58 }
59}
60
61#[derive(Debug, Copy, Clone, Eq, PartialEq)]
62pub struct GenericParamsId(u32);
63
64impl GenericParamsId {
65 pub const EMPTY: Self = GenericParamsId(u32::max_value());
66}
67
68/// The item tree of a source file.
69#[derive(Debug, Eq, PartialEq)]
70pub struct ItemTree {
71 top_level: SmallVec<[ModItem; 1]>,
72 attrs: FxHashMap<AttrOwner, Attrs>,
73 inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>,
74
75 data: Option<Box<ItemTreeData>>,
76}
77
78impl ItemTree {
79 pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
80 let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id));
81 let syntax = if let Some(node) = db.parse_or_expand(file_id) {
82 node
83 } else {
84 return Arc::new(Self::empty());
85 };
86
87 let hygiene = Hygiene::new(db.upcast(), file_id);
88 let ctx = lower::Ctx::new(db, hygiene.clone(), file_id);
89 let mut top_attrs = None;
90 let mut item_tree = match_ast! {
91 match syntax {
92 ast::SourceFile(file) => {
93 top_attrs = Some(Attrs::new(&file, &hygiene));
94 ctx.lower_module_items(&file)
95 },
96 ast::MacroItems(items) => {
97 ctx.lower_module_items(&items)
98 },
99 // Macros can expand to expressions. We return an empty item tree in this case, but
100 // still need to collect inner items.
101 ast::Expr(e) => {
102 ctx.lower_inner_items(e.syntax())
103 },
104 _ => {
105 panic!("cannot create item tree from {:?}", syntax);
106 },
107 }
108 };
109
110 if let Some(attrs) = top_attrs {
111 item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
112 }
113 item_tree.shrink_to_fit();
114 Arc::new(item_tree)
115 }
116
117 fn empty() -> Self {
118 Self {
119 top_level: Default::default(),
120 attrs: Default::default(),
121 inner_items: Default::default(),
122 data: Default::default(),
123 }
124 }
125
126 fn shrink_to_fit(&mut self) {
127 if let Some(data) = &mut self.data {
128 let ItemTreeData {
129 imports,
130 extern_crates,
131 functions,
132 structs,
133 fields,
134 unions,
135 enums,
136 variants,
137 consts,
138 statics,
139 traits,
140 impls,
141 type_aliases,
142 mods,
143 macro_calls,
144 exprs,
145 vis,
146 generics,
147 } = &mut **data;
148
149 imports.shrink_to_fit();
150 extern_crates.shrink_to_fit();
151 functions.shrink_to_fit();
152 structs.shrink_to_fit();
153 fields.shrink_to_fit();
154 unions.shrink_to_fit();
155 enums.shrink_to_fit();
156 variants.shrink_to_fit();
157 consts.shrink_to_fit();
158 statics.shrink_to_fit();
159 traits.shrink_to_fit();
160 impls.shrink_to_fit();
161 type_aliases.shrink_to_fit();
162 mods.shrink_to_fit();
163 macro_calls.shrink_to_fit();
164 exprs.shrink_to_fit();
165
166 vis.arena.shrink_to_fit();
167 generics.arena.shrink_to_fit();
168 }
169 }
170
171 /// Returns an iterator over all items located at the top level of the `HirFileId` this
172 /// `ItemTree` was created from.
173 pub fn top_level_items(&self) -> &[ModItem] {
174 &self.top_level
175 }
176
177 /// Returns the inner attributes of the source file.
178 pub fn top_level_attrs(&self) -> &Attrs {
179 self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY)
180 }
181
182 pub fn attrs(&self, of: AttrOwner) -> &Attrs {
183 self.attrs.get(&of).unwrap_or(&Attrs::EMPTY)
184 }
185
186 /// Returns the lowered inner items that `ast` corresponds to.
187 ///
188 /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered
189 /// to multiple items in the `ItemTree`.
190 pub fn inner_items(&self, ast: FileAstId<ast::Item>) -> &[ModItem] {
191 &self.inner_items[&ast]
192 }
193
194 pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ {
195 self.inner_items.values().flatten().copied()
196 }
197
198 pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source {
199 // This unwrap cannot fail, since it has either succeeded above, or resulted in an empty
200 // ItemTree (in which case there is no valid `FileItemTreeId` to call this method with).
201 let root =
202 db.parse_or_expand(of.file_id).expect("parse_or_expand failed on constructed ItemTree");
203
204 let id = self[of.value].ast_id();
205 let map = db.ast_id_map(of.file_id);
206 let ptr = map.get(id);
207 ptr.to_node(&root)
208 }
209
210 fn data(&self) -> &ItemTreeData {
211 self.data.as_ref().expect("attempted to access data of empty ItemTree")
212 }
213
214 fn data_mut(&mut self) -> &mut ItemTreeData {
215 self.data.get_or_insert_with(Box::default)
216 }
217}
218
219#[derive(Default, Debug, Eq, PartialEq)]
220struct ItemVisibilities {
221 arena: Arena<RawVisibility>,
222}
223
224impl ItemVisibilities {
225 fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
226 match &vis {
227 RawVisibility::Public => RawVisibilityId::PUB,
228 RawVisibility::Module(path) if path.segments.is_empty() => match &path.kind {
229 PathKind::Super(0) => RawVisibilityId::PRIV,
230 PathKind::Crate => RawVisibilityId::PUB_CRATE,
231 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
232 },
233 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
234 }
235 }
236}
237
238static VIS_PUB: RawVisibility = RawVisibility::Public;
239static VIS_PRIV: RawVisibility =
240 RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() });
241static VIS_PUB_CRATE: RawVisibility =
242 RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() });
243
244#[derive(Default, Debug, Eq, PartialEq)]
245struct GenericParamsStorage {
246 arena: Arena<GenericParams>,
247}
248
249impl GenericParamsStorage {
250 fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
251 if params.types.is_empty() && params.where_predicates.is_empty() {
252 return GenericParamsId::EMPTY;
253 }
254
255 GenericParamsId(self.arena.alloc(params).into_raw().into())
256 }
257}
258
259static EMPTY_GENERICS: GenericParams =
260 GenericParams { types: Arena::new(), where_predicates: Vec::new() };
261
262#[derive(Default, Debug, Eq, PartialEq)]
263struct ItemTreeData {
264 imports: Arena<Import>,
265 extern_crates: Arena<ExternCrate>,
266 functions: Arena<Function>,
267 structs: Arena<Struct>,
268 fields: Arena<Field>,
269 unions: Arena<Union>,
270 enums: Arena<Enum>,
271 variants: Arena<Variant>,
272 consts: Arena<Const>,
273 statics: Arena<Static>,
274 traits: Arena<Trait>,
275 impls: Arena<Impl>,
276 type_aliases: Arena<TypeAlias>,
277 mods: Arena<Mod>,
278 macro_calls: Arena<MacroCall>,
279 exprs: Arena<Expr>,
280
281 vis: ItemVisibilities,
282 generics: GenericParamsStorage,
283}
284
285#[derive(Debug, Eq, PartialEq, Hash)]
286pub enum AttrOwner {
287 /// Attributes on an item.
288 ModItem(ModItem),
289 /// Inner attributes of the source file.
290 TopLevel,
291
292 Variant(Idx<Variant>),
293 Field(Idx<Field>),
294 // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`.
295}
296
297macro_rules! from_attrs {
298 ( $( $var:ident($t:ty) ),+ ) => {
299 $(
300 impl From<$t> for AttrOwner {
301 fn from(t: $t) -> AttrOwner {
302 AttrOwner::$var(t)
303 }
304 }
305 )+
306 };
307}
308
309from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>));
310
311/// Trait implemented by all item nodes in the item tree.
312pub trait ItemTreeNode: Clone {
313 type Source: AstNode + Into<ast::Item>;
314
315 fn ast_id(&self) -> FileAstId<Self::Source>;
316
317 /// Looks up an instance of `Self` in an item tree.
318 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self;
319
320 /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type.
321 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>;
322
323 /// Upcasts a `FileItemTreeId` to a generic `ModItem`.
324 fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem;
325}
326
327pub struct FileItemTreeId<N: ItemTreeNode> {
328 index: Idx<N>,
329 _p: PhantomData<N>,
330}
331
332impl<N: ItemTreeNode> Clone for FileItemTreeId<N> {
333 fn clone(&self) -> Self {
334 Self { index: self.index, _p: PhantomData }
335 }
336}
337impl<N: ItemTreeNode> Copy for FileItemTreeId<N> {}
338
339impl<N: ItemTreeNode> PartialEq for FileItemTreeId<N> {
340 fn eq(&self, other: &FileItemTreeId<N>) -> bool {
341 self.index == other.index
342 }
343}
344impl<N: ItemTreeNode> Eq for FileItemTreeId<N> {}
345
346impl<N: ItemTreeNode> Hash for FileItemTreeId<N> {
347 fn hash<H: Hasher>(&self, state: &mut H) {
348 self.index.hash(state)
349 }
350}
351
352impl<N: ItemTreeNode> fmt::Debug for FileItemTreeId<N> {
353 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354 self.index.fmt(f)
355 }
356}
357
358pub type ItemTreeId<N> = InFile<FileItemTreeId<N>>;
359
360macro_rules! mod_items {
361 ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => {
362 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
363 pub enum ModItem {
364 $(
365 $typ(FileItemTreeId<$typ>),
366 )+
367 }
368
369 $(
370 impl From<FileItemTreeId<$typ>> for ModItem {
371 fn from(id: FileItemTreeId<$typ>) -> ModItem {
372 ModItem::$typ(id)
373 }
374 }
375 )+
376
377 $(
378 impl ItemTreeNode for $typ {
379 type Source = $ast;
380
381 fn ast_id(&self) -> FileAstId<Self::Source> {
382 self.ast_id
383 }
384
385 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
386 &tree.data().$fld[index]
387 }
388
389 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> {
390 if let ModItem::$typ(id) = mod_item {
391 Some(id)
392 } else {
393 None
394 }
395 }
396
397 fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem {
398 ModItem::$typ(id)
399 }
400 }
401
402 impl Index<Idx<$typ>> for ItemTree {
403 type Output = $typ;
404
405 fn index(&self, index: Idx<$typ>) -> &Self::Output {
406 &self.data().$fld[index]
407 }
408 }
409 )+
410 };
411}
412
413mod_items! {
414 Import in imports -> ast::Use,
415 ExternCrate in extern_crates -> ast::ExternCrate,
416 Function in functions -> ast::Fn,
417 Struct in structs -> ast::Struct,
418 Union in unions -> ast::Union,
419 Enum in enums -> ast::Enum,
420 Const in consts -> ast::Const,
421 Static in statics -> ast::Static,
422 Trait in traits -> ast::Trait,
423 Impl in impls -> ast::Impl,
424 TypeAlias in type_aliases -> ast::TypeAlias,
425 Mod in mods -> ast::Module,
426 MacroCall in macro_calls -> ast::MacroCall,
427}
428
429macro_rules! impl_index {
430 ( $($fld:ident: $t:ty),+ $(,)? ) => {
431 $(
432 impl Index<Idx<$t>> for ItemTree {
433 type Output = $t;
434
435 fn index(&self, index: Idx<$t>) -> &Self::Output {
436 &self.data().$fld[index]
437 }
438 }
439 )+
440 };
441}
442
443impl_index!(fields: Field, variants: Variant, exprs: Expr);
444
445impl Index<RawVisibilityId> for ItemTree {
446 type Output = RawVisibility;
447 fn index(&self, index: RawVisibilityId) -> &Self::Output {
448 match index {
449 RawVisibilityId::PRIV => &VIS_PRIV,
450 RawVisibilityId::PUB => &VIS_PUB,
451 RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
452 _ => &self.data().vis.arena[Idx::from_raw(index.0.into())],
453 }
454 }
455}
456
457impl Index<GenericParamsId> for ItemTree {
458 type Output = GenericParams;
459
460 fn index(&self, index: GenericParamsId) -> &Self::Output {
461 match index {
462 GenericParamsId::EMPTY => &EMPTY_GENERICS,
463 _ => &self.data().generics.arena[Idx::from_raw(index.0.into())],
464 }
465 }
466}
467
468impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
469 type Output = N;
470 fn index(&self, id: FileItemTreeId<N>) -> &N {
471 N::lookup(self, id.index)
472 }
473}
474
475/// A desugared `use` import.
476#[derive(Debug, Clone, Eq, PartialEq)]
477pub struct Import {
478 pub path: ModPath,
479 pub alias: Option<ImportAlias>,
480 pub visibility: RawVisibilityId,
481 pub is_glob: bool,
482 pub is_prelude: bool,
483 /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
484 /// `Import`s can map to the same `use` item.
485 pub ast_id: FileAstId<ast::Use>,
486}
487
488#[derive(Debug, Clone, Eq, PartialEq)]
489pub struct ExternCrate {
490 pub path: ModPath,
491 pub alias: Option<ImportAlias>,
492 pub visibility: RawVisibilityId,
493 /// Whether this is a `#[macro_use] extern crate ...`.
494 pub is_macro_use: bool,
495 pub ast_id: FileAstId<ast::ExternCrate>,
496}
497
498#[derive(Debug, Clone, Eq, PartialEq)]
499pub struct Function {
500 pub name: Name,
501 pub visibility: RawVisibilityId,
502 pub generic_params: GenericParamsId,
503 pub has_self_param: bool,
504 pub is_unsafe: bool,
505 pub params: Box<[TypeRef]>,
506 pub is_varargs: bool,
507 pub ret_type: TypeRef,
508 pub ast_id: FileAstId<ast::Fn>,
509}
510
511#[derive(Debug, Clone, Eq, PartialEq)]
512pub struct Struct {
513 pub name: Name,
514 pub visibility: RawVisibilityId,
515 pub generic_params: GenericParamsId,
516 pub fields: Fields,
517 pub ast_id: FileAstId<ast::Struct>,
518 pub kind: StructDefKind,
519}
520
521#[derive(Debug, Clone, Eq, PartialEq)]
522pub enum StructDefKind {
523 /// `struct S { ... }` - type namespace only.
524 Record,
525 /// `struct S(...);`
526 Tuple,
527 /// `struct S;`
528 Unit,
529}
530
531#[derive(Debug, Clone, Eq, PartialEq)]
532pub struct Union {
533 pub name: Name,
534 pub visibility: RawVisibilityId,
535 pub generic_params: GenericParamsId,
536 pub fields: Fields,
537 pub ast_id: FileAstId<ast::Union>,
538}
539
540#[derive(Debug, Clone, Eq, PartialEq)]
541pub struct Enum {
542 pub name: Name,
543 pub visibility: RawVisibilityId,
544 pub generic_params: GenericParamsId,
545 pub variants: IdRange<Variant>,
546 pub ast_id: FileAstId<ast::Enum>,
547}
548
549#[derive(Debug, Clone, Eq, PartialEq)]
550pub struct Const {
551 /// const _: () = ();
552 pub name: Option<Name>,
553 pub visibility: RawVisibilityId,
554 pub type_ref: TypeRef,
555 pub ast_id: FileAstId<ast::Const>,
556}
557
558#[derive(Debug, Clone, Eq, PartialEq)]
559pub struct Static {
560 pub name: Name,
561 pub visibility: RawVisibilityId,
562 pub mutable: bool,
563 pub type_ref: TypeRef,
564 pub ast_id: FileAstId<ast::Static>,
565}
566
567#[derive(Debug, Clone, Eq, PartialEq)]
568pub struct Trait {
569 pub name: Name,
570 pub visibility: RawVisibilityId,
571 pub generic_params: GenericParamsId,
572 pub auto: bool,
573 pub items: Box<[AssocItem]>,
574 pub ast_id: FileAstId<ast::Trait>,
575}
576
577#[derive(Debug, Clone, Eq, PartialEq)]
578pub struct Impl {
579 pub generic_params: GenericParamsId,
580 pub target_trait: Option<TypeRef>,
581 pub target_type: TypeRef,
582 pub is_negative: bool,
583 pub items: Box<[AssocItem]>,
584 pub ast_id: FileAstId<ast::Impl>,
585}
586
587#[derive(Debug, Clone, PartialEq, Eq)]
588pub struct TypeAlias {
589 pub name: Name,
590 pub visibility: RawVisibilityId,
591 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
592 pub bounds: Box<[TypeBound]>,
593 pub generic_params: GenericParamsId,
594 pub type_ref: Option<TypeRef>,
595 pub ast_id: FileAstId<ast::TypeAlias>,
596}
597
598#[derive(Debug, Clone, Eq, PartialEq)]
599pub struct Mod {
600 pub name: Name,
601 pub visibility: RawVisibilityId,
602 pub kind: ModKind,
603 pub ast_id: FileAstId<ast::Module>,
604}
605
606#[derive(Debug, Clone, Eq, PartialEq)]
607pub enum ModKind {
608 /// `mod m { ... }`
609 Inline { items: Box<[ModItem]> },
610
611 /// `mod m;`
612 Outline {},
613}
614
615#[derive(Debug, Clone, Eq, PartialEq)]
616pub struct MacroCall {
617 /// For `macro_rules!` declarations, this is the name of the declared macro.
618 pub name: Option<Name>,
619 /// Path to the called macro.
620 pub path: ModPath,
621 /// Has `#[macro_export]`.
622 pub is_export: bool,
623 /// Has `#[macro_export(local_inner_macros)]`.
624 pub is_local_inner: bool,
625 /// Has `#[rustc_builtin_macro]`.
626 pub is_builtin: bool,
627 pub ast_id: FileAstId<ast::MacroCall>,
628}
629
630// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
631// lengths, but we don't do much with them yet.
632#[derive(Debug, Clone, Eq, PartialEq)]
633pub struct Expr;
634
635macro_rules! impl_froms {
636 ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
637 $(
638 impl From<$t> for $e {
639 fn from(it: $t) -> $e {
640 $e::$v(it)
641 }
642 }
643 )*
644 }
645}
646
647impl ModItem {
648 pub fn as_assoc_item(&self) -> Option<AssocItem> {
649 match self {
650 ModItem::Import(_)
651 | ModItem::ExternCrate(_)
652 | ModItem::Struct(_)
653 | ModItem::Union(_)
654 | ModItem::Enum(_)
655 | ModItem::Static(_)
656 | ModItem::Trait(_)
657 | ModItem::Impl(_)
658 | ModItem::Mod(_) => None,
659 ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
660 ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
661 ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
662 ModItem::Function(func) => Some(AssocItem::Function(*func)),
663 }
664 }
665
666 pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> {
667 N::id_from_mod_item(self)
668 }
669}
670
671#[derive(Debug, Copy, Clone, Eq, PartialEq)]
672pub enum AssocItem {
673 Function(FileItemTreeId<Function>),
674 TypeAlias(FileItemTreeId<TypeAlias>),
675 Const(FileItemTreeId<Const>),
676 MacroCall(FileItemTreeId<MacroCall>),
677}
678
679impl_froms!(AssocItem {
680 Function(FileItemTreeId<Function>),
681 TypeAlias(FileItemTreeId<TypeAlias>),
682 Const(FileItemTreeId<Const>),
683 MacroCall(FileItemTreeId<MacroCall>),
684});
685
686impl From<AssocItem> for ModItem {
687 fn from(item: AssocItem) -> Self {
688 match item {
689 AssocItem::Function(it) => it.into(),
690 AssocItem::TypeAlias(it) => it.into(),
691 AssocItem::Const(it) => it.into(),
692 AssocItem::MacroCall(it) => it.into(),
693 }
694 }
695}
696
697#[derive(Debug, Eq, PartialEq)]
698pub struct Variant {
699 pub name: Name,
700 pub fields: Fields,
701}
702
703pub struct IdRange<T> {
704 range: Range<u32>,
705 _p: PhantomData<T>,
706}
707
708impl<T> IdRange<T> {
709 fn new(range: Range<Idx<T>>) -> Self {
710 Self { range: range.start.into_raw().into()..range.end.into_raw().into(), _p: PhantomData }
711 }
712}
713
714impl<T> Iterator for IdRange<T> {
715 type Item = Idx<T>;
716 fn next(&mut self) -> Option<Self::Item> {
717 self.range.next().map(|raw| Idx::from_raw(raw.into()))
718 }
719}
720
721impl<T> fmt::Debug for IdRange<T> {
722 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
723 f.debug_tuple(&format!("IdRange::<{}>", type_name::<T>())).field(&self.range).finish()
724 }
725}
726
727impl<T> Clone for IdRange<T> {
728 fn clone(&self) -> Self {
729 Self { range: self.range.clone(), _p: PhantomData }
730 }
731}
732
733impl<T> PartialEq for IdRange<T> {
734 fn eq(&self, other: &Self) -> bool {
735 self.range == other.range
736 }
737}
738
739impl<T> Eq for IdRange<T> {}
740
741#[derive(Debug, Clone, PartialEq, Eq)]
742pub enum Fields {
743 Record(IdRange<Field>),
744 Tuple(IdRange<Field>),
745 Unit,
746}
747
748/// A single field of an enum variant or struct
749#[derive(Debug, Clone, PartialEq, Eq)]
750pub struct Field {
751 pub name: Name,
752 pub type_ref: TypeRef,
753 pub visibility: RawVisibilityId,
754}
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
deleted file mode 100644
index 450ef8798..000000000
--- a/crates/ra_hir_def/src/item_tree/lower.rs
+++ /dev/null
@@ -1,705 +0,0 @@
1//! AST -> `ItemTree` lowering code.
2
3use std::{collections::hash_map::Entry, mem, sync::Arc};
4
5use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId};
6use ra_arena::map::ArenaMap;
7use ra_syntax::{
8 ast::{self, ModuleItemOwner},
9 SyntaxNode,
10};
11use smallvec::SmallVec;
12
13use crate::{
14 attr::Attrs,
15 generics::{GenericParams, TypeParamData, TypeParamProvenance},
16};
17
18use super::*;
19
20fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
21 FileItemTreeId { index, _p: PhantomData }
22}
23
24struct ModItems(SmallVec<[ModItem; 1]>);
25
26impl<T> From<T> for ModItems
27where
28 T: Into<ModItem>,
29{
30 fn from(t: T) -> Self {
31 ModItems(SmallVec::from_buf([t.into(); 1]))
32 }
33}
34
35pub(super) struct Ctx {
36 tree: ItemTree,
37 hygiene: Hygiene,
38 file: HirFileId,
39 source_ast_id_map: Arc<AstIdMap>,
40 body_ctx: crate::body::LowerCtx,
41 inner_items: Vec<ModItem>,
42 forced_visibility: Option<RawVisibilityId>,
43}
44
45impl Ctx {
46 pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self {
47 Self {
48 tree: ItemTree::empty(),
49 hygiene,
50 file,
51 source_ast_id_map: db.ast_id_map(file),
52 body_ctx: crate::body::LowerCtx::new(db, file),
53 inner_items: Vec::new(),
54 forced_visibility: None,
55 }
56 }
57
58 pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree {
59 self.tree.top_level = item_owner
60 .items()
61 .flat_map(|item| self.lower_mod_item(&item, false))
62 .flat_map(|items| items.0)
63 .collect();
64 self.tree
65 }
66
67 pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree {
68 self.collect_inner_items(within);
69 self.tree
70 }
71
72 fn data(&mut self) -> &mut ItemTreeData {
73 self.tree.data_mut()
74 }
75
76 fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems> {
77 assert!(inner || self.inner_items.is_empty());
78
79 // Collect inner items for 1-to-1-lowered items.
80 match item {
81 ast::Item::Struct(_)
82 | ast::Item::Union(_)
83 | ast::Item::Enum(_)
84 | ast::Item::Fn(_)
85 | ast::Item::TypeAlias(_)
86 | ast::Item::Const(_)
87 | ast::Item::Static(_)
88 | ast::Item::MacroCall(_) => {
89 // Skip this if we're already collecting inner items. We'll descend into all nodes
90 // already.
91 if !inner {
92 self.collect_inner_items(item.syntax());
93 }
94 }
95
96 // These are handled in their respective `lower_X` method (since we can't just blindly
97 // walk them).
98 ast::Item::Trait(_) | ast::Item::Impl(_) | ast::Item::ExternBlock(_) => {}
99
100 // These don't have inner items.
101 ast::Item::Module(_) | ast::Item::ExternCrate(_) | ast::Item::Use(_) => {}
102 };
103
104 let attrs = Attrs::new(item, &self.hygiene);
105 let items = match item {
106 ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into),
107 ast::Item::Union(ast) => self.lower_union(ast).map(Into::into),
108 ast::Item::Enum(ast) => self.lower_enum(ast).map(Into::into),
109 ast::Item::Fn(ast) => self.lower_function(ast).map(Into::into),
110 ast::Item::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into),
111 ast::Item::Static(ast) => self.lower_static(ast).map(Into::into),
112 ast::Item::Const(ast) => Some(self.lower_const(ast).into()),
113 ast::Item::Module(ast) => self.lower_module(ast).map(Into::into),
114 ast::Item::Trait(ast) => self.lower_trait(ast).map(Into::into),
115 ast::Item::Impl(ast) => self.lower_impl(ast).map(Into::into),
116 ast::Item::Use(ast) => Some(ModItems(
117 self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(),
118 )),
119 ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
120 ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
121 ast::Item::ExternBlock(ast) => {
122 Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
123 }
124 };
125
126 if !attrs.is_empty() {
127 for item in items.iter().flat_map(|items| &items.0) {
128 self.add_attrs((*item).into(), attrs.clone());
129 }
130 }
131
132 items
133 }
134
135 fn add_attrs(&mut self, item: AttrOwner, attrs: Attrs) {
136 match self.tree.attrs.entry(item) {
137 Entry::Occupied(mut entry) => {
138 *entry.get_mut() = entry.get().merge(attrs);
139 }
140 Entry::Vacant(entry) => {
141 entry.insert(attrs);
142 }
143 }
144 }
145
146 fn collect_inner_items(&mut self, container: &SyntaxNode) {
147 let forced_vis = self.forced_visibility.take();
148 let mut inner_items = mem::take(&mut self.tree.inner_items);
149 inner_items.extend(container.descendants().skip(1).filter_map(ast::Item::cast).filter_map(
150 |item| {
151 let ast_id = self.source_ast_id_map.ast_id(&item);
152 Some((ast_id, self.lower_mod_item(&item, true)?.0))
153 },
154 ));
155 self.tree.inner_items = inner_items;
156 self.forced_visibility = forced_vis;
157 }
158
159 fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option<AssocItem> {
160 match item {
161 ast::AssocItem::Fn(ast) => self.lower_function(ast).map(Into::into),
162 ast::AssocItem::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into),
163 ast::AssocItem::Const(ast) => Some(self.lower_const(ast).into()),
164 ast::AssocItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
165 }
166 }
167
168 fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
169 let visibility = self.lower_visibility(strukt);
170 let name = strukt.name()?.as_name();
171 let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt);
172 let fields = self.lower_fields(&strukt.kind());
173 let ast_id = self.source_ast_id_map.ast_id(strukt);
174 let kind = match strukt.kind() {
175 ast::StructKind::Record(_) => StructDefKind::Record,
176 ast::StructKind::Tuple(_) => StructDefKind::Tuple,
177 ast::StructKind::Unit => StructDefKind::Unit,
178 };
179 let res = Struct { name, visibility, generic_params, fields, ast_id, kind };
180 Some(id(self.data().structs.alloc(res)))
181 }
182
183 fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields {
184 match strukt_kind {
185 ast::StructKind::Record(it) => {
186 let range = self.lower_record_fields(it);
187 Fields::Record(range)
188 }
189 ast::StructKind::Tuple(it) => {
190 let range = self.lower_tuple_fields(it);
191 Fields::Tuple(range)
192 }
193 ast::StructKind::Unit => Fields::Unit,
194 }
195 }
196
197 fn lower_record_fields(&mut self, fields: &ast::RecordFieldList) -> IdRange<Field> {
198 let start = self.next_field_idx();
199 for field in fields.fields() {
200 if let Some(data) = self.lower_record_field(&field) {
201 let idx = self.data().fields.alloc(data);
202 self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene));
203 }
204 }
205 let end = self.next_field_idx();
206 IdRange::new(start..end)
207 }
208
209 fn lower_record_field(&mut self, field: &ast::RecordField) -> Option<Field> {
210 let name = field.name()?.as_name();
211 let visibility = self.lower_visibility(field);
212 let type_ref = self.lower_type_ref_opt(field.ty());
213 let res = Field { name, type_ref, visibility };
214 Some(res)
215 }
216
217 fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldList) -> IdRange<Field> {
218 let start = self.next_field_idx();
219 for (i, field) in fields.fields().enumerate() {
220 let data = self.lower_tuple_field(i, &field);
221 let idx = self.data().fields.alloc(data);
222 self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene));
223 }
224 let end = self.next_field_idx();
225 IdRange::new(start..end)
226 }
227
228 fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
229 let name = Name::new_tuple_field(idx);
230 let visibility = self.lower_visibility(field);
231 let type_ref = self.lower_type_ref_opt(field.ty());
232 let res = Field { name, type_ref, visibility };
233 res
234 }
235
236 fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
237 let visibility = self.lower_visibility(union);
238 let name = union.name()?.as_name();
239 let generic_params = self.lower_generic_params(GenericsOwner::Union, union);
240 let fields = match union.record_field_list() {
241 Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
242 None => Fields::Record(IdRange::new(self.next_field_idx()..self.next_field_idx())),
243 };
244 let ast_id = self.source_ast_id_map.ast_id(union);
245 let res = Union { name, visibility, generic_params, fields, ast_id };
246 Some(id(self.data().unions.alloc(res)))
247 }
248
249 fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> {
250 let visibility = self.lower_visibility(enum_);
251 let name = enum_.name()?.as_name();
252 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_);
253 let variants = match &enum_.variant_list() {
254 Some(variant_list) => self.lower_variants(variant_list),
255 None => IdRange::new(self.next_variant_idx()..self.next_variant_idx()),
256 };
257 let ast_id = self.source_ast_id_map.ast_id(enum_);
258 let res = Enum { name, visibility, generic_params, variants, ast_id };
259 Some(id(self.data().enums.alloc(res)))
260 }
261
262 fn lower_variants(&mut self, variants: &ast::VariantList) -> IdRange<Variant> {
263 let start = self.next_variant_idx();
264 for variant in variants.variants() {
265 if let Some(data) = self.lower_variant(&variant) {
266 let idx = self.data().variants.alloc(data);
267 self.add_attrs(idx.into(), Attrs::new(&variant, &self.hygiene));
268 }
269 }
270 let end = self.next_variant_idx();
271 IdRange::new(start..end)
272 }
273
274 fn lower_variant(&mut self, variant: &ast::Variant) -> Option<Variant> {
275 let name = variant.name()?.as_name();
276 let fields = self.lower_fields(&variant.kind());
277 let res = Variant { name, fields };
278 Some(res)
279 }
280
281 fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
282 let visibility = self.lower_visibility(func);
283 let name = func.name()?.as_name();
284
285 let mut params = Vec::new();
286 let mut has_self_param = false;
287 if let Some(param_list) = func.param_list() {
288 if let Some(self_param) = param_list.self_param() {
289 let self_type = match self_param.ty() {
290 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
291 None => {
292 let self_type = TypeRef::Path(name![Self].into());
293 match self_param.kind() {
294 ast::SelfParamKind::Owned => self_type,
295 ast::SelfParamKind::Ref => {
296 TypeRef::Reference(Box::new(self_type), Mutability::Shared)
297 }
298 ast::SelfParamKind::MutRef => {
299 TypeRef::Reference(Box::new(self_type), Mutability::Mut)
300 }
301 }
302 }
303 };
304 params.push(self_type);
305 has_self_param = true;
306 }
307 for param in param_list.params() {
308 let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
309 params.push(type_ref);
310 }
311 }
312
313 let mut is_varargs = false;
314 if let Some(params) = func.param_list() {
315 if let Some(last) = params.params().last() {
316 is_varargs = last.dotdotdot_token().is_some();
317 }
318 }
319
320 let ret_type = match func.ret_type().and_then(|rt| rt.ty()) {
321 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
322 _ => TypeRef::unit(),
323 };
324
325 let ret_type = if func.async_token().is_some() {
326 let future_impl = desugar_future_path(ret_type);
327 let ty_bound = TypeBound::Path(future_impl);
328 TypeRef::ImplTrait(vec![ty_bound])
329 } else {
330 ret_type
331 };
332
333 let ast_id = self.source_ast_id_map.ast_id(func);
334 let mut res = Function {
335 name,
336 visibility,
337 generic_params: GenericParamsId::EMPTY,
338 has_self_param,
339 is_unsafe: func.unsafe_token().is_some(),
340 params: params.into_boxed_slice(),
341 is_varargs,
342 ret_type,
343 ast_id,
344 };
345 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
346
347 Some(id(self.data().functions.alloc(res)))
348 }
349
350 fn lower_type_alias(
351 &mut self,
352 type_alias: &ast::TypeAlias,
353 ) -> Option<FileItemTreeId<TypeAlias>> {
354 let name = type_alias.name()?.as_name();
355 let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it));
356 let visibility = self.lower_visibility(type_alias);
357 let bounds = self.lower_type_bounds(type_alias);
358 let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias);
359 let ast_id = self.source_ast_id_map.ast_id(type_alias);
360 let res = TypeAlias {
361 name,
362 visibility,
363 bounds: bounds.into_boxed_slice(),
364 generic_params,
365 type_ref,
366 ast_id,
367 };
368 Some(id(self.data().type_aliases.alloc(res)))
369 }
370
371 fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
372 let name = static_.name()?.as_name();
373 let type_ref = self.lower_type_ref_opt(static_.ty());
374 let visibility = self.lower_visibility(static_);
375 let mutable = static_.mut_token().is_some();
376 let ast_id = self.source_ast_id_map.ast_id(static_);
377 let res = Static { name, visibility, mutable, type_ref, ast_id };
378 Some(id(self.data().statics.alloc(res)))
379 }
380
381 fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
382 let name = konst.name().map(|it| it.as_name());
383 let type_ref = self.lower_type_ref_opt(konst.ty());
384 let visibility = self.lower_visibility(konst);
385 let ast_id = self.source_ast_id_map.ast_id(konst);
386 let res = Const { name, visibility, type_ref, ast_id };
387 id(self.data().consts.alloc(res))
388 }
389
390 fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> {
391 let name = module.name()?.as_name();
392 let visibility = self.lower_visibility(module);
393 let kind = if module.semicolon_token().is_some() {
394 ModKind::Outline {}
395 } else {
396 ModKind::Inline {
397 items: module
398 .item_list()
399 .map(|list| {
400 list.items()
401 .flat_map(|item| self.lower_mod_item(&item, false))
402 .flat_map(|items| items.0)
403 .collect()
404 })
405 .unwrap_or_else(|| {
406 mark::hit!(name_res_works_for_broken_modules);
407 Box::new([]) as Box<[_]>
408 }),
409 }
410 };
411 let ast_id = self.source_ast_id_map.ast_id(module);
412 let res = Mod { name, visibility, kind, ast_id };
413 Some(id(self.data().mods.alloc(res)))
414 }
415
416 fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait>> {
417 let name = trait_def.name()?.as_name();
418 let visibility = self.lower_visibility(trait_def);
419 let generic_params =
420 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
421 let auto = trait_def.auto_token().is_some();
422 let items = trait_def.assoc_item_list().map(|list| {
423 self.with_inherited_visibility(visibility, |this| {
424 list.assoc_items()
425 .filter_map(|item| {
426 let attrs = Attrs::new(&item, &this.hygiene);
427 this.collect_inner_items(item.syntax());
428 this.lower_assoc_item(&item).map(|item| {
429 this.add_attrs(ModItem::from(item).into(), attrs);
430 item
431 })
432 })
433 .collect()
434 })
435 });
436 let ast_id = self.source_ast_id_map.ast_id(trait_def);
437 let res = Trait {
438 name,
439 visibility,
440 generic_params,
441 auto,
442 items: items.unwrap_or_default(),
443 ast_id,
444 };
445 Some(id(self.data().traits.alloc(res)))
446 }
447
448 fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
449 let generic_params =
450 self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def);
451 let target_trait = impl_def.trait_().map(|tr| self.lower_type_ref(&tr));
452 let target_type = self.lower_type_ref(&impl_def.self_ty()?);
453 let is_negative = impl_def.excl_token().is_some();
454
455 // We cannot use `assoc_items()` here as that does not include macro calls.
456 let items = impl_def
457 .assoc_item_list()