diff options
Diffstat (limited to 'crates/hir_def')
-rw-r--r-- | crates/hir_def/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/hir_def/src/adt.rs | 9 | ||||
-rw-r--r-- | crates/hir_def/src/attr.rs | 9 | ||||
-rw-r--r-- | crates/hir_def/src/body.rs | 24 | ||||
-rw-r--r-- | crates/hir_def/src/body/lower.rs | 12 | ||||
-rw-r--r-- | crates/hir_def/src/child_by_source.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/data.rs | 86 | ||||
-rw-r--r-- | crates/hir_def/src/intern.rs | 197 | ||||
-rw-r--r-- | crates/hir_def/src/item_scope.rs | 22 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 127 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/lower.rs | 93 | ||||
-rw-r--r-- | crates/hir_def/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/hir_def/src/nameres.rs | 25 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 56 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/diagnostics.rs | 20 | ||||
-rw-r--r-- | crates/hir_def/src/path.rs | 14 | ||||
-rw-r--r-- | crates/hir_def/src/path/lower.rs | 8 | ||||
-rw-r--r-- | crates/hir_def/src/test_db.rs | 13 |
18 files changed, 508 insertions, 212 deletions
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index 475d337f3..60adb655c 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -10,7 +10,9 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | bitflags = "1.2.1" | ||
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 14 | cov-mark = { version = "1.1", features = ["thread-local"] } |
15 | dashmap = { version = "4.0.2", features = ["raw-api"] } | ||
14 | log = "0.4.8" | 16 | log = "0.4.8" |
15 | once_cell = "1.3.1" | 17 | once_cell = "1.3.1" |
16 | rustc-hash = "1.1.0" | 18 | rustc-hash = "1.1.0" |
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs index 58e35353b..402fb1d8d 100644 --- a/crates/hir_def/src/adt.rs +++ b/crates/hir_def/src/adt.rs | |||
@@ -15,6 +15,7 @@ use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; | |||
15 | use crate::{ | 15 | use crate::{ |
16 | body::{CfgExpander, LowerCtx}, | 16 | body::{CfgExpander, LowerCtx}, |
17 | db::DefDatabase, | 17 | db::DefDatabase, |
18 | intern::Interned, | ||
18 | item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId}, | 19 | item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId}, |
19 | src::HasChildSource, | 20 | src::HasChildSource, |
20 | src::HasSource, | 21 | src::HasSource, |
@@ -58,7 +59,7 @@ pub enum VariantData { | |||
58 | #[derive(Debug, Clone, PartialEq, Eq)] | 59 | #[derive(Debug, Clone, PartialEq, Eq)] |
59 | pub struct FieldData { | 60 | pub struct FieldData { |
60 | pub name: Name, | 61 | pub name: Name, |
61 | pub type_ref: TypeRef, | 62 | pub type_ref: Interned<TypeRef>, |
62 | pub visibility: RawVisibility, | 63 | pub visibility: RawVisibility, |
63 | } | 64 | } |
64 | 65 | ||
@@ -292,7 +293,7 @@ fn lower_struct( | |||
292 | || Either::Left(fd.clone()), | 293 | || Either::Left(fd.clone()), |
293 | || FieldData { | 294 | || FieldData { |
294 | name: Name::new_tuple_field(i), | 295 | name: Name::new_tuple_field(i), |
295 | type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()), | 296 | type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())), |
296 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), | 297 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), |
297 | }, | 298 | }, |
298 | ); | 299 | ); |
@@ -309,7 +310,7 @@ fn lower_struct( | |||
309 | || Either::Right(fd.clone()), | 310 | || Either::Right(fd.clone()), |
310 | || FieldData { | 311 | || FieldData { |
311 | name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), | 312 | name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), |
312 | type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()), | 313 | type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())), |
313 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), | 314 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), |
314 | }, | 315 | }, |
315 | ); | 316 | ); |
@@ -358,7 +359,7 @@ fn lower_field( | |||
358 | ) -> FieldData { | 359 | ) -> FieldData { |
359 | FieldData { | 360 | FieldData { |
360 | name: field.name.clone(), | 361 | name: field.name.clone(), |
361 | type_ref: item_tree[field.type_ref].clone(), | 362 | type_ref: field.type_ref.clone(), |
362 | visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), | 363 | visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), |
363 | } | 364 | } |
364 | } | 365 | } |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 52a2bce9b..442c5fb5b 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -18,6 +18,7 @@ use tt::Subtree; | |||
18 | 18 | ||
19 | use crate::{ | 19 | use crate::{ |
20 | db::DefDatabase, | 20 | db::DefDatabase, |
21 | intern::Interned, | ||
21 | item_tree::{ItemTreeId, ItemTreeNode}, | 22 | item_tree::{ItemTreeId, ItemTreeNode}, |
22 | nameres::ModuleSource, | 23 | nameres::ModuleSource, |
23 | path::{ModPath, PathKind}, | 24 | path::{ModPath, PathKind}, |
@@ -98,7 +99,7 @@ impl RawAttrs { | |||
98 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { | 99 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { |
99 | index: i as u32, | 100 | index: i as u32, |
100 | input: Some(AttrInput::Literal(SmolStr::new(doc))), | 101 | input: Some(AttrInput::Literal(SmolStr::new(doc))), |
101 | path: ModPath::from(hir_expand::name!(doc)), | 102 | path: Interned::new(ModPath::from(hir_expand::name!(doc))), |
102 | }), | 103 | }), |
103 | }) | 104 | }) |
104 | .collect::<Arc<_>>(); | 105 | .collect::<Arc<_>>(); |
@@ -510,7 +511,7 @@ impl AttrSourceMap { | |||
510 | #[derive(Debug, Clone, PartialEq, Eq)] | 511 | #[derive(Debug, Clone, PartialEq, Eq)] |
511 | pub struct Attr { | 512 | pub struct Attr { |
512 | index: u32, | 513 | index: u32, |
513 | pub(crate) path: ModPath, | 514 | pub(crate) path: Interned<ModPath>, |
514 | pub(crate) input: Option<AttrInput>, | 515 | pub(crate) input: Option<AttrInput>, |
515 | } | 516 | } |
516 | 517 | ||
@@ -524,7 +525,7 @@ pub enum AttrInput { | |||
524 | 525 | ||
525 | impl Attr { | 526 | impl Attr { |
526 | fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> { | 527 | fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> { |
527 | let path = ModPath::from_src(ast.path()?, hygiene)?; | 528 | let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?); |
528 | let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { | 529 | let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { |
529 | let value = match lit.kind() { | 530 | let value = match lit.kind() { |
530 | ast::LiteralKind::String(string) => string.value()?.into(), | 531 | ast::LiteralKind::String(string) => string.value()?.into(), |
@@ -532,7 +533,7 @@ impl Attr { | |||
532 | }; | 533 | }; |
533 | Some(AttrInput::Literal(value)) | 534 | Some(AttrInput::Literal(value)) |
534 | } else if let Some(tt) = ast.token_tree() { | 535 | } else if let Some(tt) = ast.token_tree() { |
535 | Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0)) | 536 | Some(AttrInput::TokenTree(ast_to_token_tree(&tt).0)) |
536 | } else { | 537 | } else { |
537 | None | 538 | None |
538 | }; | 539 | }; |
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 1080d9c2c..96b959967 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -226,7 +226,7 @@ pub struct Body { | |||
226 | /// The `ExprId` of the actual body expression. | 226 | /// The `ExprId` of the actual body expression. |
227 | pub body_expr: ExprId, | 227 | pub body_expr: ExprId, |
228 | /// Block expressions in this body that may contain inner items. | 228 | /// Block expressions in this body that may contain inner items. |
229 | pub block_scopes: Vec<BlockId>, | 229 | block_scopes: Vec<BlockId>, |
230 | _c: Count<Self>, | 230 | _c: Count<Self>, |
231 | } | 231 | } |
232 | 232 | ||
@@ -302,7 +302,8 @@ impl Body { | |||
302 | } | 302 | } |
303 | }; | 303 | }; |
304 | let expander = Expander::new(db, file_id, module); | 304 | let expander = Expander::new(db, file_id, module); |
305 | let (body, source_map) = Body::new(db, expander, params, body); | 305 | let (mut body, source_map) = Body::new(db, expander, params, body); |
306 | body.shrink_to_fit(); | ||
306 | (Arc::new(body), Arc::new(source_map)) | 307 | (Arc::new(body), Arc::new(source_map)) |
307 | } | 308 | } |
308 | 309 | ||
@@ -310,6 +311,16 @@ impl Body { | |||
310 | db.body_with_source_map(def).0 | 311 | db.body_with_source_map(def).0 |
311 | } | 312 | } |
312 | 313 | ||
314 | /// Returns an iterator over all block expressions in this body that define inner items. | ||
315 | pub fn blocks<'a>( | ||
316 | &'a self, | ||
317 | db: &'a dyn DefDatabase, | ||
318 | ) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + '_ { | ||
319 | self.block_scopes | ||
320 | .iter() | ||
321 | .map(move |block| (*block, db.block_def_map(*block).expect("block ID without DefMap"))) | ||
322 | } | ||
323 | |||
313 | fn new( | 324 | fn new( |
314 | db: &dyn DefDatabase, | 325 | db: &dyn DefDatabase, |
315 | expander: Expander, | 326 | expander: Expander, |
@@ -318,6 +329,15 @@ impl Body { | |||
318 | ) -> (Body, BodySourceMap) { | 329 | ) -> (Body, BodySourceMap) { |
319 | lower::lower(db, expander, params, body) | 330 | lower::lower(db, expander, params, body) |
320 | } | 331 | } |
332 | |||
333 | fn shrink_to_fit(&mut self) { | ||
334 | let Self { _c: _, body_expr: _, block_scopes, exprs, labels, params, pats } = self; | ||
335 | block_scopes.shrink_to_fit(); | ||
336 | exprs.shrink_to_fit(); | ||
337 | labels.shrink_to_fit(); | ||
338 | params.shrink_to_fit(); | ||
339 | pats.shrink_to_fit(); | ||
340 | } | ||
321 | } | 341 | } |
322 | 342 | ||
323 | impl Index<ExprId> for Body { | 343 | impl Index<ExprId> for Body { |
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 229e81dd4..63e89a1f4 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -673,12 +673,14 @@ impl ExprCollector<'_> { | |||
673 | let block_loc = | 673 | let block_loc = |
674 | BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) }; | 674 | BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) }; |
675 | let block_id = self.db.intern_block(block_loc); | 675 | let block_id = self.db.intern_block(block_loc); |
676 | self.body.block_scopes.push(block_id); | ||
677 | 676 | ||
678 | let opt_def_map = self.db.block_def_map(block_id); | 677 | let (module, def_map) = match self.db.block_def_map(block_id) { |
679 | let has_def_map = opt_def_map.is_some(); | 678 | Some(def_map) => { |
680 | let def_map = opt_def_map.unwrap_or_else(|| self.expander.def_map.clone()); | 679 | self.body.block_scopes.push(block_id); |
681 | let module = if has_def_map { def_map.root() } else { self.expander.module }; | 680 | (def_map.root(), def_map) |
681 | } | ||
682 | None => (self.expander.module, self.expander.def_map.clone()), | ||
683 | }; | ||
682 | let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); | 684 | let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); |
683 | let prev_local_module = mem::replace(&mut self.expander.module, module); | 685 | let prev_local_module = mem::replace(&mut self.expander.module, module); |
684 | let prev_statements = std::mem::take(&mut self.statements_in_scope); | 686 | let prev_statements = std::mem::take(&mut self.statements_in_scope); |
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs index 2a331dcaf..f40a7f80d 100644 --- a/crates/hir_def/src/child_by_source.rs +++ b/crates/hir_def/src/child_by_source.rs | |||
@@ -160,7 +160,7 @@ impl ChildBySource for EnumId { | |||
160 | impl ChildBySource for DefWithBodyId { | 160 | impl ChildBySource for DefWithBodyId { |
161 | fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) { | 161 | fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) { |
162 | let body = db.body(*self); | 162 | let body = db.body(*self); |
163 | for def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) { | 163 | for (_, def_map) in body.blocks(db) { |
164 | // All block expressions are merged into the same map, because they logically all add | 164 | // All block expressions are merged into the same map, because they logically all add |
165 | // inner items to the containing `DefWithBodyId`. | 165 | // inner items to the containing `DefWithBodyId`. |
166 | def_map[def_map.root()].scope.child_by_source_to(db, res); | 166 | def_map[def_map.root()].scope.child_by_source_to(db, res); |
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index 214bcc648..b409fb45c 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs | |||
@@ -9,7 +9,8 @@ use crate::{ | |||
9 | attr::Attrs, | 9 | attr::Attrs, |
10 | body::Expander, | 10 | body::Expander, |
11 | db::DefDatabase, | 11 | db::DefDatabase, |
12 | item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param}, | 12 | intern::Interned, |
13 | item_tree::{AssocItem, FnFlags, ItemTreeId, ModItem, Param}, | ||
13 | type_ref::{TraitRef, TypeBound, TypeRef}, | 14 | type_ref::{TraitRef, TypeBound, TypeRef}, |
14 | visibility::RawVisibility, | 15 | visibility::RawVisibility, |
15 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, | 16 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, |
@@ -19,17 +20,12 @@ use crate::{ | |||
19 | #[derive(Debug, Clone, PartialEq, Eq)] | 20 | #[derive(Debug, Clone, PartialEq, Eq)] |
20 | pub struct FunctionData { | 21 | pub struct FunctionData { |
21 | pub name: Name, | 22 | pub name: Name, |
22 | pub params: Vec<TypeRef>, | 23 | pub params: Vec<Interned<TypeRef>>, |
23 | pub ret_type: TypeRef, | 24 | pub ret_type: Interned<TypeRef>, |
24 | pub attrs: Attrs, | 25 | pub attrs: Attrs, |
25 | /// True if the first param is `self`. This is relevant to decide whether this | ||
26 | /// can be called as a method. | ||
27 | pub has_self_param: bool, | ||
28 | pub has_body: bool, | ||
29 | pub qualifier: FunctionQualifier, | ||
30 | pub is_in_extern_block: bool, | ||
31 | pub is_varargs: bool, | ||
32 | pub visibility: RawVisibility, | 26 | pub visibility: RawVisibility, |
27 | pub abi: Option<Interned<str>>, | ||
28 | flags: FnFlags, | ||
33 | } | 29 | } |
34 | 30 | ||
35 | impl FunctionData { | 31 | impl FunctionData { |
@@ -52,31 +48,67 @@ impl FunctionData { | |||
52 | .next_back() | 48 | .next_back() |
53 | .map_or(false, |param| matches!(item_tree[param], Param::Varargs)); | 49 | .map_or(false, |param| matches!(item_tree[param], Param::Varargs)); |
54 | 50 | ||
51 | let mut flags = func.flags; | ||
52 | if is_varargs { | ||
53 | flags |= FnFlags::IS_VARARGS; | ||
54 | } | ||
55 | |||
55 | Arc::new(FunctionData { | 56 | Arc::new(FunctionData { |
56 | name: func.name.clone(), | 57 | name: func.name.clone(), |
57 | params: enabled_params | 58 | params: enabled_params |
58 | .clone() | 59 | .clone() |
59 | .filter_map(|id| match &item_tree[id] { | 60 | .filter_map(|id| match &item_tree[id] { |
60 | Param::Normal(ty) => Some(item_tree[*ty].clone()), | 61 | Param::Normal(ty) => Some(ty.clone()), |
61 | Param::Varargs => None, | 62 | Param::Varargs => None, |
62 | }) | 63 | }) |
63 | .collect(), | 64 | .collect(), |
64 | ret_type: item_tree[func.ret_type].clone(), | 65 | ret_type: func.ret_type.clone(), |
65 | attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), | 66 | attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), |
66 | has_self_param: func.has_self_param, | ||
67 | has_body: func.has_body, | ||
68 | qualifier: func.qualifier.clone(), | ||
69 | is_in_extern_block: func.is_in_extern_block, | ||
70 | is_varargs, | ||
71 | visibility: item_tree[func.visibility].clone(), | 67 | visibility: item_tree[func.visibility].clone(), |
68 | abi: func.abi.clone(), | ||
69 | flags, | ||
72 | }) | 70 | }) |
73 | } | 71 | } |
72 | |||
73 | pub fn has_body(&self) -> bool { | ||
74 | self.flags.contains(FnFlags::HAS_BODY) | ||
75 | } | ||
76 | |||
77 | /// True if the first param is `self`. This is relevant to decide whether this | ||
78 | /// can be called as a method. | ||
79 | pub fn has_self_param(&self) -> bool { | ||
80 | self.flags.contains(FnFlags::HAS_SELF_PARAM) | ||
81 | } | ||
82 | |||
83 | pub fn is_default(&self) -> bool { | ||
84 | self.flags.contains(FnFlags::IS_DEFAULT) | ||
85 | } | ||
86 | |||
87 | pub fn is_const(&self) -> bool { | ||
88 | self.flags.contains(FnFlags::IS_CONST) | ||
89 | } | ||
90 | |||
91 | pub fn is_async(&self) -> bool { | ||
92 | self.flags.contains(FnFlags::IS_ASYNC) | ||
93 | } | ||
94 | |||
95 | pub fn is_unsafe(&self) -> bool { | ||
96 | self.flags.contains(FnFlags::IS_UNSAFE) | ||
97 | } | ||
98 | |||
99 | pub fn is_in_extern_block(&self) -> bool { | ||
100 | self.flags.contains(FnFlags::IS_IN_EXTERN_BLOCK) | ||
101 | } | ||
102 | |||
103 | pub fn is_varargs(&self) -> bool { | ||
104 | self.flags.contains(FnFlags::IS_VARARGS) | ||
105 | } | ||
74 | } | 106 | } |
75 | 107 | ||
76 | #[derive(Debug, Clone, PartialEq, Eq)] | 108 | #[derive(Debug, Clone, PartialEq, Eq)] |
77 | pub struct TypeAliasData { | 109 | pub struct TypeAliasData { |
78 | pub name: Name, | 110 | pub name: Name, |
79 | pub type_ref: Option<TypeRef>, | 111 | pub type_ref: Option<Interned<TypeRef>>, |
80 | pub visibility: RawVisibility, | 112 | pub visibility: RawVisibility, |
81 | pub is_extern: bool, | 113 | pub is_extern: bool, |
82 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). | 114 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). |
@@ -94,7 +126,7 @@ impl TypeAliasData { | |||
94 | 126 | ||
95 | Arc::new(TypeAliasData { | 127 | Arc::new(TypeAliasData { |
96 | name: typ.name.clone(), | 128 | name: typ.name.clone(), |
97 | type_ref: typ.type_ref.map(|id| item_tree[id].clone()), | 129 | type_ref: typ.type_ref.clone(), |
98 | visibility: item_tree[typ.visibility].clone(), | 130 | visibility: item_tree[typ.visibility].clone(), |
99 | is_extern: typ.is_extern, | 131 | is_extern: typ.is_extern, |
100 | bounds: typ.bounds.to_vec(), | 132 | bounds: typ.bounds.to_vec(), |
@@ -156,8 +188,8 @@ impl TraitData { | |||
156 | 188 | ||
157 | #[derive(Debug, Clone, PartialEq, Eq)] | 189 | #[derive(Debug, Clone, PartialEq, Eq)] |
158 | pub struct ImplData { | 190 | pub struct ImplData { |
159 | pub target_trait: Option<TraitRef>, | 191 | pub target_trait: Option<Interned<TraitRef>>, |
160 | pub self_ty: TypeRef, | 192 | pub self_ty: Interned<TypeRef>, |
161 | pub items: Vec<AssocItemId>, | 193 | pub items: Vec<AssocItemId>, |
162 | pub is_negative: bool, | 194 | pub is_negative: bool, |
163 | } | 195 | } |
@@ -169,8 +201,8 @@ impl ImplData { | |||
169 | 201 | ||
170 | let item_tree = impl_loc.id.item_tree(db); | 202 | let item_tree = impl_loc.id.item_tree(db); |
171 | let impl_def = &item_tree[impl_loc.id.value]; | 203 | let impl_def = &item_tree[impl_loc.id.value]; |
172 | let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone()); | 204 | let target_trait = impl_def.target_trait.clone(); |
173 | let self_ty = item_tree[impl_def.self_ty].clone(); | 205 | let self_ty = impl_def.self_ty.clone(); |
174 | let is_negative = impl_def.is_negative; | 206 | let is_negative = impl_def.is_negative; |
175 | let module_id = impl_loc.container; | 207 | let module_id = impl_loc.container; |
176 | let container = AssocContainerId::ImplId(id); | 208 | let container = AssocContainerId::ImplId(id); |
@@ -195,7 +227,7 @@ impl ImplData { | |||
195 | pub struct ConstData { | 227 | pub struct ConstData { |
196 | /// const _: () = (); | 228 | /// const _: () = (); |
197 | pub name: Option<Name>, | 229 | pub name: Option<Name>, |
198 | pub type_ref: TypeRef, | 230 | pub type_ref: Interned<TypeRef>, |
199 | pub visibility: RawVisibility, | 231 | pub visibility: RawVisibility, |
200 | } | 232 | } |
201 | 233 | ||
@@ -207,7 +239,7 @@ impl ConstData { | |||
207 | 239 | ||
208 | Arc::new(ConstData { | 240 | Arc::new(ConstData { |
209 | name: konst.name.clone(), | 241 | name: konst.name.clone(), |
210 | type_ref: item_tree[konst.type_ref].clone(), | 242 | type_ref: konst.type_ref.clone(), |
211 | visibility: item_tree[konst.visibility].clone(), | 243 | visibility: item_tree[konst.visibility].clone(), |
212 | }) | 244 | }) |
213 | } | 245 | } |
@@ -216,7 +248,7 @@ impl ConstData { | |||
216 | #[derive(Debug, Clone, PartialEq, Eq)] | 248 | #[derive(Debug, Clone, PartialEq, Eq)] |
217 | pub struct StaticData { | 249 | pub struct StaticData { |
218 | pub name: Option<Name>, | 250 | pub name: Option<Name>, |
219 | pub type_ref: TypeRef, | 251 | pub type_ref: Interned<TypeRef>, |
220 | pub visibility: RawVisibility, | 252 | pub visibility: RawVisibility, |
221 | pub mutable: bool, | 253 | pub mutable: bool, |
222 | pub is_extern: bool, | 254 | pub is_extern: bool, |
@@ -230,7 +262,7 @@ impl StaticData { | |||
230 | 262 | ||
231 | Arc::new(StaticData { | 263 | Arc::new(StaticData { |
232 | name: Some(statik.name.clone()), | 264 | name: Some(statik.name.clone()), |
233 | type_ref: item_tree[statik.type_ref].clone(), | 265 | type_ref: statik.type_ref.clone(), |
234 | visibility: item_tree[statik.visibility].clone(), | 266 | visibility: item_tree[statik.visibility].clone(), |
235 | mutable: statik.mutable, | 267 | mutable: statik.mutable, |
236 | is_extern: statik.is_extern, | 268 | is_extern: statik.is_extern, |
diff --git a/crates/hir_def/src/intern.rs b/crates/hir_def/src/intern.rs new file mode 100644 index 000000000..d163f633f --- /dev/null +++ b/crates/hir_def/src/intern.rs | |||
@@ -0,0 +1,197 @@ | |||
1 | //! Global `Arc`-based object interning infrastructure. | ||
2 | //! | ||
3 | //! Eventually this should probably be replaced with salsa-based interning. | ||
4 | |||
5 | use std::{ | ||
6 | collections::HashMap, | ||
7 | fmt::{self, Debug}, | ||
8 | hash::{BuildHasherDefault, Hash}, | ||
9 | ops::Deref, | ||
10 | sync::Arc, | ||
11 | }; | ||
12 | |||
13 | use dashmap::{lock::RwLockWriteGuard, DashMap, SharedValue}; | ||
14 | use once_cell::sync::OnceCell; | ||
15 | use rustc_hash::FxHasher; | ||
16 | |||
17 | type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>; | ||
18 | type Guard<T> = | ||
19 | RwLockWriteGuard<'static, HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>>; | ||
20 | |||
21 | #[derive(Hash)] | ||
22 | pub struct Interned<T: Internable + ?Sized> { | ||
23 | arc: Arc<T>, | ||
24 | } | ||
25 | |||
26 | impl<T: Internable> Interned<T> { | ||
27 | pub fn new(obj: T) -> Self { | ||
28 | match Interned::lookup(&obj) { | ||
29 | Ok(this) => this, | ||
30 | Err(shard) => { | ||
31 | let arc = Arc::new(obj); | ||
32 | Self::alloc(arc, shard) | ||
33 | } | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | |||
38 | impl<T: Internable + ?Sized> Interned<T> { | ||
39 | fn lookup(obj: &T) -> Result<Self, Guard<T>> { | ||
40 | let storage = T::storage().get(); | ||
41 | let shard_idx = storage.determine_map(obj); | ||
42 | let shard = &storage.shards()[shard_idx]; | ||
43 | let shard = shard.write(); | ||
44 | |||
45 | // Atomically, | ||
46 | // - check if `obj` is already in the map | ||
47 | // - if so, clone its `Arc` and return it | ||
48 | // - if not, box it up, insert it, and return a clone | ||
49 | // This needs to be atomic (locking the shard) to avoid races with other thread, which could | ||
50 | // insert the same object between us looking it up and inserting it. | ||
51 | |||
52 | // FIXME: avoid double lookup/hashing by using raw entry API (once stable, or when | ||
53 | // hashbrown can be plugged into dashmap) | ||
54 | match shard.get_key_value(obj) { | ||
55 | Some((arc, _)) => Ok(Self { arc: arc.clone() }), | ||
56 | None => Err(shard), | ||
57 | } | ||
58 | } | ||
59 | |||
60 | fn alloc(arc: Arc<T>, mut shard: Guard<T>) -> Self { | ||
61 | let arc2 = arc.clone(); | ||
62 | |||
63 | shard.insert(arc2, SharedValue::new(())); | ||
64 | |||
65 | Self { arc } | ||
66 | } | ||
67 | } | ||
68 | |||
69 | impl Interned<str> { | ||
70 | pub fn new_str(s: &str) -> Self { | ||
71 | match Interned::lookup(s) { | ||
72 | Ok(this) => this, | ||
73 | Err(shard) => { | ||
74 | let arc = Arc::<str>::from(s); | ||
75 | Self::alloc(arc, shard) | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | impl<T: Internable + ?Sized> Drop for Interned<T> { | ||
82 | #[inline] | ||
83 | fn drop(&mut self) { | ||
84 | // When the last `Ref` is dropped, remove the object from the global map. | ||
85 | if Arc::strong_count(&self.arc) == 2 { | ||
86 | // Only `self` and the global map point to the object. | ||
87 | |||
88 | self.drop_slow(); | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | |||
93 | impl<T: Internable + ?Sized> Interned<T> { | ||
94 | #[cold] | ||
95 | fn drop_slow(&mut self) { | ||
96 | let storage = T::storage().get(); | ||
97 | let shard_idx = storage.determine_map(&self.arc); | ||
98 | let shard = &storage.shards()[shard_idx]; | ||
99 | let mut shard = shard.write(); | ||
100 | |||
101 | // FIXME: avoid double lookup | ||
102 | let (arc, _) = shard.get_key_value(&self.arc).expect("interned value removed prematurely"); | ||
103 | |||
104 | if Arc::strong_count(arc) != 2 { | ||
105 | // Another thread has interned another copy | ||
106 | return; | ||
107 | } | ||
108 | |||
109 | shard.remove(&self.arc); | ||
110 | |||
111 | // Shrink the backing storage if the shard is less than 50% occupied. | ||
112 | if shard.len() * 2 < shard.capacity() { | ||
113 | shard.shrink_to_fit(); | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /// Compares interned `Ref`s using pointer equality. | ||
119 | impl<T: Internable> PartialEq for Interned<T> { | ||
120 | // NOTE: No `?Sized` because `ptr_eq` doesn't work right with trait objects. | ||
121 | |||
122 | #[inline] | ||
123 | fn eq(&self, other: &Self) -> bool { | ||
124 | Arc::ptr_eq(&self.arc, &other.arc) | ||
125 | } | ||
126 | } | ||
127 | |||
128 | impl<T: Internable> Eq for Interned<T> {} | ||
129 | |||
130 | impl PartialEq for Interned<str> { | ||
131 | fn eq(&self, other: &Self) -> bool { | ||
132 | Arc::ptr_eq(&self.arc, &other.arc) | ||
133 | } | ||
134 | } | ||
135 | |||
136 | impl Eq for Interned<str> {} | ||
137 | |||
138 | impl<T: Internable + ?Sized> AsRef<T> for Interned<T> { | ||
139 | #[inline] | ||
140 | fn as_ref(&self) -> &T { | ||
141 | &self.arc | ||
142 | } | ||
143 | } | ||
144 | |||
145 | impl<T: Internable + ?Sized> Deref for Interned<T> { | ||
146 | type Target = T; | ||
147 | |||
148 | #[inline] | ||
149 | fn deref(&self) -> &Self::Target { | ||
150 | &self.arc | ||
151 | } | ||
152 | } | ||
153 | |||
154 | impl<T: Internable + ?Sized> Clone for Interned<T> { | ||
155 | fn clone(&self) -> Self { | ||
156 | Self { arc: self.arc.clone() } | ||
157 | } | ||
158 | } | ||
159 | |||
160 | impl<T: Debug + Internable + ?Sized> Debug for Interned<T> { | ||
161 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
162 | (*self.arc).fmt(f) | ||
163 | } | ||
164 | } | ||
165 | |||
166 | pub struct InternStorage<T: ?Sized> { | ||
167 | map: OnceCell<InternMap<T>>, | ||
168 | } | ||
169 | |||
170 | impl<T: ?Sized> InternStorage<T> { | ||
171 | pub const fn new() -> Self { | ||
172 | Self { map: OnceCell::new() } | ||
173 | } | ||
174 | } | ||
175 | |||
176 | impl<T: Internable + ?Sized> InternStorage<T> { | ||
177 | fn get(&self) -> &InternMap<T> { | ||
178 | self.map.get_or_init(DashMap::default) | ||
179 | } | ||
180 | } | ||
181 | |||
182 | pub trait Internable: Hash + Eq + 'static { | ||
183 | fn storage() -> &'static InternStorage<Self>; | ||
184 | } | ||
185 | |||
186 | macro_rules! impl_internable { | ||
187 | ( $($t:path),+ $(,)? ) => { $( | ||
188 | impl Internable for $t { | ||
189 | fn storage() -> &'static InternStorage<Self> { | ||
190 | static STORAGE: InternStorage<$t> = InternStorage::new(); | ||
191 | &STORAGE | ||
192 | } | ||
193 | } | ||
194 | )+ }; | ||
195 | } | ||
196 | |||
197 | impl_internable!(crate::type_ref::TypeRef, crate::type_ref::TraitRef, crate::path::ModPath, str); | ||
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index f3ebe7c72..a8ee5eeac 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs | |||
@@ -285,6 +285,28 @@ impl ItemScope { | |||
285 | buf.push('\n'); | 285 | buf.push('\n'); |
286 | } | 286 | } |
287 | } | 287 | } |
288 | |||
289 | pub(crate) fn shrink_to_fit(&mut self) { | ||
290 | // Exhaustive match to require handling new fields. | ||
291 | let Self { | ||
292 | types, | ||
293 | values, | ||
294 | macros, | ||
295 | unresolved, | ||
296 | defs, | ||
297 | impls, | ||
298 | unnamed_trait_imports, | ||
299 | legacy_macros, | ||
300 | } = self; | ||
301 | types.shrink_to_fit(); | ||
302 | values.shrink_to_fit(); | ||
303 | macros.shrink_to_fit(); | ||
304 | unresolved.shrink_to_fit(); | ||
305 | defs.shrink_to_fit(); | ||
306 | impls.shrink_to_fit(); | ||
307 | unnamed_trait_imports.shrink_to_fit(); | ||
308 | legacy_macros.shrink_to_fit(); | ||
309 | } | ||
288 | } | 310 | } |
289 | 311 | ||
290 | impl PerNs { | 312 | impl PerNs { |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 5449bbf5d..c6d700977 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -24,12 +24,13 @@ use la_arena::{Arena, Idx, RawIdx}; | |||
24 | use profile::Count; | 24 | use profile::Count; |
25 | use rustc_hash::FxHashMap; | 25 | use rustc_hash::FxHashMap; |
26 | use smallvec::SmallVec; | 26 | use smallvec::SmallVec; |
27 | use syntax::{ast, match_ast, SmolStr, SyntaxKind}; | 27 | use syntax::{ast, match_ast, SyntaxKind}; |
28 | 28 | ||
29 | use crate::{ | 29 | use crate::{ |
30 | attr::{Attrs, RawAttrs}, | 30 | attr::{Attrs, RawAttrs}, |
31 | db::DefDatabase, | 31 | db::DefDatabase, |
32 | generics::GenericParams, | 32 | generics::GenericParams, |
33 | intern::Interned, | ||
33 | path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, | 34 | path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, |
34 | type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, | 35 | type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, |
35 | visibility::RawVisibility, | 36 | visibility::RawVisibility, |
@@ -146,8 +147,6 @@ impl ItemTree { | |||
146 | macro_defs, | 147 | macro_defs, |
147 | vis, | 148 | vis, |
148 | generics, | 149 | generics, |
149 | type_refs, | ||
150 | trait_refs, | ||
151 | inner_items, | 150 | inner_items, |
152 | } = &mut **data; | 151 | } = &mut **data; |
153 | 152 | ||
@@ -172,9 +171,6 @@ impl ItemTree { | |||
172 | 171 | ||
173 | vis.arena.shrink_to_fit(); | 172 | vis.arena.shrink_to_fit(); |
174 | generics.arena.shrink_to_fit(); | 173 | generics.arena.shrink_to_fit(); |
175 | type_refs.arena.shrink_to_fit(); | ||
176 | type_refs.map.shrink_to_fit(); | ||
177 | trait_refs.map.shrink_to_fit(); | ||
178 | 174 | ||
179 | inner_items.shrink_to_fit(); | 175 | inner_items.shrink_to_fit(); |
180 | } | 176 | } |
@@ -271,58 +267,6 @@ static EMPTY_GENERICS: GenericParams = GenericParams { | |||
271 | where_predicates: Vec::new(), | 267 | where_predicates: Vec::new(), |
272 | }; | 268 | }; |
273 | 269 | ||
274 | /// `TypeRef` interner. | ||
275 | #[derive(Default, Debug, Eq, PartialEq)] | ||
276 | struct TypeRefStorage { | ||
277 | arena: Arena<Arc<TypeRef>>, | ||
278 | map: FxHashMap<Arc<TypeRef>, Idx<Arc<TypeRef>>>, | ||
279 | } | ||
280 | |||
281 | impl TypeRefStorage { | ||
282 | // Note: We lie about the `Idx<TypeRef>` to hide the interner details. | ||
283 | |||
284 | fn intern(&mut self, ty: TypeRef) -> Idx<TypeRef> { | ||
285 | if let Some(id) = self.map.get(&ty) { | ||
286 | return Idx::from_raw(id.into_raw()); | ||
287 | } | ||
288 | |||
289 | let ty = Arc::new(ty); | ||
290 | let idx = self.arena.alloc(ty.clone()); | ||
291 | self.map.insert(ty, idx); | ||
292 | Idx::from_raw(idx.into_raw()) | ||
293 | } | ||
294 | |||
295 | fn lookup(&self, id: Idx<TypeRef>) -> &TypeRef { | ||
296 | &self.arena[Idx::from_raw(id.into_raw())] | ||
297 | } | ||
298 | } | ||
299 | |||
300 | /// `TraitRef` interner. | ||
301 | #[derive(Default, Debug, Eq, PartialEq)] | ||
302 | struct TraitRefStorage { | ||
303 | arena: Arena<Arc<TraitRef>>, | ||
304 | map: FxHashMap<Arc<TraitRef>, Idx<Arc<TraitRef>>>, | ||
305 | } | ||
306 | |||
307 | impl TraitRefStorage { | ||
308 | // Note: We lie about the `Idx<TraitRef>` to hide the interner details. | ||
309 | |||
310 | fn intern(&mut self, ty: TraitRef) -> Idx<TraitRef> { | ||
311 | if let Some(id) = self.map.get(&ty) { | ||
312 | return Idx::from_raw(id.into_raw()); | ||
313 | } | ||
314 | |||
315 | let ty = Arc::new(ty); | ||
316 | let idx = self.arena.alloc(ty.clone()); | ||
317 | self.map.insert(ty, idx); | ||
318 | Idx::from_raw(idx.into_raw()) | ||
319 | } | ||
320 | |||
321 | fn lookup(&self, id: Idx<TraitRef>) -> &TraitRef { | ||
322 | &self.arena[Idx::from_raw(id.into_raw())] | ||
323 | } | ||
324 | } | ||
325 | |||
326 | #[derive(Default, Debug, Eq, PartialEq)] | 270 | #[derive(Default, Debug, Eq, PartialEq)] |
327 | struct ItemTreeData { | 271 | struct ItemTreeData { |
328 | imports: Arena<Import>, | 272 | imports: Arena<Import>, |
@@ -346,8 +290,6 @@ struct ItemTreeData { | |||
346 | 290 | ||
347 | vis: ItemVisibilities, | 291 | vis: ItemVisibilities, |
348 | generics: GenericParamsStorage, | 292 | generics: GenericParamsStorage, |
349 | type_refs: TypeRefStorage, | ||
350 | trait_refs: TraitRefStorage, | ||
351 | 293 | ||
352 | inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, | 294 | inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, |
353 | } | 295 | } |
@@ -577,22 +519,6 @@ impl Index<GenericParamsId> for ItemTree { | |||
577 | } | 519 | } |
578 | } | 520 | } |
579 | 521 | ||
580 | impl Index<Idx<TypeRef>> for ItemTree { | ||
581 | type Output = TypeRef; | ||
582 | |||
583 | fn index(&self, id: Idx<TypeRef>) -> &Self::Output { | ||
584 | self.data().type_refs.lookup(id) | ||
585 | } | ||
586 | } | ||
587 | |||
588 | impl Index<Idx<TraitRef>> for ItemTree { | ||
589 | type Output = TraitRef; | ||
590 | |||
591 | fn index(&self, id: Idx<TraitRef>) -> &Self::Output { | ||
592 | self.data().trait_refs.lookup(id) | ||
593 | } | ||
594 | } | ||
595 | |||
596 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | 522 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { |
597 | type Output = N; | 523 | type Output = N; |
598 | fn index(&self, id: FileItemTreeId<N>) -> &N { | 524 | fn index(&self, id: FileItemTreeId<N>) -> &N { |
@@ -603,7 +529,7 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | |||
603 | /// A desugared `use` import. | 529 | /// A desugared `use` import. |
604 | #[derive(Debug, Clone, Eq, PartialEq)] | 530 | #[derive(Debug, Clone, Eq, PartialEq)] |
605 | pub struct Import { | 531 | pub struct Import { |
606 | pub path: ModPath, | 532 | pub path: Interned<ModPath>, |
607 | pub alias: Option<ImportAlias>, | 533 | pub alias: Option<ImportAlias>, |
608 | pub visibility: RawVisibilityId, | 534 | pub visibility: RawVisibilityId, |
609 | pub is_glob: bool, | 535 | pub is_glob: bool, |
@@ -630,30 +556,33 @@ pub struct Function { | |||
630 | pub name: Name, | 556 | pub name: Name, |
631 | pub visibility: RawVisibilityId, | 557 | pub visibility: RawVisibilityId, |
632 | pub generic_params: GenericParamsId, | 558 | pub generic_params: GenericParamsId, |
633 | pub has_self_param: bool, | 559 | pub abi: Option<Interned<str>>, |
634 | pub has_body: bool, | ||
635 | pub qualifier: FunctionQualifier, | ||
636 | /// Whether the function is located in an `extern` block (*not* whether it is an | ||
637 | /// `extern "abi" fn`). | ||
638 | pub is_in_extern_block: bool, | ||
639 | pub params: IdRange<Param>, | 560 | pub params: IdRange<Param>, |
640 | pub ret_type: Idx<TypeRef>, | 561 | pub ret_type: Interned<TypeRef>, |
641 | pub ast_id: FileAstId<ast::Fn>, | 562 | pub ast_id: FileAstId<ast::Fn>, |
563 | pub(crate) flags: FnFlags, | ||
642 | } | 564 | } |
643 | 565 | ||
644 | #[derive(Debug, Clone, Eq, PartialEq)] | 566 | #[derive(Debug, Clone, Eq, PartialEq)] |
645 | pub enum Param { | 567 | pub enum Param { |
646 | Normal(Idx<TypeRef>), | 568 | Normal(Interned<TypeRef>), |
647 | Varargs, | 569 | Varargs, |
648 | } | 570 | } |
649 | 571 | ||
650 | #[derive(Debug, Clone, PartialEq, Eq)] | 572 | bitflags::bitflags! { |
651 | pub struct FunctionQualifier { | 573 | /// NOTE: Shared with `FunctionData` |
652 | pub is_default: bool, | 574 | pub(crate) struct FnFlags: u8 { |
653 | pub is_const: bool, | 575 | const HAS_SELF_PARAM = 1 << 0; |
654 | pub is_async: bool, | 576 | const HAS_BODY = 1 << 1; |
655 | pub is_unsafe: bool, | 577 | const IS_DEFAULT = 1 << 2; |
656 | pub abi: Option<SmolStr>, | 578 | const IS_CONST = 1 << 3; |
579 | const IS_ASYNC = 1 << 4; | ||
580 | const IS_UNSAFE = 1 << 5; | ||
581 | /// Whether the function is located in an `extern` block (*not* whether it is an | ||
582 | /// `extern "abi" fn`). | ||
583 | const IS_IN_EXTERN_BLOCK = 1 << 6; | ||
584 | const IS_VARARGS = 1 << 7; | ||
585 | } | ||
657 | } | 586 | } |
658 | 587 | ||
659 | #[derive(Debug, Clone, Eq, PartialEq)] | 588 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -699,7 +628,7 @@ pub struct Const { | |||
699 | /// const _: () = (); | 628 | /// const _: () = (); |
700 | pub name: Option<Name>, | 629 | pub name: Option<Name>, |
701 | pub visibility: RawVisibilityId, | 630 | pub visibility: RawVisibilityId, |
702 | pub type_ref: Idx<TypeRef>, | 631 | pub type_ref: Interned<TypeRef>, |
703 | pub ast_id: FileAstId<ast::Const>, | 632 | pub ast_id: FileAstId<ast::Const>, |
704 | } | 633 | } |
705 | 634 | ||
@@ -710,7 +639,7 @@ pub struct Static { | |||
710 | pub mutable: bool, | 639 | pub mutable: bool, |
711 | /// Whether the static is in an `extern` block. | 640 | /// Whether the static is in an `extern` block. |
712 | pub is_extern: bool, | 641 | pub is_extern: bool, |
713 | pub type_ref: Idx<TypeRef>, | 642 | pub type_ref: Interned<TypeRef>, |
714 | pub ast_id: FileAstId<ast::Static>, | 643 | pub ast_id: FileAstId<ast::Static>, |
715 | } | 644 | } |
716 | 645 | ||
@@ -729,8 +658,8 @@ pub struct Trait { | |||
729 | #[derive(Debug, Clone, Eq, PartialEq)] | 658 | #[derive(Debug, Clone, Eq, PartialEq)] |
730 | pub struct Impl { | 659 | pub struct Impl { |
731 | pub generic_params: GenericParamsId, | 660 | pub generic_params: GenericParamsId, |
732 | pub target_trait: Option<Idx<TraitRef>>, | 661 | pub target_trait: Option<Interned<TraitRef>>, |
733 | pub self_ty: Idx<TypeRef>, | 662 | pub self_ty: Interned<TypeRef>, |
734 | pub is_negative: bool, | 663 | pub is_negative: bool, |
735 | pub items: Box<[AssocItem]>, | 664 | pub items: Box<[AssocItem]>, |
736 | pub ast_id: FileAstId<ast::Impl>, | 665 | pub ast_id: FileAstId<ast::Impl>, |
@@ -743,7 +672,7 @@ pub struct TypeAlias { | |||
743 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. | 672 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. |
744 | pub bounds: Box<[TypeBound]>, | 673 | pub bounds: Box<[TypeBound]>, |
745 | pub generic_params: GenericParamsId, | 674 | pub generic_params: GenericParamsId, |
746 | pub type_ref: Option<Idx<TypeRef>>, | 675 | pub type_ref: Option<Interned<TypeRef>>, |
747 | pub is_extern: bool, | 676 | pub is_extern: bool, |
748 | pub ast_id: FileAstId<ast::TypeAlias>, | 677 | pub ast_id: FileAstId<ast::TypeAlias>, |
749 | } | 678 | } |
@@ -768,7 +697,7 @@ pub enum ModKind { | |||
768 | #[derive(Debug, Clone, Eq, PartialEq)] | 697 | #[derive(Debug, Clone, Eq, PartialEq)] |
769 | pub struct MacroCall { | 698 | pub struct MacroCall { |
770 | /// Path to the called macro. | 699 | /// Path to the called macro. |
771 | pub path: ModPath, | 700 | pub path: Interned<ModPath>, |
772 | pub ast_id: FileAstId<ast::MacroCall>, | 701 | pub ast_id: FileAstId<ast::MacroCall>, |
773 | } | 702 | } |
774 | 703 | ||
@@ -933,6 +862,6 @@ pub enum Fields { | |||
933 | #[derive(Debug, Clone, PartialEq, Eq)] | 862 | #[derive(Debug, Clone, PartialEq, Eq)] |
934 | pub struct Field { | 863 | pub struct Field { |
935 | pub name: Name, | 864 | pub name: Name, |
936 | pub type_ref: Idx<TypeRef>, | 865 | pub type_ref: Interned<TypeRef>, |
937 | pub visibility: RawVisibilityId, | 866 | pub visibility: RawVisibilityId, |
938 | } | 867 | } |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 124dcc866..39e8403b0 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -362,7 +362,7 @@ impl Ctx { | |||
362 | } | 362 | } |
363 | } | 363 | } |
364 | }; | 364 | }; |
365 | let ty = self.data().type_refs.intern(self_type); | 365 | let ty = Interned::new(self_type); |
366 | let idx = self.data().params.alloc(Param::Normal(ty)); | 366 | let idx = self.data().params.alloc(Param::Normal(ty)); |
367 | self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene)); | 367 | self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene)); |
368 | has_self_param = true; | 368 | has_self_param = true; |
@@ -372,7 +372,7 @@ impl Ctx { | |||
372 | Some(_) => self.data().params.alloc(Param::Varargs), | 372 | Some(_) => self.data().params.alloc(Param::Varargs), |
373 | None => { | 373 | None => { |
374 | let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty()); | 374 | let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty()); |
375 | let ty = self.data().type_refs.intern(type_ref); | 375 | let ty = Interned::new(type_ref); |
376 | self.data().params.alloc(Param::Normal(ty)) | 376 | self.data().params.alloc(Param::Normal(ty)) |
377 | } | 377 | } |
378 | }; | 378 | }; |
@@ -395,41 +395,51 @@ impl Ctx { | |||
395 | ret_type | 395 | ret_type |
396 | }; | 396 | }; |
397 | 397 | ||
398 | let ret_type = self.data().type_refs.intern(ret_type); | 398 | let abi = func.abi().map(|abi| { |
399 | 399 | // FIXME: Abi::abi() -> Option<SyntaxToken>? | |
400 | let has_body = func.body().is_some(); | 400 | match abi.syntax().last_token() { |
401 | Some(tok) if tok.kind() == SyntaxKind::STRING => { | ||
402 | // FIXME: Better way to unescape? | ||
403 | Interned::new_str(tok.text().trim_matches('"')) | ||
404 | } | ||
405 | _ => { | ||
406 | // `extern` default to be `extern "C"`. | ||
407 | Interned::new_str("C") | ||
408 | } | ||
409 | } | ||
410 | }); | ||
401 | 411 | ||
402 | let ast_id = self.source_ast_id_map.ast_id(func); | 412 | let ast_id = self.source_ast_id_map.ast_id(func); |
403 | let qualifier = FunctionQualifier { | 413 | |
404 | is_default: func.default_token().is_some(), | 414 | let mut flags = FnFlags::empty(); |
405 | is_const: func.const_token().is_some(), | 415 | if func.body().is_some() { |
406 | is_async: func.async_token().is_some(), | 416 | flags |= FnFlags::HAS_BODY; |
407 | is_unsafe: func.unsafe_token().is_some(), | 417 | } |
408 | abi: func.abi().map(|abi| { | 418 | if has_self_param { |
409 | // FIXME: Abi::abi() -> Option<SyntaxToken>? | 419 | flags |= FnFlags::HAS_SELF_PARAM; |
410 | match abi.syntax().last_token() { | 420 | } |
411 | Some(tok) if tok.kind() == SyntaxKind::STRING => { | 421 | if func.default_token().is_some() { |
412 | // FIXME: Better way to unescape? | 422 | flags |= FnFlags::IS_DEFAULT; |
413 | tok.text().trim_matches('"').into() | 423 | } |
414 | } | 424 | if func.const_token().is_some() { |
415 | _ => { | 425 | flags |= FnFlags::IS_CONST; |
416 | // `extern` default to be `extern "C"`. | 426 | } |
417 | "C".into() | 427 | if func.async_token().is_some() { |
418 | } | 428 | flags |= FnFlags::IS_ASYNC; |
419 | } | 429 | } |
420 | }), | 430 | if func.unsafe_token().is_some() { |
421 | }; | 431 | flags |= FnFlags::IS_UNSAFE; |
432 | } | ||
433 | |||
422 | let mut res = Function { | 434 | let mut res = Function { |
423 | name, | 435 | name, |
424 | visibility, | 436 | visibility, |
425 | generic_params: GenericParamsId::EMPTY, | 437 | generic_params: GenericParamsId::EMPTY, |
426 | has_self_param, | 438 | abi, |
427 | has_body, | ||
428 | qualifier, | ||
429 | is_in_extern_block: false, | ||
430 | params, | 439 | params, |
431 | ret_type, | 440 | ret_type: Interned::new(ret_type), |
432 | ast_id, | 441 | ast_id, |
442 | flags, | ||
433 | }; | 443 | }; |
434 | res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); | 444 | res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); |
435 | 445 | ||
@@ -579,7 +589,7 @@ impl Ctx { | |||
579 | &self.hygiene, | 589 | &self.hygiene, |
580 | |path, _use_tree, is_glob, alias| { | 590 | |path, _use_tree, is_glob, alias| { |
581 | imports.push(id(tree.imports.alloc(Import { | 591 | imports.push(id(tree.imports.alloc(Import { |
582 | path, | 592 | path: Interned::new(path), |
583 | alias, | 593 | alias, |
584 | visibility, | 594 | visibility, |
585 | is_glob, | 595 | is_glob, |
@@ -608,7 +618,7 @@ impl Ctx { | |||
608 | } | 618 | } |
609 | 619 | ||
610 | fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { | 620 | fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { |
611 | let path = ModPath::from_src(m.path()?, &self.hygiene)?; | 621 | let path = Interned::new(ModPath::from_src(m.path()?, &self.hygiene)?); |
612 | let ast_id = self.source_ast_id_map.ast_id(m); | 622 | let ast_id = self.source_ast_id_map.ast_id(m); |
613 | let res = MacroCall { path, ast_id }; | 623 | let res = MacroCall { path, ast_id }; |
614 | Some(id(self.data().macro_calls.alloc(res))) | 624 | Some(id(self.data().macro_calls.alloc(res))) |
@@ -642,8 +652,10 @@ impl Ctx { | |||
642 | ast::ExternItem::Fn(ast) => { | 652 | ast::ExternItem::Fn(ast) => { |
643 | let func_id = self.lower_function(&ast)?; | 653 | let func_id = self.lower_function(&ast)?; |
644 | let func = &mut self.data().functions[func_id.index]; | 654 | let func = &mut self.data().functions[func_id.index]; |
645 | func.qualifier.is_unsafe = is_intrinsic_fn_unsafe(&func.name); | 655 | if is_intrinsic_fn_unsafe(&func.name) { |
646 | func.is_in_extern_block = true; | 656 | func.flags |= FnFlags::IS_UNSAFE; |
657 | } | ||
658 | func.flags |= FnFlags::IS_IN_EXTERN_BLOCK; | ||
647 | func_id.into() | 659 | func_id.into() |
648 | } | 660 | } |
649 | ast::ExternItem::Static(ast) => { | 661 | ast::ExternItem::Static(ast) => { |
@@ -694,8 +706,7 @@ impl Ctx { | |||
694 | generics.fill(&self.body_ctx, sm, node); | 706 | generics.fill(&self.body_ctx, sm, node); |
695 | // lower `impl Trait` in arguments | 707 | // lower `impl Trait` in arguments |
696 | for id in func.params.clone() { | 708 | for id in func.params.clone() { |
697 | if let Param::Normal(ty) = self.data().params[id] { | 709 | if let Param::Normal(ty) = &self.data().params[id] { |
698 | let ty = self.data().type_refs.lookup(ty); | ||
699 | generics.fill_implicit_impl_trait_args(ty); | 710 | generics.fill_implicit_impl_trait_args(ty); |
700 | } | 711 | } |
701 | } | 712 | } |
@@ -749,20 +760,20 @@ impl Ctx { | |||
749 | self.data().vis.alloc(vis) | 760 | self.data().vis.alloc(vis) |
750 | } | 761 | } |
751 | 762 | ||
752 | fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Idx<TraitRef>> { | 763 | fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Interned<TraitRef>> { |
753 | let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?; | 764 | let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?; |
754 | Some(self.data().trait_refs.intern(trait_ref)) | 765 | Some(Interned::new(trait_ref)) |
755 | } | 766 | } |
756 | 767 | ||
757 | fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Idx<TypeRef> { | 768 | fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Interned<TypeRef> { |
758 | let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); | 769 | let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); |
759 | self.data().type_refs.intern(tyref) | 770 | Interned::new(tyref) |
760 | } | 771 | } |
761 | 772 | ||
762 | fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Idx<TypeRef> { | 773 | fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Interned<TypeRef> { |
763 | match type_ref.map(|ty| self.lower_type_ref(&ty)) { | 774 | match type_ref.map(|ty| self.lower_type_ref(&ty)) { |
764 | Some(it) => it, | 775 | Some(it) => it, |
765 | None => self.data().type_refs.intern(TypeRef::Error), | 776 | None => Interned::new(TypeRef::Error), |
766 | } | 777 | } |
767 | } | 778 | } |
768 | 779 | ||
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index c9e07de86..f408e510a 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -49,6 +49,7 @@ pub mod import_map; | |||
49 | 49 | ||
50 | #[cfg(test)] | 50 | #[cfg(test)] |
51 | mod test_db; | 51 | mod test_db; |
52 | mod intern; | ||
52 | 53 | ||
53 | use std::{ | 54 | use std::{ |
54 | hash::{Hash, Hasher}, | 55 | hash::{Hash, Hasher}, |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 9e8e4e9ec..7dd68219f 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -409,6 +409,31 @@ impl DefMap { | |||
409 | } | 409 | } |
410 | } | 410 | } |
411 | } | 411 | } |
412 | |||
413 | fn shrink_to_fit(&mut self) { | ||
414 | // Exhaustive match to require handling new fields. | ||
415 | let Self { | ||
416 | _c: _, | ||
417 | exported_proc_macros, | ||
418 | extern_prelude, | ||
419 | diagnostics, | ||
420 | modules, | ||
421 | block: _, | ||
422 | edition: _, | ||
423 | krate: _, | ||
424 | prelude: _, | ||
425 | root: _, | ||
426 | } = self; | ||
427 | |||
428 | extern_prelude.shrink_to_fit(); | ||
429 | exported_proc_macros.shrink_to_fit(); | ||
430 | diagnostics.shrink_to_fit(); | ||
431 | modules.shrink_to_fit(); | ||
432 | for (_, module) in modules.iter_mut() { | ||
433 | module.children.shrink_to_fit(); | ||
434 | module.scope.shrink_to_fit(); | ||
435 | } | ||
436 | } | ||
412 | } | 437 | } |
413 | 438 | ||
414 | impl ModuleData { | 439 | impl ModuleData { |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index d58135ec9..4ddc791ce 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -23,6 +23,7 @@ use crate::{ | |||
23 | attr::Attrs, | 23 | attr::Attrs, |
24 | db::DefDatabase, | 24 | db::DefDatabase, |
25 | derive_macro_as_call_id, | 25 | derive_macro_as_call_id, |
26 | intern::Interned, | ||
26 | item_scope::{ImportType, PerNsGlobImports}, | 27 | item_scope::{ImportType, PerNsGlobImports}, |
27 | item_tree::{ | 28 | item_tree::{ |
28 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod, ModItem, | 29 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod, ModItem, |
@@ -54,20 +55,22 @@ pub(super) fn collect_defs( | |||
54 | ) -> DefMap { | 55 | ) -> DefMap { |
55 | let crate_graph = db.crate_graph(); | 56 | let crate_graph = db.crate_graph(); |
56 | 57 | ||
57 | // populate external prelude | 58 | if block.is_none() { |
58 | for dep in &crate_graph[def_map.krate].dependencies { | 59 | // populate external prelude |
59 | log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); | 60 | for dep in &crate_graph[def_map.krate].dependencies { |
60 | let dep_def_map = db.crate_def_map(dep.crate_id); | 61 | log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); |
61 | def_map | 62 | let dep_def_map = db.crate_def_map(dep.crate_id); |
62 | .extern_prelude | 63 | def_map |
63 | .insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into()); | 64 | .extern_prelude |
64 | 65 | .insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into()); | |
65 | // look for the prelude | 66 | |
66 | // If the dependency defines a prelude, we overwrite an already defined | 67 | // look for the prelude |
67 | // prelude. This is necessary to import the "std" prelude if a crate | 68 | // If the dependency defines a prelude, we overwrite an already defined |
68 | // depends on both "core" and "std". | 69 | // prelude. This is necessary to import the "std" prelude if a crate |
69 | if dep_def_map.prelude.is_some() { | 70 | // depends on both "core" and "std". |
70 | def_map.prelude = dep_def_map.prelude; | 71 | if dep_def_map.prelude.is_some() { |
72 | def_map.prelude = dep_def_map.prelude; | ||
73 | } | ||
71 | } | 74 | } |
72 | } | 75 | } |
73 | 76 | ||
@@ -106,7 +109,9 @@ pub(super) fn collect_defs( | |||
106 | } | 109 | } |
107 | } | 110 | } |
108 | collector.collect(); | 111 | collector.collect(); |
109 | collector.finish() | 112 | let mut def_map = collector.finish(); |
113 | def_map.shrink_to_fit(); | ||
114 | def_map | ||
110 | } | 115 | } |
111 | 116 | ||
112 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | 117 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
@@ -137,7 +142,7 @@ enum ImportSource { | |||
137 | 142 | ||
138 | #[derive(Clone, Debug, Eq, PartialEq)] | 143 | #[derive(Clone, Debug, Eq, PartialEq)] |
139 | struct Import { | 144 | struct Import { |
140 | path: ModPath, | 145 | path: Interned<ModPath>, |
141 | alias: Option<ImportAlias>, | 146 | alias: Option<ImportAlias>, |
142 | visibility: RawVisibility, | 147 | visibility: RawVisibility, |
143 | is_glob: bool, | 148 | is_glob: bool, |
@@ -179,7 +184,10 @@ impl Import { | |||
179 | let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); | 184 | let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); |
180 | let visibility = &tree[it.visibility]; | 185 | let visibility = &tree[it.visibility]; |
181 | Self { | 186 | Self { |
182 | path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())), | 187 | path: Interned::new(ModPath::from_segments( |
188 | PathKind::Plain, | ||
189 | iter::once(it.name.clone()), | ||
190 | )), | ||
183 | alias: it.alias.clone(), | 191 | alias: it.alias.clone(), |
184 | visibility: visibility.clone(), | 192 | visibility: visibility.clone(), |
185 | is_glob: false, | 193 | is_glob: false, |
@@ -1400,8 +1408,18 @@ impl ModCollector<'_, '_> { | |||
1400 | 1408 | ||
1401 | // Case 1: builtin macros | 1409 | // Case 1: builtin macros |
1402 | if attrs.by_key("rustc_builtin_macro").exists() { | 1410 | if attrs.by_key("rustc_builtin_macro").exists() { |
1411 | // `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name. | ||
1412 | let name; | ||
1413 | let name = match attrs.by_key("rustc_builtin_macro").string_value() { | ||
1414 | Some(it) => { | ||
1415 | // FIXME: a hacky way to create a Name from string. | ||
1416 | name = tt::Ident { text: it.clone(), id: tt::TokenId::unspecified() }.as_name(); | ||
1417 | &name | ||
1418 | } | ||
1419 | None => &mac.name, | ||
1420 | }; | ||
1403 | let krate = self.def_collector.def_map.krate; | 1421 | let krate = self.def_collector.def_map.krate; |
1404 | if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) { | 1422 | if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) { |
1405 | self.def_collector.define_macro_rules( | 1423 | self.def_collector.define_macro_rules( |
1406 | self.module_id, | 1424 | self.module_id, |
1407 | mac.name.clone(), | 1425 | mac.name.clone(), |
@@ -1464,7 +1482,7 @@ impl ModCollector<'_, '_> { | |||
1464 | } | 1482 | } |
1465 | 1483 | ||
1466 | fn collect_macro_call(&mut self, mac: &MacroCall) { | 1484 | fn collect_macro_call(&mut self, mac: &MacroCall) { |
1467 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); | 1485 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, (*mac.path).clone()); |
1468 | 1486 | ||
1469 | // Case 1: try to resolve in legacy scope and expand macro_rules | 1487 | // Case 1: try to resolve in legacy scope and expand macro_rules |
1470 | let mut error = None; | 1488 | let mut error = None; |
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs index a89061c2e..fefdadb22 100644 --- a/crates/hir_def/src/nameres/tests/diagnostics.rs +++ b/crates/hir_def/src/nameres/tests/diagnostics.rs | |||
@@ -7,6 +7,11 @@ fn check_diagnostics(ra_fixture: &str) { | |||
7 | db.check_diagnostics(); | 7 | db.check_diagnostics(); |
8 | } | 8 | } |
9 | 9 | ||
10 | fn check_no_diagnostics(ra_fixture: &str) { | ||
11 | let db: TestDB = TestDB::with_files(ra_fixture); | ||
12 | db.check_no_diagnostics(); | ||
13 | } | ||
14 | |||
10 | #[test] | 15 | #[test] |
11 | fn unresolved_import() { | 16 | fn unresolved_import() { |
12 | check_diagnostics( | 17 | check_diagnostics( |
@@ -202,6 +207,21 @@ fn builtin_macro_fails_expansion() { | |||
202 | } | 207 | } |
203 | 208 | ||
204 | #[test] | 209 | #[test] |
210 | fn include_macro_should_allow_empty_content() { | ||
211 | check_no_diagnostics( | ||
212 | r#" | ||
213 | //- /lib.rs | ||
214 | #[rustc_builtin_macro] | ||
215 | macro_rules! include { () => {} } | ||
216 | |||
217 | include!("bar.rs"); | ||
218 | //- /bar.rs | ||
219 | // empty | ||
220 | "#, | ||
221 | ); | ||
222 | } | ||
223 | |||
224 | #[test] | ||
205 | fn good_out_dir_diagnostic() { | 225 | fn good_out_dir_diagnostic() { |
206 | check_diagnostics( | 226 | check_diagnostics( |
207 | r#" | 227 | r#" |
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index 8c923bb7b..a3e83e2cf 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs | |||
@@ -7,7 +7,7 @@ use std::{ | |||
7 | sync::Arc, | 7 | sync::Arc, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | use crate::{body::LowerCtx, type_ref::LifetimeRef}; | 10 | use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef}; |
11 | use base_db::CrateId; | 11 | use base_db::CrateId; |
12 | use hir_expand::{ | 12 | use hir_expand::{ |
13 | hygiene::Hygiene, | 13 | hygiene::Hygiene, |
@@ -48,7 +48,7 @@ pub enum ImportAlias { | |||
48 | 48 | ||
49 | impl ModPath { | 49 | impl ModPath { |
50 | pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { | 50 | pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { |
51 | lower::lower_path(path, hygiene).map(|it| it.mod_path) | 51 | lower::lower_path(path, hygiene).map(|it| (*it.mod_path).clone()) |
52 | } | 52 | } |
53 | 53 | ||
54 | pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { | 54 | pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { |
@@ -123,7 +123,7 @@ pub struct Path { | |||
123 | /// Type based path like `<T>::foo`. | 123 | /// Type based path like `<T>::foo`. |
124 | /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`. | 124 | /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`. |
125 | type_anchor: Option<Box<TypeRef>>, | 125 | type_anchor: Option<Box<TypeRef>>, |
126 | mod_path: ModPath, | 126 | mod_path: Interned<ModPath>, |
127 | /// Invariant: the same len as `self.mod_path.segments` | 127 | /// Invariant: the same len as `self.mod_path.segments` |
128 | generic_args: Vec<Option<Arc<GenericArgs>>>, | 128 | generic_args: Vec<Option<Arc<GenericArgs>>>, |
129 | } | 129 | } |
@@ -176,7 +176,7 @@ impl Path { | |||
176 | path: ModPath, | 176 | path: ModPath, |
177 | generic_args: Vec<Option<Arc<GenericArgs>>>, | 177 | generic_args: Vec<Option<Arc<GenericArgs>>>, |
178 | ) -> Path { | 178 | ) -> Path { |
179 | Path { type_anchor: None, mod_path: path, generic_args } | 179 | Path { type_anchor: None, mod_path: Interned::new(path), generic_args } |
180 | } | 180 | } |
181 | 181 | ||
182 | pub fn kind(&self) -> &PathKind { | 182 | pub fn kind(&self) -> &PathKind { |
@@ -204,10 +204,10 @@ impl Path { | |||
204 | } | 204 | } |
205 | let res = Path { | 205 | let res = Path { |
206 | type_anchor: self.type_anchor.clone(), | 206 | type_anchor: self.type_anchor.clone(), |
207 | mod_path: ModPath::from_segments( | 207 | mod_path: Interned::new(ModPath::from_segments( |
208 | self.mod_path.kind.clone(), | 208 | self.mod_path.kind.clone(), |
209 | self.mod_path.segments[..self.mod_path.segments.len() - 1].iter().cloned(), | 209 | self.mod_path.segments[..self.mod_path.segments.len() - 1].iter().cloned(), |
210 | ), | 210 | )), |
211 | generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(), | 211 | generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(), |
212 | }; | 212 | }; |
213 | Some(res) | 213 | Some(res) |
@@ -283,7 +283,7 @@ impl From<Name> for Path { | |||
283 | fn from(name: Name) -> Path { | 283 | fn from(name: Name) -> Path { |
284 | Path { | 284 | Path { |
285 | type_anchor: None, | 285 | type_anchor: None, |
286 | mod_path: ModPath::from_segments(PathKind::Plain, iter::once(name)), | 286 | mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))), |
287 | generic_args: vec![None], | 287 | generic_args: vec![None], |
288 | } | 288 | } |
289 | } | 289 | } |
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 4de951fd3..28f6244da 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | mod lower_use; | 3 | mod lower_use; |
4 | 4 | ||
5 | use crate::intern::Interned; | ||
5 | use std::sync::Arc; | 6 | use std::sync::Arc; |
6 | 7 | ||
7 | use either::Either; | 8 | use either::Either; |
@@ -74,10 +75,11 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
74 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | 75 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo |
75 | Some(trait_ref) => { | 76 | Some(trait_ref) => { |
76 | let path = Path::from_src(trait_ref.path()?, hygiene)?; | 77 | let path = Path::from_src(trait_ref.path()?, hygiene)?; |
78 | let mod_path = (*path.mod_path).clone(); | ||
77 | let num_segments = path.mod_path.segments.len(); | 79 | let num_segments = path.mod_path.segments.len(); |
78 | kind = path.mod_path.kind; | 80 | kind = mod_path.kind; |
79 | 81 | ||
80 | let mut prefix_segments = path.mod_path.segments; | 82 | let mut prefix_segments = mod_path.segments; |
81 | prefix_segments.reverse(); | 83 | prefix_segments.reverse(); |
82 | segments.extend(prefix_segments); | 84 | segments.extend(prefix_segments); |
83 | 85 | ||
@@ -140,7 +142,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
140 | } | 142 | } |
141 | } | 143 | } |
142 | 144 | ||
143 | let mod_path = ModPath::from_segments(kind, segments); | 145 | let mod_path = Interned::new(ModPath::from_segments(kind, segments)); |
144 | return Some(Path { type_anchor, mod_path, generic_args }); | 146 | return Some(Path { type_anchor, mod_path, generic_args }); |
145 | 147 | ||
146 | fn qualifier(path: &ast::Path) -> Option<ast::Path> { | 148 | fn qualifier(path: &ast::Path) -> Option<ast::Path> { |
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs index 10977761c..dd36106f8 100644 --- a/crates/hir_def/src/test_db.rs +++ b/crates/hir_def/src/test_db.rs | |||
@@ -265,4 +265,17 @@ impl TestDB { | |||
265 | 265 | ||
266 | assert_eq!(annotations, actual); | 266 | assert_eq!(annotations, actual); |
267 | } | 267 | } |
268 | |||
269 | pub(crate) fn check_no_diagnostics(&self) { | ||
270 | let db: &TestDB = self; | ||
271 | let annotations = db.extract_annotations(); | ||
272 | assert!(annotations.is_empty()); | ||
273 | |||
274 | let mut has_diagnostics = false; | ||
275 | db.diagnostics(|_| { | ||
276 | has_diagnostics = true; | ||
277 | }); | ||
278 | |||
279 | assert!(!has_diagnostics); | ||
280 | } | ||
268 | } | 281 | } |