aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r--crates/hir_def/src/adt.rs9
-rw-r--r--crates/hir_def/src/attr.rs168
-rw-r--r--crates/hir_def/src/body.rs24
-rw-r--r--crates/hir_def/src/body/lower.rs109
-rw-r--r--crates/hir_def/src/body/tests.rs2
-rw-r--r--crates/hir_def/src/child_by_source.rs2
-rw-r--r--crates/hir_def/src/data.rs90
-rw-r--r--crates/hir_def/src/db.rs18
-rw-r--r--crates/hir_def/src/expr.rs23
-rw-r--r--crates/hir_def/src/generics.rs62
-rw-r--r--crates/hir_def/src/intern.rs216
-rw-r--r--crates/hir_def/src/item_scope.rs35
-rw-r--r--crates/hir_def/src/item_tree.rs163
-rw-r--r--crates/hir_def/src/item_tree/lower.rs129
-rw-r--r--crates/hir_def/src/lib.rs22
-rw-r--r--crates/hir_def/src/nameres.rs25
-rw-r--r--crates/hir_def/src/nameres/collector.rs204
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs22
-rw-r--r--crates/hir_def/src/nameres/tests/macros.rs18
-rw-r--r--crates/hir_def/src/path.rs22
-rw-r--r--crates/hir_def/src/path/lower.rs14
-rw-r--r--crates/hir_def/src/resolver.rs3
-rw-r--r--crates/hir_def/src/test_db.rs13
-rw-r--r--crates/hir_def/src/type_ref.rs17
-rw-r--r--crates/hir_def/src/visibility.rs6
25 files changed, 993 insertions, 423 deletions
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};
15use crate::{ 15use 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)]
59pub struct FieldData { 60pub 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..d9df7564d 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
3use std::{ops, sync::Arc}; 3use std::{
4 convert::{TryFrom, TryInto},
5 ops,
6 sync::Arc,
7};
4 8
5use base_db::CrateId; 9use base_db::CrateId;
6use cfg::{CfgExpr, CfgOptions}; 10use cfg::{CfgExpr, CfgOptions};
@@ -12,12 +16,13 @@ use mbe::ast_to_token_tree;
12use smallvec::{smallvec, SmallVec}; 16use smallvec::{smallvec, SmallVec};
13use syntax::{ 17use syntax::{
14 ast::{self, AstNode, AttrsOwner}, 18 ast::{self, AstNode, AttrsOwner},
15 match_ast, AstToken, SmolStr, SyntaxNode, 19 match_ast, AstPtr, AstToken, SmolStr, SyntaxNode, TextRange, TextSize,
16}; 20};
17use tt::Subtree; 21use tt::Subtree;
18 22
19use crate::{ 23use 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<_>>();
@@ -210,12 +215,11 @@ impl Attrs {
210 let mut res = ArenaMap::default(); 215 let mut res = ArenaMap::default();
211 216
212 for (id, fld) in src.value.iter() { 217 for (id, fld) in src.value.iter() {
213 let attrs = match fld { 218 let owner: &dyn AttrsOwner = match fld {
214 Either::Left(_tuple) => Attrs::default(), 219 Either::Left(tuple) => tuple,
215 Either::Right(record) => { 220 Either::Right(record) => record,
216 RawAttrs::from_attrs_owner(db, src.with_value(record)).filter(db, krate)
217 }
218 }; 221 };
222 let attrs = RawAttrs::from_attrs_owner(db, src.with_value(owner)).filter(db, krate);
219 223
220 res.insert(id, attrs); 224 res.insert(id, attrs);
221 } 225 }
@@ -399,10 +403,14 @@ impl AttrsWithOwner {
399 return AttrSourceMap { attrs }; 403 return AttrSourceMap { attrs };
400 } 404 }
401 AttrDefId::FieldId(id) => { 405 AttrDefId::FieldId(id) => {
402 id.parent.child_source(db).map(|source| match &source[id.local_id] { 406 let map = db.fields_attrs_source_map(id.parent);
403 Either::Left(field) => ast::AttrsOwnerNode::new(field.clone()), 407 let file_id = id.parent.file_id(db);
404 Either::Right(field) => ast::AttrsOwnerNode::new(field.clone()), 408 let root = db.parse_or_expand(file_id).unwrap();
405 }) 409 let owner = match &map[id.local_id] {
410 Either::Left(it) => ast::AttrsOwnerNode::new(it.to_node(&root)),
411 Either::Right(it) => ast::AttrsOwnerNode::new(it.to_node(&root)),
412 };
413 InFile::new(file_id, owner)
406 } 414 }
407 AttrDefId::AdtId(adt) => match adt { 415 AttrDefId::AdtId(adt) => match adt {
408 AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 416 AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
@@ -410,10 +418,12 @@ impl AttrsWithOwner {
410 AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 418 AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
411 }, 419 },
412 AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 420 AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
413 AttrDefId::EnumVariantId(id) => id 421 AttrDefId::EnumVariantId(id) => {
414 .parent 422 let map = db.variants_attrs_source_map(id.parent);
415 .child_source(db) 423 let file_id = id.parent.lookup(db).id.file_id();
416 .map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())), 424 let root = db.parse_or_expand(file_id).unwrap();
425 InFile::new(file_id, ast::AttrsOwnerNode::new(map[id.local_id].to_node(&root)))
426 }
417 AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 427 AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
418 AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 428 AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
419 AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 429 AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
@@ -451,6 +461,55 @@ impl AttrsWithOwner {
451 .collect(), 461 .collect(),
452 } 462 }
453 } 463 }
464
465 pub fn docs_with_rangemap(
466 &self,
467 db: &dyn DefDatabase,
468 ) -> Option<(Documentation, DocsRangeMap)> {
469 // FIXME: code duplication in `docs` above
470 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? {
471 AttrInput::Literal(s) => Some((s, attr.index)),
472 AttrInput::TokenTree(_) => None,
473 });
474 let indent = docs
475 .clone()
476 .flat_map(|(s, _)| s.lines())
477 .filter(|line| !line.chars().all(|c| c.is_whitespace()))
478 .map(|line| line.chars().take_while(|c| c.is_whitespace()).count())
479 .min()
480 .unwrap_or(0);
481 let mut buf = String::new();
482 let mut mapping = Vec::new();
483 for (doc, idx) in docs {
484 // str::lines doesn't yield anything for the empty string
485 if !doc.is_empty() {
486 for line in doc.split('\n') {
487 let line = line.trim_end();
488 let line_len = line.len();
489 let (offset, line) = match line.char_indices().nth(indent) {
490 Some((offset, _)) => (offset, &line[offset..]),
491 None => (0, line),
492 };
493 let buf_offset = buf.len();
494 buf.push_str(line);
495 mapping.push((
496 TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?),
497 idx,
498 TextRange::new(offset.try_into().ok()?, line_len.try_into().ok()?),
499 ));
500 buf.push('\n');
501 }
502 } else {
503 buf.push('\n');
504 }
505 }
506 buf.pop();
507 if buf.is_empty() {
508 None
509 } else {
510 Some((Documentation(buf), DocsRangeMap { mapping, source: self.source_map(db).attrs }))
511 }
512 }
454} 513}
455 514
456fn inner_attributes( 515fn inner_attributes(
@@ -507,10 +566,48 @@ impl AttrSourceMap {
507 } 566 }
508} 567}
509 568
569/// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree.
570pub struct DocsRangeMap {
571 source: Vec<InFile<Either<ast::Attr, ast::Comment>>>,
572 // (docstring-line-range, attr_index, attr-string-range)
573 // a mapping from the text range of a line of the [`Documentation`] to the attribute index and
574 // the original (untrimmed) syntax doc line
575 mapping: Vec<(TextRange, u32, TextRange)>,
576}
577
578impl DocsRangeMap {
579 pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
580 let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
581 let (line_docs_range, idx, original_line_src_range) = self.mapping[found].clone();
582 if !line_docs_range.contains_range(range) {
583 return None;
584 }
585
586 let relative_range = range - line_docs_range.start();
587
588 let &InFile { file_id, value: ref source } = &self.source[idx as usize];
589 match source {
590 Either::Left(_) => None, // FIXME, figure out a nice way to handle doc attributes here
591 // as well as for whats done in syntax highlight doc injection
592 Either::Right(comment) => {
593 let text_range = comment.syntax().text_range();
594 let range = TextRange::at(
595 text_range.start()
596 + TextSize::try_from(comment.prefix().len()).ok()?
597 + original_line_src_range.start()
598 + relative_range.start(),
599 text_range.len().min(range.len()),
600 );
601 Some(InFile { file_id, value: range })
602 }
603 }
604 }
605}
606
510#[derive(Debug, Clone, PartialEq, Eq)] 607#[derive(Debug, Clone, PartialEq, Eq)]
511pub struct Attr { 608pub struct Attr {
512 index: u32, 609 index: u32,
513 pub(crate) path: ModPath, 610 pub(crate) path: Interned<ModPath>,
514 pub(crate) input: Option<AttrInput>, 611 pub(crate) input: Option<AttrInput>,
515} 612}
516 613
@@ -524,7 +621,7 @@ pub enum AttrInput {
524 621
525impl Attr { 622impl Attr {
526 fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> { 623 fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> {
527 let path = ModPath::from_src(ast.path()?, hygiene)?; 624 let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?);
528 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { 625 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
529 let value = match lit.kind() { 626 let value = match lit.kind() {
530 ast::LiteralKind::String(string) => string.value()?.into(), 627 ast::LiteralKind::String(string) => string.value()?.into(),
@@ -532,7 +629,7 @@ impl Attr {
532 }; 629 };
533 Some(AttrInput::Literal(value)) 630 Some(AttrInput::Literal(value))
534 } else if let Some(tt) = ast.token_tree() { 631 } else if let Some(tt) = ast.token_tree() {
535 Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0)) 632 Some(AttrInput::TokenTree(ast_to_token_tree(&tt).0))
536 } else { 633 } else {
537 None 634 None
538 }; 635 };
@@ -655,3 +752,36 @@ fn collect_attrs(
655 752
656 attrs.into_iter().map(|(_, attr)| attr) 753 attrs.into_iter().map(|(_, attr)| attr)
657} 754}
755
756pub(crate) fn variants_attrs_source_map(
757 db: &dyn DefDatabase,
758 def: EnumId,
759) -> Arc<ArenaMap<LocalEnumVariantId, AstPtr<ast::Variant>>> {
760 let mut res = ArenaMap::default();
761 let child_source = def.child_source(db);
762
763 for (idx, variant) in child_source.value.iter() {
764 res.insert(idx, AstPtr::new(variant));
765 }
766
767 Arc::new(res)
768}
769
770pub(crate) fn fields_attrs_source_map(
771 db: &dyn DefDatabase,
772 def: VariantId,
773) -> Arc<ArenaMap<LocalFieldId, Either<AstPtr<ast::TupleField>, AstPtr<ast::RecordField>>>> {
774 let mut res = ArenaMap::default();
775 let child_source = def.child_source(db);
776
777 for (idx, variant) in child_source.value.iter() {
778 res.insert(
779 idx,
780 variant
781 .as_ref()
782 .either(|l| Either::Left(AstPtr::new(l)), |r| Either::Right(AstPtr::new(r))),
783 );
784 }
785
786 Arc::new(res)
787}
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
323impl Index<ExprId> for Body { 343impl Index<ExprId> for Body {
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 19f5065d1..bfb75a8a5 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -30,6 +30,7 @@ use crate::{
30 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, 30 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
31 Statement, 31 Statement,
32 }, 32 },
33 intern::Interned,
33 item_scope::BuiltinShadowMode, 34 item_scope::BuiltinShadowMode,
34 path::{GenericArgs, Path}, 35 path::{GenericArgs, Path},
35 type_ref::{Mutability, Rawness, TypeRef}, 36 type_ref::{Mutability, Rawness, TypeRef},
@@ -74,6 +75,7 @@ pub(super) fn lower(
74 _c: Count::new(), 75 _c: Count::new(),
75 }, 76 },
76 expander, 77 expander,
78 statements_in_scope: Vec::new(),
77 } 79 }
78 .collect(params, body) 80 .collect(params, body)
79} 81}
@@ -83,6 +85,7 @@ struct ExprCollector<'a> {
83 expander: Expander, 85 expander: Expander,
84 body: Body, 86 body: Body,
85 source_map: BodySourceMap, 87 source_map: BodySourceMap,
88 statements_in_scope: Vec<Statement>,
86} 89}
87 90
88impl ExprCollector<'_> { 91impl ExprCollector<'_> {
@@ -320,8 +323,10 @@ impl ExprCollector<'_> {
320 Vec::new() 323 Vec::new()
321 }; 324 };
322 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); 325 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
323 let generic_args = 326 let generic_args = e
324 e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); 327 .generic_arg_list()
328 .and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
329 .map(Box::new);
325 self.alloc_expr( 330 self.alloc_expr(
326 Expr::MethodCall { receiver, method_name, args, generic_args }, 331 Expr::MethodCall { receiver, method_name, args, generic_args },
327 syntax_ptr, 332 syntax_ptr,
@@ -383,7 +388,7 @@ impl ExprCollector<'_> {
383 self.alloc_expr(Expr::Yield { expr }, syntax_ptr) 388 self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
384 } 389 }
385 ast::Expr::RecordExpr(e) => { 390 ast::Expr::RecordExpr(e) => {
386 let path = e.path().and_then(|path| self.expander.parse_path(path)); 391 let path = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
387 let record_lit = if let Some(nfl) = e.record_expr_field_list() { 392 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
388 let fields = nfl 393 let fields = nfl
389 .fields() 394 .fields()
@@ -428,7 +433,7 @@ impl ExprCollector<'_> {
428 } 433 }
429 ast::Expr::CastExpr(e) => { 434 ast::Expr::CastExpr(e) => {
430 let expr = self.collect_expr_opt(e.expr()); 435 let expr = self.collect_expr_opt(e.expr());
431 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty()); 436 let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
432 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) 437 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
433 } 438 }
434 ast::Expr::RefExpr(e) => { 439 ast::Expr::RefExpr(e) => {
@@ -462,13 +467,16 @@ impl ExprCollector<'_> {
462 if let Some(pl) = e.param_list() { 467 if let Some(pl) = e.param_list() {
463 for param in pl.params() { 468 for param in pl.params() {
464 let pat = self.collect_pat_opt(param.pat()); 469 let pat = self.collect_pat_opt(param.pat());
465 let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 470 let type_ref =
471 param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
466 args.push(pat); 472 args.push(pat);
467 arg_types.push(type_ref); 473 arg_types.push(type_ref);
468 } 474 }
469 } 475 }
470 let ret_type = 476 let ret_type = e
471 e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it)); 477 .ret_type()
478 .and_then(|r| r.ty())
479 .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
472 let body = self.collect_expr_opt(e.body()); 480 let body = self.collect_expr_opt(e.body());
473 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) 481 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
474 } 482 }
@@ -533,15 +541,13 @@ impl ExprCollector<'_> {
533 ids[0] 541 ids[0]
534 } 542 }
535 ast::Expr::MacroStmts(e) => { 543 ast::Expr::MacroStmts(e) => {
536 // FIXME: these statements should be held by some hir containter 544 e.statements().for_each(|s| self.collect_stmt(s));
537 for stmt in e.statements() { 545 let tail = e
538 self.collect_stmt(stmt); 546 .expr()
539 } 547 .map(|e| self.collect_expr(e))
540 if let Some(expr) = e.expr() { 548 .unwrap_or_else(|| self.alloc_expr(Expr::Missing, syntax_ptr.clone()));
541 self.collect_expr(expr) 549
542 } else { 550 self.alloc_expr(Expr::MacroStmts { tail }, syntax_ptr)
543 self.alloc_expr(Expr::Missing, syntax_ptr)
544 }
545 } 551 }
546 }) 552 })
547 } 553 }
@@ -618,58 +624,55 @@ impl ExprCollector<'_> {
618 } 624 }
619 } 625 }
620 626
621 fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> { 627 fn collect_stmt(&mut self, s: ast::Stmt) {
622 let stmt = match s { 628 match s {
623 ast::Stmt::LetStmt(stmt) => { 629 ast::Stmt::LetStmt(stmt) => {
624 self.check_cfg(&stmt)?; 630 if self.check_cfg(&stmt).is_none() {
625 631 return;
632 }
626 let pat = self.collect_pat_opt(stmt.pat()); 633 let pat = self.collect_pat_opt(stmt.pat());
627 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 634 let type_ref =
635 stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
628 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 636 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
629 vec![Statement::Let { pat, type_ref, initializer }] 637 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
630 } 638 }
631 ast::Stmt::ExprStmt(stmt) => { 639 ast::Stmt::ExprStmt(stmt) => {
632 self.check_cfg(&stmt)?; 640 if self.check_cfg(&stmt).is_none() {
641 return;
642 }
633 643
634 // Note that macro could be expended to multiple statements 644 // Note that macro could be expended to multiple statements
635 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { 645 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
636 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); 646 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
637 let mut stmts = vec![];
638 647
639 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { 648 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| {
640 match expansion { 649 match expansion {
641 Some(expansion) => { 650 Some(expansion) => {
642 let statements: ast::MacroStmts = expansion; 651 let statements: ast::MacroStmts = expansion;
643 652
644 statements.statements().for_each(|stmt| { 653 statements.statements().for_each(|stmt| this.collect_stmt(stmt));
645 if let Some(mut r) = this.collect_stmt(stmt) {
646 stmts.append(&mut r);
647 }
648 });
649 if let Some(expr) = statements.expr() { 654 if let Some(expr) = statements.expr() {
650 stmts.push(Statement::Expr(this.collect_expr(expr))); 655 let expr = this.collect_expr(expr);
656 this.statements_in_scope.push(Statement::Expr(expr));
651 } 657 }
652 } 658 }
653 None => { 659 None => {
654 stmts.push(Statement::Expr( 660 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
655 this.alloc_expr(Expr::Missing, syntax_ptr.clone()), 661 this.statements_in_scope.push(Statement::Expr(expr));
656 ));
657 } 662 }
658 } 663 }
659 }); 664 });
660 stmts
661 } else { 665 } else {
662 vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))] 666 let expr = self.collect_expr_opt(stmt.expr());
667 self.statements_in_scope.push(Statement::Expr(expr));
663 } 668 }
664 } 669 }
665 ast::Stmt::Item(item) => { 670 ast::Stmt::Item(item) => {
666 self.check_cfg(&item)?; 671 if self.check_cfg(&item).is_none() {
667 672 return;
668 return None; 673 }
669 } 674 }
670 }; 675 }
671
672 Some(stmt)
673 } 676 }
674 677
675 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { 678 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
@@ -677,18 +680,22 @@ impl ExprCollector<'_> {
677 let block_loc = 680 let block_loc =
678 BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) }; 681 BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
679 let block_id = self.db.intern_block(block_loc); 682 let block_id = self.db.intern_block(block_loc);
680 self.body.block_scopes.push(block_id);
681 683
682 let opt_def_map = self.db.block_def_map(block_id); 684 let (module, def_map) = match self.db.block_def_map(block_id) {
683 let has_def_map = opt_def_map.is_some(); 685 Some(def_map) => {
684 let def_map = opt_def_map.unwrap_or_else(|| self.expander.def_map.clone()); 686 self.body.block_scopes.push(block_id);
685 let module = if has_def_map { def_map.root() } else { self.expander.module }; 687 (def_map.root(), def_map)
688 }
689 None => (self.expander.module, self.expander.def_map.clone()),
690 };
686 let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); 691 let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
687 let prev_local_module = mem::replace(&mut self.expander.module, module); 692 let prev_local_module = mem::replace(&mut self.expander.module, module);
693 let prev_statements = std::mem::take(&mut self.statements_in_scope);
694
695 block.statements().for_each(|s| self.collect_stmt(s));
688 696
689 let statements =
690 block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect();
691 let tail = block.tail_expr().map(|e| self.collect_expr(e)); 697 let tail = block.tail_expr().map(|e| self.collect_expr(e));
698 let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements);
692 let syntax_node_ptr = AstPtr::new(&block.into()); 699 let syntax_node_ptr = AstPtr::new(&block.into());
693 let expr_id = self.alloc_expr( 700 let expr_id = self.alloc_expr(
694 Expr::Block { id: block_id, statements, tail, label: None }, 701 Expr::Block { id: block_id, statements, tail, label: None },
@@ -755,7 +762,7 @@ impl ExprCollector<'_> {
755 } 762 }
756 } 763 }
757 ast::Pat::TupleStructPat(p) => { 764 ast::Pat::TupleStructPat(p) => {
758 let path = p.path().and_then(|path| self.expander.parse_path(path)); 765 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
759 let (args, ellipsis) = self.collect_tuple_pat(p.fields()); 766 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
760 Pat::TupleStruct { path, args, ellipsis } 767 Pat::TupleStruct { path, args, ellipsis }
761 } 768 }
@@ -765,7 +772,7 @@ impl ExprCollector<'_> {
765 Pat::Ref { pat, mutability } 772 Pat::Ref { pat, mutability }
766 } 773 }
767 ast::Pat::PathPat(p) => { 774 ast::Pat::PathPat(p) => {
768 let path = p.path().and_then(|path| self.expander.parse_path(path)); 775 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
769 path.map(Pat::Path).unwrap_or(Pat::Missing) 776 path.map(Pat::Path).unwrap_or(Pat::Missing)
770 } 777 }
771 ast::Pat::OrPat(p) => { 778 ast::Pat::OrPat(p) => {
@@ -779,7 +786,7 @@ impl ExprCollector<'_> {
779 } 786 }
780 ast::Pat::WildcardPat(_) => Pat::Wild, 787 ast::Pat::WildcardPat(_) => Pat::Wild,
781 ast::Pat::RecordPat(p) => { 788 ast::Pat::RecordPat(p) => {
782 let path = p.path().and_then(|path| self.expander.parse_path(path)); 789 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
783 let args: Vec<_> = p 790 let args: Vec<_> = p
784 .record_pat_field_list() 791 .record_pat_field_list()
785 .expect("every struct should have a field list") 792 .expect("every struct should have a field list")
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index faa133297..c1d3e998f 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -143,7 +143,7 @@ fn f() {
143 //^^^^^^^^^^^^^ could not convert tokens 143 //^^^^^^^^^^^^^ could not convert tokens
144 144
145 env!("OUT_DIR"); 145 env!("OUT_DIR");
146 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 146 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
147 147
148 compile_error!("compile_error works"); 148 compile_error!("compile_error works");
149 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works 149 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
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 {
160impl ChildBySource for DefWithBodyId { 160impl 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)]
20pub struct FunctionData { 21pub 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
35impl FunctionData { 31impl 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)]
77pub struct TypeAliasData { 109pub 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)]
158pub struct ImplData { 190pub 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 {
195pub struct ConstData { 227pub 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)]
217pub struct StaticData { 249pub 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..7eadc8e0d 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -2,9 +2,10 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use base_db::{salsa, CrateId, SourceDatabase, Upcast}; 4use base_db::{salsa, CrateId, SourceDatabase, Upcast};
5use either::Either;
5use hir_expand::{db::AstDatabase, HirFileId}; 6use hir_expand::{db::AstDatabase, HirFileId};
6use la_arena::ArenaMap; 7use la_arena::ArenaMap;
7use syntax::SmolStr; 8use syntax::{ast, AstPtr, SmolStr};
8 9
9use crate::{ 10use crate::{
10 adt::{EnumData, StructData}, 11 adt::{EnumData, StructData},
@@ -13,6 +14,7 @@ use crate::{
13 data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData}, 14 data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData},
14 generics::GenericParams, 15 generics::GenericParams,
15 import_map::ImportMap, 16 import_map::ImportMap,
17 intern::Interned,
16 item_tree::ItemTree, 18 item_tree::ItemTree,
17 lang_item::{LangItemTarget, LangItems}, 19 lang_item::{LangItemTarget, LangItems},
18 nameres::DefMap, 20 nameres::DefMap,
@@ -113,7 +115,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
113 fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>; 115 fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
114 116
115 #[salsa::invoke(GenericParams::generic_params_query)] 117 #[salsa::invoke(GenericParams::generic_params_query)]
116 fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; 118 fn generic_params(&self, def: GenericDefId) -> Interned<GenericParams>;
117 119
118 #[salsa::invoke(Attrs::variants_attrs_query)] 120 #[salsa::invoke(Attrs::variants_attrs_query)]
119 fn variants_attrs(&self, def: EnumId) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>>; 121 fn variants_attrs(&self, def: EnumId) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>>;
@@ -121,6 +123,18 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
121 #[salsa::invoke(Attrs::fields_attrs_query)] 123 #[salsa::invoke(Attrs::fields_attrs_query)]
122 fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>; 124 fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>;
123 125
126 #[salsa::invoke(crate::attr::variants_attrs_source_map)]
127 fn variants_attrs_source_map(
128 &self,
129 def: EnumId,
130 ) -> Arc<ArenaMap<LocalEnumVariantId, AstPtr<ast::Variant>>>;
131
132 #[salsa::invoke(crate::attr::fields_attrs_source_map)]
133 fn fields_attrs_source_map(
134 &self,
135 def: VariantId,
136 ) -> Arc<ArenaMap<LocalFieldId, Either<AstPtr<ast::TupleField>, AstPtr<ast::RecordField>>>>;
137
124 #[salsa::invoke(AttrsWithOwner::attrs_query)] 138 #[salsa::invoke(AttrsWithOwner::attrs_query)]
125 fn attrs(&self, def: AttrDefId) -> AttrsWithOwner; 139 fn attrs(&self, def: AttrDefId) -> AttrsWithOwner;
126 140
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs
index 24be93773..b4ad984bd 100644
--- a/crates/hir_def/src/expr.rs
+++ b/crates/hir_def/src/expr.rs
@@ -18,6 +18,7 @@ use syntax::ast::RangeOp;
18 18
19use crate::{ 19use crate::{
20 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, 20 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
21 intern::Interned,
21 path::{GenericArgs, Path}, 22 path::{GenericArgs, Path},
22 type_ref::{Mutability, Rawness, TypeRef}, 23 type_ref::{Mutability, Rawness, TypeRef},
23 BlockId, 24 BlockId,
@@ -86,7 +87,7 @@ pub enum Expr {
86 receiver: ExprId, 87 receiver: ExprId,
87 method_name: Name, 88 method_name: Name,
88 args: Vec<ExprId>, 89 args: Vec<ExprId>,
89 generic_args: Option<GenericArgs>, 90 generic_args: Option<Box<GenericArgs>>,
90 }, 91 },
91 Match { 92 Match {
92 expr: ExprId, 93 expr: ExprId,
@@ -106,7 +107,7 @@ pub enum Expr {
106 expr: Option<ExprId>, 107 expr: Option<ExprId>,
107 }, 108 },
108 RecordLit { 109 RecordLit {
109 path: Option<Path>, 110 path: Option<Box<Path>>,
110 fields: Vec<RecordLitField>, 111 fields: Vec<RecordLitField>,
111 spread: Option<ExprId>, 112 spread: Option<ExprId>,
112 }, 113 },
@@ -131,7 +132,7 @@ pub enum Expr {
131 }, 132 },
132 Cast { 133 Cast {
133 expr: ExprId, 134 expr: ExprId,
134 type_ref: TypeRef, 135 type_ref: Interned<TypeRef>,
135 }, 136 },
136 Ref { 137 Ref {
137 expr: ExprId, 138 expr: ExprId,
@@ -161,8 +162,8 @@ pub enum Expr {
161 }, 162 },
162 Lambda { 163 Lambda {
163 args: Vec<PatId>, 164 args: Vec<PatId>,
164 arg_types: Vec<Option<TypeRef>>, 165 arg_types: Vec<Option<Interned<TypeRef>>>,
165 ret_type: Option<TypeRef>, 166 ret_type: Option<Interned<TypeRef>>,
166 body: ExprId, 167 body: ExprId,
167 }, 168 },
168 Tuple { 169 Tuple {
@@ -171,6 +172,9 @@ pub enum Expr {
171 Unsafe { 172 Unsafe {
172 body: ExprId, 173 body: ExprId,
173 }, 174 },
175 MacroStmts {
176 tail: ExprId,
177 },
174 Array(Array), 178 Array(Array),
175 Literal(Literal), 179 Literal(Literal),
176} 180}
@@ -237,7 +241,7 @@ pub struct RecordLitField {
237 241
238#[derive(Debug, Clone, Eq, PartialEq)] 242#[derive(Debug, Clone, Eq, PartialEq)]
239pub enum Statement { 243pub enum Statement {
240 Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> }, 244 Let { pat: PatId, type_ref: Option<Interned<TypeRef>>, initializer: Option<ExprId> },
241 Expr(ExprId), 245 Expr(ExprId),
242} 246}
243 247
@@ -357,6 +361,7 @@ impl Expr {
357 f(*repeat) 361 f(*repeat)
358 } 362 }
359 }, 363 },
364 Expr::MacroStmts { tail } => f(*tail),
360 Expr::Literal(_) => {} 365 Expr::Literal(_) => {}
361 } 366 }
362 } 367 }
@@ -408,13 +413,13 @@ pub enum Pat {
408 Wild, 413 Wild,
409 Tuple { args: Vec<PatId>, ellipsis: Option<usize> }, 414 Tuple { args: Vec<PatId>, ellipsis: Option<usize> },
410 Or(Vec<PatId>), 415 Or(Vec<PatId>),
411 Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool }, 416 Record { path: Option<Box<Path>>, args: Vec<RecordFieldPat>, ellipsis: bool },
412 Range { start: ExprId, end: ExprId }, 417 Range { start: ExprId, end: ExprId },
413 Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> }, 418 Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> },
414 Path(Path), 419 Path(Box<Path>),
415 Lit(ExprId), 420 Lit(ExprId),
416 Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, 421 Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
417 TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, 422 TupleStruct { path: Option<Box<Path>>, args: Vec<PatId>, ellipsis: Option<usize> },
418 Ref { pat: PatId, mutability: Mutability }, 423 Ref { pat: PatId, mutability: Mutability },
419 Box { inner: PatId }, 424 Box { inner: PatId },
420 ConstBlock(ExprId), 425 ConstBlock(ExprId),
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.
5use std::sync::Arc;
6 5
7use base_db::FileId; 6use base_db::FileId;
8use either::Either; 7use 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)]
30pub struct TypeParamData { 30pub 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)]
38pub struct LifetimeParamData { 38pub 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)]
44pub struct ConstParamData { 44pub 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)]
50pub enum TypeParamProvenance { 50pub 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)]
58pub struct GenericParams { 58pub 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)]
70pub enum WherePredicate { 70pub 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)]
77pub enum WherePredicateTypeTarget { 77pub 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
5use std::{
6 collections::HashMap,
7 fmt::{self, Debug},
8 hash::{BuildHasherDefault, Hash, Hasher},
9 ops::Deref,
10 sync::Arc,
11};
12
13use dashmap::{lock::RwLockWriteGuard, DashMap, SharedValue};
14use once_cell::sync::OnceCell;
15use rustc_hash::FxHasher;
16
17use crate::generics::GenericParams;
18
19type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>;
20type Guard<T> =
21 RwLockWriteGuard<'static, HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>>;
22
23pub struct Interned<T: Internable + ?Sized> {
24 arc: Arc<T>,
25}
26
27impl<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
39impl<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
70impl 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
82impl<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
94impl<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.
120impl<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
129impl<T: Internable> Eq for Interned<T> {}
130
131impl PartialEq for Interned<str> {
132 fn eq(&self, other: &Self) -> bool {
133 Arc::ptr_eq(&self.arc, &other.arc)
134 }
135}
136
137impl Eq for Interned<str> {}
138
139impl<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
146impl<T: Internable + ?Sized> AsRef<T> for Interned<T> {
147 #[inline]
148 fn as_ref(&self) -> &T {
149 &self.arc
150 }
151}
152
153impl<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
162impl<T: Internable + ?Sized> Clone for Interned<T> {
163 fn clone(&self) -> Self {
164 Self { arc: self.arc.clone() }
165 }
166}
167
168impl<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
174pub struct InternStorage<T: ?Sized> {
175 map: OnceCell<InternMap<T>>,
176}
177
178impl<T: ?Sized> InternStorage<T> {
179 pub const fn new() -> Self {
180 Self { map: OnceCell::new() }
181 }
182}
183
184impl<T: Internable + ?Sized> InternStorage<T> {
185 fn get(&self) -> &InternMap<T> {
186 self.map.get_or_init(DashMap::default)
187 }
188}
189
190pub 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)]
197macro_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
208pub use crate::_impl_internable as impl_internable;
209
210impl_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..9014468ea 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -11,7 +11,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
11use stdx::format_to; 11use stdx::format_to;
12 12
13use crate::{ 13use crate::{
14 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, 14 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ImplId,
15 LocalModuleId, MacroDefId, ModuleDefId, ModuleId, TraitId, 15 LocalModuleId, MacroDefId, ModuleDefId, ModuleId, TraitId,
16}; 16};
17 17
@@ -37,6 +37,7 @@ pub struct ItemScope {
37 37
38 defs: Vec<ModuleDefId>, 38 defs: Vec<ModuleDefId>,
39 impls: Vec<ImplId>, 39 impls: Vec<ImplId>,
40 unnamed_consts: Vec<ConstId>,
40 /// Traits imported via `use Trait as _;`. 41 /// Traits imported via `use Trait as _;`.
41 unnamed_trait_imports: FxHashMap<TraitId, Visibility>, 42 unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
42 /// Macros visible in current module in legacy textual scope 43 /// Macros visible in current module in legacy textual scope
@@ -106,6 +107,10 @@ impl ItemScope {
106 .map(|(_, v)| v) 107 .map(|(_, v)| v)
107 } 108 }
108 109
110 pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
111 self.unnamed_consts.iter().copied()
112 }
113
109 /// Iterate over all module scoped macros 114 /// Iterate over all module scoped macros
110 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { 115 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
111 self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) 116 self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
@@ -156,6 +161,10 @@ impl ItemScope {
156 self.impls.push(imp) 161 self.impls.push(imp)
157 } 162 }
158 163
164 pub(crate) fn define_unnamed_const(&mut self, konst: ConstId) {
165 self.unnamed_consts.push(konst);
166 }
167
159 pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) { 168 pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
160 self.legacy_macros.insert(name, mac); 169 self.legacy_macros.insert(name, mac);
161 } 170 }
@@ -285,6 +294,30 @@ impl ItemScope {
285 buf.push('\n'); 294 buf.push('\n');
286 } 295 }
287 } 296 }
297
298 pub(crate) fn shrink_to_fit(&mut self) {
299 // Exhaustive match to require handling new fields.
300 let Self {
301 types,
302 values,
303 macros,
304 unresolved,
305 defs,
306 impls,
307 unnamed_consts,
308 unnamed_trait_imports,
309 legacy_macros,
310 } = self;
311 types.shrink_to_fit();
312 values.shrink_to_fit();
313 macros.shrink_to_fit();
314 unresolved.shrink_to_fit();
315 defs.shrink_to_fit();
316 impls.shrink_to_fit();
317 unnamed_consts.shrink_to_fit();
318 unnamed_trait_imports.shrink_to_fit();
319 legacy_macros.shrink_to_fit();
320 }
288} 321}
289 322
290impl PerNs { 323impl PerNs {
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index ae2475b4e..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};
24use profile::Count; 24use profile::Count;
25use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
26use smallvec::SmallVec; 26use smallvec::SmallVec;
27use syntax::{ast, match_ast, SmolStr, SyntaxKind}; 27use syntax::{ast, match_ast, SyntaxKind};
28 28
29use crate::{ 29use 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)]
61pub struct GenericParamsId(u32);
62
63impl 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)]
69pub struct ItemTree { 63pub struct ItemTree {
@@ -110,15 +104,6 @@ impl ItemTree {
110 // still need to collect inner items. 104 // still need to collect inner items.
111 ctx.lower_inner_items(e.syntax()) 105 ctx.lower_inner_items(e.syntax())
112 }, 106 },
113 ast::ExprStmt(stmt) => {
114 // Macros can expand to stmt. We return an empty item tree in this case, but
115 // still need to collect inner items.
116 ctx.lower_inner_items(stmt.syntax())
117 },
118 ast::Item(item) => {
119 // Macros can expand to stmt and other item, and we add it as top level item
120 ctx.lower_single_item(item)
121 },
122 _ => { 107 _ => {
123 panic!("cannot create item tree from {:?} {}", syntax, syntax); 108 panic!("cannot create item tree from {:?} {}", syntax, syntax);
124 }, 109 },
@@ -154,8 +139,6 @@ impl ItemTree {
154 macro_rules, 139 macro_rules,
155 macro_defs, 140 macro_defs,
156 vis, 141 vis,
157 generics,
158 type_refs,
159 inner_items, 142 inner_items,
160 } = &mut **data; 143 } = &mut **data;
161 144
@@ -179,9 +162,6 @@ impl ItemTree {
179 macro_defs.shrink_to_fit(); 162 macro_defs.shrink_to_fit();
180 163
181 vis.arena.shrink_to_fit(); 164 vis.arena.shrink_to_fit();
182 generics.arena.shrink_to_fit();
183 type_refs.arena.shrink_to_fit();
184 type_refs.map.shrink_to_fit();
185 165
186 inner_items.shrink_to_fit(); 166 inner_items.shrink_to_fit();
187 } 167 }
@@ -253,58 +233,6 @@ static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKi
253static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate)); 233static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate));
254 234
255#[derive(Default, Debug, Eq, PartialEq)] 235#[derive(Default, Debug, Eq, PartialEq)]
256struct GenericParamsStorage {
257 arena: Arena<GenericParams>,
258}
259
260impl GenericParamsStorage {
261 fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
262 if params.types.is_empty()
263 && params.lifetimes.is_empty()
264 && params.consts.is_empty()
265 && params.where_predicates.is_empty()
266 {
267 return GenericParamsId::EMPTY;
268 }
269
270 GenericParamsId(self.arena.alloc(params).into_raw().into())
271 }
272}
273
274static EMPTY_GENERICS: GenericParams = GenericParams {
275 types: Arena::new(),
276 lifetimes: Arena::new(),
277 consts: Arena::new(),
278 where_predicates: Vec::new(),
279};
280
281/// `TypeRef` interner.
282#[derive(Default, Debug, Eq, PartialEq)]
283struct TypeRefStorage {
284 arena: Arena<Arc<TypeRef>>,
285 map: FxHashMap<Arc<TypeRef>, Idx<Arc<TypeRef>>>,
286}
287
288impl TypeRefStorage {
289 // Note: We lie about the `Idx<TypeRef>` to hide the interner details.
290
291 fn intern(&mut self, ty: TypeRef) -> Idx<TypeRef> {
292 if let Some(id) = self.map.get(&ty) {
293 return Idx::from_raw(id.into_raw());
294 }
295
296 let ty = Arc::new(ty);
297 let idx = self.arena.alloc(ty.clone());
298 self.map.insert(ty, idx);
299 Idx::from_raw(idx.into_raw())
300 }
301
302 fn lookup(&self, id: Idx<TypeRef>) -> &TypeRef {
303 &self.arena[Idx::from_raw(id.into_raw())]
304 }
305}
306
307#[derive(Default, Debug, Eq, PartialEq)]
308struct ItemTreeData { 236struct ItemTreeData {
309 imports: Arena<Import>, 237 imports: Arena<Import>,
310 extern_crates: Arena<ExternCrate>, 238 extern_crates: Arena<ExternCrate>,
@@ -326,8 +254,6 @@ struct ItemTreeData {
326 macro_defs: Arena<MacroDef>, 254 macro_defs: Arena<MacroDef>,
327 255
328 vis: ItemVisibilities, 256 vis: ItemVisibilities,
329 generics: GenericParamsStorage,
330 type_refs: TypeRefStorage,
331 257
332 inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, 258 inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
333} 259}
@@ -546,25 +472,6 @@ impl Index<RawVisibilityId> for ItemTree {
546 } 472 }
547} 473}
548 474
549impl Index<GenericParamsId> for ItemTree {
550 type Output = GenericParams;
551
552 fn index(&self, index: GenericParamsId) -> &Self::Output {
553 match index {
554 GenericParamsId::EMPTY => &EMPTY_GENERICS,
555 _ => &self.data().generics.arena[Idx::from_raw(index.0.into())],
556 }
557 }
558}
559
560impl Index<Idx<TypeRef>> for ItemTree {
561 type Output = TypeRef;
562
563 fn index(&self, id: Idx<TypeRef>) -> &Self::Output {
564 self.data().type_refs.lookup(id)
565 }
566}
567
568impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { 475impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
569 type Output = N; 476 type Output = N;
570 fn index(&self, id: FileItemTreeId<N>) -> &N { 477 fn index(&self, id: FileItemTreeId<N>) -> &N {
@@ -575,7 +482,7 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
575/// A desugared `use` import. 482/// A desugared `use` import.
576#[derive(Debug, Clone, Eq, PartialEq)] 483#[derive(Debug, Clone, Eq, PartialEq)]
577pub struct Import { 484pub struct Import {
578 pub path: ModPath, 485 pub path: Interned<ModPath>,
579 pub alias: Option<ImportAlias>, 486 pub alias: Option<ImportAlias>,
580 pub visibility: RawVisibilityId, 487 pub visibility: RawVisibilityId,
581 pub is_glob: bool, 488 pub is_glob: bool,
@@ -601,38 +508,42 @@ pub struct ExternCrate {
601pub struct Function { 508pub struct Function {
602 pub name: Name, 509 pub name: Name,
603 pub visibility: RawVisibilityId, 510 pub visibility: RawVisibilityId,
604 pub generic_params: GenericParamsId, 511 pub generic_params: Interned<GenericParams>,
605 pub has_self_param: bool, 512 pub abi: Option<Interned<str>>,
606 pub has_body: bool,
607 pub qualifier: FunctionQualifier,
608 /// Whether the function is located in an `extern` block (*not* whether it is an
609 /// `extern "abi" fn`).
610 pub is_in_extern_block: bool,
611 pub params: IdRange<Param>, 513 pub params: IdRange<Param>,
612 pub ret_type: Idx<TypeRef>, 514 pub ret_type: Interned<TypeRef>,
613 pub ast_id: FileAstId<ast::Fn>, 515 pub ast_id: FileAstId<ast::Fn>,
516 pub(crate) flags: FnFlags,
614} 517}
615 518
616#[derive(Debug, Clone, Eq, PartialEq)] 519#[derive(Debug, Clone, Eq, PartialEq)]
617pub enum Param { 520pub enum Param {
618 Normal(Idx<TypeRef>), 521 Normal(Interned<TypeRef>),
619 Varargs, 522 Varargs,
620} 523}
621 524
622#[derive(Debug, Clone, PartialEq, Eq)] 525#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
623pub struct FunctionQualifier { 526pub(crate) struct FnFlags {
624 pub is_default: bool, 527 pub(crate) bits: u8,
625 pub is_const: bool, 528}
626 pub is_async: bool, 529impl FnFlags {
627 pub is_unsafe: bool, 530 pub(crate) const HAS_SELF_PARAM: u8 = 1 << 0;
628 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;
629} 540}
630 541
631#[derive(Debug, Clone, Eq, PartialEq)] 542#[derive(Debug, Clone, Eq, PartialEq)]
632pub struct Struct { 543pub struct Struct {
633 pub name: Name, 544 pub name: Name,
634 pub visibility: RawVisibilityId, 545 pub visibility: RawVisibilityId,
635 pub generic_params: GenericParamsId, 546 pub generic_params: Interned<GenericParams>,
636 pub fields: Fields, 547 pub fields: Fields,
637 pub ast_id: FileAstId<ast::Struct>, 548 pub ast_id: FileAstId<ast::Struct>,
638 pub kind: StructDefKind, 549 pub kind: StructDefKind,
@@ -652,7 +563,7 @@ pub enum StructDefKind {
652pub struct Union { 563pub struct Union {
653 pub name: Name, 564 pub name: Name,
654 pub visibility: RawVisibilityId, 565 pub visibility: RawVisibilityId,
655 pub generic_params: GenericParamsId, 566 pub generic_params: Interned<GenericParams>,
656 pub fields: Fields, 567 pub fields: Fields,
657 pub ast_id: FileAstId<ast::Union>, 568 pub ast_id: FileAstId<ast::Union>,
658} 569}
@@ -661,7 +572,7 @@ pub struct Union {
661pub struct Enum { 572pub struct Enum {
662 pub name: Name, 573 pub name: Name,
663 pub visibility: RawVisibilityId, 574 pub visibility: RawVisibilityId,
664 pub generic_params: GenericParamsId, 575 pub generic_params: Interned<GenericParams>,
665 pub variants: IdRange<Variant>, 576 pub variants: IdRange<Variant>,
666 pub ast_id: FileAstId<ast::Enum>, 577 pub ast_id: FileAstId<ast::Enum>,
667} 578}
@@ -671,7 +582,7 @@ pub struct Const {
671 /// const _: () = (); 582 /// const _: () = ();
672 pub name: Option<Name>, 583 pub name: Option<Name>,
673 pub visibility: RawVisibilityId, 584 pub visibility: RawVisibilityId,
674 pub type_ref: Idx<TypeRef>, 585 pub type_ref: Interned<TypeRef>,
675 pub ast_id: FileAstId<ast::Const>, 586 pub ast_id: FileAstId<ast::Const>,
676} 587}
677 588
@@ -682,7 +593,7 @@ pub struct Static {
682 pub mutable: bool, 593 pub mutable: bool,
683 /// Whether the static is in an `extern` block. 594 /// Whether the static is in an `extern` block.
684 pub is_extern: bool, 595 pub is_extern: bool,
685 pub type_ref: Idx<TypeRef>, 596 pub type_ref: Interned<TypeRef>,
686 pub ast_id: FileAstId<ast::Static>, 597 pub ast_id: FileAstId<ast::Static>,
687} 598}
688 599
@@ -690,7 +601,7 @@ pub struct Static {
690pub struct Trait { 601pub struct Trait {
691 pub name: Name, 602 pub name: Name,
692 pub visibility: RawVisibilityId, 603 pub visibility: RawVisibilityId,
693 pub generic_params: GenericParamsId, 604 pub generic_params: Interned<GenericParams>,
694 pub is_auto: bool, 605 pub is_auto: bool,
695 pub is_unsafe: bool, 606 pub is_unsafe: bool,
696 pub bounds: Box<[TypeBound]>, 607 pub bounds: Box<[TypeBound]>,
@@ -700,9 +611,9 @@ pub struct Trait {
700 611
701#[derive(Debug, Clone, Eq, PartialEq)] 612#[derive(Debug, Clone, Eq, PartialEq)]
702pub struct Impl { 613pub struct Impl {
703 pub generic_params: GenericParamsId, 614 pub generic_params: Interned<GenericParams>,
704 pub target_trait: Option<Idx<TypeRef>>, 615 pub target_trait: Option<Interned<TraitRef>>,
705 pub target_type: Idx<TypeRef>, 616 pub self_ty: Interned<TypeRef>,
706 pub is_negative: bool, 617 pub is_negative: bool,
707 pub items: Box<[AssocItem]>, 618 pub items: Box<[AssocItem]>,
708 pub ast_id: FileAstId<ast::Impl>, 619 pub ast_id: FileAstId<ast::Impl>,
@@ -714,8 +625,8 @@ pub struct TypeAlias {
714 pub visibility: RawVisibilityId, 625 pub visibility: RawVisibilityId,
715 /// 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;`.
716 pub bounds: Box<[TypeBound]>, 627 pub bounds: Box<[TypeBound]>,
717 pub generic_params: GenericParamsId, 628 pub generic_params: Interned<GenericParams>,
718 pub type_ref: Option<Idx<TypeRef>>, 629 pub type_ref: Option<Interned<TypeRef>>,
719 pub is_extern: bool, 630 pub is_extern: bool,
720 pub ast_id: FileAstId<ast::TypeAlias>, 631 pub ast_id: FileAstId<ast::TypeAlias>,
721} 632}
@@ -740,7 +651,7 @@ pub enum ModKind {
740#[derive(Debug, Clone, Eq, PartialEq)] 651#[derive(Debug, Clone, Eq, PartialEq)]
741pub struct MacroCall { 652pub struct MacroCall {
742 /// Path to the called macro. 653 /// Path to the called macro.
743 pub path: ModPath, 654 pub path: Interned<ModPath>,
744 pub ast_id: FileAstId<ast::MacroCall>, 655 pub ast_id: FileAstId<ast::MacroCall>,
745} 656}
746 657
@@ -905,6 +816,6 @@ pub enum Fields {
905#[derive(Debug, Clone, PartialEq, Eq)] 816#[derive(Debug, Clone, PartialEq, Eq)]
906pub struct Field { 817pub struct Field {
907 pub name: Name, 818 pub name: Name,
908 pub type_ref: Idx<TypeRef>, 819 pub type_ref: Interned<TypeRef>,
909 pub visibility: RawVisibilityId, 820 pub visibility: RawVisibilityId,
910} 821}
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index d3fe1ce1e..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
12use crate::{ 12use crate::{
13 generics::{GenericParams, TypeParamData, TypeParamProvenance}, 13 generics::{GenericParams, TypeParamData, TypeParamProvenance},
14 type_ref::LifetimeRef, 14 type_ref::{LifetimeRef, TraitRef},
15}; 15};
16 16
17use super::*; 17use super::*;
@@ -87,14 +87,6 @@ impl Ctx {
87 self.tree 87 self.tree
88 } 88 }
89 89
90 pub(super) fn lower_single_item(mut self, item: ast::Item) -> ItemTree {
91 self.tree.top_level = self
92 .lower_mod_item(&item, false)
93 .map(|item| item.0)
94 .unwrap_or_else(|| Default::default());
95 self.tree
96 }
97
98 pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { 90 pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree {
99 self.collect_inner_items(within); 91 self.collect_inner_items(within);
100 self.tree 92 self.tree
@@ -182,6 +174,12 @@ impl Ctx {
182 let forced_vis = self.forced_visibility.take(); 174 let forced_vis = self.forced_visibility.take();
183 175
184 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
185 for event in container.preorder().skip(1) { 183 for event in container.preorder().skip(1) {
186 match event { 184 match event {
187 WalkEvent::Enter(node) => { 185 WalkEvent::Enter(node) => {
@@ -364,7 +362,7 @@ impl Ctx {
364 } 362 }
365 } 363 }
366 }; 364 };
367 let ty = self.data().type_refs.intern(self_type); 365 let ty = Interned::new(self_type);
368 let idx = self.data().params.alloc(Param::Normal(ty)); 366 let idx = self.data().params.alloc(Param::Normal(ty));
369 self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene)); 367 self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene));
370 has_self_param = true; 368 has_self_param = true;
@@ -374,7 +372,7 @@ impl Ctx {
374 Some(_) => self.data().params.alloc(Param::Varargs), 372 Some(_) => self.data().params.alloc(Param::Varargs),
375 None => { 373 None => {
376 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());
377 let ty = self.data().type_refs.intern(type_ref); 375 let ty = Interned::new(type_ref);
378 self.data().params.alloc(Param::Normal(ty)) 376 self.data().params.alloc(Param::Normal(ty))
379 } 377 }
380 }; 378 };
@@ -397,41 +395,51 @@ impl Ctx {
397 ret_type 395 ret_type
398 }; 396 };
399 397
400 let ret_type = self.data().type_refs.intern(ret_type); 398 let abi = func.abi().map(|abi| {
401 399 // FIXME: Abi::abi() -> Option<SyntaxToken>?
402 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 });
403 411
404 let ast_id = self.source_ast_id_map.ast_id(func); 412 let ast_id = self.source_ast_id_map.ast_id(func);
405 let qualifier = FunctionQualifier { 413
406 is_default: func.default_token().is_some(), 414 let mut flags = FnFlags::default();
407 is_const: func.const_token().is_some(), 415 if func.body().is_some() {
408 is_async: func.async_token().is_some(), 416 flags.bits |= FnFlags::HAS_BODY;
409 is_unsafe: func.unsafe_token().is_some(), 417 }
410 abi: func.abi().map(|abi| { 418 if has_self_param {
411 // FIXME: Abi::abi() -> Option<SyntaxToken>? 419 flags.bits |= FnFlags::HAS_SELF_PARAM;
412 match abi.syntax().last_token() { 420 }
413 Some(tok) if tok.kind() == SyntaxKind::STRING => { 421 if func.default_token().is_some() {
414 // FIXME: Better way to unescape? 422 flags.bits |= FnFlags::IS_DEFAULT;
415 tok.text().trim_matches('"').into() 423 }
416 } 424 if func.const_token().is_some() {
417 _ => { 425 flags.bits |= FnFlags::IS_CONST;
418 // `extern` default to be `extern "C"`. 426 }
419 "C".into() 427 if func.async_token().is_some() {
420 } 428 flags.bits |= FnFlags::IS_ASYNC;
421 } 429 }
422 }), 430 if func.unsafe_token().is_some() {
423 }; 431 flags.bits |= FnFlags::IS_UNSAFE;
432 }
433
424 let mut res = Function { 434 let mut res = Function {
425 name, 435 name,
426 visibility, 436 visibility,
427 generic_params: GenericParamsId::EMPTY, 437 generic_params: Interned::new(GenericParams::default()),
428 has_self_param, 438 abi,
429 has_body,
430 qualifier,
431 is_in_extern_block: false,
432 params, 439 params,
433 ret_type, 440 ret_type: Interned::new(ret_type),
434 ast_id, 441 ast_id,
442 flags,
435 }; 443 };
436 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); 444 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
437 445
@@ -544,8 +552,11 @@ impl Ctx {
544 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>> {
545 let generic_params = 553 let generic_params =
546 self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); 554 self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def);
547 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
548 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()?);
549 let is_negative = impl_def.excl_token().is_some(); 560 let is_negative = impl_def.excl_token().is_some();
550 561
551 // 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.
@@ -562,7 +573,7 @@ impl Ctx {
562 }) 573 })
563 .collect(); 574 .collect();
564 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);
565 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 };
566 Some(id(self.data().impls.alloc(res))) 577 Some(id(self.data().impls.alloc(res)))
567 } 578 }
568 579
@@ -578,7 +589,7 @@ impl Ctx {
578 &self.hygiene, 589 &self.hygiene,
579 |path, _use_tree, is_glob, alias| { 590 |path, _use_tree, is_glob, alias| {
580 imports.push(id(tree.imports.alloc(Import { 591 imports.push(id(tree.imports.alloc(Import {
581 path, 592 path: Interned::new(path),
582 alias, 593 alias,
583 visibility, 594 visibility,
584 is_glob, 595 is_glob,
@@ -607,7 +618,7 @@ impl Ctx {
607 } 618 }
608 619
609 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>> {
610 let path = ModPath::from_src(m.path()?, &self.hygiene)?; 621 let path = Interned::new(ModPath::from_src(m.path()?, &self.hygiene)?);
611 let ast_id = self.source_ast_id_map.ast_id(m); 622 let ast_id = self.source_ast_id_map.ast_id(m);
612 let res = MacroCall { path, ast_id }; 623 let res = MacroCall { path, ast_id };
613 Some(id(self.data().macro_calls.alloc(res))) 624 Some(id(self.data().macro_calls.alloc(res)))
@@ -641,8 +652,10 @@ impl Ctx {
641 ast::ExternItem::Fn(ast) => { 652 ast::ExternItem::Fn(ast) => {
642 let func_id = self.lower_function(&ast)?; 653 let func_id = self.lower_function(&ast)?;
643 let func = &mut self.data().functions[func_id.index]; 654 let func = &mut self.data().functions[func_id.index];
644 func.qualifier.is_unsafe = is_intrinsic_fn_unsafe(&func.name); 655 if is_intrinsic_fn_unsafe(&func.name) {
645 func.is_in_extern_block = true; 656 func.flags.bits |= FnFlags::IS_UNSAFE;
657 }
658 func.flags.bits |= FnFlags::IS_IN_EXTERN_BLOCK;
646 func_id.into() 659 func_id.into()
647 } 660 }
648 ast::ExternItem::Static(ast) => { 661 ast::ExternItem::Static(ast) => {
@@ -669,7 +682,7 @@ impl Ctx {
669 &mut self, 682 &mut self,
670 owner: GenericsOwner<'_>, 683 owner: GenericsOwner<'_>,
671 node: &impl ast::GenericParamsOwner, 684 node: &impl ast::GenericParamsOwner,
672 ) -> GenericParamsId { 685 ) -> Interned<GenericParams> {
673 // 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.
674 if let Some(params) = node.generic_param_list() { 687 if let Some(params) = node.generic_param_list() {
675 self.collect_inner_items(params.syntax()); 688 self.collect_inner_items(params.syntax());
@@ -685,7 +698,7 @@ impl Ctx {
685 &mut self, 698 &mut self,
686 owner: GenericsOwner<'_>, 699 owner: GenericsOwner<'_>,
687 node: &impl ast::GenericParamsOwner, 700 node: &impl ast::GenericParamsOwner,
688 ) -> GenericParamsId { 701 ) -> Interned<GenericParams> {
689 let mut sm = &mut Default::default(); 702 let mut sm = &mut Default::default();
690 let mut generics = GenericParams::default(); 703 let mut generics = GenericParams::default();
691 match owner { 704 match owner {
@@ -693,8 +706,7 @@ impl Ctx {
693 generics.fill(&self.body_ctx, sm, node); 706 generics.fill(&self.body_ctx, sm, node);
694 // lower `impl Trait` in arguments 707 // lower `impl Trait` in arguments
695 for id in func.params.clone() { 708 for id in func.params.clone() {
696 if let Param::Normal(ty) = self.data().params[id] { 709 if let Param::Normal(ty) = &self.data().params[id] {
697 let ty = self.data().type_refs.lookup(ty);
698 generics.fill_implicit_impl_trait_args(ty); 710 generics.fill_implicit_impl_trait_args(ty);
699 } 711 }
700 } 712 }
@@ -727,7 +739,8 @@ impl Ctx {
727 } 739 }
728 } 740 }
729 741
730 self.data().generics.alloc(generics) 742 generics.shrink_to_fit();
743 Interned::new(generics)
731 } 744 }
732 745
733 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> {
@@ -748,14 +761,20 @@ impl Ctx {
748 self.data().vis.alloc(vis) 761 self.data().vis.alloc(vis)
749 } 762 }
750 763
751 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> {
752 let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); 770 let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone());
753 self.data().type_refs.intern(tyref) 771 Interned::new(tyref)
754 } 772 }
755 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> {
756 match type_ref.map(|ty| self.lower_type_ref(&ty)) { 775 match type_ref.map(|ty| self.lower_type_ref(&ty)) {
757 Some(it) => it, 776 Some(it) => it,
758 None => self.data().type_refs.intern(TypeRef::Error), 777 None => Interned::new(TypeRef::Error),
759 } 778 }
760 } 779 }
761 780
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index c9e07de86..e2af0e514 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -27,6 +27,7 @@ pub mod dyn_map;
27pub mod keys; 27pub mod keys;
28 28
29pub mod item_tree; 29pub mod item_tree;
30pub mod intern;
30 31
31pub mod adt; 32pub mod adt;
32pub mod data; 33pub mod data;
@@ -55,6 +56,7 @@ use std::{
55 sync::Arc, 56 sync::Arc,
56}; 57};
57 58
59use adt::VariantData;
58use base_db::{impl_intern_key, salsa, CrateId}; 60use base_db::{impl_intern_key, salsa, CrateId};
59use hir_expand::{ 61use hir_expand::{
60 ast_id_map::FileAstId, 62 ast_id_map::FileAstId,
@@ -441,6 +443,26 @@ pub enum VariantId {
441} 443}
442impl_from!(EnumVariantId, StructId, UnionId for VariantId); 444impl_from!(EnumVariantId, StructId, UnionId for VariantId);
443 445
446impl VariantId {
447 pub fn variant_data(self, db: &dyn db::DefDatabase) -> Arc<VariantData> {
448 match self {
449 VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
450 VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
451 VariantId::EnumVariantId(it) => {
452 db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
453 }
454 }
455 }
456
457 pub fn file_id(self, db: &dyn db::DefDatabase) -> HirFileId {
458 match self {
459 VariantId::EnumVariantId(it) => it.parent.lookup(db).id.file_id(),
460 VariantId::StructId(it) => it.lookup(db).id.file_id(),
461 VariantId::UnionId(it) => it.lookup(db).id.file_id(),
462 }
463 }
464}
465
444trait Intern { 466trait Intern {
445 type ID; 467 type ID;
446 fn intern(self, db: &dyn db::DefDatabase) -> Self::ID; 468 fn intern(self, db: &dyn db::DefDatabase) -> Self::ID;
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
414impl ModuleData { 439impl ModuleData {
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index d8fabe49b..492d8c71f 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)]
139struct Import { 144struct 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,
@@ -207,7 +215,7 @@ struct MacroDirective {
207 215
208#[derive(Clone, Debug, Eq, PartialEq)] 216#[derive(Clone, Debug, Eq, PartialEq)]
209enum MacroDirectiveKind { 217enum MacroDirectiveKind {
210 FnLike { ast_id: AstIdWithPath<ast::MacroCall>, legacy: Option<MacroCallId> }, 218 FnLike { ast_id: AstIdWithPath<ast::MacroCall> },
211 Derive { ast_id: AstIdWithPath<ast::Item> }, 219 Derive { ast_id: AstIdWithPath<ast::Item> },
212} 220}
213 221
@@ -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.
@@ -783,13 +806,7 @@ impl DefCollector<'_> {
783 let mut res = ReachedFixedPoint::Yes; 806 let mut res = ReachedFixedPoint::Yes;
784 macros.retain(|directive| { 807 macros.retain(|directive| {
785 match &directive.kind { 808 match &directive.kind {
786 MacroDirectiveKind::FnLike { ast_id, legacy } => { 809 MacroDirectiveKind::FnLike { ast_id } => {
787 if let Some(call_id) = legacy {
788 res = ReachedFixedPoint::No;
789 resolved.push((directive.module_id, *call_id, directive.depth));
790 return false;
791 }
792
793 match macro_call_as_call_id( 810 match macro_call_as_call_id(
794 ast_id, 811 ast_id,
795 self.db, 812 self.db,
@@ -1067,40 +1084,7 @@ impl ModCollector<'_, '_> {
1067 } 1084 }
1068 ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), 1085 ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
1069 ModItem::MacroRules(id) => self.collect_macro_rules(id), 1086 ModItem::MacroRules(id) => self.collect_macro_rules(id),
1070 ModItem::MacroDef(id) => { 1087 ModItem::MacroDef(id) => self.collect_macro_def(id),
1071 let mac = &self.item_tree[id];
1072 let ast_id = InFile::new(self.file_id, mac.ast_id.upcast());
1073
1074 // "Macro 2.0" is not currently supported by rust-analyzer, but libcore uses it
1075 // to define builtin macros, so we support at least that part.
1076 let attrs = self.item_tree.attrs(
1077 self.def_collector.db,
1078 krate,
1079 ModItem::from(id).into(),
1080 );
1081 if attrs.by_key("rustc_builtin_macro").exists() {
1082 let krate = self.def_collector.def_map.krate;
1083 let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
1084 .or_else(|| find_builtin_derive(&mac.name, krate, ast_id));
1085 if let Some(macro_id) = macro_id {
1086 let vis = self
1087 .def_collector
1088 .def_map
1089 .resolve_visibility(
1090 self.def_collector.db,
1091 self.module_id,
1092 &self.item_tree[mac.visibility],
1093 )
1094 .unwrap_or(Visibility::Public);
1095 self.def_collector.update(
1096 self.module_id,
1097 &[(Some(mac.name.clone()), PerNs::macros(macro_id, vis))],
1098 vis,
1099 ImportType::Named,
1100 );
1101 }
1102 }
1103 }
1104 ModItem::Impl(imp) => { 1088 ModItem::Impl(imp) => {
1105 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);
1106 let impl_id = 1090 let impl_id =
@@ -1179,19 +1163,27 @@ impl ModCollector<'_, '_> {
1179 } 1163 }
1180 ModItem::Const(id) => { 1164 ModItem::Const(id) => {
1181 let it = &self.item_tree[id]; 1165 let it = &self.item_tree[id];
1182 1166 let const_id = ConstLoc {
1183 if let Some(name) = &it.name { 1167 container: module.into(),
1184 def = Some(DefData { 1168 id: ItemTreeId::new(self.file_id, id),
1185 id: ConstLoc { 1169 }
1186 container: module.into(), 1170 .intern(self.def_collector.db);
1187 id: ItemTreeId::new(self.file_id, id), 1171
1188 } 1172 match &it.name {
1189 .intern(self.def_collector.db) 1173 Some(name) => {
1190 .into(), 1174 def = Some(DefData {
1191 name, 1175 id: const_id.into(),
1192 visibility: &self.item_tree[it.visibility], 1176 name,
1193 has_constructor: false, 1177 visibility: &self.item_tree[it.visibility],
1194 }); 1178 has_constructor: false,
1179 });
1180 }
1181 None => {
1182 // const _: T = ...;
1183 self.def_collector.def_map.modules[self.module_id]
1184 .scope
1185 .define_unnamed_const(const_id);
1186 }
1195 } 1187 }
1196 } 1188 }
1197 ModItem::Static(id) => { 1189 ModItem::Static(id) => {
@@ -1418,9 +1410,19 @@ impl ModCollector<'_, '_> {
1418 1410
1419 // Case 1: builtin macros 1411 // Case 1: builtin macros
1420 if attrs.by_key("rustc_builtin_macro").exists() { 1412 if attrs.by_key("rustc_builtin_macro").exists() {
1413 // `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name.
1414 let name;
1415 let name = match attrs.by_key("rustc_builtin_macro").string_value() {
1416 Some(it) => {
1417 // FIXME: a hacky way to create a Name from string.
1418 name = tt::Ident { text: it.clone(), id: tt::TokenId::unspecified() }.as_name();
1419 &name
1420 }
1421 None => &mac.name,
1422 };
1421 let krate = self.def_collector.def_map.krate; 1423 let krate = self.def_collector.def_map.krate;
1422 if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) { 1424 if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) {
1423 self.def_collector.define_macro( 1425 self.def_collector.define_macro_rules(
1424 self.module_id, 1426 self.module_id,
1425 mac.name.clone(), 1427 mac.name.clone(),
1426 macro_id, 1428 macro_id,
@@ -1436,11 +1438,53 @@ impl ModCollector<'_, '_> {
1436 kind: MacroDefKind::Declarative(ast_id), 1438 kind: MacroDefKind::Declarative(ast_id),
1437 local_inner: is_local_inner, 1439 local_inner: is_local_inner,
1438 }; 1440 };
1439 self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export); 1441 self.def_collector.define_macro_rules(
1442 self.module_id,
1443 mac.name.clone(),
1444 macro_id,
1445 is_export,
1446 );
1447 }
1448
1449 fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>) {
1450 let krate = self.def_collector.def_map.krate;
1451 let mac = &self.item_tree[id];
1452 let ast_id = InFile::new(self.file_id, mac.ast_id.upcast());
1453
1454 // Case 1: bulitin macros
1455 let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
1456 if attrs.by_key("rustc_builtin_macro").exists() {
1457 let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
1458 .or_else(|| find_builtin_derive(&mac.name, krate, ast_id));
1459
1460 if let Some(macro_id) = macro_id {
1461 self.def_collector.define_macro_def(
1462 self.module_id,
1463 mac.name.clone(),
1464 macro_id,
1465 &self.item_tree[mac.visibility],
1466 );
1467 }
1468 return;
1469 }
1470
1471 // Case 2: normal `macro`
1472 let macro_id = MacroDefId {
1473 krate: self.def_collector.def_map.krate,
1474 kind: MacroDefKind::Declarative(ast_id),
1475 local_inner: false,
1476 };
1477
1478 self.def_collector.define_macro_def(
1479 self.module_id,
1480 mac.name.clone(),
1481 macro_id,
1482 &self.item_tree[mac.visibility],
1483 );
1440 } 1484 }
1441 1485
1442 fn collect_macro_call(&mut self, mac: &MacroCall) { 1486 fn collect_macro_call(&mut self, mac: &MacroCall) {
1443 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); 1487 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, (*mac.path).clone());
1444 1488
1445 // Case 1: try to resolve in legacy scope and expand macro_rules 1489 // Case 1: try to resolve in legacy scope and expand macro_rules
1446 let mut error = None; 1490 let mut error = None;
@@ -1493,7 +1537,7 @@ impl ModCollector<'_, '_> {
1493 self.def_collector.unexpanded_macros.push(MacroDirective { 1537 self.def_collector.unexpanded_macros.push(MacroDirective {
1494 module_id: self.module_id, 1538 module_id: self.module_id,
1495 depth: self.macro_depth + 1, 1539 depth: self.macro_depth + 1,
1496 kind: MacroDirectiveKind::FnLike { ast_id, legacy: None }, 1540 kind: MacroDirectiveKind::FnLike { ast_id },
1497 }); 1541 });
1498 } 1542 }
1499 1543
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index a89061c2e..1ac88fc89 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
10fn 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]
11fn unresolved_import() { 16fn 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]
210fn 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]
205fn good_out_dir_diagnostic() { 225fn good_out_dir_diagnostic() {
206 check_diagnostics( 226 check_diagnostics(
207 r#" 227 r#"
@@ -213,7 +233,7 @@ fn good_out_dir_diagnostic() {
213 macro_rules! concat { () => {} } 233 macro_rules! concat { () => {} }
214 234
215 include!(concat!(env!("OUT_DIR"), "/out.rs")); 235 include!(concat!(env!("OUT_DIR"), "/out.rs"));
216 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 236 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
217 "#, 237 "#,
218 ); 238 );
219} 239}
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]
842fn resolve_macro_def() {
843 check(
844 r#"
845//- /lib.rs
846pub macro structs($($i:ident),*) {
847 $(struct $i { field: u32 } )*
848}
849structs!(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..b528ff8ba 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
10use crate::{body::LowerCtx, type_ref::LifetimeRef}; 10use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef};
11use base_db::CrateId; 11use base_db::CrateId;
12use hir_expand::{ 12use hir_expand::{
13 hygiene::Hygiene, 13 hygiene::Hygiene,
@@ -48,7 +48,7 @@ pub enum ImportAlias {
48 48
49impl ModPath { 49impl 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 {
122pub struct Path { 122pub 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,12 +283,18 @@ 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 }
290} 290}
291 291
292impl From<Name> for Box<Path> {
293 fn from(name: Name) -> Box<Path> {
294 Box::new(Path::from(name))
295 }
296}
297
292impl From<Name> for ModPath { 298impl From<Name> for ModPath {
293 fn from(name: Name) -> ModPath { 299 fn from(name: Name) -> ModPath {
294 ModPath::from_segments(PathKind::Plain, iter::once(name)) 300 ModPath::from_segments(PathKind::Plain, iter::once(name))
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
3mod lower_use; 3mod lower_use;
4 4
5use crate::intern::Interned;
5use std::sync::Arc; 6use std::sync::Arc;
6 7
7use either::Either; 8use 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)]
55pub struct TraitRef {
56 pub path: Path,
57}
58
59impl 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)]
56pub enum TypeRef { 73pub 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
27impl RawVisibility { 27impl 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.
219pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility { 219pub(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}