aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/attr.rs196
-rw-r--r--crates/hir_def/src/body.rs26
-rw-r--r--crates/hir_def/src/body/lower.rs105
-rw-r--r--crates/hir_def/src/body/tests.rs12
-rw-r--r--crates/hir_def/src/body/tests/block.rs24
-rw-r--r--crates/hir_def/src/child_by_source.rs4
-rw-r--r--crates/hir_def/src/db.rs18
-rw-r--r--crates/hir_def/src/diagnostics.rs5
-rw-r--r--crates/hir_def/src/expr.rs19
-rw-r--r--crates/hir_def/src/find_path.rs667
-rw-r--r--crates/hir_def/src/generics.rs62
-rw-r--r--crates/hir_def/src/intern.rs27
-rw-r--r--crates/hir_def/src/item_scope.rs13
-rw-r--r--crates/hir_def/src/item_tree.rs78
-rw-r--r--crates/hir_def/src/item_tree/lower.rs11
-rw-r--r--crates/hir_def/src/lib.rs76
-rw-r--r--crates/hir_def/src/nameres.rs55
-rw-r--r--crates/hir_def/src/nameres/collector.rs80
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs59
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs6
-rw-r--r--crates/hir_def/src/path.rs15
-rw-r--r--crates/hir_def/src/path/lower.rs19
-rw-r--r--crates/hir_def/src/resolver.rs3
-rw-r--r--crates/hir_def/src/test_db.rs51
-rw-r--r--crates/hir_def/src/type_ref.rs18
-rw-r--r--crates/hir_def/src/visibility.rs16
26 files changed, 1110 insertions, 555 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 442c5fb5b..d9294d93a 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -1,18 +1,22 @@
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};
7use either::Either; 11use either::Either;
8use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile}; 12use hir_expand::{hygiene::Hygiene, name::AsName, AstId, AttrId, InFile};
9use itertools::Itertools; 13use itertools::Itertools;
10use la_arena::ArenaMap; 14use la_arena::ArenaMap;
11use mbe::ast_to_token_tree; 15use 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
@@ -94,13 +98,16 @@ impl RawAttrs {
94 pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self { 98 pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self {
95 let entries = collect_attrs(owner) 99 let entries = collect_attrs(owner)
96 .enumerate() 100 .enumerate()
97 .flat_map(|(i, attr)| match attr { 101 .flat_map(|(i, attr)| {
98 Either::Left(attr) => Attr::from_src(attr, hygiene, i as u32), 102 let index = AttrId(i as u32);
99 Either::Right(comment) => comment.doc_comment().map(|doc| Attr { 103 match attr {
100 index: i as u32, 104 Either::Left(attr) => Attr::from_src(attr, hygiene, index),
101 input: Some(AttrInput::Literal(SmolStr::new(doc))), 105 Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
102 path: Interned::new(ModPath::from(hir_expand::name!(doc))), 106 id: index,
103 }), 107 input: Some(AttrInput::Literal(SmolStr::new(doc))),
108 path: Interned::new(ModPath::from(hir_expand::name!(doc))),
109 }),
110 }
104 }) 111 })
105 .collect::<Arc<_>>(); 112 .collect::<Arc<_>>();
106 113
@@ -157,7 +164,7 @@ impl RawAttrs {
157 let cfg = parts.next().unwrap(); 164 let cfg = parts.next().unwrap();
158 let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; 165 let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
159 let cfg = CfgExpr::parse(&cfg); 166 let cfg = CfgExpr::parse(&cfg);
160 let index = attr.index; 167 let index = attr.id;
161 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { 168 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| {
162 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; 169 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() };
163 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; 170 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?;
@@ -211,12 +218,11 @@ impl Attrs {
211 let mut res = ArenaMap::default(); 218 let mut res = ArenaMap::default();
212 219
213 for (id, fld) in src.value.iter() { 220 for (id, fld) in src.value.iter() {
214 let attrs = match fld { 221 let owner: &dyn AttrsOwner = match fld {
215 Either::Left(_tuple) => Attrs::default(), 222 Either::Left(tuple) => tuple,
216 Either::Right(record) => { 223 Either::Right(record) => record,
217 RawAttrs::from_attrs_owner(db, src.with_value(record)).filter(db, krate)
218 }
219 }; 224 };
225 let attrs = RawAttrs::from_attrs_owner(db, src.with_value(owner)).filter(db, krate);
220 226
221 res.insert(id, attrs); 227 res.insert(id, attrs);
222 } 228 }
@@ -400,10 +406,14 @@ impl AttrsWithOwner {
400 return AttrSourceMap { attrs }; 406 return AttrSourceMap { attrs };
401 } 407 }
402 AttrDefId::FieldId(id) => { 408 AttrDefId::FieldId(id) => {
403 id.parent.child_source(db).map(|source| match &source[id.local_id] { 409 let map = db.fields_attrs_source_map(id.parent);
404 Either::Left(field) => ast::AttrsOwnerNode::new(field.clone()), 410 let file_id = id.parent.file_id(db);
405 Either::Right(field) => ast::AttrsOwnerNode::new(field.clone()), 411 let root = db.parse_or_expand(file_id).unwrap();
406 }) 412 let owner = match &map[id.local_id] {
413 Either::Left(it) => ast::AttrsOwnerNode::new(it.to_node(&root)),
414 Either::Right(it) => ast::AttrsOwnerNode::new(it.to_node(&root)),
415 };
416 InFile::new(file_id, owner)
407 } 417 }
408 AttrDefId::AdtId(adt) => match adt { 418 AttrDefId::AdtId(adt) => match adt {
409 AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 419 AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
@@ -411,10 +421,12 @@ impl AttrsWithOwner {
411 AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 421 AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
412 }, 422 },
413 AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 423 AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
414 AttrDefId::EnumVariantId(id) => id 424 AttrDefId::EnumVariantId(id) => {
415 .parent 425 let map = db.variants_attrs_source_map(id.parent);
416 .child_source(db) 426 let file_id = id.parent.lookup(db).id.file_id();
417 .map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())), 427 let root = db.parse_or_expand(file_id).unwrap();
428 InFile::new(file_id, ast::AttrsOwnerNode::new(map[id.local_id].to_node(&root)))
429 }
418 AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 430 AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
419 AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 431 AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
420 AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 432 AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
@@ -452,6 +464,55 @@ impl AttrsWithOwner {
452 .collect(), 464 .collect(),
453 } 465 }
454 } 466 }
467
468 pub fn docs_with_rangemap(
469 &self,
470 db: &dyn DefDatabase,
471 ) -> Option<(Documentation, DocsRangeMap)> {
472 // FIXME: code duplication in `docs` above
473 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? {
474 AttrInput::Literal(s) => Some((s, attr.id)),
475 AttrInput::TokenTree(_) => None,
476 });
477 let indent = docs
478 .clone()
479 .flat_map(|(s, _)| s.lines())
480 .filter(|line| !line.chars().all(|c| c.is_whitespace()))
481 .map(|line| line.chars().take_while(|c| c.is_whitespace()).count())
482 .min()
483 .unwrap_or(0);
484 let mut buf = String::new();
485 let mut mapping = Vec::new();
486 for (doc, idx) in docs {
487 // str::lines doesn't yield anything for the empty string
488 if !doc.is_empty() {
489 for line in doc.split('\n') {
490 let line = line.trim_end();
491 let line_len = line.len();
492 let (offset, line) = match line.char_indices().nth(indent) {
493 Some((offset, _)) => (offset, &line[offset..]),
494 None => (0, line),
495 };
496 let buf_offset = buf.len();
497 buf.push_str(line);
498 mapping.push((
499 TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?),
500 idx,
501 TextRange::new(offset.try_into().ok()?, line_len.try_into().ok()?),
502 ));
503 buf.push('\n');
504 }
505 } else {
506 buf.push('\n');
507 }
508 }
509 buf.pop();
510 if buf.is_empty() {
511 None
512 } else {
513 Some((Documentation(buf), DocsRangeMap { mapping, source: self.source_map(db).attrs }))
514 }
515 }
455} 516}
456 517
457fn inner_attributes( 518fn inner_attributes(
@@ -484,7 +545,7 @@ fn inner_attributes(
484 _ => return None, 545 _ => return None,
485 } 546 }
486 }; 547 };
487 let attrs = attrs.filter(|attr| attr.excl_token().is_some()); 548 let attrs = attrs.filter(|attr| attr.kind().is_inner());
488 let docs = docs.filter(|doc| doc.is_inner()); 549 let docs = docs.filter(|doc| doc.is_inner());
489 Some((attrs, docs)) 550 Some((attrs, docs))
490} 551}
@@ -502,15 +563,53 @@ impl AttrSourceMap {
502 /// the attribute represented by `Attr`. 563 /// the attribute represented by `Attr`.
503 pub fn source_of(&self, attr: &Attr) -> InFile<&Either<ast::Attr, ast::Comment>> { 564 pub fn source_of(&self, attr: &Attr) -> InFile<&Either<ast::Attr, ast::Comment>> {
504 self.attrs 565 self.attrs
505 .get(attr.index as usize) 566 .get(attr.id.0 as usize)
506 .unwrap_or_else(|| panic!("cannot find `Attr` at index {}", attr.index)) 567 .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", attr.id))
507 .as_ref() 568 .as_ref()
508 } 569 }
509} 570}
510 571
572/// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree.
573pub struct DocsRangeMap {
574 source: Vec<InFile<Either<ast::Attr, ast::Comment>>>,
575 // (docstring-line-range, attr_index, attr-string-range)
576 // a mapping from the text range of a line of the [`Documentation`] to the attribute index and
577 // the original (untrimmed) syntax doc line
578 mapping: Vec<(TextRange, AttrId, TextRange)>,
579}
580
581impl DocsRangeMap {
582 pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
583 let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
584 let (line_docs_range, idx, original_line_src_range) = self.mapping[found].clone();
585 if !line_docs_range.contains_range(range) {
586 return None;
587 }
588
589 let relative_range = range - line_docs_range.start();
590
591 let &InFile { file_id, value: ref source } = &self.source[idx.0 as usize];
592 match source {
593 Either::Left(_) => None, // FIXME, figure out a nice way to handle doc attributes here
594 // as well as for whats done in syntax highlight doc injection
595 Either::Right(comment) => {
596 let text_range = comment.syntax().text_range();
597 let range = TextRange::at(
598 text_range.start()
599 + TextSize::try_from(comment.prefix().len()).ok()?
600 + original_line_src_range.start()
601 + relative_range.start(),
602 text_range.len().min(range.len()),
603 );
604 Some(InFile { file_id, value: range })
605 }
606 }
607 }
608}
609
511#[derive(Debug, Clone, PartialEq, Eq)] 610#[derive(Debug, Clone, PartialEq, Eq)]
512pub struct Attr { 611pub struct Attr {
513 index: u32, 612 pub(crate) id: AttrId,
514 pub(crate) path: Interned<ModPath>, 613 pub(crate) path: Interned<ModPath>,
515 pub(crate) input: Option<AttrInput>, 614 pub(crate) input: Option<AttrInput>,
516} 615}
@@ -524,7 +623,7 @@ pub enum AttrInput {
524} 623}
525 624
526impl Attr { 625impl Attr {
527 fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> { 626 fn from_src(ast: ast::Attr, hygiene: &Hygiene, id: AttrId) -> Option<Attr> {
528 let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?); 627 let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?);
529 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { 628 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
530 let value = match lit.kind() { 629 let value = match lit.kind() {
@@ -537,7 +636,7 @@ impl Attr {
537 } else { 636 } else {
538 None 637 None
539 }; 638 };
540 Some(Attr { index, path, input }) 639 Some(Attr { id, path, input })
541 } 640 }
542 641
543 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths 642 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths
@@ -641,7 +740,7 @@ fn collect_attrs(
641 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) 740 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax())
642 .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs))); 741 .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs)));
643 742
644 let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); 743 let outer_attrs = owner.attrs().filter(|attr| attr.kind().is_outer());
645 let attrs = outer_attrs 744 let attrs = outer_attrs
646 .chain(inner_attrs.into_iter().flatten()) 745 .chain(inner_attrs.into_iter().flatten())
647 .map(|attr| (attr.syntax().text_range().start(), Either::Left(attr))); 746 .map(|attr| (attr.syntax().text_range().start(), Either::Left(attr)));
@@ -652,7 +751,38 @@ fn collect_attrs(
652 .chain(inner_docs.into_iter().flatten()) 751 .chain(inner_docs.into_iter().flatten())
653 .map(|docs_text| (docs_text.syntax().text_range().start(), Either::Right(docs_text))); 752 .map(|docs_text| (docs_text.syntax().text_range().start(), Either::Right(docs_text)));
654 // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved 753 // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved
655 let attrs: Vec<_> = docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect(); 754 docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).map(|(_, attr)| attr)
755}
756
757pub(crate) fn variants_attrs_source_map(
758 db: &dyn DefDatabase,
759 def: EnumId,
760) -> Arc<ArenaMap<LocalEnumVariantId, AstPtr<ast::Variant>>> {
761 let mut res = ArenaMap::default();
762 let child_source = def.child_source(db);
763
764 for (idx, variant) in child_source.value.iter() {
765 res.insert(idx, AstPtr::new(variant));
766 }
767
768 Arc::new(res)
769}
770
771pub(crate) fn fields_attrs_source_map(
772 db: &dyn DefDatabase,
773 def: VariantId,
774) -> Arc<ArenaMap<LocalFieldId, Either<AstPtr<ast::TupleField>, AstPtr<ast::RecordField>>>> {
775 let mut res = ArenaMap::default();
776 let child_source = def.child_source(db);
777
778 for (idx, variant) in child_source.value.iter() {
779 res.insert(
780 idx,
781 variant
782 .as_ref()
783 .either(|l| Either::Left(AstPtr::new(l)), |r| Either::Right(AstPtr::new(r))),
784 );
785 }
656 786
657 attrs.into_iter().map(|(_, attr)| attr) 787 Arc::new(res)
658} 788}
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 96b959967..131f424cc 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -21,7 +21,7 @@ use profile::Count;
21use rustc_hash::FxHashMap; 21use rustc_hash::FxHashMap;
22use syntax::{ast, AstNode, AstPtr}; 22use syntax::{ast, AstNode, AstPtr};
23 23
24pub(crate) use lower::LowerCtx; 24pub use lower::LowerCtx;
25 25
26use crate::{ 26use crate::{
27 attr::{Attrs, RawAttrs}, 27 attr::{Attrs, RawAttrs},
@@ -37,13 +37,15 @@ use crate::{
37 37
38/// A subset of Expander that only deals with cfg attributes. We only need it to 38/// A subset of Expander that only deals with cfg attributes. We only need it to
39/// avoid cyclic queries in crate def map during enum processing. 39/// avoid cyclic queries in crate def map during enum processing.
40#[derive(Debug)]
40pub(crate) struct CfgExpander { 41pub(crate) struct CfgExpander {
41 cfg_options: CfgOptions, 42 cfg_options: CfgOptions,
42 hygiene: Hygiene, 43 hygiene: Hygiene,
43 krate: CrateId, 44 krate: CrateId,
44} 45}
45 46
46pub(crate) struct Expander { 47#[derive(Debug)]
48pub struct Expander {
47 cfg_expander: CfgExpander, 49 cfg_expander: CfgExpander,
48 def_map: Arc<DefMap>, 50 def_map: Arc<DefMap>,
49 current_file_id: HirFileId, 51 current_file_id: HirFileId,
@@ -80,11 +82,7 @@ impl CfgExpander {
80} 82}
81 83
82impl Expander { 84impl Expander {
83 pub(crate) fn new( 85 pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
84 db: &dyn DefDatabase,
85 current_file_id: HirFileId,
86 module: ModuleId,
87 ) -> Expander {
88 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); 86 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
89 let def_map = module.def_map(db); 87 let def_map = module.def_map(db);
90 let ast_id_map = db.ast_id_map(current_file_id); 88 let ast_id_map = db.ast_id_map(current_file_id);
@@ -98,7 +96,7 @@ impl Expander {
98 } 96 }
99 } 97 }
100 98
101 pub(crate) fn enter_expand<T: ast::AstNode>( 99 pub fn enter_expand<T: ast::AstNode>(
102 &mut self, 100 &mut self,
103 db: &dyn DefDatabase, 101 db: &dyn DefDatabase,
104 macro_call: ast::MacroCall, 102 macro_call: ast::MacroCall,
@@ -170,7 +168,7 @@ impl Expander {
170 Ok(ExpandResult { value: Some((mark, node)), err }) 168 Ok(ExpandResult { value: Some((mark, node)), err })
171 } 169 }
172 170
173 pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { 171 pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
174 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); 172 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
175 self.current_file_id = mark.file_id; 173 self.current_file_id = mark.file_id;
176 self.ast_id_map = mem::take(&mut mark.ast_id_map); 174 self.ast_id_map = mem::take(&mut mark.ast_id_map);
@@ -190,8 +188,13 @@ impl Expander {
190 &self.cfg_expander.cfg_options 188 &self.cfg_expander.cfg_options
191 } 189 }
192 190
191 pub fn current_file_id(&self) -> HirFileId {
192 self.current_file_id
193 }
194
193 fn parse_path(&mut self, path: ast::Path) -> Option<Path> { 195 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
194 Path::from_src(path, &self.cfg_expander.hygiene) 196 let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene);
197 Path::from_src(path, &ctx)
195 } 198 }
196 199
197 fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { 200 fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> {
@@ -204,7 +207,8 @@ impl Expander {
204 } 207 }
205} 208}
206 209
207pub(crate) struct Mark { 210#[derive(Debug)]
211pub struct Mark {
208 file_id: HirFileId, 212 file_id: HirFileId,
209 ast_id_map: Arc<AstIdMap>, 213 ast_id_map: Arc<AstIdMap>,
210 bomb: DropBomb, 214 bomb: DropBomb,
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 63e89a1f4..c11da30d2 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -1,10 +1,11 @@
1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` 1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2//! representation. 2//! representation.
3 3
4use std::mem; 4use std::{mem, sync::Arc};
5 5
6use either::Either; 6use either::Either;
7use hir_expand::{ 7use hir_expand::{
8 ast_id_map::{AstIdMap, FileAstId},
8 hygiene::Hygiene, 9 hygiene::Hygiene,
9 name::{name, AsName, Name}, 10 name::{name, AsName, Name},
10 ExpandError, HirFileId, 11 ExpandError, HirFileId,
@@ -30,6 +31,7 @@ use crate::{
30 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, 31 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
31 Statement, 32 Statement,
32 }, 33 },
34 intern::Interned,
33 item_scope::BuiltinShadowMode, 35 item_scope::BuiltinShadowMode,
34 path::{GenericArgs, Path}, 36 path::{GenericArgs, Path},
35 type_ref::{Mutability, Rawness, TypeRef}, 37 type_ref::{Mutability, Rawness, TypeRef},
@@ -38,20 +40,39 @@ use crate::{
38 40
39use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; 41use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
40 42
41pub(crate) struct LowerCtx { 43pub struct LowerCtx {
42 hygiene: Hygiene, 44 hygiene: Hygiene,
45 file_id: Option<HirFileId>,
46 source_ast_id_map: Option<Arc<AstIdMap>>,
43} 47}
44 48
45impl LowerCtx { 49impl LowerCtx {
46 pub(crate) fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { 50 pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self {
47 LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) } 51 LowerCtx {
52 hygiene: Hygiene::new(db.upcast(), file_id),
53 file_id: Some(file_id),
54 source_ast_id_map: Some(db.ast_id_map(file_id)),
55 }
48 } 56 }
49 pub(crate) fn with_hygiene(hygiene: &Hygiene) -> Self { 57
50 LowerCtx { hygiene: hygiene.clone() } 58 pub fn with_hygiene(hygiene: &Hygiene) -> Self {
59 LowerCtx { hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None }
60 }
61
62 pub(crate) fn hygiene(&self) -> &Hygiene {
63 &self.hygiene
64 }
65
66 pub(crate) fn file_id(&self) -> HirFileId {
67 self.file_id.unwrap()
51 } 68 }
52 69
53 pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> { 70 pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
54 Path::from_src(ast, &self.hygiene) 71 Path::from_src(ast, self)
72 }
73
74 pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> Option<FileAstId<N>> {
75 self.source_ast_id_map.as_ref().map(|ast_id_map| ast_id_map.ast_id(item))
55 } 76 }
56} 77}
57 78
@@ -322,8 +343,10 @@ impl ExprCollector<'_> {
322 Vec::new() 343 Vec::new()
323 }; 344 };
324 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); 345 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
325 let generic_args = 346 let generic_args = e
326 e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); 347 .generic_arg_list()
348 .and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
349 .map(Box::new);
327 self.alloc_expr( 350 self.alloc_expr(
328 Expr::MethodCall { receiver, method_name, args, generic_args }, 351 Expr::MethodCall { receiver, method_name, args, generic_args },
329 syntax_ptr, 352 syntax_ptr,
@@ -385,7 +408,7 @@ impl ExprCollector<'_> {
385 self.alloc_expr(Expr::Yield { expr }, syntax_ptr) 408 self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
386 } 409 }
387 ast::Expr::RecordExpr(e) => { 410 ast::Expr::RecordExpr(e) => {
388 let path = e.path().and_then(|path| self.expander.parse_path(path)); 411 let path = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
389 let record_lit = if let Some(nfl) = e.record_expr_field_list() { 412 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
390 let fields = nfl 413 let fields = nfl
391 .fields() 414 .fields()
@@ -430,7 +453,7 @@ impl ExprCollector<'_> {
430 } 453 }
431 ast::Expr::CastExpr(e) => { 454 ast::Expr::CastExpr(e) => {
432 let expr = self.collect_expr_opt(e.expr()); 455 let expr = self.collect_expr_opt(e.expr());
433 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty()); 456 let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
434 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) 457 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
435 } 458 }
436 ast::Expr::RefExpr(e) => { 459 ast::Expr::RefExpr(e) => {
@@ -464,13 +487,16 @@ impl ExprCollector<'_> {
464 if let Some(pl) = e.param_list() { 487 if let Some(pl) = e.param_list() {
465 for param in pl.params() { 488 for param in pl.params() {
466 let pat = self.collect_pat_opt(param.pat()); 489 let pat = self.collect_pat_opt(param.pat());
467 let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 490 let type_ref =
491 param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
468 args.push(pat); 492 args.push(pat);
469 arg_types.push(type_ref); 493 arg_types.push(type_ref);
470 } 494 }
471 } 495 }
472 let ret_type = 496 let ret_type = e
473 e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it)); 497 .ret_type()
498 .and_then(|r| r.ty())
499 .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
474 let body = self.collect_expr_opt(e.body()); 500 let body = self.collect_expr_opt(e.body());
475 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) 501 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
476 } 502 }
@@ -525,8 +551,9 @@ impl ExprCollector<'_> {
525 } 551 }
526 } 552 }
527 ast::Expr::MacroCall(e) => { 553 ast::Expr::MacroCall(e) => {
554 let macro_ptr = AstPtr::new(&e);
528 let mut ids = vec![]; 555 let mut ids = vec![];
529 self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| { 556 self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
530 ids.push(match expansion { 557 ids.push(match expansion {
531 Some(it) => this.collect_expr(it), 558 Some(it) => this.collect_expr(it),
532 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), 559 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
@@ -549,7 +576,7 @@ impl ExprCollector<'_> {
549 fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>( 576 fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
550 &mut self, 577 &mut self,
551 e: ast::MacroCall, 578 e: ast::MacroCall,
552 syntax_ptr: AstPtr<ast::Expr>, 579 syntax_ptr: AstPtr<ast::MacroCall>,
553 is_error_recoverable: bool, 580 is_error_recoverable: bool,
554 mut collector: F, 581 mut collector: F,
555 ) { 582 ) {
@@ -561,9 +588,13 @@ impl ExprCollector<'_> {
561 588
562 let res = match res { 589 let res = match res {
563 Ok(res) => res, 590 Ok(res) => res,
564 Err(UnresolvedMacro) => { 591 Err(UnresolvedMacro { path }) => {
565 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall( 592 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall(
566 UnresolvedMacroCall { file: outer_file, node: syntax_ptr.cast().unwrap() }, 593 UnresolvedMacroCall {
594 file: outer_file,
595 node: syntax_ptr.cast().unwrap(),
596 path,
597 },
567 )); 598 ));
568 collector(self, None); 599 collector(self, None);
569 return; 600 return;
@@ -625,7 +656,8 @@ impl ExprCollector<'_> {
625 return; 656 return;
626 } 657 }
627 let pat = self.collect_pat_opt(stmt.pat()); 658 let pat = self.collect_pat_opt(stmt.pat());
628 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 659 let type_ref =
660 stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
629 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 661 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
630 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer }); 662 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
631 } 663 }
@@ -636,10 +668,14 @@ impl ExprCollector<'_> {
636 668
637 // Note that macro could be expended to multiple statements 669 // Note that macro could be expended to multiple statements
638 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { 670 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
671 let macro_ptr = AstPtr::new(&m);
639 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); 672 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
640 673
641 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { 674 self.collect_macro_call(
642 match expansion { 675 m,
676 macro_ptr,
677 false,
678 |this, expansion| match expansion {
643 Some(expansion) => { 679 Some(expansion) => {
644 let statements: ast::MacroStmts = expansion; 680 let statements: ast::MacroStmts = expansion;
645 681
@@ -653,8 +689,8 @@ impl ExprCollector<'_> {
653 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone()); 689 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
654 this.statements_in_scope.push(Statement::Expr(expr)); 690 this.statements_in_scope.push(Statement::Expr(expr));
655 } 691 }
656 } 692 },
657 }); 693 );
658 } else { 694 } else {
659 let expr = self.collect_expr_opt(stmt.expr()); 695 let expr = self.collect_expr_opt(stmt.expr());
660 self.statements_in_scope.push(Statement::Expr(expr)); 696 self.statements_in_scope.push(Statement::Expr(expr));
@@ -755,7 +791,7 @@ impl ExprCollector<'_> {
755 } 791 }
756 } 792 }
757 ast::Pat::TupleStructPat(p) => { 793 ast::Pat::TupleStructPat(p) => {
758 let path = p.path().and_then(|path| self.expander.parse_path(path)); 794 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()); 795 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
760 Pat::TupleStruct { path, args, ellipsis } 796 Pat::TupleStruct { path, args, ellipsis }
761 } 797 }
@@ -765,7 +801,7 @@ impl ExprCollector<'_> {
765 Pat::Ref { pat, mutability } 801 Pat::Ref { pat, mutability }
766 } 802 }
767 ast::Pat::PathPat(p) => { 803 ast::Pat::PathPat(p) => {
768 let path = p.path().and_then(|path| self.expander.parse_path(path)); 804 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
769 path.map(Pat::Path).unwrap_or(Pat::Missing) 805 path.map(Pat::Path).unwrap_or(Pat::Missing)
770 } 806 }
771 ast::Pat::OrPat(p) => { 807 ast::Pat::OrPat(p) => {
@@ -779,7 +815,7 @@ impl ExprCollector<'_> {
779 } 815 }
780 ast::Pat::WildcardPat(_) => Pat::Wild, 816 ast::Pat::WildcardPat(_) => Pat::Wild,
781 ast::Pat::RecordPat(p) => { 817 ast::Pat::RecordPat(p) => {
782 let path = p.path().and_then(|path| self.expander.parse_path(path)); 818 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
783 let args: Vec<_> = p 819 let args: Vec<_> = p
784 .record_pat_field_list() 820 .record_pat_field_list()
785 .expect("every struct should have a field list") 821 .expect("every struct should have a field list")
@@ -841,8 +877,23 @@ impl ExprCollector<'_> {
841 Pat::Missing 877 Pat::Missing
842 } 878 }
843 } 879 }
880 ast::Pat::MacroPat(mac) => match mac.macro_call() {
881 Some(call) => {
882 let macro_ptr = AstPtr::new(&call);
883 let mut pat = None;
884 self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
885 pat = Some(this.collect_pat_opt(expanded_pat));
886 });
887
888 match pat {
889 Some(pat) => return pat,
890 None => Pat::Missing,
891 }
892 }
893 None => Pat::Missing,
894 },
844 // FIXME: implement 895 // FIXME: implement
845 ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, 896 ast::Pat::RangePat(_) => Pat::Missing,
846 }; 897 };
847 let ptr = AstPtr::new(&pat); 898 let ptr = AstPtr::new(&pat);
848 self.alloc_pat(pattern, Either::Left(ptr)) 899 self.alloc_pat(pattern, Either::Left(ptr))
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index faa133297..3e8f16306 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -40,6 +40,14 @@ fn block_def_map_at(ra_fixture: &str) -> String {
40 module.def_map(&db).dump(&db) 40 module.def_map(&db).dump(&db)
41} 41}
42 42
43fn check_block_scopes_at(ra_fixture: &str, expect: Expect) {
44 let (db, position) = crate::test_db::TestDB::with_position(ra_fixture);
45
46 let module = db.module_at_position(position);
47 let actual = module.def_map(&db).dump_block_scopes(&db);
48 expect.assert_eq(&actual);
49}
50
43fn check_at(ra_fixture: &str, expect: Expect) { 51fn check_at(ra_fixture: &str, expect: Expect) {
44 let actual = block_def_map_at(ra_fixture); 52 let actual = block_def_map_at(ra_fixture);
45 expect.assert_eq(&actual); 53 expect.assert_eq(&actual);
@@ -143,7 +151,7 @@ fn f() {
143 //^^^^^^^^^^^^^ could not convert tokens 151 //^^^^^^^^^^^^^ could not convert tokens
144 152
145 env!("OUT_DIR"); 153 env!("OUT_DIR");
146 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 154 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
147 155
148 compile_error!("compile_error works"); 156 compile_error!("compile_error works");
149 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works 157 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
@@ -180,7 +188,7 @@ fn unresolved_macro_diag() {
180 r#" 188 r#"
181fn f() { 189fn f() {
182 m!(); 190 m!();
183 //^^^^ unresolved macro call 191 //^^^^ unresolved macro `m!`
184} 192}
185 "#, 193 "#,
186 ); 194 );
diff --git a/crates/hir_def/src/body/tests/block.rs b/crates/hir_def/src/body/tests/block.rs
index 3b6ba4cde..bc3d0f138 100644
--- a/crates/hir_def/src/body/tests/block.rs
+++ b/crates/hir_def/src/body/tests/block.rs
@@ -134,6 +134,30 @@ struct Struct {}
134} 134}
135 135
136#[test] 136#[test]
137fn nested_module_scoping() {
138 check_block_scopes_at(
139 r#"
140fn f() {
141 mod module {
142 struct Struct {}
143 fn f() {
144 use self::Struct;
145 $0
146 }
147 }
148}
149 "#,
150 expect![[r#"
151 BlockId(1) in ModuleId { krate: CrateId(0), block: Some(BlockId(0)), local_id: Idx::<ModuleData>(0) }
152 BlockId(0) in ModuleId { krate: CrateId(0), block: None, local_id: Idx::<ModuleData>(0) }
153 crate scope
154 "#]],
155 );
156 // FIXME: The module nesting here is wrong!
157 // The first block map should be located in module #1 (`mod module`), not #0 (BlockId(0) root module)
158}
159
160#[test]
137fn legacy_macro_items() { 161fn legacy_macro_items() {
138 // Checks that legacy-scoped `macro_rules!` from parent namespaces are resolved and expanded 162 // Checks that legacy-scoped `macro_rules!` from parent namespaces are resolved and expanded
139 // correctly. 163 // correctly.
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index f40a7f80d..f2e809ca9 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -80,6 +80,10 @@ impl ChildBySource for ModuleId {
80impl ChildBySource for ItemScope { 80impl ChildBySource for ItemScope {
81 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) { 81 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
82 self.declarations().for_each(|item| add_module_def(db, res, item)); 82 self.declarations().for_each(|item| add_module_def(db, res, item));
83 self.unnamed_consts().for_each(|konst| {
84 let src = konst.lookup(db).source(db);
85 res[keys::CONST].insert(src, konst);
86 });
83 self.impls().for_each(|imp| add_impl(db, res, imp)); 87 self.impls().for_each(|imp| add_impl(db, res, imp));
84 88
85 fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) { 89 fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) {
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/diagnostics.rs b/crates/hir_def/src/diagnostics.rs
index 97abf8653..a71ae2668 100644
--- a/crates/hir_def/src/diagnostics.rs
+++ b/crates/hir_def/src/diagnostics.rs
@@ -8,7 +8,7 @@ use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink};
8use hir_expand::{HirFileId, InFile}; 8use hir_expand::{HirFileId, InFile};
9use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; 9use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
10 10
11use crate::{db::DefDatabase, DefWithBodyId}; 11use crate::{db::DefDatabase, path::ModPath, DefWithBodyId};
12 12
13pub fn validate_body(db: &dyn DefDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) { 13pub fn validate_body(db: &dyn DefDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) {
14 let source_map = db.body_with_source_map(owner).1; 14 let source_map = db.body_with_source_map(owner).1;
@@ -103,6 +103,7 @@ impl Diagnostic for UnresolvedImport {
103pub struct UnresolvedMacroCall { 103pub struct UnresolvedMacroCall {
104 pub file: HirFileId, 104 pub file: HirFileId,
105 pub node: AstPtr<ast::MacroCall>, 105 pub node: AstPtr<ast::MacroCall>,
106 pub path: ModPath,
106} 107}
107 108
108impl Diagnostic for UnresolvedMacroCall { 109impl Diagnostic for UnresolvedMacroCall {
@@ -110,7 +111,7 @@ impl Diagnostic for UnresolvedMacroCall {
110 DiagnosticCode("unresolved-macro-call") 111 DiagnosticCode("unresolved-macro-call")
111 } 112 }
112 fn message(&self) -> String { 113 fn message(&self) -> String {
113 "unresolved macro call".to_string() 114 format!("unresolved macro `{}!`", self.path)
114 } 115 }
115 fn display_source(&self) -> InFile<SyntaxNodePtr> { 116 fn display_source(&self) -> InFile<SyntaxNodePtr> {
116 InFile::new(self.file, self.node.clone().into()) 117 InFile::new(self.file, self.node.clone().into())
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs
index 6c7376fad..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 {
@@ -240,7 +241,7 @@ pub struct RecordLitField {
240 241
241#[derive(Debug, Clone, Eq, PartialEq)] 242#[derive(Debug, Clone, Eq, PartialEq)]
242pub enum Statement { 243pub enum Statement {
243 Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> }, 244 Let { pat: PatId, type_ref: Option<Interned<TypeRef>>, initializer: Option<ExprId> },
244 Expr(ExprId), 245 Expr(ExprId),
245} 246}
246 247
@@ -412,13 +413,13 @@ pub enum Pat {
412 Wild, 413 Wild,
413 Tuple { args: Vec<PatId>, ellipsis: Option<usize> }, 414 Tuple { args: Vec<PatId>, ellipsis: Option<usize> },
414 Or(Vec<PatId>), 415 Or(Vec<PatId>),
415 Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool }, 416 Record { path: Option<Box<Path>>, args: Vec<RecordFieldPat>, ellipsis: bool },
416 Range { start: ExprId, end: ExprId }, 417 Range { start: ExprId, end: ExprId },
417 Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> }, 418 Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> },
418 Path(Path), 419 Path(Box<Path>),
419 Lit(ExprId), 420 Lit(ExprId),
420 Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, 421 Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
421 TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, 422 TupleStruct { path: Option<Box<Path>>, args: Vec<PatId>, ellipsis: Option<usize> },
422 Ref { pat: PatId, mutability: Mutability }, 423 Ref { pat: PatId, mutability: Mutability },
423 Box { inner: PatId }, 424 Box { inner: PatId },
424 ConstBlock(ExprId), 425 ConstBlock(ExprId),
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index 109d3552f..dc3f2908f 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -119,8 +119,7 @@ fn find_path_inner(
119 119
120 // - if the item is the crate root, return `crate` 120 // - if the item is the crate root, return `crate`
121 let root = def_map.crate_root(db); 121 let root = def_map.crate_root(db);
122 if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) && def_map.block_id().is_none() { 122 if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) {
123 // FIXME: the `block_id()` check should be unnecessary, but affects the result
124 return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); 123 return Some(ModPath::from_segments(PathKind::Crate, Vec::new()));
125 } 124 }
126 125
@@ -131,7 +130,7 @@ fn find_path_inner(
131 } 130 }
132 131
133 // - if the item is the crate root of a dependency crate, return the name from the extern prelude 132 // - if the item is the crate root of a dependency crate, return the name from the extern prelude
134 for (name, def_id) in def_map.extern_prelude() { 133 for (name, def_id) in root.def_map(db).extern_prelude() {
135 if item == ItemInNs::Types(*def_id) { 134 if item == ItemInNs::Types(*def_id) {
136 let name = scope_name.unwrap_or_else(|| name.clone()); 135 let name = scope_name.unwrap_or_else(|| name.clone());
137 return Some(ModPath::from_segments(PathKind::Plain, vec![name])); 136 return Some(ModPath::from_segments(PathKind::Plain, vec![name]));
@@ -298,6 +297,7 @@ fn find_local_import_locations(
298 let data = &def_map[from.local_id]; 297 let data = &def_map[from.local_id];
299 let mut worklist = 298 let mut worklist =
300 data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>(); 299 data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>();
300 // FIXME: do we need to traverse out of block expressions here?
301 for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) { 301 for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) {
302 worklist.push(ancestor); 302 worklist.push(ancestor);
303 } 303 }
@@ -425,106 +425,142 @@ mod tests {
425 425
426 #[test] 426 #[test]
427 fn same_module() { 427 fn same_module() {
428 let code = r#" 428 check_found_path(
429 //- /main.rs 429 r#"
430 struct S; 430struct S;
431 $0 431$0
432 "#; 432 "#,
433 check_found_path(code, "S", "S", "crate::S", "self::S"); 433 "S",
434 "S",
435 "crate::S",
436 "self::S",
437 );
434 } 438 }
435 439
436 #[test] 440 #[test]
437 fn enum_variant() { 441 fn enum_variant() {
438 let code = r#" 442 check_found_path(
439 //- /main.rs 443 r#"
440 enum E { A } 444enum E { A }
441 $0 445$0
442 "#; 446 "#,
443 check_found_path(code, "E::A", "E::A", "E::A", "E::A"); 447 "E::A",
448 "E::A",
449 "E::A",
450 "E::A",
451 );
444 } 452 }
445 453
446 #[test] 454 #[test]
447 fn sub_module() { 455 fn sub_module() {
448 let code = r#" 456 check_found_path(
449 //- /main.rs 457 r#"
450 mod foo { 458mod foo {
451 pub struct S; 459 pub struct S;
452 } 460}
453 $0 461$0
454 "#; 462 "#,
455 check_found_path(code, "foo::S", "foo::S", "crate::foo::S", "self::foo::S"); 463 "foo::S",
464 "foo::S",
465 "crate::foo::S",
466 "self::foo::S",
467 );
456 } 468 }
457 469
458 #[test] 470 #[test]
459 fn super_module() { 471 fn super_module() {
460 let code = r#" 472 check_found_path(
461 //- /main.rs 473 r#"
462 mod foo; 474//- /main.rs
463 //- /foo.rs 475mod foo;
464 mod bar; 476//- /foo.rs
465 struct S; 477mod bar;
466 //- /foo/bar.rs 478struct S;
467 $0 479//- /foo/bar.rs
468 "#; 480$0
469 check_found_path(code, "super::S", "super::S", "crate::foo::S", "super::S"); 481 "#,
482 "super::S",
483 "super::S",
484 "crate::foo::S",
485 "super::S",
486 );
470 } 487 }
471 488
472 #[test] 489 #[test]
473 fn self_module() { 490 fn self_module() {
474 let code = r#" 491 check_found_path(
475 //- /main.rs 492 r#"
476 mod foo; 493//- /main.rs
477 //- /foo.rs 494mod foo;
478 $0 495//- /foo.rs
479 "#; 496$0
480 check_found_path(code, "self", "self", "crate::foo", "self"); 497 "#,
498 "self",
499 "self",
500 "crate::foo",
501 "self",
502 );
481 } 503 }
482 504
483 #[test] 505 #[test]
484 fn crate_root() { 506 fn crate_root() {
485 let code = r#" 507 check_found_path(
486 //- /main.rs 508 r#"
487 mod foo; 509//- /main.rs
488 //- /foo.rs 510mod foo;
489 $0 511//- /foo.rs
490 "#; 512$0
491 check_found_path(code, "crate", "crate", "crate", "crate"); 513 "#,
514 "crate",
515 "crate",
516 "crate",
517 "crate",
518 );
492 } 519 }
493 520
494 #[test] 521 #[test]
495 fn same_crate() { 522 fn same_crate() {
496 let code = r#" 523 check_found_path(
497 //- /main.rs 524 r#"
498 mod foo; 525//- /main.rs
499 struct S; 526mod foo;
500 //- /foo.rs 527struct S;
501 $0 528//- /foo.rs
502 "#; 529$0
503 check_found_path(code, "crate::S", "crate::S", "crate::S", "crate::S"); 530 "#,
531 "crate::S",
532 "crate::S",
533 "crate::S",
534 "crate::S",
535 );
504 } 536 }
505 537
506 #[test] 538 #[test]
507 fn different_crate() { 539 fn different_crate() {
508 let code = r#" 540 check_found_path(
509 //- /main.rs crate:main deps:std 541 r#"
510 $0 542//- /main.rs crate:main deps:std
511 //- /std.rs crate:std 543$0
512 pub struct S; 544//- /std.rs crate:std
513 "#; 545pub struct S;
514 check_found_path(code, "std::S", "std::S", "std::S", "std::S"); 546 "#,
547 "std::S",
548 "std::S",
549 "std::S",
550 "std::S",
551 );
515 } 552 }
516 553
517 #[test] 554 #[test]
518 fn different_crate_renamed() { 555 fn different_crate_renamed() {
519 let code = r#"
520 //- /main.rs crate:main deps:std
521 extern crate std as std_renamed;
522 $0
523 //- /std.rs crate:std
524 pub struct S;
525 "#;
526 check_found_path( 556 check_found_path(
527 code, 557 r#"
558//- /main.rs crate:main deps:std
559extern crate std as std_renamed;
560$0
561//- /std.rs crate:std
562pub struct S;
563 "#,
528 "std_renamed::S", 564 "std_renamed::S",
529 "std_renamed::S", 565 "std_renamed::S",
530 "std_renamed::S", 566 "std_renamed::S",
@@ -537,41 +573,38 @@ mod tests {
537 cov_mark::check!(partially_imported); 573 cov_mark::check!(partially_imported);
538 // Tests that short paths are used even for external items, when parts of the path are 574 // Tests that short paths are used even for external items, when parts of the path are
539 // already in scope. 575 // already in scope.
540 let code = r#" 576 check_found_path(
541 //- /main.rs crate:main deps:syntax 577 r#"
578//- /main.rs crate:main deps:syntax
542 579
543 use syntax::ast; 580use syntax::ast;
544 $0 581$0
545 582
546 //- /lib.rs crate:syntax 583//- /lib.rs crate:syntax
547 pub mod ast { 584pub mod ast {
548 pub enum ModuleItem { 585 pub enum ModuleItem {
549 A, B, C, 586 A, B, C,
550 } 587 }
551 } 588}
552 "#; 589 "#,
553 check_found_path(
554 code,
555 "ast::ModuleItem", 590 "ast::ModuleItem",
556 "syntax::ast::ModuleItem", 591 "syntax::ast::ModuleItem",
557 "syntax::ast::ModuleItem", 592 "syntax::ast::ModuleItem",
558 "syntax::ast::ModuleItem", 593 "syntax::ast::ModuleItem",
559 ); 594 );
560 595
561 let code = r#"
562 //- /main.rs crate:main deps:syntax
563
564 $0
565
566 //- /lib.rs crate:syntax
567 pub mod ast {
568 pub enum ModuleItem {
569 A, B, C,
570 }
571 }
572 "#;
573 check_found_path( 596 check_found_path(
574 code, 597 r#"
598//- /main.rs crate:main deps:syntax
599$0
600
601//- /lib.rs crate:syntax
602pub mod ast {
603 pub enum ModuleItem {
604 A, B, C,
605 }
606}
607 "#,
575 "syntax::ast::ModuleItem", 608 "syntax::ast::ModuleItem",
576 "syntax::ast::ModuleItem", 609 "syntax::ast::ModuleItem",
577 "syntax::ast::ModuleItem", 610 "syntax::ast::ModuleItem",
@@ -581,68 +614,86 @@ mod tests {
581 614
582 #[test] 615 #[test]
583 fn same_crate_reexport() { 616 fn same_crate_reexport() {
584 let code = r#" 617 check_found_path(
585 //- /main.rs 618 r#"
586 mod bar { 619mod bar {
587 mod foo { pub(super) struct S; } 620 mod foo { pub(super) struct S; }
588 pub(crate) use foo::*; 621 pub(crate) use foo::*;
589 } 622}
590 $0 623$0
591 "#; 624 "#,
592 check_found_path(code, "bar::S", "bar::S", "crate::bar::S", "self::bar::S"); 625 "bar::S",
626 "bar::S",
627 "crate::bar::S",
628 "self::bar::S",
629 );
593 } 630 }
594 631
595 #[test] 632 #[test]
596 fn same_crate_reexport_rename() { 633 fn same_crate_reexport_rename() {
597 let code = r#" 634 check_found_path(
598 //- /main.rs 635 r#"
599 mod bar { 636mod bar {
600 mod foo { pub(super) struct S; } 637 mod foo { pub(super) struct S; }
601 pub(crate) use foo::S as U; 638 pub(crate) use foo::S as U;
602 } 639}
603 $0 640$0
604 "#; 641 "#,
605 check_found_path(code, "bar::U", "bar::U", "crate::bar::U", "self::bar::U"); 642 "bar::U",
643 "bar::U",
644 "crate::bar::U",
645 "self::bar::U",
646 );
606 } 647 }
607 648
608 #[test] 649 #[test]
609 fn different_crate_reexport() { 650 fn different_crate_reexport() {
610 let code = r#" 651 check_found_path(
611 //- /main.rs crate:main deps:std 652 r#"
612 $0 653//- /main.rs crate:main deps:std
613 //- /std.rs crate:std deps:core 654$0
614 pub use core::S; 655//- /std.rs crate:std deps:core
615 //- /core.rs crate:core 656pub use core::S;
616 pub struct S; 657//- /core.rs crate:core
617 "#; 658pub struct S;
618 check_found_path(code, "std::S", "std::S", "std::S", "std::S"); 659 "#,
660 "std::S",
661 "std::S",
662 "std::S",
663 "std::S",
664 );
619 } 665 }
620 666
621 #[test] 667 #[test]
622 fn prelude() { 668 fn prelude() {
623 let code = r#" 669 check_found_path(
624 //- /main.rs crate:main deps:std 670 r#"
625 $0 671//- /main.rs crate:main deps:std
626 //- /std.rs crate:std 672$0
627 pub mod prelude { pub struct S; } 673//- /std.rs crate:std
628 #[prelude_import] 674pub mod prelude { pub struct S; }
629 pub use prelude::*; 675#[prelude_import]
630 "#; 676pub use prelude::*;
631 check_found_path(code, "S", "S", "S", "S"); 677 "#,
678 "S",
679 "S",
680 "S",
681 "S",
682 );
632 } 683 }
633 684
634 #[test] 685 #[test]
635 fn enum_variant_from_prelude() { 686 fn enum_variant_from_prelude() {
636 let code = r#" 687 let code = r#"
637 //- /main.rs crate:main deps:std 688//- /main.rs crate:main deps:std
638 $0 689$0
639 //- /std.rs crate:std 690//- /std.rs crate:std
640 pub mod prelude { 691pub mod prelude {
641 pub enum Option<T> { Some(T), None } 692 pub enum Option<T> { Some(T), None }
642 pub use Option::*; 693 pub use Option::*;
643 } 694}
644 #[prelude_import] 695#[prelude_import]
645 pub use prelude::*; 696pub use prelude::*;
646 "#; 697 "#;
647 check_found_path(code, "None", "None", "None", "None"); 698 check_found_path(code, "None", "None", "None", "None");
648 check_found_path(code, "Some", "Some", "Some", "Some"); 699 check_found_path(code, "Some", "Some", "Some", "Some");
@@ -650,71 +701,85 @@ mod tests {
650 701
651 #[test] 702 #[test]
652 fn shortest_path() { 703 fn shortest_path() {
653 let code = r#" 704 check_found_path(
654 //- /main.rs 705 r#"
655 pub mod foo; 706//- /main.rs
656 pub mod baz; 707pub mod foo;
657 struct S; 708pub mod baz;
658 $0 709struct S;
659 //- /foo.rs 710$0
660 pub mod bar { pub struct S; } 711//- /foo.rs
661 //- /baz.rs 712pub mod bar { pub struct S; }
662 pub use crate::foo::bar::S; 713//- /baz.rs
663 "#; 714pub use crate::foo::bar::S;
664 check_found_path(code, "baz::S", "baz::S", "crate::baz::S", "self::baz::S"); 715 "#,
716 "baz::S",
717 "baz::S",
718 "crate::baz::S",
719 "self::baz::S",
720 );
665 } 721 }
666 722
667 #[test] 723 #[test]
668 fn discount_private_imports() { 724 fn discount_private_imports() {
669 let code = r#" 725 check_found_path(
670 //- /main.rs 726 r#"
671 mod foo; 727//- /main.rs
672 pub mod bar { pub struct S; } 728mod foo;
673 use bar::S; 729pub mod bar { pub struct S; }
674 //- /foo.rs 730use bar::S;
675 $0 731//- /foo.rs
676 "#; 732$0
677 // crate::S would be shorter, but using private imports seems wrong 733 "#,
678 check_found_path(code, "crate::bar::S", "crate::bar::S", "crate::bar::S", "crate::bar::S"); 734 // crate::S would be shorter, but using private imports seems wrong
735 "crate::bar::S",
736 "crate::bar::S",
737 "crate::bar::S",
738 "crate::bar::S",
739 );
679 } 740 }
680 741
681 #[test] 742 #[test]
682 fn import_cycle() { 743 fn import_cycle() {
683 let code = r#" 744 check_found_path(
684 //- /main.rs 745 r#"
685 pub mod foo; 746//- /main.rs
686 pub mod bar; 747pub mod foo;
687 pub mod baz; 748pub mod bar;
688 //- /bar.rs 749pub mod baz;
689 $0 750//- /bar.rs
690 //- /foo.rs 751$0
691 pub use super::baz; 752//- /foo.rs
692 pub struct S; 753pub use super::baz;
693 //- /baz.rs 754pub struct S;
694 pub use super::foo; 755//- /baz.rs
695 "#; 756pub use super::foo;
696 check_found_path(code, "crate::foo::S", "crate::foo::S", "crate::foo::S", "crate::foo::S"); 757 "#,
758 "crate::foo::S",
759 "crate::foo::S",
760 "crate::foo::S",
761 "crate::foo::S",
762 );
697 } 763 }
698 764
699 #[test] 765 #[test]
700 fn prefer_std_paths_over_alloc() { 766 fn prefer_std_paths_over_alloc() {
701 cov_mark::check!(prefer_std_paths); 767 cov_mark::check!(prefer_std_paths);
702 let code = r#" 768 check_found_path(
703 //- /main.rs crate:main deps:alloc,std 769 r#"
704 $0 770//- /main.rs crate:main deps:alloc,std
771$0
705 772
706 //- /std.rs crate:std deps:alloc 773//- /std.rs crate:std deps:alloc
707 pub mod sync { 774pub mod sync {
708 pub use alloc::sync::Arc; 775 pub use alloc::sync::Arc;
709 } 776}
710 777
711 //- /zzz.rs crate:alloc 778//- /zzz.rs crate:alloc
712 pub mod sync { 779pub mod sync {
713 pub struct Arc; 780 pub struct Arc;
714 } 781}
715 "#; 782 "#,
716 check_found_path(
717 code,
718 "std::sync::Arc", 783 "std::sync::Arc",
719 "std::sync::Arc", 784 "std::sync::Arc",
720 "std::sync::Arc", 785 "std::sync::Arc",
@@ -725,26 +790,25 @@ mod tests {
725 #[test] 790 #[test]
726 fn prefer_core_paths_over_std() { 791 fn prefer_core_paths_over_std() {
727 cov_mark::check!(prefer_no_std_paths); 792 cov_mark::check!(prefer_no_std_paths);
728 let code = r#" 793 check_found_path(
729 //- /main.rs crate:main deps:core,std 794 r#"
730 #![no_std] 795//- /main.rs crate:main deps:core,std
796#![no_std]
731 797
732 $0 798$0
733 799
734 //- /std.rs crate:std deps:core 800//- /std.rs crate:std deps:core
735 801
736 pub mod fmt { 802pub mod fmt {
737 pub use core::fmt::Error; 803 pub use core::fmt::Error;
738 } 804}
739 805
740 //- /zzz.rs crate:core 806//- /zzz.rs crate:core
741 807
742 pub mod fmt { 808pub mod fmt {
743 pub struct Error; 809 pub struct Error;
744 } 810}
745 "#; 811 "#,
746 check_found_path(
747 code,
748 "core::fmt::Error", 812 "core::fmt::Error",
749 "core::fmt::Error", 813 "core::fmt::Error",
750 "core::fmt::Error", 814 "core::fmt::Error",
@@ -754,26 +818,25 @@ mod tests {
754 818
755 #[test] 819 #[test]
756 fn prefer_alloc_paths_over_std() { 820 fn prefer_alloc_paths_over_std() {
757 let code = r#" 821 check_found_path(
758 //- /main.rs crate:main deps:alloc,std 822 r#"
759 #![no_std] 823//- /main.rs crate:main deps:alloc,std
824#![no_std]
760 825
761 $0 826$0
762 827
763 //- /std.rs crate:std deps:alloc 828//- /std.rs crate:std deps:alloc
764 829
765 pub mod sync { 830pub mod sync {
766 pub use alloc::sync::Arc; 831 pub use alloc::sync::Arc;
767 } 832}
768 833
769 //- /zzz.rs crate:alloc 834//- /zzz.rs crate:alloc
770 835
771 pub mod sync { 836pub mod sync {
772 pub struct Arc; 837 pub struct Arc;
773 } 838}
774 "#; 839 "#,
775 check_found_path(
776 code,
777 "alloc::sync::Arc", 840 "alloc::sync::Arc",
778 "alloc::sync::Arc", 841 "alloc::sync::Arc",
779 "alloc::sync::Arc", 842 "alloc::sync::Arc",
@@ -783,20 +846,19 @@ mod tests {
783 846
784 #[test] 847 #[test]
785 fn prefer_shorter_paths_if_not_alloc() { 848 fn prefer_shorter_paths_if_not_alloc() {
786 let code = r#" 849 check_found_path(
787 //- /main.rs crate:main deps:megaalloc,std 850 r#"
788 $0 851//- /main.rs crate:main deps:megaalloc,std
852$0
789 853
790 //- /std.rs crate:std deps:megaalloc 854//- /std.rs crate:std deps:megaalloc
791 pub mod sync { 855pub mod sync {
792 pub use megaalloc::sync::Arc; 856 pub use megaalloc::sync::Arc;
793 } 857}
794 858
795 //- /zzz.rs crate:megaalloc 859//- /zzz.rs crate:megaalloc
796 pub struct Arc; 860pub struct Arc;
797 "#; 861 "#,
798 check_found_path(
799 code,
800 "megaalloc::Arc", 862 "megaalloc::Arc",
801 "megaalloc::Arc", 863 "megaalloc::Arc",
802 "megaalloc::Arc", 864 "megaalloc::Arc",
@@ -807,12 +869,11 @@ mod tests {
807 #[test] 869 #[test]
808 fn builtins_are_in_scope() { 870 fn builtins_are_in_scope() {
809 let code = r#" 871 let code = r#"
810 //- /main.rs 872$0
811 $0
812 873
813 pub mod primitive { 874pub mod primitive {
814 pub use u8; 875 pub use u8;
815 } 876}
816 "#; 877 "#;
817 check_found_path(code, "u8", "u8", "u8", "u8"); 878 check_found_path(code, "u8", "u8", "u8", "u8");
818 check_found_path(code, "u16", "u16", "u16", "u16"); 879 check_found_path(code, "u16", "u16", "u16", "u16");
@@ -822,10 +883,10 @@ mod tests {
822 fn inner_items() { 883 fn inner_items() {
823 check_found_path( 884 check_found_path(
824 r#" 885 r#"
825 fn main() { 886fn main() {
826 struct Inner {} 887 struct Inner {}
827 $0 888 $0
828 } 889}
829 "#, 890 "#,
830 "Inner", 891 "Inner",
831 "Inner", 892 "Inner",
@@ -838,12 +899,12 @@ mod tests {
838 fn inner_items_from_outer_scope() { 899 fn inner_items_from_outer_scope() {
839 check_found_path( 900 check_found_path(
840 r#" 901 r#"
841 fn main() { 902fn main() {
842 struct Struct {} 903 struct Struct {}
843 { 904 {
844 $0 905 $0
845 } 906 }
846 } 907}
847 "#, 908 "#,
848 "Struct", 909 "Struct",
849 "Struct", 910 "Struct",
@@ -857,14 +918,14 @@ mod tests {
857 cov_mark::check!(prefixed_in_block_expression); 918 cov_mark::check!(prefixed_in_block_expression);
858 check_found_path( 919 check_found_path(
859 r#" 920 r#"
860 fn main() { 921fn main() {
861 mod module { 922 mod module {
862 struct Struct {} 923 struct Struct {}
863 } 924 }
864 { 925 {
865 $0 926 $0
866 } 927 }
867 } 928}
868 "#, 929 "#,
869 "module::Struct", 930 "module::Struct",
870 "module::Struct", 931 "module::Struct",
@@ -877,19 +938,65 @@ mod tests {
877 fn outer_items_with_inner_items_present() { 938 fn outer_items_with_inner_items_present() {
878 check_found_path( 939 check_found_path(
879 r#" 940 r#"
880 mod module { 941mod module {
881 pub struct CompleteMe; 942 pub struct CompleteMe;
882 } 943}
883 944
884 fn main() { 945fn main() {
885 fn inner() {} 946 fn inner() {}
886 $0 947 $0
887 } 948}
888 "#, 949 "#,
950 // FIXME: these could use fewer/better prefixes
889 "module::CompleteMe", 951 "module::CompleteMe",
890 "module::CompleteMe",
891 "crate::module::CompleteMe", 952 "crate::module::CompleteMe",
892 "self::module::CompleteMe", 953 "crate::module::CompleteMe",
954 "crate::module::CompleteMe",
955 )
956 }
957
958 #[test]
959 fn from_inside_module() {
960 // This worked correctly, but the test suite logic was broken.
961 cov_mark::check!(submodule_in_testdb);
962 check_found_path(
963 r#"
964mod baz {
965 pub struct Foo {}
966}
967
968mod bar {
969 fn bar() {
970 $0
971 }
972}
973 "#,
974 "crate::baz::Foo",
975 "crate::baz::Foo",
976 "crate::baz::Foo",
977 "crate::baz::Foo",
978 )
979 }
980
981 #[test]
982 fn from_inside_module_with_inner_items() {
983 check_found_path(
984 r#"
985mod baz {
986 pub struct Foo {}
987}
988
989mod bar {
990 fn bar() {
991 fn inner() {}
992 $0
993 }
994}
995 "#,
996 "crate::baz::Foo",
997 "crate::baz::Foo",
998 "crate::baz::Foo",
999 "crate::baz::Foo",
893 ) 1000 )
894 } 1001 }
895 1002
@@ -920,4 +1027,34 @@ pub mod name {
920 "self::name::AsName", 1027 "self::name::AsName",
921 ); 1028 );
922 } 1029 }
1030
1031 #[test]
1032 fn extern_crate() {
1033 check_found_path(
1034 r#"
1035//- /main.rs crate:main deps:dep
1036$0
1037//- /dep.rs crate:dep
1038"#,
1039 "dep",
1040 "dep",
1041 "dep",
1042 "dep",
1043 );
1044
1045 check_found_path(
1046 r#"
1047//- /main.rs crate:main deps:dep
1048fn f() {
1049 fn inner() {}
1050 $0
1051}
1052//- /dep.rs crate:dep
1053"#,
1054 "dep",
1055 "dep",
1056 "dep",
1057 "dep",
1058 );
1059 }
923} 1060}
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
index d163f633f..abc304ef0 100644
--- a/crates/hir_def/src/intern.rs
+++ b/crates/hir_def/src/intern.rs
@@ -5,7 +5,7 @@
5use std::{ 5use std::{
6 collections::HashMap, 6 collections::HashMap,
7 fmt::{self, Debug}, 7 fmt::{self, Debug},
8 hash::{BuildHasherDefault, Hash}, 8 hash::{BuildHasherDefault, Hash, Hasher},
9 ops::Deref, 9 ops::Deref,
10 sync::Arc, 10 sync::Arc,
11}; 11};
@@ -14,11 +14,12 @@ use dashmap::{lock::RwLockWriteGuard, DashMap, SharedValue};
14use once_cell::sync::OnceCell; 14use once_cell::sync::OnceCell;
15use rustc_hash::FxHasher; 15use rustc_hash::FxHasher;
16 16
17use crate::generics::GenericParams;
18
17type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>; 19type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>;
18type Guard<T> = 20type Guard<T> =
19 RwLockWriteGuard<'static, HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>>; 21 RwLockWriteGuard<'static, HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>>;
20 22
21#[derive(Hash)]
22pub struct Interned<T: Internable + ?Sized> { 23pub struct Interned<T: Internable + ?Sized> {
23 arc: Arc<T>, 24 arc: Arc<T>,
24} 25}
@@ -135,6 +136,13 @@ impl PartialEq for Interned<str> {
135 136
136impl Eq for Interned<str> {} 137impl Eq for Interned<str> {}
137 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
138impl<T: Internable + ?Sized> AsRef<T> for Interned<T> { 146impl<T: Internable + ?Sized> AsRef<T> for Interned<T> {
139 #[inline] 147 #[inline]
140 fn as_ref(&self) -> &T { 148 fn as_ref(&self) -> &T {
@@ -183,7 +191,10 @@ pub trait Internable: Hash + Eq + 'static {
183 fn storage() -> &'static InternStorage<Self>; 191 fn storage() -> &'static InternStorage<Self>;
184} 192}
185 193
186macro_rules! impl_internable { 194/// Implements `Internable` for a given list of types, making them usable with `Interned`.
195#[macro_export]
196#[doc(hidden)]
197macro_rules! _impl_internable {
187 ( $($t:path),+ $(,)? ) => { $( 198 ( $($t:path),+ $(,)? ) => { $(
188 impl Internable for $t { 199 impl Internable for $t {
189 fn storage() -> &'static InternStorage<Self> { 200 fn storage() -> &'static InternStorage<Self> {
@@ -194,4 +205,12 @@ macro_rules! impl_internable {
194 )+ }; 205 )+ };
195} 206}
196 207
197impl_internable!(crate::type_ref::TypeRef, crate::type_ref::TraitRef, crate::path::ModPath, str); 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 a8ee5eeac..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 }
@@ -295,6 +304,7 @@ impl ItemScope {
295 unresolved, 304 unresolved,
296 defs, 305 defs,
297 impls, 306 impls,
307 unnamed_consts,
298 unnamed_trait_imports, 308 unnamed_trait_imports,
299 legacy_macros, 309 legacy_macros,
300 } = self; 310 } = self;
@@ -304,6 +314,7 @@ impl ItemScope {
304 unresolved.shrink_to_fit(); 314 unresolved.shrink_to_fit();
305 defs.shrink_to_fit(); 315 defs.shrink_to_fit();
306 impls.shrink_to_fit(); 316 impls.shrink_to_fit();
317 unnamed_consts.shrink_to_fit();
307 unnamed_trait_imports.shrink_to_fit(); 318 unnamed_trait_imports.shrink_to_fit();
308 legacy_macros.shrink_to_fit(); 319 legacy_macros.shrink_to_fit();
309 } 320 }
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 739906778..eaeca01bd 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -58,13 +58,6 @@ impl fmt::Debug for RawVisibilityId {
58 } 58 }
59} 59}
60 60
61#[derive(Debug, Copy, Clone, Eq, PartialEq)]
62pub struct GenericParamsId(u32);
63
64impl GenericParamsId {
65 pub const EMPTY: Self = GenericParamsId(u32::max_value());
66}
67
68/// The item tree of a source file. 61/// The item tree of a source file.
69#[derive(Debug, Default, Eq, PartialEq)] 62#[derive(Debug, Default, Eq, PartialEq)]
70pub struct ItemTree { 63pub struct ItemTree {
@@ -106,6 +99,16 @@ impl ItemTree {
106 // items. 99 // items.
107 ctx.lower_macro_stmts(stmts) 100 ctx.lower_macro_stmts(stmts)
108 }, 101 },
102 ast::Pat(_pat) => {
103 // FIXME: This occurs because macros in pattern position are treated as inner
104 // items and expanded during block DefMap computation
105 return Default::default();
106 },
107 ast::Type(ty) => {
108 // Types can contain inner items. We return an empty item tree in this case, but
109 // still need to collect inner items.
110 ctx.lower_inner_items(ty.syntax())
111 },
109 ast::Expr(e) => { 112 ast::Expr(e) => {
110 // Macros can expand to expressions. We return an empty item tree in this case, but 113 // Macros can expand to expressions. We return an empty item tree in this case, but
111 // still need to collect inner items. 114 // still need to collect inner items.
@@ -146,7 +149,6 @@ impl ItemTree {
146 macro_rules, 149 macro_rules,
147 macro_defs, 150 macro_defs,
148 vis, 151 vis,
149 generics,
150 inner_items, 152 inner_items,
151 } = &mut **data; 153 } = &mut **data;
152 154
@@ -170,7 +172,6 @@ impl ItemTree {
170 macro_defs.shrink_to_fit(); 172 macro_defs.shrink_to_fit();
171 173
172 vis.arena.shrink_to_fit(); 174 vis.arena.shrink_to_fit();
173 generics.arena.shrink_to_fit();
174 175
175 inner_items.shrink_to_fit(); 176 inner_items.shrink_to_fit();
176 } 177 }
@@ -195,13 +196,6 @@ impl ItemTree {
195 self.raw_attrs(of).clone().filter(db, krate) 196 self.raw_attrs(of).clone().filter(db, krate)
196 } 197 }
197 198
198 pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ {
199 match &self.data {
200 Some(data) => Some(data.inner_items.values().flatten().copied()).into_iter().flatten(),
201 None => None.into_iter().flatten(),
202 }
203 }
204
205 pub fn inner_items_of_block(&self, block: FileAstId<ast::BlockExpr>) -> &[ModItem] { 199 pub fn inner_items_of_block(&self, block: FileAstId<ast::BlockExpr>) -> &[ModItem] {
206 match &self.data { 200 match &self.data {
207 Some(data) => data.inner_items.get(&block).map(|it| &**it).unwrap_or(&[]), 201 Some(data) => data.inner_items.get(&block).map(|it| &**it).unwrap_or(&[]),
@@ -242,32 +236,6 @@ static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKi
242static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate)); 236static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate));
243 237
244#[derive(Default, Debug, Eq, PartialEq)] 238#[derive(Default, Debug, Eq, PartialEq)]
245struct GenericParamsStorage {
246 arena: Arena<GenericParams>,
247}
248
249impl GenericParamsStorage {
250 fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
251 if params.types.is_empty()
252 && params.lifetimes.is_empty()
253 && params.consts.is_empty()
254 && params.where_predicates.is_empty()
255 {
256 return GenericParamsId::EMPTY;
257 }
258
259 GenericParamsId(self.arena.alloc(params).into_raw().into())
260 }
261}
262
263static EMPTY_GENERICS: GenericParams = GenericParams {
264 types: Arena::new(),
265 lifetimes: Arena::new(),
266 consts: Arena::new(),
267 where_predicates: Vec::new(),
268};
269
270#[derive(Default, Debug, Eq, PartialEq)]
271struct ItemTreeData { 239struct ItemTreeData {
272 imports: Arena<Import>, 240 imports: Arena<Import>,
273 extern_crates: Arena<ExternCrate>, 241 extern_crates: Arena<ExternCrate>,
@@ -289,7 +257,6 @@ struct ItemTreeData {
289 macro_defs: Arena<MacroDef>, 257 macro_defs: Arena<MacroDef>,
290 258
291 vis: ItemVisibilities, 259 vis: ItemVisibilities,
292 generics: GenericParamsStorage,
293 260
294 inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, 261 inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
295} 262}
@@ -508,17 +475,6 @@ impl Index<RawVisibilityId> for ItemTree {
508 } 475 }
509} 476}
510 477
511impl Index<GenericParamsId> for ItemTree {
512 type Output = GenericParams;
513
514 fn index(&self, index: GenericParamsId) -> &Self::Output {
515 match index {
516 GenericParamsId::EMPTY => &EMPTY_GENERICS,
517 _ => &self.data().generics.arena[Idx::from_raw(index.0.into())],
518 }
519 }
520}
521
522impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { 478impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
523 type Output = N; 479 type Output = N;
524 fn index(&self, id: FileItemTreeId<N>) -> &N { 480 fn index(&self, id: FileItemTreeId<N>) -> &N {
@@ -555,7 +511,7 @@ pub struct ExternCrate {
555pub struct Function { 511pub struct Function {
556 pub name: Name, 512 pub name: Name,
557 pub visibility: RawVisibilityId, 513 pub visibility: RawVisibilityId,
558 pub generic_params: GenericParamsId, 514 pub generic_params: Interned<GenericParams>,
559 pub abi: Option<Interned<str>>, 515 pub abi: Option<Interned<str>>,
560 pub params: IdRange<Param>, 516 pub params: IdRange<Param>,
561 pub ret_type: Interned<TypeRef>, 517 pub ret_type: Interned<TypeRef>,
@@ -590,7 +546,7 @@ impl FnFlags {
590pub struct Struct { 546pub struct Struct {
591 pub name: Name, 547 pub name: Name,
592 pub visibility: RawVisibilityId, 548 pub visibility: RawVisibilityId,
593 pub generic_params: GenericParamsId, 549 pub generic_params: Interned<GenericParams>,
594 pub fields: Fields, 550 pub fields: Fields,
595 pub ast_id: FileAstId<ast::Struct>, 551 pub ast_id: FileAstId<ast::Struct>,
596 pub kind: StructDefKind, 552 pub kind: StructDefKind,
@@ -610,7 +566,7 @@ pub enum StructDefKind {
610pub struct Union { 566pub struct Union {
611 pub name: Name, 567 pub name: Name,
612 pub visibility: RawVisibilityId, 568 pub visibility: RawVisibilityId,
613 pub generic_params: GenericParamsId, 569 pub generic_params: Interned<GenericParams>,
614 pub fields: Fields, 570 pub fields: Fields,
615 pub ast_id: FileAstId<ast::Union>, 571 pub ast_id: FileAstId<ast::Union>,
616} 572}
@@ -619,7 +575,7 @@ pub struct Union {
619pub struct Enum { 575pub struct Enum {
620 pub name: Name, 576 pub name: Name,
621 pub visibility: RawVisibilityId, 577 pub visibility: RawVisibilityId,
622 pub generic_params: GenericParamsId, 578 pub generic_params: Interned<GenericParams>,
623 pub variants: IdRange<Variant>, 579 pub variants: IdRange<Variant>,
624 pub ast_id: FileAstId<ast::Enum>, 580 pub ast_id: FileAstId<ast::Enum>,
625} 581}
@@ -648,7 +604,7 @@ pub struct Static {
648pub struct Trait { 604pub struct Trait {
649 pub name: Name, 605 pub name: Name,
650 pub visibility: RawVisibilityId, 606 pub visibility: RawVisibilityId,
651 pub generic_params: GenericParamsId, 607 pub generic_params: Interned<GenericParams>,
652 pub is_auto: bool, 608 pub is_auto: bool,
653 pub is_unsafe: bool, 609 pub is_unsafe: bool,
654 pub bounds: Box<[TypeBound]>, 610 pub bounds: Box<[TypeBound]>,
@@ -658,7 +614,7 @@ pub struct Trait {
658 614
659#[derive(Debug, Clone, Eq, PartialEq)] 615#[derive(Debug, Clone, Eq, PartialEq)]
660pub struct Impl { 616pub struct Impl {
661 pub generic_params: GenericParamsId, 617 pub generic_params: Interned<GenericParams>,
662 pub target_trait: Option<Interned<TraitRef>>, 618 pub target_trait: Option<Interned<TraitRef>>,
663 pub self_ty: Interned<TypeRef>, 619 pub self_ty: Interned<TypeRef>,
664 pub is_negative: bool, 620 pub is_negative: bool,
@@ -672,7 +628,7 @@ pub struct TypeAlias {
672 pub visibility: RawVisibilityId, 628 pub visibility: RawVisibilityId,
673 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. 629 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
674 pub bounds: Box<[TypeBound]>, 630 pub bounds: Box<[TypeBound]>,
675 pub generic_params: GenericParamsId, 631 pub generic_params: Interned<GenericParams>,
676 pub type_ref: Option<Interned<TypeRef>>, 632 pub type_ref: Option<Interned<TypeRef>>,
677 pub is_extern: bool, 633 pub is_extern: bool,
678 pub ast_id: FileAstId<ast::TypeAlias>, 634 pub ast_id: FileAstId<ast::TypeAlias>,
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index ab7ad8310..45b099cf3 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -189,7 +189,7 @@ impl Ctx {
189 block_stack.push(self.source_ast_id_map.ast_id(&block)); 189 block_stack.push(self.source_ast_id_map.ast_id(&block));
190 }, 190 },
191 ast::Item(item) => { 191 ast::Item(item) => {
192 // FIXME: This triggers for macro calls in expression position 192 // FIXME: This triggers for macro calls in expression/pattern/type position
193 let mod_items = self.lower_mod_item(&item, true); 193 let mod_items = self.lower_mod_item(&item, true);
194 let current_block = block_stack.last(); 194 let current_block = block_stack.last();
195 if let (Some(mod_items), Some(block)) = (mod_items, current_block) { 195 if let (Some(mod_items), Some(block)) = (mod_items, current_block) {
@@ -434,7 +434,7 @@ impl Ctx {
434 let mut res = Function { 434 let mut res = Function {
435 name, 435 name,
436 visibility, 436 visibility,
437 generic_params: GenericParamsId::EMPTY, 437 generic_params: Interned::new(GenericParams::default()),
438 abi, 438 abi,
439 params, 439 params,
440 ret_type: Interned::new(ret_type), 440 ret_type: Interned::new(ret_type),
@@ -682,7 +682,7 @@ impl Ctx {
682 &mut self, 682 &mut self,
683 owner: GenericsOwner<'_>, 683 owner: GenericsOwner<'_>,
684 node: &impl ast::GenericParamsOwner, 684 node: &impl ast::GenericParamsOwner,
685 ) -> GenericParamsId { 685 ) -> Interned<GenericParams> {
686 // 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.
687 if let Some(params) = node.generic_param_list() { 687 if let Some(params) = node.generic_param_list() {
688 self.collect_inner_items(params.syntax()); 688 self.collect_inner_items(params.syntax());
@@ -698,7 +698,7 @@ impl Ctx {
698 &mut self, 698 &mut self,
699 owner: GenericsOwner<'_>, 699 owner: GenericsOwner<'_>,
700 node: &impl ast::GenericParamsOwner, 700 node: &impl ast::GenericParamsOwner,
701 ) -> GenericParamsId { 701 ) -> Interned<GenericParams> {
702 let mut sm = &mut Default::default(); 702 let mut sm = &mut Default::default();
703 let mut generics = GenericParams::default(); 703 let mut generics = GenericParams::default();
704 match owner { 704 match owner {
@@ -739,7 +739,8 @@ impl Ctx {
739 } 739 }
740 } 740 }
741 741
742 self.data().generics.alloc(generics) 742 generics.shrink_to_fit();
743 Interned::new(generics)
743 } 744 }
744 745
745 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> {
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index f408e510a..25694f037 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;
@@ -49,22 +50,23 @@ pub mod import_map;
49 50
50#[cfg(test)] 51#[cfg(test)]
51mod test_db; 52mod test_db;
52mod intern;
53 53
54use std::{ 54use std::{
55 hash::{Hash, Hasher}, 55 hash::{Hash, Hasher},
56 sync::Arc, 56 sync::Arc,
57}; 57};
58 58
59use adt::VariantData;
59use base_db::{impl_intern_key, salsa, CrateId}; 60use base_db::{impl_intern_key, salsa, CrateId};
60use hir_expand::{ 61use hir_expand::{
61 ast_id_map::FileAstId, 62 ast_id_map::FileAstId,
62 eager::{expand_eager_macro, ErrorEmitted, ErrorSink}, 63 eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
63 hygiene::Hygiene, 64 hygiene::Hygiene,
64 AstId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 65 AstId, AttrId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
65}; 66};
66use la_arena::Idx; 67use la_arena::Idx;
67use nameres::DefMap; 68use nameres::DefMap;
69use path::ModPath;
68use syntax::ast; 70use syntax::ast;
69 71
70use crate::builtin_type::BuiltinType; 72use crate::builtin_type::BuiltinType;
@@ -106,6 +108,18 @@ impl ModuleId {
106 pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> { 108 pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
107 self.def_map(db).containing_module(self.local_id) 109 self.def_map(db).containing_module(self.local_id)
108 } 110 }
111
112 /// Returns `true` if this module represents a block expression.
113 ///
114 /// Returns `false` if this module is a submodule *inside* a block expression
115 /// (eg. `m` in `{ mod m {} }`).
116 pub fn is_block_root(&self, db: &dyn db::DefDatabase) -> bool {
117 if self.block.is_none() {
118 return false;
119 }
120
121 self.def_map(db)[self.local_id].parent.is_none()
122 }
109} 123}
110 124
111/// An ID of a module, **local** to a specific crate 125/// An ID of a module, **local** to a specific crate
@@ -434,6 +448,16 @@ impl_from!(
434 for AttrDefId 448 for AttrDefId
435); 449);
436 450
451impl From<AssocContainerId> for AttrDefId {
452 fn from(acid: AssocContainerId) -> Self {
453 match acid {
454 AssocContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
455 AssocContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
456 AssocContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
457 }
458 }
459}
460
437#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 461#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
438pub enum VariantId { 462pub enum VariantId {
439 EnumVariantId(EnumVariantId), 463 EnumVariantId(EnumVariantId),
@@ -442,6 +466,26 @@ pub enum VariantId {
442} 466}
443impl_from!(EnumVariantId, StructId, UnionId for VariantId); 467impl_from!(EnumVariantId, StructId, UnionId for VariantId);
444 468
469impl VariantId {
470 pub fn variant_data(self, db: &dyn db::DefDatabase) -> Arc<VariantData> {
471 match self {
472 VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
473 VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
474 VariantId::EnumVariantId(it) => {
475 db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
476 }
477 }
478 }
479
480 pub fn file_id(self, db: &dyn db::DefDatabase) -> HirFileId {
481 match self {
482 VariantId::EnumVariantId(it) => it.parent.lookup(db).id.file_id(),
483 VariantId::StructId(it) => it.lookup(db).id.file_id(),
484 VariantId::UnionId(it) => it.lookup(db).id.file_id(),
485 }
486 }
487}
488
445trait Intern { 489trait Intern {
446 type ID; 490 type ID;
447 fn intern(self, db: &dyn db::DefDatabase) -> Self::ID; 491 fn intern(self, db: &dyn db::DefDatabase) -> Self::ID;
@@ -644,7 +688,10 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
644 } 688 }
645} 689}
646 690
647pub struct UnresolvedMacro; 691#[derive(Debug)]
692pub struct UnresolvedMacro {
693 pub path: ModPath,
694}
648 695
649fn macro_call_as_call_id( 696fn macro_call_as_call_id(
650 call: &AstIdWithPath<ast::MacroCall>, 697 call: &AstIdWithPath<ast::MacroCall>,
@@ -653,7 +700,8 @@ fn macro_call_as_call_id(
653 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 700 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
654 error_sink: &mut dyn FnMut(mbe::ExpandError), 701 error_sink: &mut dyn FnMut(mbe::ExpandError),
655) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { 702) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
656 let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?; 703 let def: MacroDefId =
704 resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
657 705
658 let res = if let MacroDefKind::BuiltInEager(..) = def.kind { 706 let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
659 let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast())); 707 let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
@@ -669,24 +717,36 @@ fn macro_call_as_call_id(
669 ) 717 )
670 .map(MacroCallId::from) 718 .map(MacroCallId::from)
671 } else { 719 } else {
672 Ok(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(call.ast_id)).into()) 720 Ok(def
721 .as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike { ast_id: call.ast_id })
722 .into())
673 }; 723 };
674 Ok(res) 724 Ok(res)
675} 725}
676 726
677fn derive_macro_as_call_id( 727fn derive_macro_as_call_id(
678 item_attr: &AstIdWithPath<ast::Item>, 728 item_attr: &AstIdWithPath<ast::Item>,
729 derive_attr: AttrId,
679 db: &dyn db::DefDatabase, 730 db: &dyn db::DefDatabase,
680 krate: CrateId, 731 krate: CrateId,
681 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 732 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
682) -> Result<MacroCallId, UnresolvedMacro> { 733) -> Result<MacroCallId, UnresolvedMacro> {
683 let def: MacroDefId = resolver(item_attr.path.clone()).ok_or(UnresolvedMacro)?; 734 let def: MacroDefId = resolver(item_attr.path.clone())
684 let last_segment = item_attr.path.segments().last().ok_or(UnresolvedMacro)?; 735 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
736 let last_segment = item_attr
737 .path
738 .segments()
739 .last()
740 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
685 let res = def 741 let res = def
686 .as_lazy_macro( 742 .as_lazy_macro(
687 db.upcast(), 743 db.upcast(),
688 krate, 744 krate,
689 MacroCallKind::Derive(item_attr.ast_id, last_segment.to_string()), 745 MacroCallKind::Derive {
746 ast_id: item_attr.ast_id,
747 derive_name: last_segment.to_string(),
748 derive_attr,
749 },
690 ) 750 )
691 .into(); 751 .into();
692 Ok(res) 752 Ok(res)
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 7dd68219f..ba027c44a 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -410,6 +410,20 @@ impl DefMap {
410 } 410 }
411 } 411 }
412 412
413 pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String {
414 let mut buf = String::new();
415 let mut arc;
416 let mut current_map = self;
417 while let Some(block) = &current_map.block {
418 format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
419 arc = block.parent.def_map(db);
420 current_map = &*arc;
421 }
422
423 format_to!(buf, "crate scope\n");
424 buf
425 }
426
413 fn shrink_to_fit(&mut self) { 427 fn shrink_to_fit(&mut self) {
414 // Exhaustive match to require handling new fields. 428 // Exhaustive match to require handling new fields.
415 let Self { 429 let Self {
@@ -481,7 +495,7 @@ mod diagnostics {
481 495
482 UnresolvedProcMacro { ast: MacroCallKind }, 496 UnresolvedProcMacro { ast: MacroCallKind },
483 497
484 UnresolvedMacroCall { ast: AstId<ast::MacroCall> }, 498 UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
485 499
486 MacroError { ast: MacroCallKind, message: String }, 500 MacroError { ast: MacroCallKind, message: String },
487 } 501 }
@@ -546,8 +560,9 @@ mod diagnostics {
546 pub(super) fn unresolved_macro_call( 560 pub(super) fn unresolved_macro_call(
547 container: LocalModuleId, 561 container: LocalModuleId,
548 ast: AstId<ast::MacroCall>, 562 ast: AstId<ast::MacroCall>,
563 path: ModPath,
549 ) -> Self { 564 ) -> Self {
550 Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast } } 565 Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast, path } }
551 } 566 }
552 567
553 pub(super) fn add_to( 568 pub(super) fn add_to(
@@ -613,12 +628,12 @@ mod diagnostics {
613 DiagnosticKind::UnresolvedProcMacro { ast } => { 628 DiagnosticKind::UnresolvedProcMacro { ast } => {
614 let mut precise_location = None; 629 let mut precise_location = None;
615 let (file, ast, name) = match ast { 630 let (file, ast, name) = match ast {
616 MacroCallKind::FnLike(ast) => { 631 MacroCallKind::FnLike { ast_id } => {
617 let node = ast.to_node(db.upcast()); 632 let node = ast_id.to_node(db.upcast());
618 (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) 633 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
619 } 634 }
620 MacroCallKind::Derive(ast, name) => { 635 MacroCallKind::Derive { ast_id, derive_name, .. } => {
621 let node = ast.to_node(db.upcast()); 636 let node = ast_id.to_node(db.upcast());
622 637
623 // Compute the precise location of the macro name's token in the derive 638 // Compute the precise location of the macro name's token in the derive
624 // list. 639 // list.
@@ -639,7 +654,7 @@ mod diagnostics {
639 }); 654 });
640 for token in tokens { 655 for token in tokens {
641 if token.kind() == SyntaxKind::IDENT 656 if token.kind() == SyntaxKind::IDENT
642 && token.text() == name.as_str() 657 && token.text() == derive_name.as_str()
643 { 658 {
644 precise_location = Some(token.text_range()); 659 precise_location = Some(token.text_range());
645 break 'outer; 660 break 'outer;
@@ -648,9 +663,9 @@ mod diagnostics {
648 } 663 }
649 664
650 ( 665 (
651 ast.file_id, 666 ast_id.file_id,
652 SyntaxNodePtr::from(AstPtr::new(&node)), 667 SyntaxNodePtr::from(AstPtr::new(&node)),
653 Some(name.clone()), 668 Some(derive_name.clone()),
654 ) 669 )
655 } 670 }
656 }; 671 };
@@ -662,20 +677,24 @@ mod diagnostics {
662 }); 677 });
663 } 678 }
664 679
665 DiagnosticKind::UnresolvedMacroCall { ast } => { 680 DiagnosticKind::UnresolvedMacroCall { ast, path } => {
666 let node = ast.to_node(db.upcast()); 681 let node = ast.to_node(db.upcast());
667 sink.push(UnresolvedMacroCall { file: ast.file_id, node: AstPtr::new(&node) }); 682 sink.push(UnresolvedMacroCall {
683 file: ast.file_id,
684 node: AstPtr::new(&node),
685 path: path.clone(),
686 });
668 } 687 }
669 688
670 DiagnosticKind::MacroError { ast, message } => { 689 DiagnosticKind::MacroError { ast, message } => {
671 let (file, ast) = match ast { 690 let (file, ast) = match ast {
672 MacroCallKind::FnLike(ast) => { 691 MacroCallKind::FnLike { ast_id, .. } => {
673 let node = ast.to_node(db.upcast()); 692 let node = ast_id.to_node(db.upcast());
674 (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) 693 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
675 } 694 }
676 MacroCallKind::Derive(ast, _) => { 695 MacroCallKind::Derive { ast_id, .. } => {
677 let node = ast.to_node(db.upcast()); 696 let node = ast_id.to_node(db.upcast());
678 (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) 697 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
679 } 698 }
680 }; 699 };
681 sink.push(MacroError { file, node: ast, message: message.clone() }); 700 sink.push(MacroError { file, node: ast, message: message.clone() });
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 4ddc791ce..05ceb1efb 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -13,7 +13,7 @@ use hir_expand::{
13 builtin_macro::find_builtin_macro, 13 builtin_macro::find_builtin_macro,
14 name::{AsName, Name}, 14 name::{AsName, Name},
15 proc_macro::ProcMacroExpander, 15 proc_macro::ProcMacroExpander,
16 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 16 AttrId, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
17}; 17};
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use rustc_hash::{FxHashMap, FxHashSet}; 19use rustc_hash::{FxHashMap, FxHashSet};
@@ -215,8 +215,8 @@ struct MacroDirective {
215 215
216#[derive(Clone, Debug, Eq, PartialEq)] 216#[derive(Clone, Debug, Eq, PartialEq)]
217enum MacroDirectiveKind { 217enum MacroDirectiveKind {
218 FnLike { ast_id: AstIdWithPath<ast::MacroCall>, legacy: Option<MacroCallId> }, 218 FnLike { ast_id: AstIdWithPath<ast::MacroCall> },
219 Derive { ast_id: AstIdWithPath<ast::Item> }, 219 Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId },
220} 220}
221 221
222struct DefData<'a> { 222struct DefData<'a> {
@@ -478,7 +478,7 @@ impl DefCollector<'_> {
478 self.def_map.edition, 478 self.def_map.edition,
479 ); 479 );
480 480
481 let res = self.def_map.resolve_name_in_extern_prelude(&extern_crate.name); 481 let res = self.def_map.resolve_name_in_extern_prelude(self.db, &extern_crate.name);
482 482
483 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { 483 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
484 cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); 484 cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
@@ -534,6 +534,7 @@ impl DefCollector<'_> {
534 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 534 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
535 if import.is_extern_crate { 535 if import.is_extern_crate {
536 let res = self.def_map.resolve_name_in_extern_prelude( 536 let res = self.def_map.resolve_name_in_extern_prelude(
537 self.db,
537 &import 538 &import
538 .path 539 .path
539 .as_ident() 540 .as_ident()
@@ -806,13 +807,7 @@ impl DefCollector<'_> {
806 let mut res = ReachedFixedPoint::Yes; 807 let mut res = ReachedFixedPoint::Yes;
807 macros.retain(|directive| { 808 macros.retain(|directive| {
808 match &directive.kind { 809 match &directive.kind {
809 MacroDirectiveKind::FnLike { ast_id, legacy } => { 810 MacroDirectiveKind::FnLike { ast_id } => {
810 if let Some(call_id) = legacy {
811 res = ReachedFixedPoint::No;
812 resolved.push((directive.module_id, *call_id, directive.depth));
813 return false;
814 }
815
816 match macro_call_as_call_id( 811 match macro_call_as_call_id(
817 ast_id, 812 ast_id,
818 self.db, 813 self.db,
@@ -834,19 +829,23 @@ impl DefCollector<'_> {
834 res = ReachedFixedPoint::No; 829 res = ReachedFixedPoint::No;
835 return false; 830 return false;
836 } 831 }
837 Err(UnresolvedMacro) | Ok(Err(_)) => {} 832 Err(UnresolvedMacro { .. }) | Ok(Err(_)) => {}
838 } 833 }
839 } 834 }
840 MacroDirectiveKind::Derive { ast_id } => { 835 MacroDirectiveKind::Derive { ast_id, derive_attr } => {
841 match derive_macro_as_call_id(ast_id, self.db, self.def_map.krate, |path| { 836 match derive_macro_as_call_id(
842 self.resolve_derive_macro(directive.module_id, &path) 837 ast_id,
843 }) { 838 *derive_attr,
839 self.db,
840 self.def_map.krate,
841 |path| self.resolve_derive_macro(directive.module_id, &path),
842 ) {
844 Ok(call_id) => { 843 Ok(call_id) => {
845 resolved.push((directive.module_id, call_id, 0)); 844 resolved.push((directive.module_id, call_id, directive.depth));
846 res = ReachedFixedPoint::No; 845 res = ReachedFixedPoint::No;
847 return false; 846 return false;
848 } 847 }
849 Err(UnresolvedMacro) => (), 848 Err(UnresolvedMacro { .. }) => (),
850 } 849 }
851 } 850 }
852 } 851 }
@@ -944,10 +943,11 @@ impl DefCollector<'_> {
944 &mut |_| (), 943 &mut |_| (),
945 ) { 944 ) {
946 Ok(_) => (), 945 Ok(_) => (),
947 Err(UnresolvedMacro) => { 946 Err(UnresolvedMacro { path }) => {
948 self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( 947 self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
949 directive.module_id, 948 directive.module_id,
950 ast_id.ast_id, 949 ast_id.ast_id,
950 path,
951 )); 951 ));
952 } 952 }
953 }, 953 },
@@ -1169,19 +1169,27 @@ impl ModCollector<'_, '_> {
1169 } 1169 }
1170 ModItem::Const(id) => { 1170 ModItem::Const(id) => {
1171 let it = &self.item_tree[id]; 1171 let it = &self.item_tree[id];
1172 1172 let const_id = ConstLoc {
1173 if let Some(name) = &it.name { 1173 container: module.into(),
1174 def = Some(DefData { 1174 id: ItemTreeId::new(self.file_id, id),
1175 id: ConstLoc { 1175 }
1176 container: module.into(), 1176 .intern(self.def_collector.db);
1177 id: ItemTreeId::new(self.file_id, id), 1177
1178 } 1178 match &it.name {
1179 .intern(self.def_collector.db) 1179 Some(name) => {
1180 .into(), 1180 def = Some(DefData {
1181 name, 1181 id: const_id.into(),
1182 visibility: &self.item_tree[it.visibility], 1182 name,
1183 has_constructor: false, 1183 visibility: &self.item_tree[it.visibility],
1184 }); 1184 has_constructor: false,
1185 });
1186 }
1187 None => {
1188 // const _: T = ...;
1189 self.def_collector.def_map.modules[self.module_id]
1190 .scope
1191 .define_unnamed_const(const_id);
1192 }
1185 } 1193 }
1186 } 1194 }
1187 ModItem::Static(id) => { 1195 ModItem::Static(id) => {
@@ -1366,7 +1374,7 @@ impl ModCollector<'_, '_> {
1366 self.def_collector.unexpanded_macros.push(MacroDirective { 1374 self.def_collector.unexpanded_macros.push(MacroDirective {
1367 module_id: self.module_id, 1375 module_id: self.module_id,
1368 depth: self.macro_depth + 1, 1376 depth: self.macro_depth + 1,
1369 kind: MacroDirectiveKind::Derive { ast_id }, 1377 kind: MacroDirectiveKind::Derive { ast_id, derive_attr: derive.id },
1370 }); 1378 });
1371 } 1379 }
1372 } 1380 }
@@ -1518,12 +1526,12 @@ impl ModCollector<'_, '_> {
1518 // Built-in macro failed eager expansion. 1526 // Built-in macro failed eager expansion.
1519 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( 1527 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
1520 self.module_id, 1528 self.module_id,
1521 MacroCallKind::FnLike(ast_id.ast_id), 1529 MacroCallKind::FnLike { ast_id: ast_id.ast_id },
1522 error.unwrap().to_string(), 1530 error.unwrap().to_string(),
1523 )); 1531 ));
1524 return; 1532 return;
1525 } 1533 }
1526 Err(UnresolvedMacro) => (), 1534 Err(UnresolvedMacro { .. }) => (),
1527 } 1535 }
1528 1536
1529 // Case 2: resolve in module scope, expand during name resolution. 1537 // Case 2: resolve in module scope, expand during name resolution.
@@ -1535,7 +1543,7 @@ impl ModCollector<'_, '_> {
1535 self.def_collector.unexpanded_macros.push(MacroDirective { 1543 self.def_collector.unexpanded_macros.push(MacroDirective {
1536 module_id: self.module_id, 1544 module_id: self.module_id,
1537 depth: self.macro_depth + 1, 1545 depth: self.macro_depth + 1,
1538 kind: MacroDirectiveKind::FnLike { ast_id, legacy: None }, 1546 kind: MacroDirectiveKind::FnLike { ast_id },
1539 }); 1547 });
1540 } 1548 }
1541 1549
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index 60471937c..c984148c3 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -60,12 +60,26 @@ impl ResolvePathResult {
60} 60}
61 61
62impl DefMap { 62impl DefMap {
63 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { 63 pub(super) fn resolve_name_in_extern_prelude(
64 &self,
65 db: &dyn DefDatabase,
66 name: &Name,
67 ) -> PerNs {
64 if name == &name!(self) { 68 if name == &name!(self) {
65 cov_mark::hit!(extern_crate_self_as); 69 cov_mark::hit!(extern_crate_self_as);
66 return PerNs::types(self.module_id(self.root).into(), Visibility::Public); 70 return PerNs::types(self.module_id(self.root).into(), Visibility::Public);
67 } 71 }
68 self.extern_prelude 72
73 let arc;
74 let root = match self.block {
75 Some(_) => {
76 arc = self.crate_root(db).def_map(db);
77 &*arc
78 }
79 None => self,
80 };
81
82 root.extern_prelude
69 .get(name) 83 .get(name)
70 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)) 84 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public))
71 } 85 }
@@ -191,7 +205,7 @@ impl DefMap {
191 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 205 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
192 }; 206 };
193 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 207 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
194 self.resolve_name_in_crate_root_or_extern_prelude(&segment) 208 self.resolve_name_in_crate_root_or_extern_prelude(db, &segment)
195 } 209 }
196 PathKind::Plain => { 210 PathKind::Plain => {
197 let (_, segment) = match segments.next() { 211 let (_, segment) = match segments.next() {
@@ -373,7 +387,13 @@ impl DefMap {
373 .get_legacy_macro(name) 387 .get_legacy_macro(name)
374 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public)); 388 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
375 let from_scope = self[module].scope.get(name); 389 let from_scope = self[module].scope.get(name);
376 let from_builtin = BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none); 390 let from_builtin = match self.block {
391 Some(_) => {
392 // Only resolve to builtins in the root `DefMap`.
393 PerNs::none()
394 }
395 None => BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none),
396 };
377 let from_scope_or_builtin = match shadow { 397 let from_scope_or_builtin = match shadow {
378 BuiltinShadowMode::Module => from_scope.or(from_builtin), 398 BuiltinShadowMode::Module => from_scope.or(from_builtin),
379 BuiltinShadowMode::Other => { 399 BuiltinShadowMode::Other => {
@@ -384,24 +404,31 @@ impl DefMap {
384 } 404 }
385 } 405 }
386 }; 406 };
387 // Give precedence to names in outer `DefMap`s over the extern prelude; only check prelude 407 let from_extern_prelude = self
388 // from the crate DefMap. 408 .extern_prelude
389 let from_extern_prelude = match self.block { 409 .get(name)
390 Some(_) => PerNs::none(), 410 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public));
391 None => self
392 .extern_prelude
393 .get(name)
394 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)),
395 };
396 411
397 let from_prelude = self.resolve_in_prelude(db, name); 412 let from_prelude = self.resolve_in_prelude(db, name);
398 413
399 from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude) 414 from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude)
400 } 415 }
401 416
402 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { 417 fn resolve_name_in_crate_root_or_extern_prelude(
403 let from_crate_root = self[self.root].scope.get(name); 418 &self,
404 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 419 db: &dyn DefDatabase,
420 name: &Name,
421 ) -> PerNs {
422 let arc;
423 let crate_def_map = match self.block {
424 Some(_) => {
425 arc = self.crate_root(db).def_map(db);
426 &arc
427 }
428 None => self,
429 };
430 let from_crate_root = crate_def_map[crate_def_map.root].scope.get(name);
431 let from_extern_prelude = self.resolve_name_in_extern_prelude(db, name);
405 432
406 from_crate_root.or(from_extern_prelude) 433 from_crate_root.or(from_extern_prelude)
407 } 434 }
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index fefdadb22..543975e07 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -170,7 +170,7 @@ fn unresolved_legacy_scope_macro() {
170 170
171 m!(); 171 m!();
172 m2!(); 172 m2!();
173 //^^^^^^ unresolved macro call 173 //^^^^^^ unresolved macro `self::m2!`
174 "#, 174 "#,
175 ); 175 );
176} 176}
@@ -187,7 +187,7 @@ fn unresolved_module_scope_macro() {
187 187
188 self::m!(); 188 self::m!();
189 self::m2!(); 189 self::m2!();
190 //^^^^^^^^^^^^ unresolved macro call 190 //^^^^^^^^^^^^ unresolved macro `self::m2!`
191 "#, 191 "#,
192 ); 192 );
193} 193}
@@ -233,7 +233,7 @@ fn good_out_dir_diagnostic() {
233 macro_rules! concat { () => {} } 233 macro_rules! concat { () => {} }
234 234
235 include!(concat!(env!("OUT_DIR"), "/out.rs")); 235 include!(concat!(env!("OUT_DIR"), "/out.rs"));
236 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 236 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
237 "#, 237 "#,
238 ); 238 );
239} 239}
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index a3e83e2cf..509f77850 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -48,7 +48,8 @@ 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).clone()) 51 let ctx = LowerCtx::with_hygiene(hygiene);
52 lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone())
52 } 53 }
53 54
54 pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { 55 pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
@@ -122,7 +123,7 @@ impl ModPath {
122pub struct Path { 123pub struct Path {
123 /// Type based path like `<T>::foo`. 124 /// Type based path like `<T>::foo`.
124 /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`. 125 /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
125 type_anchor: Option<Box<TypeRef>>, 126 type_anchor: Option<Interned<TypeRef>>,
126 mod_path: Interned<ModPath>, 127 mod_path: Interned<ModPath>,
127 /// Invariant: the same len as `self.mod_path.segments` 128 /// Invariant: the same len as `self.mod_path.segments`
128 generic_args: Vec<Option<Arc<GenericArgs>>>, 129 generic_args: Vec<Option<Arc<GenericArgs>>>,
@@ -167,8 +168,8 @@ pub enum GenericArg {
167impl Path { 168impl Path {
168 /// Converts an `ast::Path` to `Path`. Works with use trees. 169 /// Converts an `ast::Path` to `Path`. Works with use trees.
169 /// It correctly handles `$crate` based path from macro call. 170 /// It correctly handles `$crate` based path from macro call.
170 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 171 pub fn from_src(path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
171 lower::lower_path(path, hygiene) 172 lower::lower_path(path, ctx)
172 } 173 }
173 174
174 /// Converts a known mod path to `Path`. 175 /// Converts a known mod path to `Path`.
@@ -289,6 +290,12 @@ impl From<Name> for Path {
289 } 290 }
290} 291}
291 292
293impl From<Name> for Box<Path> {
294 fn from(name: Name) -> Box<Path> {
295 Box::new(Path::from(name))
296 }
297}
298
292impl From<Name> for ModPath { 299impl From<Name> for ModPath {
293 fn from(name: Name) -> ModPath { 300 fn from(name: Name) -> ModPath {
294 ModPath::from_segments(PathKind::Plain, iter::once(name)) 301 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 28f6244da..1df6db525 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -6,10 +6,7 @@ use crate::intern::Interned;
6use std::sync::Arc; 6use std::sync::Arc;
7 7
8use either::Either; 8use either::Either;
9use hir_expand::{ 9use hir_expand::name::{name, AsName};
10 hygiene::Hygiene,
11 name::{name, AsName},
12};
13use syntax::ast::{self, AstNode, TypeBoundsOwner}; 10use syntax::ast::{self, AstNode, TypeBoundsOwner};
14 11
15use super::AssociatedTypeBinding; 12use super::AssociatedTypeBinding;
@@ -23,12 +20,12 @@ pub(super) use lower_use::lower_use_tree;
23 20
24/// Converts an `ast::Path` to `Path`. Works with use trees. 21/// Converts an `ast::Path` to `Path`. Works with use trees.
25/// It correctly handles `$crate` based path from macro call. 22/// It correctly handles `$crate` based path from macro call.
26pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 23pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
27 let mut kind = PathKind::Plain; 24 let mut kind = PathKind::Plain;
28 let mut type_anchor = None; 25 let mut type_anchor = None;
29 let mut segments = Vec::new(); 26 let mut segments = Vec::new();
30 let mut generic_args = Vec::new(); 27 let mut generic_args = Vec::new();
31 let ctx = LowerCtx::with_hygiene(hygiene); 28 let hygiene = ctx.hygiene();
32 loop { 29 loop {
33 let segment = path.segment()?; 30 let segment = path.segment()?;
34 31
@@ -43,10 +40,10 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
43 Either::Left(name) => { 40 Either::Left(name) => {
44 let args = segment 41 let args = segment
45 .generic_arg_list() 42 .generic_arg_list()
46 .and_then(|it| lower_generic_args(&ctx, it)) 43 .and_then(|it| lower_generic_args(ctx, it))
47 .or_else(|| { 44 .or_else(|| {
48 lower_generic_args_from_fn_path( 45 lower_generic_args_from_fn_path(
49 &ctx, 46 ctx,
50 segment.param_list(), 47 segment.param_list(),
51 segment.ret_type(), 48 segment.ret_type(),
52 ) 49 )
@@ -64,17 +61,17 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
64 ast::PathSegmentKind::Type { type_ref, trait_ref } => { 61 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
65 assert!(path.qualifier().is_none()); // this can only occur at the first segment 62 assert!(path.qualifier().is_none()); // this can only occur at the first segment
66 63
67 let self_type = TypeRef::from_ast(&ctx, type_ref?); 64 let self_type = TypeRef::from_ast(ctx, type_ref?);
68 65
69 match trait_ref { 66 match trait_ref {
70 // <T>::foo 67 // <T>::foo
71 None => { 68 None => {
72 type_anchor = Some(Box::new(self_type)); 69 type_anchor = Some(Interned::new(self_type));
73 kind = PathKind::Plain; 70 kind = PathKind::Plain;
74 } 71 }
75 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo 72 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
76 Some(trait_ref) => { 73 Some(trait_ref) => {
77 let path = Path::from_src(trait_ref.path()?, hygiene)?; 74 let path = Path::from_src(trait_ref.path()?, ctx)?;
78 let mod_path = (*path.mod_path).clone(); 75 let mod_path = (*path.mod_path).clone();
79 let num_segments = path.mod_path.segments.len(); 76 let num_segments = path.mod_path.segments.len();
80 kind = mod_path.kind; 77 kind = mod_path.kind;
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 dd36106f8..8fa703a57 100644
--- a/crates/hir_def/src/test_db.rs
+++ b/crates/hir_def/src/test_db.rs
@@ -15,7 +15,12 @@ use rustc_hash::FxHashSet;
15use syntax::{algo, ast, AstNode, TextRange, TextSize}; 15use syntax::{algo, ast, AstNode, TextRange, TextSize};
16use test_utils::extract_annotations; 16use test_utils::extract_annotations;
17 17
18use crate::{db::DefDatabase, nameres::DefMap, src::HasSource, Lookup, ModuleDefId, ModuleId}; 18use crate::{
19 db::DefDatabase,
20 nameres::{DefMap, ModuleSource},
21 src::HasSource,
22 LocalModuleId, Lookup, ModuleDefId, ModuleId,
23};
19 24
20#[salsa::database( 25#[salsa::database(
21 base_db::SourceDatabaseExtStorage, 26 base_db::SourceDatabaseExtStorage,
@@ -87,10 +92,11 @@ impl TestDB {
87 pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId { 92 pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId {
88 let file_module = self.module_for_file(position.file_id); 93 let file_module = self.module_for_file(position.file_id);
89 let mut def_map = file_module.def_map(self); 94 let mut def_map = file_module.def_map(self);
95 let module = self.mod_at_position(&def_map, position);
90 96
91 def_map = match self.block_at_position(&def_map, position) { 97 def_map = match self.block_at_position(&def_map, position) {
92 Some(it) => it, 98 Some(it) => it,
93 None => return file_module, 99 None => return def_map.module_id(module),
94 }; 100 };
95 loop { 101 loop {
96 let new_map = self.block_at_position(&def_map, position); 102 let new_map = self.block_at_position(&def_map, position);
@@ -106,6 +112,47 @@ impl TestDB {
106 } 112 }
107 } 113 }
108 114
115 /// Finds the smallest/innermost module in `def_map` containing `position`.
116 fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> LocalModuleId {
117 let mut size = None;
118 let mut res = def_map.root();
119 for (module, data) in def_map.modules() {
120 let src = data.definition_source(self);
121 if src.file_id != position.file_id.into() {
122 continue;
123 }
124
125 let range = match src.value {
126 ModuleSource::SourceFile(it) => it.syntax().text_range(),
127 ModuleSource::Module(it) => it.syntax().text_range(),
128 ModuleSource::BlockExpr(it) => it.syntax().text_range(),
129 };
130
131 if !range.contains(position.offset) {
132 continue;
133 }
134
135 let new_size = match size {
136 None => range.len(),
137 Some(size) => {
138 if range.len() < size {
139 range.len()
140 } else {
141 size
142 }
143 }
144 };
145
146 if size != Some(new_size) {
147 cov_mark::hit!(submodule_in_testdb);
148 size = Some(new_size);
149 res = module;
150 }
151 }
152
153 res
154 }
155
109 fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<Arc<DefMap>> { 156 fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<Arc<DefMap>> {
110 // Find the smallest (innermost) function in `def_map` containing the cursor. 157 // Find the smallest (innermost) function in `def_map` containing the cursor.
111 let mut size = None; 158 let mut size = None;
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index 4c24aae94..ea29da5da 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -1,6 +1,7 @@
1//! HIR for references to types. Paths in these are not yet resolved. They can 1//! HIR for references to types. Paths in these are not yet resolved. They can
2//! be directly created from an ast::TypeRef, without further queries. 2//! be directly created from an ast::TypeRef, without further queries.
3use hir_expand::name::Name; 3
4use hir_expand::{name::Name, AstId, InFile};
4use syntax::ast; 5use syntax::ast;
5 6
6use crate::{body::LowerCtx, path::Path}; 7use crate::{body::LowerCtx, path::Path};
@@ -68,6 +69,7 @@ impl TraitRef {
68 } 69 }
69 } 70 }
70} 71}
72
71/// Compare ty::Ty 73/// Compare ty::Ty
72#[derive(Clone, PartialEq, Eq, Hash, Debug)] 74#[derive(Clone, PartialEq, Eq, Hash, Debug)]
73pub enum TypeRef { 75pub enum TypeRef {
@@ -84,6 +86,7 @@ pub enum TypeRef {
84 // For 86 // For
85 ImplTrait(Vec<TypeBound>), 87 ImplTrait(Vec<TypeBound>),
86 DynTrait(Vec<TypeBound>), 88 DynTrait(Vec<TypeBound>),
89 Macro(AstId<ast::MacroCall>),
87 Error, 90 Error,
88} 91}
89 92
@@ -116,7 +119,7 @@ pub enum TypeBound {
116 119
117impl TypeRef { 120impl TypeRef {
118 /// Converts an `ast::TypeRef` to a `hir::TypeRef`. 121 /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
119 pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self { 122 pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
120 match node { 123 match node {
121 ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()), 124 ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
122 ast::Type::TupleType(inner) => { 125 ast::Type::TupleType(inner) => {
@@ -176,8 +179,13 @@ impl TypeRef {
176 ast::Type::DynTraitType(inner) => { 179 ast::Type::DynTraitType(inner) => {
177 TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) 180 TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
178 } 181 }
179 // FIXME: Macros in type position are not yet supported. 182 ast::Type::MacroType(mt) => match mt.macro_call() {
180 ast::Type::MacroType(_) => TypeRef::Error, 183 Some(mc) => ctx
184 .ast_id(&mc)
185 .map(|mc| TypeRef::Macro(InFile::new(ctx.file_id(), mc)))
186 .unwrap_or(TypeRef::Error),
187 None => TypeRef::Error,
188 },
181 } 189 }
182 } 190 }
183 191
@@ -215,7 +223,7 @@ impl TypeRef {
215 } 223 }
216 } 224 }
217 TypeRef::Path(path) => go_path(path, f), 225 TypeRef::Path(path) => go_path(path, f),
218 TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {} 226 TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
219 }; 227 };
220 } 228 }
221 229
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs
index 7d00a37c4..d4b7c9970 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
@@ -123,11 +123,19 @@ impl Visibility {
123 def_map: &DefMap, 123 def_map: &DefMap,
124 mut from_module: crate::LocalModuleId, 124 mut from_module: crate::LocalModuleId,
125 ) -> bool { 125 ) -> bool {
126 let to_module = match self { 126 let mut to_module = match self {
127 Visibility::Module(m) => m, 127 Visibility::Module(m) => m,
128 Visibility::Public => return true, 128 Visibility::Public => return true,
129 }; 129 };
130 130
131 // `to_module` might be the root module of a block expression. Those have the same
132 // visibility as the containing module (even though no items are directly nameable from
133 // there, getting this right is important for method resolution).
134 // In that case, we adjust the visibility of `to_module` to point to the containing module.
135 if to_module.is_block_root(db) {
136 to_module = to_module.containing_module(db).unwrap();
137 }
138
131 // from_module needs to be a descendant of to_module 139 // from_module needs to be a descendant of to_module
132 let mut def_map = def_map; 140 let mut def_map = def_map;
133 let mut parent_arc; 141 let mut parent_arc;
@@ -217,6 +225,6 @@ pub(crate) fn field_visibilities_query(
217 225
218/// Resolve visibility of a function. 226/// Resolve visibility of a function.
219pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility { 227pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility {
220 let resolver = ModuleDefId::from(def).module(db).unwrap().resolver(db); 228 let resolver = def.resolver(db);
221 db.function_data(def).visibility.resolve(db, &resolver) 229 db.function_data(def).visibility.resolve(db, &resolver)
222} 230}