diff options
Diffstat (limited to 'crates/hir_def')
24 files changed, 799 insertions, 312 deletions
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index 475d337f3..43324d8d9 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -11,6 +11,7 @@ doctest = false | |||
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 13 | cov-mark = { version = "1.1", features = ["thread-local"] } |
14 | dashmap = { version = "4.0.2", features = ["raw-api"] } | ||
14 | log = "0.4.8" | 15 | log = "0.4.8" |
15 | once_cell = "1.3.1" | 16 | once_cell = "1.3.1" |
16 | rustc-hash = "1.1.0" | 17 | 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..ab77d924a 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -1,6 +1,10 @@ | |||
1 | //! A higher level attributes based on TokenTree, with also some shortcuts. | 1 | //! A higher level attributes based on TokenTree, with also some shortcuts. |
2 | 2 | ||
3 | use std::{ops, sync::Arc}; | 3 | use std::{ |
4 | convert::{TryFrom, TryInto}, | ||
5 | ops, | ||
6 | sync::Arc, | ||
7 | }; | ||
4 | 8 | ||
5 | use base_db::CrateId; | 9 | use base_db::CrateId; |
6 | use cfg::{CfgExpr, CfgOptions}; | 10 | use cfg::{CfgExpr, CfgOptions}; |
@@ -12,12 +16,13 @@ use mbe::ast_to_token_tree; | |||
12 | use smallvec::{smallvec, SmallVec}; | 16 | use smallvec::{smallvec, SmallVec}; |
13 | use syntax::{ | 17 | use syntax::{ |
14 | ast::{self, AstNode, AttrsOwner}, | 18 | ast::{self, AstNode, AttrsOwner}, |
15 | match_ast, AstToken, SmolStr, SyntaxNode, | 19 | match_ast, AstToken, SmolStr, SyntaxNode, TextRange, TextSize, |
16 | }; | 20 | }; |
17 | use tt::Subtree; | 21 | use tt::Subtree; |
18 | 22 | ||
19 | use crate::{ | 23 | use crate::{ |
20 | db::DefDatabase, | 24 | db::DefDatabase, |
25 | intern::Interned, | ||
21 | item_tree::{ItemTreeId, ItemTreeNode}, | 26 | item_tree::{ItemTreeId, ItemTreeNode}, |
22 | nameres::ModuleSource, | 27 | nameres::ModuleSource, |
23 | path::{ModPath, PathKind}, | 28 | path::{ModPath, PathKind}, |
@@ -98,7 +103,7 @@ impl RawAttrs { | |||
98 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { | 103 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { |
99 | index: i as u32, | 104 | index: i as u32, |
100 | input: Some(AttrInput::Literal(SmolStr::new(doc))), | 105 | input: Some(AttrInput::Literal(SmolStr::new(doc))), |
101 | path: ModPath::from(hir_expand::name!(doc)), | 106 | path: Interned::new(ModPath::from(hir_expand::name!(doc))), |
102 | }), | 107 | }), |
103 | }) | 108 | }) |
104 | .collect::<Arc<_>>(); | 109 | .collect::<Arc<_>>(); |
@@ -451,6 +456,55 @@ impl AttrsWithOwner { | |||
451 | .collect(), | 456 | .collect(), |
452 | } | 457 | } |
453 | } | 458 | } |
459 | |||
460 | pub fn docs_with_rangemap( | ||
461 | &self, | ||
462 | db: &dyn DefDatabase, | ||
463 | ) -> Option<(Documentation, DocsRangeMap)> { | ||
464 | // FIXME: code duplication in `docs` above | ||
465 | let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { | ||
466 | AttrInput::Literal(s) => Some((s, attr.index)), | ||
467 | AttrInput::TokenTree(_) => None, | ||
468 | }); | ||
469 | let indent = docs | ||
470 | .clone() | ||
471 | .flat_map(|(s, _)| s.lines()) | ||
472 | .filter(|line| !line.chars().all(|c| c.is_whitespace())) | ||
473 | .map(|line| line.chars().take_while(|c| c.is_whitespace()).count()) | ||
474 | .min() | ||
475 | .unwrap_or(0); | ||
476 | let mut buf = String::new(); | ||
477 | let mut mapping = Vec::new(); | ||
478 | for (doc, idx) in docs { | ||
479 | // str::lines doesn't yield anything for the empty string | ||
480 | if !doc.is_empty() { | ||
481 | for line in doc.split('\n') { | ||
482 | let line = line.trim_end(); | ||
483 | let line_len = line.len(); | ||
484 | let (offset, line) = match line.char_indices().nth(indent) { | ||
485 | Some((offset, _)) => (offset, &line[offset..]), | ||
486 | None => (0, line), | ||
487 | }; | ||
488 | let buf_offset = buf.len(); | ||
489 | buf.push_str(line); | ||
490 | mapping.push(( | ||
491 | TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?), | ||
492 | idx, | ||
493 | TextRange::new(offset.try_into().ok()?, line_len.try_into().ok()?), | ||
494 | )); | ||
495 | buf.push('\n'); | ||
496 | } | ||
497 | } else { | ||
498 | buf.push('\n'); | ||
499 | } | ||
500 | } | ||
501 | buf.pop(); | ||
502 | if buf.is_empty() { | ||
503 | None | ||
504 | } else { | ||
505 | Some((Documentation(buf), DocsRangeMap { mapping, source: self.source_map(db).attrs })) | ||
506 | } | ||
507 | } | ||
454 | } | 508 | } |
455 | 509 | ||
456 | fn inner_attributes( | 510 | fn inner_attributes( |
@@ -507,10 +561,48 @@ impl AttrSourceMap { | |||
507 | } | 561 | } |
508 | } | 562 | } |
509 | 563 | ||
564 | /// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree. | ||
565 | pub struct DocsRangeMap { | ||
566 | source: Vec<InFile<Either<ast::Attr, ast::Comment>>>, | ||
567 | // (docstring-line-range, attr_index, attr-string-range) | ||
568 | // a mapping from the text range of a line of the [`Documentation`] to the attribute index and | ||
569 | // the original (untrimmed) syntax doc line | ||
570 | mapping: Vec<(TextRange, u32, TextRange)>, | ||
571 | } | ||
572 | |||
573 | impl DocsRangeMap { | ||
574 | pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> { | ||
575 | let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?; | ||
576 | let (line_docs_range, idx, original_line_src_range) = self.mapping[found].clone(); | ||
577 | if !line_docs_range.contains_range(range) { | ||
578 | return None; | ||
579 | } | ||
580 | |||
581 | let relative_range = range - line_docs_range.start(); | ||
582 | |||
583 | let &InFile { file_id, value: ref source } = &self.source[idx as usize]; | ||
584 | match source { | ||
585 | Either::Left(_) => None, // FIXME, figure out a nice way to handle doc attributes here | ||
586 | // as well as for whats done in syntax highlight doc injection | ||
587 | Either::Right(comment) => { | ||
588 | let text_range = comment.syntax().text_range(); | ||
589 | let range = TextRange::at( | ||
590 | text_range.start() | ||
591 | + TextSize::try_from(comment.prefix().len()).ok()? | ||
592 | + original_line_src_range.start() | ||
593 | + relative_range.start(), | ||
594 | text_range.len().min(range.len()), | ||
595 | ); | ||
596 | Some(InFile { file_id, value: range }) | ||
597 | } | ||
598 | } | ||
599 | } | ||
600 | } | ||
601 | |||
510 | #[derive(Debug, Clone, PartialEq, Eq)] | 602 | #[derive(Debug, Clone, PartialEq, Eq)] |
511 | pub struct Attr { | 603 | pub struct Attr { |
512 | index: u32, | 604 | index: u32, |
513 | pub(crate) path: ModPath, | 605 | pub(crate) path: Interned<ModPath>, |
514 | pub(crate) input: Option<AttrInput>, | 606 | pub(crate) input: Option<AttrInput>, |
515 | } | 607 | } |
516 | 608 | ||
@@ -524,7 +616,7 @@ pub enum AttrInput { | |||
524 | 616 | ||
525 | impl Attr { | 617 | impl Attr { |
526 | fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> { | 618 | fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> { |
527 | let path = ModPath::from_src(ast.path()?, hygiene)?; | 619 | let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?); |
528 | let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { | 620 | let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { |
529 | let value = match lit.kind() { | 621 | let value = match lit.kind() { |
530 | ast::LiteralKind::String(string) => string.value()?.into(), | 622 | ast::LiteralKind::String(string) => string.value()?.into(), |
@@ -532,7 +624,7 @@ impl Attr { | |||
532 | }; | 624 | }; |
533 | Some(AttrInput::Literal(value)) | 625 | Some(AttrInput::Literal(value)) |
534 | } else if let Some(tt) = ast.token_tree() { | 626 | } else if let Some(tt) = ast.token_tree() { |
535 | Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0)) | 627 | Some(AttrInput::TokenTree(ast_to_token_tree(&tt).0)) |
536 | } else { | 628 | } else { |
537 | None | 629 | None |
538 | }; | 630 | }; |
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 0be868ba2..135a6698e 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs | |||
@@ -9,8 +9,9 @@ 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 | type_ref::{TypeBound, TypeRef}, | 13 | item_tree::{AssocItem, FnFlags, ItemTreeId, ModItem, Param}, |
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, |
16 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | 17 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, |
@@ -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.bits |= 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.bits & FnFlags::HAS_BODY != 0 | ||
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.bits & FnFlags::HAS_SELF_PARAM != 0 | ||
81 | } | ||
82 | |||
83 | pub fn is_default(&self) -> bool { | ||
84 | self.flags.bits & FnFlags::IS_DEFAULT != 0 | ||
85 | } | ||
86 | |||
87 | pub fn is_const(&self) -> bool { | ||
88 | self.flags.bits & FnFlags::IS_CONST != 0 | ||
89 | } | ||
90 | |||
91 | pub fn is_async(&self) -> bool { | ||
92 | self.flags.bits & FnFlags::IS_ASYNC != 0 | ||
93 | } | ||
94 | |||
95 | pub fn is_unsafe(&self) -> bool { | ||
96 | self.flags.bits & FnFlags::IS_UNSAFE != 0 | ||
97 | } | ||
98 | |||
99 | pub fn is_in_extern_block(&self) -> bool { | ||
100 | self.flags.bits & FnFlags::IS_IN_EXTERN_BLOCK != 0 | ||
101 | } | ||
102 | |||
103 | pub fn is_varargs(&self) -> bool { | ||
104 | self.flags.bits & FnFlags::IS_VARARGS != 0 | ||
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<TypeRef>, | 191 | pub target_trait: Option<Interned<TraitRef>>, |
160 | pub target_type: 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 target_type = item_tree[impl_def.target_type].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); |
@@ -187,7 +219,7 @@ impl ImplData { | |||
187 | ); | 219 | ); |
188 | let items = items.into_iter().map(|(_, item)| item).collect(); | 220 | let items = items.into_iter().map(|(_, item)| item).collect(); |
189 | 221 | ||
190 | Arc::new(ImplData { target_trait, target_type, items, is_negative }) | 222 | Arc::new(ImplData { target_trait, self_ty, items, is_negative }) |
191 | } | 223 | } |
192 | } | 224 | } |
193 | 225 | ||
@@ -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/db.rs b/crates/hir_def/src/db.rs index 068b2ee38..9b7a213a1 100644 --- a/crates/hir_def/src/db.rs +++ b/crates/hir_def/src/db.rs | |||
@@ -13,6 +13,7 @@ use crate::{ | |||
13 | data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData}, | 13 | data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData}, |
14 | generics::GenericParams, | 14 | generics::GenericParams, |
15 | import_map::ImportMap, | 15 | import_map::ImportMap, |
16 | intern::Interned, | ||
16 | item_tree::ItemTree, | 17 | item_tree::ItemTree, |
17 | lang_item::{LangItemTarget, LangItems}, | 18 | lang_item::{LangItemTarget, LangItems}, |
18 | nameres::DefMap, | 19 | nameres::DefMap, |
@@ -113,7 +114,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | |||
113 | fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>; | 114 | fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>; |
114 | 115 | ||
115 | #[salsa::invoke(GenericParams::generic_params_query)] | 116 | #[salsa::invoke(GenericParams::generic_params_query)] |
116 | fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; | 117 | fn generic_params(&self, def: GenericDefId) -> Interned<GenericParams>; |
117 | 118 | ||
118 | #[salsa::invoke(Attrs::variants_attrs_query)] | 119 | #[salsa::invoke(Attrs::variants_attrs_query)] |
119 | fn variants_attrs(&self, def: EnumId) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>>; | 120 | fn variants_attrs(&self, def: EnumId) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>>; |
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 7c6cbff11..de5acced8 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -2,7 +2,6 @@ | |||
2 | //! structs, impls, traits, etc. This module provides a common HIR for these | 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 | 3 | //! generic parameters. See also the `Generics` type and the `generics_of` query |
4 | //! in rustc. | 4 | //! in rustc. |
5 | use std::sync::Arc; | ||
6 | 5 | ||
7 | use base_db::FileId; | 6 | use base_db::FileId; |
8 | use either::Either; | 7 | use either::Either; |
@@ -18,6 +17,7 @@ use crate::{ | |||
18 | child_by_source::ChildBySource, | 17 | child_by_source::ChildBySource, |
19 | db::DefDatabase, | 18 | db::DefDatabase, |
20 | dyn_map::DynMap, | 19 | dyn_map::DynMap, |
20 | intern::Interned, | ||
21 | keys, | 21 | keys, |
22 | src::{HasChildSource, HasSource}, | 22 | src::{HasChildSource, HasSource}, |
23 | type_ref::{LifetimeRef, TypeBound, TypeRef}, | 23 | type_ref::{LifetimeRef, TypeBound, TypeRef}, |
@@ -26,27 +26,27 @@ use crate::{ | |||
26 | }; | 26 | }; |
27 | 27 | ||
28 | /// Data about a generic type parameter (to a function, struct, impl, ...). | 28 | /// Data about a generic type parameter (to a function, struct, impl, ...). |
29 | #[derive(Clone, PartialEq, Eq, Debug)] | 29 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
30 | pub struct TypeParamData { | 30 | pub struct TypeParamData { |
31 | pub name: Option<Name>, | 31 | pub name: Option<Name>, |
32 | pub default: Option<TypeRef>, | 32 | pub default: Option<Interned<TypeRef>>, |
33 | pub provenance: TypeParamProvenance, | 33 | pub provenance: TypeParamProvenance, |
34 | } | 34 | } |
35 | 35 | ||
36 | /// Data about a generic lifetime parameter (to a function, struct, impl, ...). | 36 | /// Data about a generic lifetime parameter (to a function, struct, impl, ...). |
37 | #[derive(Clone, PartialEq, Eq, Debug)] | 37 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
38 | pub struct LifetimeParamData { | 38 | pub struct LifetimeParamData { |
39 | pub name: Name, | 39 | pub name: Name, |
40 | } | 40 | } |
41 | 41 | ||
42 | /// Data about a generic const parameter (to a function, struct, impl, ...). | 42 | /// Data about a generic const parameter (to a function, struct, impl, ...). |
43 | #[derive(Clone, PartialEq, Eq, Debug)] | 43 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
44 | pub struct ConstParamData { | 44 | pub struct ConstParamData { |
45 | pub name: Name, | 45 | pub name: Name, |
46 | pub ty: TypeRef, | 46 | pub ty: Interned<TypeRef>, |
47 | } | 47 | } |
48 | 48 | ||
49 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | 49 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] |
50 | pub enum TypeParamProvenance { | 50 | pub enum TypeParamProvenance { |
51 | TypeParamList, | 51 | TypeParamList, |
52 | TraitSelf, | 52 | TraitSelf, |
@@ -54,7 +54,7 @@ pub enum TypeParamProvenance { | |||
54 | } | 54 | } |
55 | 55 | ||
56 | /// Data about the generic parameters of a function, struct, impl, etc. | 56 | /// Data about the generic parameters of a function, struct, impl, etc. |
57 | #[derive(Clone, PartialEq, Eq, Debug, Default)] | 57 | #[derive(Clone, PartialEq, Eq, Debug, Default, Hash)] |
58 | pub struct GenericParams { | 58 | pub struct GenericParams { |
59 | pub types: Arena<TypeParamData>, | 59 | pub types: Arena<TypeParamData>, |
60 | pub lifetimes: Arena<LifetimeParamData>, | 60 | pub lifetimes: Arena<LifetimeParamData>, |
@@ -66,16 +66,16 @@ pub struct GenericParams { | |||
66 | /// where clauses like `where T: Foo + Bar` are turned into multiple of these. | 66 | /// where clauses like `where T: Foo + Bar` are turned into multiple of these. |
67 | /// It might still result in multiple actual predicates though, because of | 67 | /// It might still result in multiple actual predicates though, because of |
68 | /// associated type bindings like `Iterator<Item = u32>`. | 68 | /// associated type bindings like `Iterator<Item = u32>`. |
69 | #[derive(Clone, PartialEq, Eq, Debug)] | 69 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
70 | pub enum WherePredicate { | 70 | pub enum WherePredicate { |
71 | TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, | 71 | TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, |
72 | Lifetime { target: LifetimeRef, bound: LifetimeRef }, | 72 | Lifetime { target: LifetimeRef, bound: LifetimeRef }, |
73 | ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, | 73 | ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, |
74 | } | 74 | } |
75 | 75 | ||
76 | #[derive(Clone, PartialEq, Eq, Debug)] | 76 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
77 | pub enum WherePredicateTypeTarget { | 77 | pub enum WherePredicateTypeTarget { |
78 | TypeRef(TypeRef), | 78 | TypeRef(Interned<TypeRef>), |
79 | /// For desugared where predicates that can directly refer to a type param. | 79 | /// For desugared where predicates that can directly refer to a type param. |
80 | TypeParam(LocalTypeParamId), | 80 | TypeParam(LocalTypeParamId), |
81 | } | 81 | } |
@@ -91,7 +91,7 @@ impl GenericParams { | |||
91 | pub(crate) fn generic_params_query( | 91 | pub(crate) fn generic_params_query( |
92 | db: &dyn DefDatabase, | 92 | db: &dyn DefDatabase, |
93 | def: GenericDefId, | 93 | def: GenericDefId, |
94 | ) -> Arc<GenericParams> { | 94 | ) -> Interned<GenericParams> { |
95 | let _p = profile::span("generic_params_query"); | 95 | let _p = profile::span("generic_params_query"); |
96 | 96 | ||
97 | let generics = match def { | 97 | let generics = match def { |
@@ -99,47 +99,49 @@ impl GenericParams { | |||
99 | let id = id.lookup(db).id; | 99 | let id = id.lookup(db).id; |
100 | let tree = id.item_tree(db); | 100 | let tree = id.item_tree(db); |
101 | let item = &tree[id.value]; | 101 | let item = &tree[id.value]; |
102 | tree[item.generic_params].clone() | 102 | item.generic_params.clone() |
103 | } | 103 | } |
104 | GenericDefId::AdtId(AdtId::StructId(id)) => { | 104 | GenericDefId::AdtId(AdtId::StructId(id)) => { |
105 | let id = id.lookup(db).id; | 105 | let id = id.lookup(db).id; |
106 | let tree = id.item_tree(db); | 106 | let tree = id.item_tree(db); |
107 | let item = &tree[id.value]; | 107 | let item = &tree[id.value]; |
108 | tree[item.generic_params].clone() | 108 | item.generic_params.clone() |
109 | } | 109 | } |
110 | GenericDefId::AdtId(AdtId::EnumId(id)) => { | 110 | GenericDefId::AdtId(AdtId::EnumId(id)) => { |
111 | let id = id.lookup(db).id; | 111 | let id = id.lookup(db).id; |
112 | let tree = id.item_tree(db); | 112 | let tree = id.item_tree(db); |
113 | let item = &tree[id.value]; | 113 | let item = &tree[id.value]; |
114 | tree[item.generic_params].clone() | 114 | item.generic_params.clone() |
115 | } | 115 | } |
116 | GenericDefId::AdtId(AdtId::UnionId(id)) => { | 116 | GenericDefId::AdtId(AdtId::UnionId(id)) => { |
117 | let id = id.lookup(db).id; | 117 | let id = id.lookup(db).id; |
118 | let tree = id.item_tree(db); | 118 | let tree = id.item_tree(db); |
119 | let item = &tree[id.value]; | 119 | let item = &tree[id.value]; |
120 | tree[item.generic_params].clone() | 120 | item.generic_params.clone() |
121 | } | 121 | } |
122 | GenericDefId::TraitId(id) => { | 122 | GenericDefId::TraitId(id) => { |
123 | let id = id.lookup(db).id; | 123 | let id = id.lookup(db).id; |
124 | let tree = id.item_tree(db); | 124 | let tree = id.item_tree(db); |
125 | let item = &tree[id.value]; | 125 | let item = &tree[id.value]; |
126 | tree[item.generic_params].clone() | 126 | item.generic_params.clone() |
127 | } | 127 | } |
128 | GenericDefId::TypeAliasId(id) => { | 128 | GenericDefId::TypeAliasId(id) => { |
129 | let id = id.lookup(db).id; | 129 | let id = id.lookup(db).id; |
130 | let tree = id.item_tree(db); | 130 | let tree = id.item_tree(db); |
131 | let item = &tree[id.value]; | 131 | let item = &tree[id.value]; |
132 | tree[item.generic_params].clone() | 132 | item.generic_params.clone() |
133 | } | 133 | } |
134 | GenericDefId::ImplId(id) => { | 134 | GenericDefId::ImplId(id) => { |
135 | let id = id.lookup(db).id; | 135 | let id = id.lookup(db).id; |
136 | let tree = id.item_tree(db); | 136 | let tree = id.item_tree(db); |
137 | let item = &tree[id.value]; | 137 | let item = &tree[id.value]; |
138 | tree[item.generic_params].clone() | 138 | item.generic_params.clone() |
139 | } | ||
140 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => { | ||
141 | Interned::new(GenericParams::default()) | ||
139 | } | 142 | } |
140 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(), | ||
141 | }; | 143 | }; |
142 | Arc::new(generics) | 144 | generics |
143 | } | 145 | } |
144 | 146 | ||
145 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { | 147 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { |
@@ -217,6 +219,7 @@ impl GenericParams { | |||
217 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(), | 219 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(), |
218 | }; | 220 | }; |
219 | 221 | ||
222 | generics.shrink_to_fit(); | ||
220 | (generics, InFile::new(file_id, sm)) | 223 | (generics, InFile::new(file_id, sm)) |
221 | } | 224 | } |
222 | 225 | ||
@@ -256,7 +259,8 @@ impl GenericParams { | |||
256 | for type_param in params.type_params() { | 259 | for type_param in params.type_params() { |
257 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); | 260 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); |
258 | // FIXME: Use `Path::from_src` | 261 | // FIXME: Use `Path::from_src` |
259 | let default = type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it)); | 262 | let default = |
263 | type_param.default_type().map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it))); | ||
260 | let param = TypeParamData { | 264 | let param = TypeParamData { |
261 | name: Some(name.clone()), | 265 | name: Some(name.clone()), |
262 | default, | 266 | default, |
@@ -280,7 +284,7 @@ impl GenericParams { | |||
280 | for const_param in params.const_params() { | 284 | for const_param in params.const_params() { |
281 | let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); | 285 | let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); |
282 | let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it)); | 286 | let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it)); |
283 | let param = ConstParamData { name, ty }; | 287 | let param = ConstParamData { name, ty: Interned::new(ty) }; |
284 | let param_id = self.consts.alloc(param); | 288 | let param_id = self.consts.alloc(param); |
285 | sm.const_params.insert(param_id, const_param.clone()); | 289 | sm.const_params.insert(param_id, const_param.clone()); |
286 | } | 290 | } |
@@ -334,11 +338,11 @@ impl GenericParams { | |||
334 | (Either::Left(type_ref), bound) => match hrtb_lifetimes { | 338 | (Either::Left(type_ref), bound) => match hrtb_lifetimes { |
335 | Some(hrtb_lifetimes) => WherePredicate::ForLifetime { | 339 | Some(hrtb_lifetimes) => WherePredicate::ForLifetime { |
336 | lifetimes: hrtb_lifetimes.clone(), | 340 | lifetimes: hrtb_lifetimes.clone(), |
337 | target: WherePredicateTypeTarget::TypeRef(type_ref), | 341 | target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), |
338 | bound, | 342 | bound, |
339 | }, | 343 | }, |
340 | None => WherePredicate::TypeBound { | 344 | None => WherePredicate::TypeBound { |
341 | target: WherePredicateTypeTarget::TypeRef(type_ref), | 345 | target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), |
342 | bound, | 346 | bound, |
343 | }, | 347 | }, |
344 | }, | 348 | }, |
@@ -369,6 +373,14 @@ impl GenericParams { | |||
369 | }); | 373 | }); |
370 | } | 374 | } |
371 | 375 | ||
376 | pub(crate) fn shrink_to_fit(&mut self) { | ||
377 | let Self { consts, lifetimes, types, where_predicates } = self; | ||
378 | consts.shrink_to_fit(); | ||
379 | lifetimes.shrink_to_fit(); | ||
380 | types.shrink_to_fit(); | ||
381 | where_predicates.shrink_to_fit(); | ||
382 | } | ||
383 | |||
372 | pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { | 384 | pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { |
373 | self.types | 385 | self.types |
374 | .iter() | 386 | .iter() |
diff --git a/crates/hir_def/src/intern.rs b/crates/hir_def/src/intern.rs new file mode 100644 index 000000000..abc304ef0 --- /dev/null +++ b/crates/hir_def/src/intern.rs | |||
@@ -0,0 +1,216 @@ | |||
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, Hasher}, | ||
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 | use crate::generics::GenericParams; | ||
18 | |||
19 | type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>; | ||
20 | type Guard<T> = | ||
21 | RwLockWriteGuard<'static, HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>>; | ||
22 | |||
23 | pub struct Interned<T: Internable + ?Sized> { | ||
24 | arc: Arc<T>, | ||
25 | } | ||
26 | |||
27 | impl<T: Internable> Interned<T> { | ||
28 | pub fn new(obj: T) -> Self { | ||
29 | match Interned::lookup(&obj) { | ||
30 | Ok(this) => this, | ||
31 | Err(shard) => { | ||
32 | let arc = Arc::new(obj); | ||
33 | Self::alloc(arc, shard) | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | |||
39 | impl<T: Internable + ?Sized> Interned<T> { | ||
40 | fn lookup(obj: &T) -> Result<Self, Guard<T>> { | ||
41 | let storage = T::storage().get(); | ||
42 | let shard_idx = storage.determine_map(obj); | ||
43 | let shard = &storage.shards()[shard_idx]; | ||
44 | let shard = shard.write(); | ||
45 | |||
46 | // Atomically, | ||
47 | // - check if `obj` is already in the map | ||
48 | // - if so, clone its `Arc` and return it | ||
49 | // - if not, box it up, insert it, and return a clone | ||
50 | // This needs to be atomic (locking the shard) to avoid races with other thread, which could | ||
51 | // insert the same object between us looking it up and inserting it. | ||
52 | |||
53 | // FIXME: avoid double lookup/hashing by using raw entry API (once stable, or when | ||
54 | // hashbrown can be plugged into dashmap) | ||
55 | match shard.get_key_value(obj) { | ||
56 | Some((arc, _)) => Ok(Self { arc: arc.clone() }), | ||
57 | None => Err(shard), | ||
58 | } | ||
59 | } | ||
60 | |||
61 | fn alloc(arc: Arc<T>, mut shard: Guard<T>) -> Self { | ||
62 | let arc2 = arc.clone(); | ||
63 | |||
64 | shard.insert(arc2, SharedValue::new(())); | ||
65 | |||
66 | Self { arc } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | impl Interned<str> { | ||
71 | pub fn new_str(s: &str) -> Self { | ||
72 | match Interned::lookup(s) { | ||
73 | Ok(this) => this, | ||
74 | Err(shard) => { | ||
75 | let arc = Arc::<str>::from(s); | ||
76 | Self::alloc(arc, shard) | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | } | ||
81 | |||
82 | impl<T: Internable + ?Sized> Drop for Interned<T> { | ||
83 | #[inline] | ||
84 | fn drop(&mut self) { | ||
85 | // When the last `Ref` is dropped, remove the object from the global map. | ||
86 | if Arc::strong_count(&self.arc) == 2 { | ||
87 | // Only `self` and the global map point to the object. | ||
88 | |||
89 | self.drop_slow(); | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | |||
94 | impl<T: Internable + ?Sized> Interned<T> { | ||
95 | #[cold] | ||
96 | fn drop_slow(&mut self) { | ||
97 | let storage = T::storage().get(); | ||
98 | let shard_idx = storage.determine_map(&self.arc); | ||
99 | let shard = &storage.shards()[shard_idx]; | ||
100 | let mut shard = shard.write(); | ||
101 | |||
102 | // FIXME: avoid double lookup | ||
103 | let (arc, _) = shard.get_key_value(&self.arc).expect("interned value removed prematurely"); | ||
104 | |||
105 | if Arc::strong_count(arc) != 2 { | ||
106 | // Another thread has interned another copy | ||
107 | return; | ||
108 | } | ||
109 | |||
110 | shard.remove(&self.arc); | ||
111 | |||
112 | // Shrink the backing storage if the shard is less than 50% occupied. | ||
113 | if shard.len() * 2 < shard.capacity() { | ||
114 | shard.shrink_to_fit(); | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | /// Compares interned `Ref`s using pointer equality. | ||
120 | impl<T: Internable> PartialEq for Interned<T> { | ||
121 | // NOTE: No `?Sized` because `ptr_eq` doesn't work right with trait objects. | ||
122 | |||
123 | #[inline] | ||
124 | fn eq(&self, other: &Self) -> bool { | ||
125 | Arc::ptr_eq(&self.arc, &other.arc) | ||
126 | } | ||
127 | } | ||
128 | |||
129 | impl<T: Internable> Eq for Interned<T> {} | ||
130 | |||
131 | impl PartialEq for Interned<str> { | ||
132 | fn eq(&self, other: &Self) -> bool { | ||
133 | Arc::ptr_eq(&self.arc, &other.arc) | ||
134 | } | ||
135 | } | ||
136 | |||
137 | impl Eq for Interned<str> {} | ||
138 | |||
139 | impl<T: Internable + ?Sized> Hash for Interned<T> { | ||
140 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
141 | // NOTE: Cast disposes vtable pointer / slice/str length. | ||
142 | state.write_usize(Arc::as_ptr(&self.arc) as *const () as usize) | ||
143 | } | ||
144 | } | ||
145 | |||
146 | impl<T: Internable + ?Sized> AsRef<T> for Interned<T> { | ||
147 | #[inline] | ||
148 | fn as_ref(&self) -> &T { | ||
149 | &self.arc | ||
150 | } | ||
151 | } | ||
152 | |||
153 | impl<T: Internable + ?Sized> Deref for Interned<T> { | ||
154 | type Target = T; | ||
155 | |||
156 | #[inline] | ||
157 | fn deref(&self) -> &Self::Target { | ||
158 | &self.arc | ||
159 | } | ||
160 | } | ||
161 | |||
162 | impl<T: Internable + ?Sized> Clone for Interned<T> { | ||
163 | fn clone(&self) -> Self { | ||
164 | Self { arc: self.arc.clone() } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | impl<T: Debug + Internable + ?Sized> Debug for Interned<T> { | ||
169 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
170 | (*self.arc).fmt(f) | ||
171 | } | ||
172 | } | ||
173 | |||
174 | pub struct InternStorage<T: ?Sized> { | ||
175 | map: OnceCell<InternMap<T>>, | ||
176 | } | ||
177 | |||
178 | impl<T: ?Sized> InternStorage<T> { | ||
179 | pub const fn new() -> Self { | ||
180 | Self { map: OnceCell::new() } | ||
181 | } | ||
182 | } | ||
183 | |||
184 | impl<T: Internable + ?Sized> InternStorage<T> { | ||
185 | fn get(&self) -> &InternMap<T> { | ||
186 | self.map.get_or_init(DashMap::default) | ||
187 | } | ||
188 | } | ||
189 | |||
190 | pub trait Internable: Hash + Eq + 'static { | ||
191 | fn storage() -> &'static InternStorage<Self>; | ||
192 | } | ||
193 | |||
194 | /// Implements `Internable` for a given list of types, making them usable with `Interned`. | ||
195 | #[macro_export] | ||
196 | #[doc(hidden)] | ||
197 | macro_rules! _impl_internable { | ||
198 | ( $($t:path),+ $(,)? ) => { $( | ||
199 | impl Internable for $t { | ||
200 | fn storage() -> &'static InternStorage<Self> { | ||
201 | static STORAGE: InternStorage<$t> = InternStorage::new(); | ||
202 | &STORAGE | ||
203 | } | ||
204 | } | ||
205 | )+ }; | ||
206 | } | ||
207 | |||
208 | pub use crate::_impl_internable as impl_internable; | ||
209 | |||
210 | impl_internable!( | ||
211 | crate::type_ref::TypeRef, | ||
212 | crate::type_ref::TraitRef, | ||
213 | crate::path::ModPath, | ||
214 | GenericParams, | ||
215 | str, | ||
216 | ); | ||
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 ca0048b16..240662486 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -24,14 +24,15 @@ 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, TypeBound, TypeRef}, | 35 | type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, |
35 | visibility::RawVisibility, | 36 | visibility::RawVisibility, |
36 | }; | 37 | }; |
37 | 38 | ||
@@ -57,13 +58,6 @@ impl fmt::Debug for RawVisibilityId { | |||
57 | } | 58 | } |
58 | } | 59 | } |
59 | 60 | ||
60 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
61 | pub struct GenericParamsId(u32); | ||
62 | |||
63 | impl GenericParamsId { | ||
64 | pub const EMPTY: Self = GenericParamsId(u32::max_value()); | ||
65 | } | ||
66 | |||
67 | /// The item tree of a source file. | 61 | /// The item tree of a source file. |
68 | #[derive(Debug, Default, Eq, PartialEq)] | 62 | #[derive(Debug, Default, Eq, PartialEq)] |
69 | pub struct ItemTree { | 63 | pub struct ItemTree { |
@@ -145,8 +139,6 @@ impl ItemTree { | |||
145 | macro_rules, | 139 | macro_rules, |
146 | macro_defs, | 140 | macro_defs, |
147 | vis, | 141 | vis, |
148 | generics, | ||
149 | type_refs, | ||
150 | inner_items, | 142 | inner_items, |
151 | } = &mut **data; | 143 | } = &mut **data; |
152 | 144 | ||
@@ -170,9 +162,6 @@ impl ItemTree { | |||
170 | macro_defs.shrink_to_fit(); | 162 | macro_defs.shrink_to_fit(); |
171 | 163 | ||
172 | vis.arena.shrink_to_fit(); | 164 | vis.arena.shrink_to_fit(); |
173 | generics.arena.shrink_to_fit(); | ||
174 | type_refs.arena.shrink_to_fit(); | ||
175 | type_refs.map.shrink_to_fit(); | ||
176 | 165 | ||
177 | inner_items.shrink_to_fit(); | 166 | inner_items.shrink_to_fit(); |
178 | } | 167 | } |
@@ -244,58 +233,6 @@ static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKi | |||
244 | static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate)); | 233 | static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate)); |
245 | 234 | ||
246 | #[derive(Default, Debug, Eq, PartialEq)] | 235 | #[derive(Default, Debug, Eq, PartialEq)] |
247 | struct GenericParamsStorage { | ||
248 | arena: Arena<GenericParams>, | ||
249 | } | ||
250 | |||
251 | impl GenericParamsStorage { | ||
252 | fn alloc(&mut self, params: GenericParams) -> GenericParamsId { | ||
253 | if params.types.is_empty() | ||
254 | && params.lifetimes.is_empty() | ||
255 | && params.consts.is_empty() | ||
256 | && params.where_predicates.is_empty() | ||
257 | { | ||
258 | return GenericParamsId::EMPTY; | ||
259 | } | ||
260 | |||
261 | GenericParamsId(self.arena.alloc(params).into_raw().into()) | ||
262 | } | ||
263 | } | ||
264 | |||
265 | static EMPTY_GENERICS: GenericParams = GenericParams { | ||
266 | types: Arena::new(), | ||
267 | lifetimes: Arena::new(), | ||
268 | consts: Arena::new(), | ||
269 | where_predicates: Vec::new(), | ||
270 | }; | ||
271 | |||
272 | /// `TypeRef` interner. | ||
273 | #[derive(Default, Debug, Eq, PartialEq)] | ||
274 | struct TypeRefStorage { | ||
275 | arena: Arena<Arc<TypeRef>>, | ||
276 | map: FxHashMap<Arc<TypeRef>, Idx<Arc<TypeRef>>>, | ||
277 | } | ||
278 | |||
279 | impl TypeRefStorage { | ||
280 | // Note: We lie about the `Idx<TypeRef>` to hide the interner details. | ||
281 | |||
282 | fn intern(&mut self, ty: TypeRef) -> Idx<TypeRef> { | ||
283 | if let Some(id) = self.map.get(&ty) { | ||
284 | return Idx::from_raw(id.into_raw()); | ||
285 | } | ||
286 | |||
287 | let ty = Arc::new(ty); | ||
288 | let idx = self.arena.alloc(ty.clone()); | ||
289 | self.map.insert(ty, idx); | ||
290 | Idx::from_raw(idx.into_raw()) | ||
291 | } | ||
292 | |||
293 | fn lookup(&self, id: Idx<TypeRef>) -> &TypeRef { | ||
294 | &self.arena[Idx::from_raw(id.into_raw())] | ||
295 | } | ||
296 | } | ||
297 | |||
298 | #[derive(Default, Debug, Eq, PartialEq)] | ||
299 | struct ItemTreeData { | 236 | struct ItemTreeData { |
300 | imports: Arena<Import>, | 237 | imports: Arena<Import>, |
301 | extern_crates: Arena<ExternCrate>, | 238 | extern_crates: Arena<ExternCrate>, |
@@ -317,8 +254,6 @@ struct ItemTreeData { | |||
317 | macro_defs: Arena<MacroDef>, | 254 | macro_defs: Arena<MacroDef>, |
318 | 255 | ||
319 | vis: ItemVisibilities, | 256 | vis: ItemVisibilities, |
320 | generics: GenericParamsStorage, | ||
321 | type_refs: TypeRefStorage, | ||
322 | 257 | ||
323 | inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, | 258 | inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, |
324 | } | 259 | } |
@@ -537,25 +472,6 @@ impl Index<RawVisibilityId> for ItemTree { | |||
537 | } | 472 | } |
538 | } | 473 | } |
539 | 474 | ||
540 | impl Index<GenericParamsId> for ItemTree { | ||
541 | type Output = GenericParams; | ||
542 | |||
543 | fn index(&self, index: GenericParamsId) -> &Self::Output { | ||
544 | match index { | ||
545 | GenericParamsId::EMPTY => &EMPTY_GENERICS, | ||
546 | _ => &self.data().generics.arena[Idx::from_raw(index.0.into())], | ||
547 | } | ||
548 | } | ||
549 | } | ||
550 | |||
551 | impl Index<Idx<TypeRef>> for ItemTree { | ||
552 | type Output = TypeRef; | ||
553 | |||
554 | fn index(&self, id: Idx<TypeRef>) -> &Self::Output { | ||
555 | self.data().type_refs.lookup(id) | ||
556 | } | ||
557 | } | ||
558 | |||
559 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | 475 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { |
560 | type Output = N; | 476 | type Output = N; |
561 | fn index(&self, id: FileItemTreeId<N>) -> &N { | 477 | fn index(&self, id: FileItemTreeId<N>) -> &N { |
@@ -566,7 +482,7 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | |||
566 | /// A desugared `use` import. | 482 | /// A desugared `use` import. |
567 | #[derive(Debug, Clone, Eq, PartialEq)] | 483 | #[derive(Debug, Clone, Eq, PartialEq)] |
568 | pub struct Import { | 484 | pub struct Import { |
569 | pub path: ModPath, | 485 | pub path: Interned<ModPath>, |
570 | pub alias: Option<ImportAlias>, | 486 | pub alias: Option<ImportAlias>, |
571 | pub visibility: RawVisibilityId, | 487 | pub visibility: RawVisibilityId, |
572 | pub is_glob: bool, | 488 | pub is_glob: bool, |
@@ -592,38 +508,42 @@ pub struct ExternCrate { | |||
592 | pub struct Function { | 508 | pub struct Function { |
593 | pub name: Name, | 509 | pub name: Name, |
594 | pub visibility: RawVisibilityId, | 510 | pub visibility: RawVisibilityId, |
595 | pub generic_params: GenericParamsId, | 511 | pub generic_params: Interned<GenericParams>, |
596 | pub has_self_param: bool, | 512 | pub abi: Option<Interned<str>>, |
597 | pub has_body: bool, | ||
598 | pub qualifier: FunctionQualifier, | ||
599 | /// Whether the function is located in an `extern` block (*not* whether it is an | ||
600 | /// `extern "abi" fn`). | ||
601 | pub is_in_extern_block: bool, | ||
602 | pub params: IdRange<Param>, | 513 | pub params: IdRange<Param>, |
603 | pub ret_type: Idx<TypeRef>, | 514 | pub ret_type: Interned<TypeRef>, |
604 | pub ast_id: FileAstId<ast::Fn>, | 515 | pub ast_id: FileAstId<ast::Fn>, |
516 | pub(crate) flags: FnFlags, | ||
605 | } | 517 | } |
606 | 518 | ||
607 | #[derive(Debug, Clone, Eq, PartialEq)] | 519 | #[derive(Debug, Clone, Eq, PartialEq)] |
608 | pub enum Param { | 520 | pub enum Param { |
609 | Normal(Idx<TypeRef>), | 521 | Normal(Interned<TypeRef>), |
610 | Varargs, | 522 | Varargs, |
611 | } | 523 | } |
612 | 524 | ||
613 | #[derive(Debug, Clone, PartialEq, Eq)] | 525 | #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] |
614 | pub struct FunctionQualifier { | 526 | pub(crate) struct FnFlags { |
615 | pub is_default: bool, | 527 | pub(crate) bits: u8, |
616 | pub is_const: bool, | 528 | } |
617 | pub is_async: bool, | 529 | impl FnFlags { |
618 | pub is_unsafe: bool, | 530 | pub(crate) const HAS_SELF_PARAM: u8 = 1 << 0; |
619 | pub abi: Option<SmolStr>, | 531 | pub(crate) const HAS_BODY: u8 = 1 << 1; |
532 | pub(crate) const IS_DEFAULT: u8 = 1 << 2; | ||
533 | pub(crate) const IS_CONST: u8 = 1 << 3; | ||
534 | pub(crate) const IS_ASYNC: u8 = 1 << 4; | ||
535 | pub(crate) const IS_UNSAFE: u8 = 1 << 5; | ||
536 | /// Whether the function is located in an `extern` block (*not* whether it is an | ||
537 | /// `extern "abi" fn`). | ||
538 | pub(crate) const IS_IN_EXTERN_BLOCK: u8 = 1 << 6; | ||
539 | pub(crate) const IS_VARARGS: u8 = 1 << 7; | ||
620 | } | 540 | } |
621 | 541 | ||
622 | #[derive(Debug, Clone, Eq, PartialEq)] | 542 | #[derive(Debug, Clone, Eq, PartialEq)] |
623 | pub struct Struct { | 543 | pub struct Struct { |
624 | pub name: Name, | 544 | pub name: Name, |
625 | pub visibility: RawVisibilityId, | 545 | pub visibility: RawVisibilityId, |
626 | pub generic_params: GenericParamsId, | 546 | pub generic_params: Interned<GenericParams>, |
627 | pub fields: Fields, | 547 | pub fields: Fields, |
628 | pub ast_id: FileAstId<ast::Struct>, | 548 | pub ast_id: FileAstId<ast::Struct>, |
629 | pub kind: StructDefKind, | 549 | pub kind: StructDefKind, |
@@ -643,7 +563,7 @@ pub enum StructDefKind { | |||
643 | pub struct Union { | 563 | pub struct Union { |
644 | pub name: Name, | 564 | pub name: Name, |
645 | pub visibility: RawVisibilityId, | 565 | pub visibility: RawVisibilityId, |
646 | pub generic_params: GenericParamsId, | 566 | pub generic_params: Interned<GenericParams>, |
647 | pub fields: Fields, | 567 | pub fields: Fields, |
648 | pub ast_id: FileAstId<ast::Union>, | 568 | pub ast_id: FileAstId<ast::Union>, |
649 | } | 569 | } |
@@ -652,7 +572,7 @@ pub struct Union { | |||
652 | pub struct Enum { | 572 | pub struct Enum { |
653 | pub name: Name, | 573 | pub name: Name, |
654 | pub visibility: RawVisibilityId, | 574 | pub visibility: RawVisibilityId, |
655 | pub generic_params: GenericParamsId, | 575 | pub generic_params: Interned<GenericParams>, |
656 | pub variants: IdRange<Variant>, | 576 | pub variants: IdRange<Variant>, |
657 | pub ast_id: FileAstId<ast::Enum>, | 577 | pub ast_id: FileAstId<ast::Enum>, |
658 | } | 578 | } |
@@ -662,7 +582,7 @@ pub struct Const { | |||
662 | /// const _: () = (); | 582 | /// const _: () = (); |
663 | pub name: Option<Name>, | 583 | pub name: Option<Name>, |
664 | pub visibility: RawVisibilityId, | 584 | pub visibility: RawVisibilityId, |
665 | pub type_ref: Idx<TypeRef>, | 585 | pub type_ref: Interned<TypeRef>, |
666 | pub ast_id: FileAstId<ast::Const>, | 586 | pub ast_id: FileAstId<ast::Const>, |
667 | } | 587 | } |
668 | 588 | ||
@@ -673,7 +593,7 @@ pub struct Static { | |||
673 | pub mutable: bool, | 593 | pub mutable: bool, |
674 | /// Whether the static is in an `extern` block. | 594 | /// Whether the static is in an `extern` block. |
675 | pub is_extern: bool, | 595 | pub is_extern: bool, |
676 | pub type_ref: Idx<TypeRef>, | 596 | pub type_ref: Interned<TypeRef>, |
677 | pub ast_id: FileAstId<ast::Static>, | 597 | pub ast_id: FileAstId<ast::Static>, |
678 | } | 598 | } |
679 | 599 | ||
@@ -681,7 +601,7 @@ pub struct Static { | |||
681 | pub struct Trait { | 601 | pub struct Trait { |
682 | pub name: Name, | 602 | pub name: Name, |
683 | pub visibility: RawVisibilityId, | 603 | pub visibility: RawVisibilityId, |
684 | pub generic_params: GenericParamsId, | 604 | pub generic_params: Interned<GenericParams>, |
685 | pub is_auto: bool, | 605 | pub is_auto: bool, |
686 | pub is_unsafe: bool, | 606 | pub is_unsafe: bool, |
687 | pub bounds: Box<[TypeBound]>, | 607 | pub bounds: Box<[TypeBound]>, |
@@ -691,9 +611,9 @@ pub struct Trait { | |||
691 | 611 | ||
692 | #[derive(Debug, Clone, Eq, PartialEq)] | 612 | #[derive(Debug, Clone, Eq, PartialEq)] |
693 | pub struct Impl { | 613 | pub struct Impl { |
694 | pub generic_params: GenericParamsId, | 614 | pub generic_params: Interned<GenericParams>, |
695 | pub target_trait: Option<Idx<TypeRef>>, | 615 | pub target_trait: Option<Interned<TraitRef>>, |
696 | pub target_type: Idx<TypeRef>, | 616 | pub self_ty: Interned<TypeRef>, |
697 | pub is_negative: bool, | 617 | pub is_negative: bool, |
698 | pub items: Box<[AssocItem]>, | 618 | pub items: Box<[AssocItem]>, |
699 | pub ast_id: FileAstId<ast::Impl>, | 619 | pub ast_id: FileAstId<ast::Impl>, |
@@ -705,8 +625,8 @@ pub struct TypeAlias { | |||
705 | pub visibility: RawVisibilityId, | 625 | pub visibility: RawVisibilityId, |
706 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. | 626 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. |
707 | pub bounds: Box<[TypeBound]>, | 627 | pub bounds: Box<[TypeBound]>, |
708 | pub generic_params: GenericParamsId, | 628 | pub generic_params: Interned<GenericParams>, |
709 | pub type_ref: Option<Idx<TypeRef>>, | 629 | pub type_ref: Option<Interned<TypeRef>>, |
710 | pub is_extern: bool, | 630 | pub is_extern: bool, |
711 | pub ast_id: FileAstId<ast::TypeAlias>, | 631 | pub ast_id: FileAstId<ast::TypeAlias>, |
712 | } | 632 | } |
@@ -731,7 +651,7 @@ pub enum ModKind { | |||
731 | #[derive(Debug, Clone, Eq, PartialEq)] | 651 | #[derive(Debug, Clone, Eq, PartialEq)] |
732 | pub struct MacroCall { | 652 | pub struct MacroCall { |
733 | /// Path to the called macro. | 653 | /// Path to the called macro. |
734 | pub path: ModPath, | 654 | pub path: Interned<ModPath>, |
735 | pub ast_id: FileAstId<ast::MacroCall>, | 655 | pub ast_id: FileAstId<ast::MacroCall>, |
736 | } | 656 | } |
737 | 657 | ||
@@ -896,6 +816,6 @@ pub enum Fields { | |||
896 | #[derive(Debug, Clone, PartialEq, Eq)] | 816 | #[derive(Debug, Clone, PartialEq, Eq)] |
897 | pub struct Field { | 817 | pub struct Field { |
898 | pub name: Name, | 818 | pub name: Name, |
899 | pub type_ref: Idx<TypeRef>, | 819 | pub type_ref: Interned<TypeRef>, |
900 | pub visibility: RawVisibilityId, | 820 | pub visibility: RawVisibilityId, |
901 | } | 821 | } |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 3f558edd8..c5629af24 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -11,7 +11,7 @@ use syntax::{ | |||
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | generics::{GenericParams, TypeParamData, TypeParamProvenance}, | 13 | generics::{GenericParams, TypeParamData, TypeParamProvenance}, |
14 | type_ref::LifetimeRef, | 14 | type_ref::{LifetimeRef, TraitRef}, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | use super::*; | 17 | use super::*; |
@@ -174,6 +174,12 @@ impl Ctx { | |||
174 | let forced_vis = self.forced_visibility.take(); | 174 | let forced_vis = self.forced_visibility.take(); |
175 | 175 | ||
176 | let mut block_stack = Vec::new(); | 176 | let mut block_stack = Vec::new(); |
177 | |||
178 | // if container itself is block, add it to the stack | ||
179 | if let Some(block) = ast::BlockExpr::cast(container.clone()) { | ||
180 | block_stack.push(self.source_ast_id_map.ast_id(&block)); | ||
181 | } | ||
182 | |||
177 | for event in container.preorder().skip(1) { | 183 | for event in container.preorder().skip(1) { |
178 | match event { | 184 | match event { |
179 | WalkEvent::Enter(node) => { | 185 | WalkEvent::Enter(node) => { |
@@ -356,7 +362,7 @@ impl Ctx { | |||
356 | } | 362 | } |
357 | } | 363 | } |
358 | }; | 364 | }; |
359 | let ty = self.data().type_refs.intern(self_type); | 365 | let ty = Interned::new(self_type); |
360 | let idx = self.data().params.alloc(Param::Normal(ty)); | 366 | let idx = self.data().params.alloc(Param::Normal(ty)); |
361 | self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene)); | 367 | self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene)); |
362 | has_self_param = true; | 368 | has_self_param = true; |
@@ -366,7 +372,7 @@ impl Ctx { | |||
366 | Some(_) => self.data().params.alloc(Param::Varargs), | 372 | Some(_) => self.data().params.alloc(Param::Varargs), |
367 | None => { | 373 | None => { |
368 | 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()); |
369 | let ty = self.data().type_refs.intern(type_ref); | 375 | let ty = Interned::new(type_ref); |
370 | self.data().params.alloc(Param::Normal(ty)) | 376 | self.data().params.alloc(Param::Normal(ty)) |
371 | } | 377 | } |
372 | }; | 378 | }; |
@@ -389,41 +395,51 @@ impl Ctx { | |||
389 | ret_type | 395 | ret_type |
390 | }; | 396 | }; |
391 | 397 | ||
392 | let ret_type = self.data().type_refs.intern(ret_type); | 398 | let abi = func.abi().map(|abi| { |
393 | 399 | // FIXME: Abi::abi() -> Option<SyntaxToken>? | |
394 | 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 | }); | ||
395 | 411 | ||
396 | let ast_id = self.source_ast_id_map.ast_id(func); | 412 | let ast_id = self.source_ast_id_map.ast_id(func); |
397 | let qualifier = FunctionQualifier { | 413 | |
398 | is_default: func.default_token().is_some(), | 414 | let mut flags = FnFlags::default(); |
399 | is_const: func.const_token().is_some(), | 415 | if func.body().is_some() { |
400 | is_async: func.async_token().is_some(), | 416 | flags.bits |= FnFlags::HAS_BODY; |
401 | is_unsafe: func.unsafe_token().is_some(), | 417 | } |
402 | abi: func.abi().map(|abi| { | 418 | if has_self_param { |
403 | // FIXME: Abi::abi() -> Option<SyntaxToken>? | 419 | flags.bits |= FnFlags::HAS_SELF_PARAM; |
404 | match abi.syntax().last_token() { | 420 | } |
405 | Some(tok) if tok.kind() == SyntaxKind::STRING => { | 421 | if func.default_token().is_some() { |
406 | // FIXME: Better way to unescape? | 422 | flags.bits |= FnFlags::IS_DEFAULT; |
407 | tok.text().trim_matches('"').into() | 423 | } |
408 | } | 424 | if func.const_token().is_some() { |
409 | _ => { | 425 | flags.bits |= FnFlags::IS_CONST; |
410 | // `extern` default to be `extern "C"`. | 426 | } |
411 | "C".into() | 427 | if func.async_token().is_some() { |
412 | } | 428 | flags.bits |= FnFlags::IS_ASYNC; |
413 | } | 429 | } |
414 | }), | 430 | if func.unsafe_token().is_some() { |
415 | }; | 431 | flags.bits |= FnFlags::IS_UNSAFE; |
432 | } | ||
433 | |||
416 | let mut res = Function { | 434 | let mut res = Function { |
417 | name, | 435 | name, |
418 | visibility, | 436 | visibility, |
419 | generic_params: GenericParamsId::EMPTY, | 437 | generic_params: Interned::new(GenericParams::default()), |
420 | has_self_param, | 438 | abi, |
421 | has_body, | ||
422 | qualifier, | ||
423 | is_in_extern_block: false, | ||
424 | params, | 439 | params, |
425 | ret_type, | 440 | ret_type: Interned::new(ret_type), |
426 | ast_id, | 441 | ast_id, |
442 | flags, | ||
427 | }; | 443 | }; |
428 | res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); | 444 | res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); |
429 | 445 | ||
@@ -536,8 +552,11 @@ impl Ctx { | |||
536 | fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> { | 552 | fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> { |
537 | let generic_params = | 553 | let generic_params = |
538 | self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); | 554 | self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); |
539 | let target_trait = impl_def.trait_().map(|tr| self.lower_type_ref(&tr)); | 555 | // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl |
540 | let target_type = self.lower_type_ref(&impl_def.self_ty()?); | 556 | // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only |
557 | // equals itself. | ||
558 | let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr)); | ||
559 | let self_ty = self.lower_type_ref(&impl_def.self_ty()?); | ||
541 | let is_negative = impl_def.excl_token().is_some(); | 560 | let is_negative = impl_def.excl_token().is_some(); |
542 | 561 | ||
543 | // We cannot use `assoc_items()` here as that does not include macro calls. | 562 | // We cannot use `assoc_items()` here as that does not include macro calls. |
@@ -554,7 +573,7 @@ impl Ctx { | |||
554 | }) | 573 | }) |
555 | .collect(); | 574 | .collect(); |
556 | let ast_id = self.source_ast_id_map.ast_id(impl_def); | 575 | let ast_id = self.source_ast_id_map.ast_id(impl_def); |
557 | let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }; | 576 | let res = Impl { generic_params, target_trait, self_ty, is_negative, items, ast_id }; |
558 | Some(id(self.data().impls.alloc(res))) | 577 | Some(id(self.data().impls.alloc(res))) |
559 | } | 578 | } |
560 | 579 | ||
@@ -570,7 +589,7 @@ impl Ctx { | |||
570 | &self.hygiene, | 589 | &self.hygiene, |
571 | |path, _use_tree, is_glob, alias| { | 590 | |path, _use_tree, is_glob, alias| { |
572 | imports.push(id(tree.imports.alloc(Import { | 591 | imports.push(id(tree.imports.alloc(Import { |
573 | path, | 592 | path: Interned::new(path), |
574 | alias, | 593 | alias, |
575 | visibility, | 594 | visibility, |
576 | is_glob, | 595 | is_glob, |
@@ -599,7 +618,7 @@ impl Ctx { | |||
599 | } | 618 | } |
600 | 619 | ||
601 | 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>> { |
602 | let path = ModPath::from_src(m.path()?, &self.hygiene)?; | 621 | let path = Interned::new(ModPath::from_src(m.path()?, &self.hygiene)?); |
603 | let ast_id = self.source_ast_id_map.ast_id(m); | 622 | let ast_id = self.source_ast_id_map.ast_id(m); |
604 | let res = MacroCall { path, ast_id }; | 623 | let res = MacroCall { path, ast_id }; |
605 | Some(id(self.data().macro_calls.alloc(res))) | 624 | Some(id(self.data().macro_calls.alloc(res))) |
@@ -633,8 +652,10 @@ impl Ctx { | |||
633 | ast::ExternItem::Fn(ast) => { | 652 | ast::ExternItem::Fn(ast) => { |
634 | let func_id = self.lower_function(&ast)?; | 653 | let func_id = self.lower_function(&ast)?; |
635 | let func = &mut self.data().functions[func_id.index]; | 654 | let func = &mut self.data().functions[func_id.index]; |
636 | func.qualifier.is_unsafe = is_intrinsic_fn_unsafe(&func.name); | 655 | if is_intrinsic_fn_unsafe(&func.name) { |
637 | func.is_in_extern_block = true; | 656 | func.flags.bits |= FnFlags::IS_UNSAFE; |
657 | } | ||
658 | func.flags.bits |= FnFlags::IS_IN_EXTERN_BLOCK; | ||
638 | func_id.into() | 659 | func_id.into() |
639 | } | 660 | } |
640 | ast::ExternItem::Static(ast) => { | 661 | ast::ExternItem::Static(ast) => { |
@@ -661,7 +682,7 @@ impl Ctx { | |||
661 | &mut self, | 682 | &mut self, |
662 | owner: GenericsOwner<'_>, | 683 | owner: GenericsOwner<'_>, |
663 | node: &impl ast::GenericParamsOwner, | 684 | node: &impl ast::GenericParamsOwner, |
664 | ) -> GenericParamsId { | 685 | ) -> Interned<GenericParams> { |
665 | // Generics are part of item headers and may contain inner items we need to collect. | 686 | // Generics are part of item headers and may contain inner items we need to collect. |
666 | if let Some(params) = node.generic_param_list() { | 687 | if let Some(params) = node.generic_param_list() { |
667 | self.collect_inner_items(params.syntax()); | 688 | self.collect_inner_items(params.syntax()); |
@@ -677,7 +698,7 @@ impl Ctx { | |||
677 | &mut self, | 698 | &mut self, |
678 | owner: GenericsOwner<'_>, | 699 | owner: GenericsOwner<'_>, |
679 | node: &impl ast::GenericParamsOwner, | 700 | node: &impl ast::GenericParamsOwner, |
680 | ) -> GenericParamsId { | 701 | ) -> Interned<GenericParams> { |
681 | let mut sm = &mut Default::default(); | 702 | let mut sm = &mut Default::default(); |
682 | let mut generics = GenericParams::default(); | 703 | let mut generics = GenericParams::default(); |
683 | match owner { | 704 | match owner { |
@@ -685,8 +706,7 @@ impl Ctx { | |||
685 | generics.fill(&self.body_ctx, sm, node); | 706 | generics.fill(&self.body_ctx, sm, node); |
686 | // lower `impl Trait` in arguments | 707 | // lower `impl Trait` in arguments |
687 | for id in func.params.clone() { | 708 | for id in func.params.clone() { |
688 | if let Param::Normal(ty) = self.data().params[id] { | 709 | if let Param::Normal(ty) = &self.data().params[id] { |
689 | let ty = self.data().type_refs.lookup(ty); | ||
690 | generics.fill_implicit_impl_trait_args(ty); | 710 | generics.fill_implicit_impl_trait_args(ty); |
691 | } | 711 | } |
692 | } | 712 | } |
@@ -719,7 +739,8 @@ impl Ctx { | |||
719 | } | 739 | } |
720 | } | 740 | } |
721 | 741 | ||
722 | self.data().generics.alloc(generics) | 742 | generics.shrink_to_fit(); |
743 | Interned::new(generics) | ||
723 | } | 744 | } |
724 | 745 | ||
725 | fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> { | 746 | fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> { |
@@ -740,14 +761,20 @@ impl Ctx { | |||
740 | self.data().vis.alloc(vis) | 761 | self.data().vis.alloc(vis) |
741 | } | 762 | } |
742 | 763 | ||
743 | fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Idx<TypeRef> { | 764 | fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Interned<TraitRef>> { |
765 | let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?; | ||
766 | Some(Interned::new(trait_ref)) | ||
767 | } | ||
768 | |||
769 | fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Interned<TypeRef> { | ||
744 | let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); | 770 | let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); |
745 | self.data().type_refs.intern(tyref) | 771 | Interned::new(tyref) |
746 | } | 772 | } |
747 | fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Idx<TypeRef> { | 773 | |
774 | fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Interned<TypeRef> { | ||
748 | match type_ref.map(|ty| self.lower_type_ref(&ty)) { | 775 | match type_ref.map(|ty| self.lower_type_ref(&ty)) { |
749 | Some(it) => it, | 776 | Some(it) => it, |
750 | None => self.data().type_refs.intern(TypeRef::Error), | 777 | None => Interned::new(TypeRef::Error), |
751 | } | 778 | } |
752 | } | 779 | } |
753 | 780 | ||
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index c9e07de86..be9a5e1a0 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -27,6 +27,7 @@ pub mod dyn_map; | |||
27 | pub mod keys; | 27 | pub mod keys; |
28 | 28 | ||
29 | pub mod item_tree; | 29 | pub mod item_tree; |
30 | pub mod intern; | ||
30 | 31 | ||
31 | pub mod adt; | 32 | pub mod adt; |
32 | pub mod data; | 33 | pub mod data; |
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 f4e2bda86..f42f92702 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -23,10 +23,11 @@ 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, MacroRules, Mod, ModItem, ModKind, | 29 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod, ModItem, |
29 | StructDefKind, | 30 | ModKind, StructDefKind, |
30 | }, | 31 | }, |
31 | macro_call_as_call_id, | 32 | macro_call_as_call_id, |
32 | nameres::{ | 33 | nameres::{ |
@@ -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, |
@@ -395,7 +403,7 @@ impl DefCollector<'_> { | |||
395 | /// macro_rules! foo { () => {} } | 403 | /// macro_rules! foo { () => {} } |
396 | /// use foo as bar; | 404 | /// use foo as bar; |
397 | /// ``` | 405 | /// ``` |
398 | fn define_macro( | 406 | fn define_macro_rules( |
399 | &mut self, | 407 | &mut self, |
400 | module_id: LocalModuleId, | 408 | module_id: LocalModuleId, |
401 | name: Name, | 409 | name: Name, |
@@ -430,6 +438,21 @@ impl DefCollector<'_> { | |||
430 | self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); | 438 | self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); |
431 | } | 439 | } |
432 | 440 | ||
441 | /// Define a macro 2.0 macro | ||
442 | /// | ||
443 | /// The scoped of macro 2.0 macro is equal to normal function | ||
444 | fn define_macro_def( | ||
445 | &mut self, | ||
446 | module_id: LocalModuleId, | ||
447 | name: Name, | ||
448 | macro_: MacroDefId, | ||
449 | vis: &RawVisibility, | ||
450 | ) { | ||
451 | let vis = | ||
452 | self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public); | ||
453 | self.update(module_id, &[(Some(name), PerNs::macros(macro_, vis))], vis, ImportType::Named); | ||
454 | } | ||
455 | |||
433 | /// Define a proc macro | 456 | /// Define a proc macro |
434 | /// | 457 | /// |
435 | /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. | 458 | /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. |
@@ -1061,40 +1084,7 @@ impl ModCollector<'_, '_> { | |||
1061 | } | 1084 | } |
1062 | ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), | 1085 | ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), |
1063 | ModItem::MacroRules(id) => self.collect_macro_rules(id), | 1086 | ModItem::MacroRules(id) => self.collect_macro_rules(id), |
1064 | ModItem::MacroDef(id) => { | 1087 | ModItem::MacroDef(id) => self.collect_macro_def(id), |
1065 | let mac = &self.item_tree[id]; | ||
1066 | let ast_id = InFile::new(self.file_id, mac.ast_id.upcast()); | ||
1067 | |||
1068 | // "Macro 2.0" is not currently supported by rust-analyzer, but libcore uses it | ||
1069 | // to define builtin macros, so we support at least that part. | ||
1070 | let attrs = self.item_tree.attrs( | ||
1071 | self.def_collector.db, | ||
1072 | krate, | ||
1073 | ModItem::from(id).into(), | ||
1074 | ); | ||
1075 | if attrs.by_key("rustc_builtin_macro").exists() { | ||
1076 | let krate = self.def_collector.def_map.krate; | ||
1077 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) | ||
1078 | .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); | ||
1079 | if let Some(macro_id) = macro_id { | ||
1080 | let vis = self | ||
1081 | .def_collector | ||
1082 | .def_map | ||
1083 | .resolve_visibility( | ||
1084 | self.def_collector.db, | ||
1085 | self.module_id, | ||
1086 | &self.item_tree[mac.visibility], | ||
1087 | ) | ||
1088 | .unwrap_or(Visibility::Public); | ||
1089 | self.def_collector.update( | ||
1090 | self.module_id, | ||
1091 | &[(Some(mac.name.clone()), PerNs::macros(macro_id, vis))], | ||
1092 | vis, | ||
1093 | ImportType::Named, | ||
1094 | ); | ||
1095 | } | ||
1096 | } | ||
1097 | } | ||
1098 | ModItem::Impl(imp) => { | 1088 | ModItem::Impl(imp) => { |
1099 | let module = self.def_collector.def_map.module_id(self.module_id); | 1089 | let module = self.def_collector.def_map.module_id(self.module_id); |
1100 | let impl_id = | 1090 | let impl_id = |
@@ -1412,9 +1402,19 @@ impl ModCollector<'_, '_> { | |||
1412 | 1402 | ||
1413 | // Case 1: builtin macros | 1403 | // Case 1: builtin macros |
1414 | if attrs.by_key("rustc_builtin_macro").exists() { | 1404 | if attrs.by_key("rustc_builtin_macro").exists() { |
1405 | // `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name. | ||
1406 | let name; | ||
1407 | let name = match attrs.by_key("rustc_builtin_macro").string_value() { | ||
1408 | Some(it) => { | ||
1409 | // FIXME: a hacky way to create a Name from string. | ||
1410 | name = tt::Ident { text: it.clone(), id: tt::TokenId::unspecified() }.as_name(); | ||
1411 | &name | ||
1412 | } | ||
1413 | None => &mac.name, | ||
1414 | }; | ||
1415 | let krate = self.def_collector.def_map.krate; | 1415 | let krate = self.def_collector.def_map.krate; |
1416 | if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) { | 1416 | if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) { |
1417 | self.def_collector.define_macro( | 1417 | self.def_collector.define_macro_rules( |
1418 | self.module_id, | 1418 | self.module_id, |
1419 | mac.name.clone(), | 1419 | mac.name.clone(), |
1420 | macro_id, | 1420 | macro_id, |
@@ -1430,11 +1430,53 @@ impl ModCollector<'_, '_> { | |||
1430 | kind: MacroDefKind::Declarative(ast_id), | 1430 | kind: MacroDefKind::Declarative(ast_id), |
1431 | local_inner: is_local_inner, | 1431 | local_inner: is_local_inner, |
1432 | }; | 1432 | }; |
1433 | self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export); | 1433 | self.def_collector.define_macro_rules( |
1434 | self.module_id, | ||
1435 | mac.name.clone(), | ||
1436 | macro_id, | ||
1437 | is_export, | ||
1438 | ); | ||
1439 | } | ||
1440 | |||
1441 | fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>) { | ||
1442 | let krate = self.def_collector.def_map.krate; | ||
1443 | let mac = &self.item_tree[id]; | ||
1444 | let ast_id = InFile::new(self.file_id, mac.ast_id.upcast()); | ||
1445 | |||
1446 | // Case 1: bulitin macros | ||
1447 | let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); | ||
1448 | if attrs.by_key("rustc_builtin_macro").exists() { | ||
1449 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) | ||
1450 | .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); | ||
1451 | |||
1452 | if let Some(macro_id) = macro_id { | ||
1453 | self.def_collector.define_macro_def( | ||
1454 | self.module_id, | ||
1455 | mac.name.clone(), | ||
1456 | macro_id, | ||
1457 | &self.item_tree[mac.visibility], | ||
1458 | ); | ||
1459 | } | ||
1460 | return; | ||
1461 | } | ||
1462 | |||
1463 | // Case 2: normal `macro` | ||
1464 | let macro_id = MacroDefId { | ||
1465 | krate: self.def_collector.def_map.krate, | ||
1466 | kind: MacroDefKind::Declarative(ast_id), | ||
1467 | local_inner: false, | ||
1468 | }; | ||
1469 | |||
1470 | self.def_collector.define_macro_def( | ||
1471 | self.module_id, | ||
1472 | mac.name.clone(), | ||
1473 | macro_id, | ||
1474 | &self.item_tree[mac.visibility], | ||
1475 | ); | ||
1434 | } | 1476 | } |
1435 | 1477 | ||
1436 | fn collect_macro_call(&mut self, mac: &MacroCall) { | 1478 | fn collect_macro_call(&mut self, mac: &MacroCall) { |
1437 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); | 1479 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, (*mac.path).clone()); |
1438 | 1480 | ||
1439 | // Case 1: try to resolve in legacy scope and expand macro_rules | 1481 | // Case 1: try to resolve in legacy scope and expand macro_rules |
1440 | let mut error = None; | 1482 | 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/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index 6d3cb8d7a..c37f915ab 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -837,3 +837,21 @@ fn collects_derive_helpers() { | |||
837 | _ => unreachable!(), | 837 | _ => unreachable!(), |
838 | } | 838 | } |
839 | } | 839 | } |
840 | |||
841 | #[test] | ||
842 | fn resolve_macro_def() { | ||
843 | check( | ||
844 | r#" | ||
845 | //- /lib.rs | ||
846 | pub macro structs($($i:ident),*) { | ||
847 | $(struct $i { field: u32 } )* | ||
848 | } | ||
849 | structs!(Foo); | ||
850 | "#, | ||
851 | expect![[r#" | ||
852 | crate | ||
853 | Foo: t | ||
854 | structs: m | ||
855 | "#]], | ||
856 | ); | ||
857 | } | ||
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index 8c923bb7b..f9c8328f0 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 { |
@@ -122,8 +122,8 @@ impl ModPath { | |||
122 | pub struct Path { | 122 | 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<Interned<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 505493a74..7b29d9d4f 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; |
@@ -68,15 +69,17 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
68 | match trait_ref { | 69 | match trait_ref { |
69 | // <T>::foo | 70 | // <T>::foo |
70 | None => { | 71 | None => { |
71 | type_anchor = Some(Box::new(self_type)); | 72 | type_anchor = Some(Interned::new(self_type)); |
72 | kind = PathKind::Plain; | 73 | kind = PathKind::Plain; |
73 | } | 74 | } |
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)?; |
77 | kind = path.mod_path.kind; | 78 | let mod_path = (*path.mod_path).clone(); |
79 | let num_segments = path.mod_path.segments.len(); | ||
80 | kind = mod_path.kind; | ||
78 | 81 | ||
79 | let mut prefix_segments = path.mod_path.segments; | 82 | let mut prefix_segments = mod_path.segments; |
80 | prefix_segments.reverse(); | 83 | prefix_segments.reverse(); |
81 | segments.extend(prefix_segments); | 84 | segments.extend(prefix_segments); |
82 | 85 | ||
@@ -85,7 +88,8 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
85 | generic_args.extend(prefix_args); | 88 | generic_args.extend(prefix_args); |
86 | 89 | ||
87 | // Insert the type reference (T in the above example) as Self parameter for the trait | 90 | // Insert the type reference (T in the above example) as Self parameter for the trait |
88 | let last_segment = generic_args.last_mut()?; | 91 | let last_segment = |
92 | generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?; | ||
89 | if last_segment.is_none() { | 93 | if last_segment.is_none() { |
90 | *last_segment = Some(Arc::new(GenericArgs::empty())); | 94 | *last_segment = Some(Arc::new(GenericArgs::empty())); |
91 | }; | 95 | }; |
@@ -138,7 +142,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
138 | } | 142 | } |
139 | } | 143 | } |
140 | 144 | ||
141 | let mod_path = ModPath::from_segments(kind, segments); | 145 | let mod_path = Interned::new(ModPath::from_segments(kind, segments)); |
142 | return Some(Path { type_anchor, mod_path, generic_args }); | 146 | return Some(Path { type_anchor, mod_path, generic_args }); |
143 | 147 | ||
144 | fn qualifier(path: &ast::Path) -> Option<ast::Path> { | 148 | fn qualifier(path: &ast::Path) -> Option<ast::Path> { |
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index a73585ee7..0391cc49b 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs | |||
@@ -14,6 +14,7 @@ use crate::{ | |||
14 | db::DefDatabase, | 14 | db::DefDatabase, |
15 | expr::{ExprId, LabelId, PatId}, | 15 | expr::{ExprId, LabelId, PatId}, |
16 | generics::GenericParams, | 16 | generics::GenericParams, |
17 | intern::Interned, | ||
17 | item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, | 18 | item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, |
18 | nameres::DefMap, | 19 | nameres::DefMap, |
19 | path::{ModPath, PathKind}, | 20 | path::{ModPath, PathKind}, |
@@ -50,7 +51,7 @@ enum Scope { | |||
50 | /// All the items and imported names of a module | 51 | /// All the items and imported names of a module |
51 | ModuleScope(ModuleItemMap), | 52 | ModuleScope(ModuleItemMap), |
52 | /// Brings the generic parameters of an item into scope | 53 | /// Brings the generic parameters of an item into scope |
53 | GenericParams { def: GenericDefId, params: Arc<GenericParams> }, | 54 | GenericParams { def: GenericDefId, params: Interned<GenericParams> }, |
54 | /// Brings `Self` in `impl` block into scope | 55 | /// Brings `Self` in `impl` block into scope |
55 | ImplDefScope(ImplId), | 56 | ImplDefScope(ImplId), |
56 | /// Brings `Self` in enum, struct and union definitions into scope | 57 | /// Brings `Self` in enum, struct and union definitions into scope |
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 | } |
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs index 049b2e462..4c24aae94 100644 --- a/crates/hir_def/src/type_ref.rs +++ b/crates/hir_def/src/type_ref.rs | |||
@@ -51,6 +51,23 @@ impl Rawness { | |||
51 | } | 51 | } |
52 | } | 52 | } |
53 | 53 | ||
54 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||
55 | pub struct TraitRef { | ||
56 | pub path: Path, | ||
57 | } | ||
58 | |||
59 | impl TraitRef { | ||
60 | /// Converts an `ast::PathType` to a `hir::TraitRef`. | ||
61 | pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Option<Self> { | ||
62 | // FIXME: Use `Path::from_src` | ||
63 | match node { | ||
64 | ast::Type::PathType(path) => { | ||
65 | path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path }) | ||
66 | } | ||
67 | _ => None, | ||
68 | } | ||
69 | } | ||
70 | } | ||
54 | /// Compare ty::Ty | 71 | /// Compare ty::Ty |
55 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | 72 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] |
56 | pub enum TypeRef { | 73 | pub enum TypeRef { |
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs index 7d00a37c4..9908cd926 100644 --- a/crates/hir_def/src/visibility.rs +++ b/crates/hir_def/src/visibility.rs | |||
@@ -11,7 +11,7 @@ use crate::{ | |||
11 | nameres::DefMap, | 11 | nameres::DefMap, |
12 | path::{ModPath, PathKind}, | 12 | path::{ModPath, PathKind}, |
13 | resolver::HasResolver, | 13 | resolver::HasResolver, |
14 | FunctionId, HasModule, LocalFieldId, ModuleDefId, ModuleId, VariantId, | 14 | FunctionId, HasModule, LocalFieldId, ModuleId, VariantId, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | /// Visibility of an item, not yet resolved. | 17 | /// Visibility of an item, not yet resolved. |
@@ -25,7 +25,7 @@ pub enum RawVisibility { | |||
25 | } | 25 | } |
26 | 26 | ||
27 | impl RawVisibility { | 27 | impl RawVisibility { |
28 | pub(crate) const fn private() -> RawVisibility { | 28 | pub(crate) fn private() -> RawVisibility { |
29 | RawVisibility::Module(ModPath::from_kind(PathKind::Super(0))) | 29 | RawVisibility::Module(ModPath::from_kind(PathKind::Super(0))) |
30 | } | 30 | } |
31 | 31 | ||
@@ -217,6 +217,6 @@ pub(crate) fn field_visibilities_query( | |||
217 | 217 | ||
218 | /// Resolve visibility of a function. | 218 | /// Resolve visibility of a function. |
219 | pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility { | 219 | pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility { |
220 | let resolver = ModuleDefId::from(def).module(db).unwrap().resolver(db); | 220 | let resolver = def.resolver(db); |
221 | db.function_data(def).visibility.resolve(db, &resolver) | 221 | db.function_data(def).visibility.resolve(db, &resolver) |
222 | } | 222 | } |