diff options
Diffstat (limited to 'crates/hir_def/src')
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 | ||
3 | use std::{ops, sync::Arc}; | 3 | use std::{ |
4 | convert::{TryFrom, TryInto}, | ||
5 | ops, | ||
6 | sync::Arc, | ||
7 | }; | ||
4 | 8 | ||
5 | use base_db::CrateId; | 9 | use base_db::CrateId; |
6 | use cfg::{CfgExpr, CfgOptions}; | 10 | use cfg::{CfgExpr, CfgOptions}; |
7 | use either::Either; | 11 | use either::Either; |
8 | use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile}; | 12 | use hir_expand::{hygiene::Hygiene, name::AsName, AstId, AttrId, InFile}; |
9 | use itertools::Itertools; | 13 | use itertools::Itertools; |
10 | use la_arena::ArenaMap; | 14 | use la_arena::ArenaMap; |
11 | use mbe::ast_to_token_tree; | 15 | use mbe::ast_to_token_tree; |
12 | use smallvec::{smallvec, SmallVec}; | 16 | use smallvec::{smallvec, SmallVec}; |
13 | use syntax::{ | 17 | use syntax::{ |
14 | ast::{self, AstNode, AttrsOwner}, | 18 | ast::{self, AstNode, AttrsOwner}, |
15 | match_ast, AstToken, SmolStr, SyntaxNode, | 19 | match_ast, AstPtr, AstToken, SmolStr, SyntaxNode, TextRange, TextSize, |
16 | }; | 20 | }; |
17 | use tt::Subtree; | 21 | use 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 | ||
457 | fn inner_attributes( | 518 | fn 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. | ||
573 | pub 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 | |||
581 | impl 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)] |
512 | pub struct Attr { | 611 | pub 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 | ||
526 | impl Attr { | 625 | impl 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 | |||
757 | pub(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 | |||
771 | pub(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; | |||
21 | use rustc_hash::FxHashMap; | 21 | use rustc_hash::FxHashMap; |
22 | use syntax::{ast, AstNode, AstPtr}; | 22 | use syntax::{ast, AstNode, AstPtr}; |
23 | 23 | ||
24 | pub(crate) use lower::LowerCtx; | 24 | pub use lower::LowerCtx; |
25 | 25 | ||
26 | use crate::{ | 26 | use 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)] | ||
40 | pub(crate) struct CfgExpander { | 41 | pub(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 | ||
46 | pub(crate) struct Expander { | 47 | #[derive(Debug)] |
48 | pub 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 | ||
82 | impl Expander { | 84 | impl 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 | ||
207 | pub(crate) struct Mark { | 210 | #[derive(Debug)] |
211 | pub 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 | ||
4 | use std::mem; | 4 | use std::{mem, sync::Arc}; |
5 | 5 | ||
6 | use either::Either; | 6 | use either::Either; |
7 | use hir_expand::{ | 7 | use 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 | ||
39 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; | 41 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; |
40 | 42 | ||
41 | pub(crate) struct LowerCtx { | 43 | pub 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 | ||
45 | impl LowerCtx { | 49 | impl 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 | ||
43 | fn 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 | |||
43 | fn check_at(ra_fixture: &str, expect: Expect) { | 51 | fn 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#" |
181 | fn f() { | 189 | fn 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] |
137 | fn nested_module_scoping() { | ||
138 | check_block_scopes_at( | ||
139 | r#" | ||
140 | fn 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] | ||
137 | fn legacy_macro_items() { | 161 | fn 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 { | |||
80 | impl ChildBySource for ItemScope { | 80 | impl 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 @@ | |||
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; | 4 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; |
5 | use either::Either; | ||
5 | use hir_expand::{db::AstDatabase, HirFileId}; | 6 | use hir_expand::{db::AstDatabase, HirFileId}; |
6 | use la_arena::ArenaMap; | 7 | use la_arena::ArenaMap; |
7 | use syntax::SmolStr; | 8 | use syntax::{ast, AstPtr, SmolStr}; |
8 | 9 | ||
9 | use crate::{ | 10 | use 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}; | |||
8 | use hir_expand::{HirFileId, InFile}; | 8 | use hir_expand::{HirFileId, InFile}; |
9 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; | 9 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; |
10 | 10 | ||
11 | use crate::{db::DefDatabase, DefWithBodyId}; | 11 | use crate::{db::DefDatabase, path::ModPath, DefWithBodyId}; |
12 | 12 | ||
13 | pub fn validate_body(db: &dyn DefDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) { | 13 | pub 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 { | |||
103 | pub struct UnresolvedMacroCall { | 103 | pub 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 | ||
108 | impl Diagnostic for UnresolvedMacroCall { | 109 | impl 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 | ||
19 | use crate::{ | 19 | use 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)] |
242 | pub enum Statement { | 243 | pub 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; | 430 | struct 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 } | 444 | enum 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 { | 458 | mod 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 | 475 | mod foo; |
464 | mod bar; | 476 | //- /foo.rs |
465 | struct S; | 477 | mod bar; |
466 | //- /foo/bar.rs | 478 | struct 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 | 494 | mod 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 | 510 | mod 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; | 526 | mod foo; |
500 | //- /foo.rs | 527 | struct 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 | "#; | 545 | pub 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 | ||
559 | extern crate std as std_renamed; | ||
560 | $0 | ||
561 | //- /std.rs crate:std | ||
562 | pub 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; | 580 | use syntax::ast; |
544 | $0 | 581 | $0 |
545 | 582 | ||
546 | //- /lib.rs crate:syntax | 583 | //- /lib.rs crate:syntax |
547 | pub mod ast { | 584 | pub 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 | ||
602 | pub 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 { | 619 | mod 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 { | 636 | mod 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 | 656 | pub use core::S; |
616 | pub struct S; | 657 | //- /core.rs crate:core |
617 | "#; | 658 | pub 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] | 674 | pub mod prelude { pub struct S; } |
629 | pub use prelude::*; | 675 | #[prelude_import] |
630 | "#; | 676 | pub 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 { | 691 | pub 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::*; | 696 | pub 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; | 707 | pub mod foo; |
657 | struct S; | 708 | pub mod baz; |
658 | $0 | 709 | struct S; |
659 | //- /foo.rs | 710 | $0 |
660 | pub mod bar { pub struct S; } | 711 | //- /foo.rs |
661 | //- /baz.rs | 712 | pub mod bar { pub struct S; } |
662 | pub use crate::foo::bar::S; | 713 | //- /baz.rs |
663 | "#; | 714 | pub 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; } | 728 | mod foo; |
673 | use bar::S; | 729 | pub mod bar { pub struct S; } |
674 | //- /foo.rs | 730 | use 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; | 747 | pub mod foo; |
687 | pub mod baz; | 748 | pub mod bar; |
688 | //- /bar.rs | 749 | pub mod baz; |
689 | $0 | 750 | //- /bar.rs |
690 | //- /foo.rs | 751 | $0 |
691 | pub use super::baz; | 752 | //- /foo.rs |
692 | pub struct S; | 753 | pub use super::baz; |
693 | //- /baz.rs | 754 | pub struct S; |
694 | pub use super::foo; | 755 | //- /baz.rs |
695 | "#; | 756 | pub 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 { | 774 | pub 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 { | 779 | pub 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 { | 802 | pub 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 { | 808 | pub 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 { | 830 | pub 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 { | 836 | pub 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 { | 855 | pub 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; | 860 | pub 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 { | 874 | pub 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() { | 886 | fn 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() { | 902 | fn 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() { | 921 | fn 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 { | 941 | mod module { |
881 | pub struct CompleteMe; | 942 | pub struct CompleteMe; |
882 | } | 943 | } |
883 | 944 | ||
884 | fn main() { | 945 | fn 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#" | ||
964 | mod baz { | ||
965 | pub struct Foo {} | ||
966 | } | ||
967 | |||
968 | mod 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#" | ||
985 | mod baz { | ||
986 | pub struct Foo {} | ||
987 | } | ||
988 | |||
989 | mod 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 | ||
1048 | fn 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. |
5 | use std::sync::Arc; | ||
6 | 5 | ||
7 | use base_db::FileId; | 6 | use base_db::FileId; |
8 | use either::Either; | 7 | use either::Either; |
@@ -18,6 +17,7 @@ use crate::{ | |||
18 | child_by_source::ChildBySource, | 17 | child_by_source::ChildBySource, |
19 | db::DefDatabase, | 18 | db::DefDatabase, |
20 | dyn_map::DynMap, | 19 | dyn_map::DynMap, |
20 | intern::Interned, | ||
21 | keys, | 21 | keys, |
22 | src::{HasChildSource, HasSource}, | 22 | src::{HasChildSource, HasSource}, |
23 | type_ref::{LifetimeRef, TypeBound, TypeRef}, | 23 | type_ref::{LifetimeRef, TypeBound, TypeRef}, |
@@ -26,27 +26,27 @@ use crate::{ | |||
26 | }; | 26 | }; |
27 | 27 | ||
28 | /// Data about a generic type parameter (to a function, struct, impl, ...). | 28 | /// Data about a generic type parameter (to a function, struct, impl, ...). |
29 | #[derive(Clone, PartialEq, Eq, Debug)] | 29 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
30 | pub struct TypeParamData { | 30 | pub struct TypeParamData { |
31 | pub name: Option<Name>, | 31 | pub name: Option<Name>, |
32 | pub default: Option<TypeRef>, | 32 | pub default: Option<Interned<TypeRef>>, |
33 | pub provenance: TypeParamProvenance, | 33 | pub provenance: TypeParamProvenance, |
34 | } | 34 | } |
35 | 35 | ||
36 | /// Data about a generic lifetime parameter (to a function, struct, impl, ...). | 36 | /// Data about a generic lifetime parameter (to a function, struct, impl, ...). |
37 | #[derive(Clone, PartialEq, Eq, Debug)] | 37 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
38 | pub struct LifetimeParamData { | 38 | pub struct LifetimeParamData { |
39 | pub name: Name, | 39 | pub name: Name, |
40 | } | 40 | } |
41 | 41 | ||
42 | /// Data about a generic const parameter (to a function, struct, impl, ...). | 42 | /// Data about a generic const parameter (to a function, struct, impl, ...). |
43 | #[derive(Clone, PartialEq, Eq, Debug)] | 43 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
44 | pub struct ConstParamData { | 44 | pub struct ConstParamData { |
45 | pub name: Name, | 45 | pub name: Name, |
46 | pub ty: TypeRef, | 46 | pub ty: Interned<TypeRef>, |
47 | } | 47 | } |
48 | 48 | ||
49 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | 49 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] |
50 | pub enum TypeParamProvenance { | 50 | pub enum TypeParamProvenance { |
51 | TypeParamList, | 51 | TypeParamList, |
52 | TraitSelf, | 52 | TraitSelf, |
@@ -54,7 +54,7 @@ pub enum TypeParamProvenance { | |||
54 | } | 54 | } |
55 | 55 | ||
56 | /// Data about the generic parameters of a function, struct, impl, etc. | 56 | /// Data about the generic parameters of a function, struct, impl, etc. |
57 | #[derive(Clone, PartialEq, Eq, Debug, Default)] | 57 | #[derive(Clone, PartialEq, Eq, Debug, Default, Hash)] |
58 | pub struct GenericParams { | 58 | pub struct GenericParams { |
59 | pub types: Arena<TypeParamData>, | 59 | pub types: Arena<TypeParamData>, |
60 | pub lifetimes: Arena<LifetimeParamData>, | 60 | pub lifetimes: Arena<LifetimeParamData>, |
@@ -66,16 +66,16 @@ pub struct GenericParams { | |||
66 | /// where clauses like `where T: Foo + Bar` are turned into multiple of these. | 66 | /// where clauses like `where T: Foo + Bar` are turned into multiple of these. |
67 | /// It might still result in multiple actual predicates though, because of | 67 | /// It might still result in multiple actual predicates though, because of |
68 | /// associated type bindings like `Iterator<Item = u32>`. | 68 | /// associated type bindings like `Iterator<Item = u32>`. |
69 | #[derive(Clone, PartialEq, Eq, Debug)] | 69 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
70 | pub enum WherePredicate { | 70 | pub enum WherePredicate { |
71 | TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, | 71 | TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, |
72 | Lifetime { target: LifetimeRef, bound: LifetimeRef }, | 72 | Lifetime { target: LifetimeRef, bound: LifetimeRef }, |
73 | ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, | 73 | ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, |
74 | } | 74 | } |
75 | 75 | ||
76 | #[derive(Clone, PartialEq, Eq, Debug)] | 76 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
77 | pub enum WherePredicateTypeTarget { | 77 | pub enum WherePredicateTypeTarget { |
78 | TypeRef(TypeRef), | 78 | TypeRef(Interned<TypeRef>), |
79 | /// For desugared where predicates that can directly refer to a type param. | 79 | /// For desugared where predicates that can directly refer to a type param. |
80 | TypeParam(LocalTypeParamId), | 80 | TypeParam(LocalTypeParamId), |
81 | } | 81 | } |
@@ -91,7 +91,7 @@ impl GenericParams { | |||
91 | pub(crate) fn generic_params_query( | 91 | pub(crate) fn generic_params_query( |
92 | db: &dyn DefDatabase, | 92 | db: &dyn DefDatabase, |
93 | def: GenericDefId, | 93 | def: GenericDefId, |
94 | ) -> Arc<GenericParams> { | 94 | ) -> Interned<GenericParams> { |
95 | let _p = profile::span("generic_params_query"); | 95 | let _p = profile::span("generic_params_query"); |
96 | 96 | ||
97 | let generics = match def { | 97 | let generics = match def { |
@@ -99,47 +99,49 @@ impl GenericParams { | |||
99 | let id = id.lookup(db).id; | 99 | let id = id.lookup(db).id; |
100 | let tree = id.item_tree(db); | 100 | let tree = id.item_tree(db); |
101 | let item = &tree[id.value]; | 101 | let item = &tree[id.value]; |
102 | tree[item.generic_params].clone() | 102 | item.generic_params.clone() |
103 | } | 103 | } |
104 | GenericDefId::AdtId(AdtId::StructId(id)) => { | 104 | GenericDefId::AdtId(AdtId::StructId(id)) => { |
105 | let id = id.lookup(db).id; | 105 | let id = id.lookup(db).id; |
106 | let tree = id.item_tree(db); | 106 | let tree = id.item_tree(db); |
107 | let item = &tree[id.value]; | 107 | let item = &tree[id.value]; |
108 | tree[item.generic_params].clone() | 108 | item.generic_params.clone() |
109 | } | 109 | } |
110 | GenericDefId::AdtId(AdtId::EnumId(id)) => { | 110 | GenericDefId::AdtId(AdtId::EnumId(id)) => { |
111 | let id = id.lookup(db).id; | 111 | let id = id.lookup(db).id; |
112 | let tree = id.item_tree(db); | 112 | let tree = id.item_tree(db); |
113 | let item = &tree[id.value]; | 113 | let item = &tree[id.value]; |
114 | tree[item.generic_params].clone() | 114 | item.generic_params.clone() |
115 | } | 115 | } |
116 | GenericDefId::AdtId(AdtId::UnionId(id)) => { | 116 | GenericDefId::AdtId(AdtId::UnionId(id)) => { |
117 | let id = id.lookup(db).id; | 117 | let id = id.lookup(db).id; |
118 | let tree = id.item_tree(db); | 118 | let tree = id.item_tree(db); |
119 | let item = &tree[id.value]; | 119 | let item = &tree[id.value]; |
120 | tree[item.generic_params].clone() | 120 | item.generic_params.clone() |
121 | } | 121 | } |
122 | GenericDefId::TraitId(id) => { | 122 | GenericDefId::TraitId(id) => { |
123 | let id = id.lookup(db).id; | 123 | let id = id.lookup(db).id; |
124 | let tree = id.item_tree(db); | 124 | let tree = id.item_tree(db); |
125 | let item = &tree[id.value]; | 125 | let item = &tree[id.value]; |
126 | tree[item.generic_params].clone() | 126 | item.generic_params.clone() |
127 | } | 127 | } |
128 | GenericDefId::TypeAliasId(id) => { | 128 | GenericDefId::TypeAliasId(id) => { |
129 | let id = id.lookup(db).id; | 129 | let id = id.lookup(db).id; |
130 | let tree = id.item_tree(db); | 130 | let tree = id.item_tree(db); |
131 | let item = &tree[id.value]; | 131 | let item = &tree[id.value]; |
132 | tree[item.generic_params].clone() | 132 | item.generic_params.clone() |
133 | } | 133 | } |
134 | GenericDefId::ImplId(id) => { | 134 | GenericDefId::ImplId(id) => { |
135 | let id = id.lookup(db).id; | 135 | let id = id.lookup(db).id; |
136 | let tree = id.item_tree(db); | 136 | let tree = id.item_tree(db); |
137 | let item = &tree[id.value]; | 137 | let item = &tree[id.value]; |
138 | tree[item.generic_params].clone() | 138 | item.generic_params.clone() |
139 | } | ||
140 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => { | ||
141 | Interned::new(GenericParams::default()) | ||
139 | } | 142 | } |
140 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(), | ||
141 | }; | 143 | }; |
142 | Arc::new(generics) | 144 | generics |
143 | } | 145 | } |
144 | 146 | ||
145 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { | 147 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { |
@@ -217,6 +219,7 @@ impl GenericParams { | |||
217 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(), | 219 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(), |
218 | }; | 220 | }; |
219 | 221 | ||
222 | generics.shrink_to_fit(); | ||
220 | (generics, InFile::new(file_id, sm)) | 223 | (generics, InFile::new(file_id, sm)) |
221 | } | 224 | } |
222 | 225 | ||
@@ -256,7 +259,8 @@ impl GenericParams { | |||
256 | for type_param in params.type_params() { | 259 | for type_param in params.type_params() { |
257 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); | 260 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); |
258 | // FIXME: Use `Path::from_src` | 261 | // FIXME: Use `Path::from_src` |
259 | let default = type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it)); | 262 | let default = |
263 | type_param.default_type().map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it))); | ||
260 | let param = TypeParamData { | 264 | let param = TypeParamData { |
261 | name: Some(name.clone()), | 265 | name: Some(name.clone()), |
262 | default, | 266 | default, |
@@ -280,7 +284,7 @@ impl GenericParams { | |||
280 | for const_param in params.const_params() { | 284 | for const_param in params.const_params() { |
281 | let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); | 285 | let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); |
282 | let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it)); | 286 | let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it)); |
283 | let param = ConstParamData { name, ty }; | 287 | let param = ConstParamData { name, ty: Interned::new(ty) }; |
284 | let param_id = self.consts.alloc(param); | 288 | let param_id = self.consts.alloc(param); |
285 | sm.const_params.insert(param_id, const_param.clone()); | 289 | sm.const_params.insert(param_id, const_param.clone()); |
286 | } | 290 | } |
@@ -334,11 +338,11 @@ impl GenericParams { | |||
334 | (Either::Left(type_ref), bound) => match hrtb_lifetimes { | 338 | (Either::Left(type_ref), bound) => match hrtb_lifetimes { |
335 | Some(hrtb_lifetimes) => WherePredicate::ForLifetime { | 339 | Some(hrtb_lifetimes) => WherePredicate::ForLifetime { |
336 | lifetimes: hrtb_lifetimes.clone(), | 340 | lifetimes: hrtb_lifetimes.clone(), |
337 | target: WherePredicateTypeTarget::TypeRef(type_ref), | 341 | target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), |
338 | bound, | 342 | bound, |
339 | }, | 343 | }, |
340 | None => WherePredicate::TypeBound { | 344 | None => WherePredicate::TypeBound { |
341 | target: WherePredicateTypeTarget::TypeRef(type_ref), | 345 | target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), |
342 | bound, | 346 | bound, |
343 | }, | 347 | }, |
344 | }, | 348 | }, |
@@ -369,6 +373,14 @@ impl GenericParams { | |||
369 | }); | 373 | }); |
370 | } | 374 | } |
371 | 375 | ||
376 | pub(crate) fn shrink_to_fit(&mut self) { | ||
377 | let Self { consts, lifetimes, types, where_predicates } = self; | ||
378 | consts.shrink_to_fit(); | ||
379 | lifetimes.shrink_to_fit(); | ||
380 | types.shrink_to_fit(); | ||
381 | where_predicates.shrink_to_fit(); | ||
382 | } | ||
383 | |||
372 | pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { | 384 | pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { |
373 | self.types | 385 | self.types |
374 | .iter() | 386 | .iter() |
diff --git a/crates/hir_def/src/intern.rs b/crates/hir_def/src/intern.rs index d163f633f..abc304ef0 100644 --- a/crates/hir_def/src/intern.rs +++ b/crates/hir_def/src/intern.rs | |||
@@ -5,7 +5,7 @@ | |||
5 | use std::{ | 5 | use 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}; | |||
14 | use once_cell::sync::OnceCell; | 14 | use once_cell::sync::OnceCell; |
15 | use rustc_hash::FxHasher; | 15 | use rustc_hash::FxHasher; |
16 | 16 | ||
17 | use crate::generics::GenericParams; | ||
18 | |||
17 | type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>; | 19 | type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>; |
18 | type Guard<T> = | 20 | type 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)] | ||
22 | pub struct Interned<T: Internable + ?Sized> { | 23 | pub 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 | ||
136 | impl Eq for Interned<str> {} | 137 | impl Eq for Interned<str> {} |
137 | 138 | ||
139 | impl<T: Internable + ?Sized> Hash for Interned<T> { | ||
140 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
141 | // NOTE: Cast disposes vtable pointer / slice/str length. | ||
142 | state.write_usize(Arc::as_ptr(&self.arc) as *const () as usize) | ||
143 | } | ||
144 | } | ||
145 | |||
138 | impl<T: Internable + ?Sized> AsRef<T> for Interned<T> { | 146 | impl<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 | ||
186 | macro_rules! impl_internable { | 194 | /// Implements `Internable` for a given list of types, making them usable with `Interned`. |
195 | #[macro_export] | ||
196 | #[doc(hidden)] | ||
197 | macro_rules! _impl_internable { | ||
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 | ||
197 | impl_internable!(crate::type_ref::TypeRef, crate::type_ref::TraitRef, crate::path::ModPath, str); | 208 | pub use crate::_impl_internable as impl_internable; |
209 | |||
210 | impl_internable!( | ||
211 | crate::type_ref::TypeRef, | ||
212 | crate::type_ref::TraitRef, | ||
213 | crate::path::ModPath, | ||
214 | GenericParams, | ||
215 | str, | ||
216 | ); | ||
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index 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}; | |||
11 | use stdx::format_to; | 11 | use stdx::format_to; |
12 | 12 | ||
13 | use crate::{ | 13 | use 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)] | ||
62 | pub struct GenericParamsId(u32); | ||
63 | |||
64 | impl 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)] |
70 | pub struct ItemTree { | 63 | pub 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 | |||
242 | static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate)); | 236 | static 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)] |
245 | struct GenericParamsStorage { | ||
246 | arena: Arena<GenericParams>, | ||
247 | } | ||
248 | |||
249 | impl 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 | |||
263 | static 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)] | ||
271 | struct ItemTreeData { | 239 | struct 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 | ||
511 | impl 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 | |||
522 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | 478 | impl<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 { | |||
555 | pub struct Function { | 511 | pub 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 { | |||
590 | pub struct Struct { | 546 | pub 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 { | |||
610 | pub struct Union { | 566 | pub 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 { | |||
619 | pub struct Enum { | 575 | pub 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 { | |||
648 | pub struct Trait { | 604 | pub 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)] |
660 | pub struct Impl { | 616 | pub 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; | |||
27 | pub mod keys; | 27 | pub mod keys; |
28 | 28 | ||
29 | pub mod item_tree; | 29 | pub mod item_tree; |
30 | pub mod intern; | ||
30 | 31 | ||
31 | pub mod adt; | 32 | pub mod adt; |
32 | pub mod data; | 33 | pub mod data; |
@@ -49,22 +50,23 @@ pub mod import_map; | |||
49 | 50 | ||
50 | #[cfg(test)] | 51 | #[cfg(test)] |
51 | mod test_db; | 52 | mod test_db; |
52 | mod intern; | ||
53 | 53 | ||
54 | use std::{ | 54 | use std::{ |
55 | hash::{Hash, Hasher}, | 55 | hash::{Hash, Hasher}, |
56 | sync::Arc, | 56 | sync::Arc, |
57 | }; | 57 | }; |
58 | 58 | ||
59 | use adt::VariantData; | ||
59 | use base_db::{impl_intern_key, salsa, CrateId}; | 60 | use base_db::{impl_intern_key, salsa, CrateId}; |
60 | use hir_expand::{ | 61 | use 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 | }; |
66 | use la_arena::Idx; | 67 | use la_arena::Idx; |
67 | use nameres::DefMap; | 68 | use nameres::DefMap; |
69 | use path::ModPath; | ||
68 | use syntax::ast; | 70 | use syntax::ast; |
69 | 71 | ||
70 | use crate::builtin_type::BuiltinType; | 72 | use 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 | ||
451 | impl 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)] |
438 | pub enum VariantId { | 462 | pub enum VariantId { |
439 | EnumVariantId(EnumVariantId), | 463 | EnumVariantId(EnumVariantId), |
@@ -442,6 +466,26 @@ pub enum VariantId { | |||
442 | } | 466 | } |
443 | impl_from!(EnumVariantId, StructId, UnionId for VariantId); | 467 | impl_from!(EnumVariantId, StructId, UnionId for VariantId); |
444 | 468 | ||
469 | impl 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 | |||
445 | trait Intern { | 489 | trait 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 | ||
647 | pub struct UnresolvedMacro; | 691 | #[derive(Debug)] |
692 | pub struct UnresolvedMacro { | ||
693 | pub path: ModPath, | ||
694 | } | ||
648 | 695 | ||
649 | fn macro_call_as_call_id( | 696 | fn 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 | ||
677 | fn derive_macro_as_call_id( | 727 | fn 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) = ¤t_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 | }; |
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -215,8 +215,8 @@ struct MacroDirective { | |||
215 | 215 | ||
216 | #[derive(Clone, Debug, Eq, PartialEq)] | 216 | #[derive(Clone, Debug, Eq, PartialEq)] |
217 | enum MacroDirectiveKind { | 217 | enum 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 | ||
222 | struct DefData<'a> { | 222 | struct 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 | ||
62 | impl DefMap { | 62 | impl 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 | ||
49 | impl ModPath { | 49 | impl ModPath { |
50 | pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { | 50 | pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { |
51 | lower::lower_path(path, hygiene).map(|it| (*it.mod_path).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 { | |||
122 | pub struct Path { | 123 | pub 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 { | |||
167 | impl Path { | 168 | impl 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 | ||
293 | impl From<Name> for Box<Path> { | ||
294 | fn from(name: Name) -> Box<Path> { | ||
295 | Box::new(Path::from(name)) | ||
296 | } | ||
297 | } | ||
298 | |||
292 | impl From<Name> for ModPath { | 299 | impl 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; | |||
6 | use std::sync::Arc; | 6 | use std::sync::Arc; |
7 | 7 | ||
8 | use either::Either; | 8 | use either::Either; |
9 | use hir_expand::{ | 9 | use hir_expand::name::{name, AsName}; |
10 | hygiene::Hygiene, | ||
11 | name::{name, AsName}, | ||
12 | }; | ||
13 | use syntax::ast::{self, AstNode, TypeBoundsOwner}; | 10 | use syntax::ast::{self, AstNode, TypeBoundsOwner}; |
14 | 11 | ||
15 | use super::AssociatedTypeBinding; | 12 | use 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. |
26 | pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> { | 23 | pub(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; | |||
15 | use syntax::{algo, ast, AstNode, TextRange, TextSize}; | 15 | use syntax::{algo, ast, AstNode, TextRange, TextSize}; |
16 | use test_utils::extract_annotations; | 16 | use test_utils::extract_annotations; |
17 | 17 | ||
18 | use crate::{db::DefDatabase, nameres::DefMap, src::HasSource, Lookup, ModuleDefId, ModuleId}; | 18 | use 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. |
3 | use hir_expand::name::Name; | 3 | |
4 | use hir_expand::{name::Name, AstId, InFile}; | ||
4 | use syntax::ast; | 5 | use syntax::ast; |
5 | 6 | ||
6 | use crate::{body::LowerCtx, path::Path}; | 7 | use 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)] |
73 | pub enum TypeRef { | 75 | pub 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 | ||
117 | impl TypeRef { | 120 | impl 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 | ||
27 | impl RawVisibility { | 27 | impl RawVisibility { |
28 | pub(crate) const fn private() -> RawVisibility { | 28 | pub(crate) fn private() -> RawVisibility { |
29 | RawVisibility::Module(ModPath::from_kind(PathKind::Super(0))) | 29 | RawVisibility::Module(ModPath::from_kind(PathKind::Super(0))) |
30 | } | 30 | } |
31 | 31 | ||
@@ -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. |
219 | pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility { | 227 | pub(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 | } |