aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/attr.rs24
-rw-r--r--crates/hir_def/src/body.rs25
-rw-r--r--crates/hir_def/src/body/diagnostics.rs32
-rw-r--r--crates/hir_def/src/body/lower.rs45
-rw-r--r--crates/hir_def/src/body/tests.rs16
-rw-r--r--crates/hir_def/src/data.rs8
-rw-r--r--crates/hir_def/src/diagnostics.rs227
-rw-r--r--crates/hir_def/src/generics.rs20
-rw-r--r--crates/hir_def/src/intern.rs3
-rw-r--r--crates/hir_def/src/item_tree.rs134
-rw-r--r--crates/hir_def/src/item_tree/lower.rs207
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs53
-rw-r--r--crates/hir_def/src/item_tree/tests.rs21
-rw-r--r--crates/hir_def/src/lib.rs17
-rw-r--r--crates/hir_def/src/nameres.rs252
-rw-r--r--crates/hir_def/src/nameres/collector.rs84
-rw-r--r--crates/hir_def/src/nameres/diagnostics.rs96
-rw-r--r--crates/hir_def/src/nameres/proc_macro.rs10
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs57
-rw-r--r--crates/hir_def/src/nameres/tests/incremental.rs74
-rw-r--r--crates/hir_def/src/path.rs29
-rw-r--r--crates/hir_def/src/path/lower.rs44
-rw-r--r--crates/hir_def/src/path/lower/lower_use.rs78
-rw-r--r--crates/hir_def/src/resolver.rs38
-rw-r--r--crates/hir_def/src/test_db.rs85
-rw-r--r--crates/hir_def/src/type_ref.rs14
26 files changed, 769 insertions, 924 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 89a1ea770..385ba8c80 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -105,7 +105,7 @@ impl RawAttrs {
105 Either::Left(attr) => Attr::from_src(db, attr, hygiene, id), 105 Either::Left(attr) => Attr::from_src(db, attr, hygiene, id),
106 Either::Right(comment) => comment.doc_comment().map(|doc| Attr { 106 Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
107 id, 107 id,
108 input: Some(AttrInput::Literal(SmolStr::new(doc))), 108 input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))),
109 path: Interned::new(ModPath::from(hir_expand::name!(doc))), 109 path: Interned::new(ModPath::from(hir_expand::name!(doc))),
110 }), 110 }),
111 }) 111 })
@@ -151,7 +151,7 @@ impl RawAttrs {
151 return smallvec![attr.clone()]; 151 return smallvec![attr.clone()];
152 } 152 }
153 153
154 let subtree = match &attr.input { 154 let subtree = match attr.input.as_deref() {
155 Some(AttrInput::TokenTree(it)) => it, 155 Some(AttrInput::TokenTree(it)) => it,
156 _ => return smallvec![attr.clone()], 156 _ => return smallvec![attr.clone()],
157 }; 157 };
@@ -251,7 +251,7 @@ impl Attrs {
251 } 251 }
252 252
253 pub fn docs(&self) -> Option<Documentation> { 253 pub fn docs(&self) -> Option<Documentation> {
254 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { 254 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? {
255 AttrInput::Literal(s) => Some(s), 255 AttrInput::Literal(s) => Some(s),
256 AttrInput::TokenTree(_) => None, 256 AttrInput::TokenTree(_) => None,
257 }); 257 });
@@ -454,7 +454,7 @@ impl AttrsWithOwner {
454 db: &dyn DefDatabase, 454 db: &dyn DefDatabase,
455 ) -> Option<(Documentation, DocsRangeMap)> { 455 ) -> Option<(Documentation, DocsRangeMap)> {
456 // FIXME: code duplication in `docs` above 456 // FIXME: code duplication in `docs` above
457 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { 457 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? {
458 AttrInput::Literal(s) => Some((s, attr.id)), 458 AttrInput::Literal(s) => Some((s, attr.id)),
459 AttrInput::TokenTree(_) => None, 459 AttrInput::TokenTree(_) => None,
460 }); 460 });
@@ -637,10 +637,10 @@ pub(crate) struct AttrId {
637pub struct Attr { 637pub struct Attr {
638 pub(crate) id: AttrId, 638 pub(crate) id: AttrId,
639 pub(crate) path: Interned<ModPath>, 639 pub(crate) path: Interned<ModPath>,
640 pub(crate) input: Option<AttrInput>, 640 pub(crate) input: Option<Interned<AttrInput>>,
641} 641}
642 642
643#[derive(Debug, Clone, PartialEq, Eq)] 643#[derive(Debug, Clone, PartialEq, Eq, Hash)]
644pub enum AttrInput { 644pub enum AttrInput {
645 /// `#[attr = "string"]` 645 /// `#[attr = "string"]`
646 Literal(SmolStr), 646 Literal(SmolStr),
@@ -670,9 +670,9 @@ impl Attr {
670 ast::LiteralKind::String(string) => string.value()?.into(), 670 ast::LiteralKind::String(string) => string.value()?.into(),
671 _ => lit.syntax().first_token()?.text().trim_matches('"').into(), 671 _ => lit.syntax().first_token()?.text().trim_matches('"').into(),
672 }; 672 };
673 Some(AttrInput::Literal(value)) 673 Some(Interned::new(AttrInput::Literal(value)))
674 } else if let Some(tt) = ast.token_tree() { 674 } else if let Some(tt) = ast.token_tree() {
675 Some(AttrInput::TokenTree(ast_to_token_tree(&tt).0)) 675 Some(Interned::new(AttrInput::TokenTree(ast_to_token_tree(&tt).0)))
676 } else { 676 } else {
677 None 677 None
678 }; 678 };
@@ -688,7 +688,7 @@ impl Attr {
688 return None; 688 return None;
689 } 689 }
690 690
691 match &self.input { 691 match self.input.as_deref() {
692 Some(AttrInput::TokenTree(args)) => { 692 Some(AttrInput::TokenTree(args)) => {
693 let mut counter = 0; 693 let mut counter = 0;
694 let paths = args 694 let paths = args
@@ -720,7 +720,7 @@ impl Attr {
720 } 720 }
721 721
722 pub fn string_value(&self) -> Option<&SmolStr> { 722 pub fn string_value(&self) -> Option<&SmolStr> {
723 match self.input.as_ref()? { 723 match self.input.as_deref()? {
724 AttrInput::Literal(it) => Some(it), 724 AttrInput::Literal(it) => Some(it),
725 _ => None, 725 _ => None,
726 } 726 }
@@ -735,14 +735,14 @@ pub struct AttrQuery<'a> {
735 735
736impl<'a> AttrQuery<'a> { 736impl<'a> AttrQuery<'a> {
737 pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> { 737 pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> {
738 self.attrs().filter_map(|attr| match attr.input.as_ref()? { 738 self.attrs().filter_map(|attr| match attr.input.as_deref()? {
739 AttrInput::TokenTree(it) => Some(it), 739 AttrInput::TokenTree(it) => Some(it),
740 _ => None, 740 _ => None,
741 }) 741 })
742 } 742 }
743 743
744 pub fn string_value(self) -> Option<&'a SmolStr> { 744 pub fn string_value(self) -> Option<&'a SmolStr> {
745 self.attrs().find_map(|attr| match attr.input.as_ref()? { 745 self.attrs().find_map(|attr| match attr.input.as_deref()? {
746 AttrInput::Literal(it) => Some(it), 746 AttrInput::Literal(it) => Some(it),
747 _ => None, 747 _ => None,
748 }) 748 })
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 98b485b60..c521879c8 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -1,7 +1,6 @@
1//! Defines `Body`: a lowered representation of bodies of functions, statics and 1//! Defines `Body`: a lowered representation of bodies of functions, statics and
2//! consts. 2//! consts.
3mod lower; 3mod lower;
4mod diagnostics;
5#[cfg(test)] 4#[cfg(test)]
6mod tests; 5mod tests;
7pub mod scope; 6pub mod scope;
@@ -9,17 +8,16 @@ pub mod scope;
9use std::{mem, ops::Index, sync::Arc}; 8use std::{mem, ops::Index, sync::Arc};
10 9
11use base_db::CrateId; 10use base_db::CrateId;
12use cfg::CfgOptions; 11use cfg::{CfgExpr, CfgOptions};
13use drop_bomb::DropBomb; 12use drop_bomb::DropBomb;
14use either::Either; 13use either::Either;
15use hir_expand::{ 14use hir_expand::{
16 ast_id_map::AstIdMap, diagnostics::DiagnosticSink, hygiene::Hygiene, AstId, ExpandResult, 15 ast_id_map::AstIdMap, hygiene::Hygiene, AstId, ExpandResult, HirFileId, InFile, MacroDefId,
17 HirFileId, InFile, MacroDefId,
18}; 16};
19use la_arena::{Arena, ArenaMap}; 17use la_arena::{Arena, ArenaMap};
20use profile::Count; 18use profile::Count;
21use rustc_hash::FxHashMap; 19use rustc_hash::FxHashMap;
22use syntax::{ast, AstNode, AstPtr}; 20use syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
23 21
24use crate::{ 22use crate::{
25 attr::{Attrs, RawAttrs}, 23 attr::{Attrs, RawAttrs},
@@ -273,12 +271,20 @@ pub struct BodySourceMap {
273 271
274 /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in 272 /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in
275 /// the source map (since they're just as volatile). 273 /// the source map (since they're just as volatile).
276 diagnostics: Vec<diagnostics::BodyDiagnostic>, 274 diagnostics: Vec<BodyDiagnostic>,
277} 275}
278 276
279#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] 277#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
280pub struct SyntheticSyntax; 278pub struct SyntheticSyntax;
281 279
280#[derive(Debug, Eq, PartialEq)]
281pub enum BodyDiagnostic {
282 InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions },
283 MacroError { node: InFile<AstPtr<ast::MacroCall>>, message: String },
284 UnresolvedProcMacro { node: InFile<AstPtr<ast::MacroCall>> },
285 UnresolvedMacroCall { node: InFile<AstPtr<ast::MacroCall>>, path: ModPath },
286}
287
282impl Body { 288impl Body {
283 pub(crate) fn body_with_source_map_query( 289 pub(crate) fn body_with_source_map_query(
284 db: &dyn DefDatabase, 290 db: &dyn DefDatabase,
@@ -416,9 +422,8 @@ impl BodySourceMap {
416 self.field_map.get(&src).cloned() 422 self.field_map.get(&src).cloned()
417 } 423 }
418 424
419 pub(crate) fn add_diagnostics(&self, _db: &dyn DefDatabase, sink: &mut DiagnosticSink<'_>) { 425 /// Get a reference to the body source map's diagnostics.
420 for diag in &self.diagnostics { 426 pub fn diagnostics(&self) -> &[BodyDiagnostic] {
421 diag.add_to(sink); 427 &self.diagnostics
422 }
423 } 428 }
424} 429}
diff --git a/crates/hir_def/src/body/diagnostics.rs b/crates/hir_def/src/body/diagnostics.rs
deleted file mode 100644
index f6992c9a8..000000000
--- a/crates/hir_def/src/body/diagnostics.rs
+++ /dev/null
@@ -1,32 +0,0 @@
1//! Diagnostics emitted during body lowering.
2
3use hir_expand::diagnostics::DiagnosticSink;
4
5use crate::diagnostics::{InactiveCode, MacroError, UnresolvedMacroCall, UnresolvedProcMacro};
6
7#[derive(Debug, Eq, PartialEq)]
8pub(crate) enum BodyDiagnostic {
9 InactiveCode(InactiveCode),
10 MacroError(MacroError),
11 UnresolvedProcMacro(UnresolvedProcMacro),
12 UnresolvedMacroCall(UnresolvedMacroCall),
13}
14
15impl BodyDiagnostic {
16 pub(crate) fn add_to(&self, sink: &mut DiagnosticSink<'_>) {
17 match self {
18 BodyDiagnostic::InactiveCode(diag) => {
19 sink.push(diag.clone());
20 }
21 BodyDiagnostic::MacroError(diag) => {
22 sink.push(diag.clone());
23 }
24 BodyDiagnostic::UnresolvedProcMacro(diag) => {
25 sink.push(diag.clone());
26 }
27 BodyDiagnostic::UnresolvedMacroCall(diag) => {
28 sink.push(diag.clone());
29 }
30 }
31 }
32}
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 2a7e0205f..da1fdac33 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -8,7 +8,7 @@ use hir_expand::{
8 ast_id_map::{AstIdMap, FileAstId}, 8 ast_id_map::{AstIdMap, FileAstId},
9 hygiene::Hygiene, 9 hygiene::Hygiene,
10 name::{name, AsName, Name}, 10 name::{name, AsName, Name},
11 ExpandError, HirFileId, 11 ExpandError, HirFileId, InFile,
12}; 12};
13use la_arena::Arena; 13use la_arena::Arena;
14use profile::Count; 14use profile::Count;
@@ -23,9 +23,9 @@ use syntax::{
23use crate::{ 23use crate::{
24 adt::StructKind, 24 adt::StructKind,
25 body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax}, 25 body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
26 body::{BodyDiagnostic, ExprSource, PatSource},
26 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, 27 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
27 db::DefDatabase, 28 db::DefDatabase,
28 diagnostics::{InactiveCode, MacroError, UnresolvedMacroCall, UnresolvedProcMacro},
29 expr::{ 29 expr::{
30 dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label, 30 dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label,
31 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, 31 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
@@ -38,8 +38,6 @@ use crate::{
38 AdtId, BlockLoc, ModuleDefId, UnresolvedMacro, 38 AdtId, BlockLoc, ModuleDefId, UnresolvedMacro,
39}; 39};
40 40
41use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
42
43pub struct LowerCtx<'a> { 41pub struct LowerCtx<'a> {
44 pub db: &'a dyn DefDatabase, 42 pub db: &'a dyn DefDatabase,
45 hygiene: Hygiene, 43 hygiene: Hygiene,
@@ -592,13 +590,10 @@ impl ExprCollector<'_> {
592 let res = match res { 590 let res = match res {
593 Ok(res) => res, 591 Ok(res) => res,
594 Err(UnresolvedMacro { path }) => { 592 Err(UnresolvedMacro { path }) => {
595 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall( 593 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall {
596 UnresolvedMacroCall { 594 node: InFile::new(outer_file, syntax_ptr),
597 file: outer_file, 595 path,
598 node: syntax_ptr.cast().unwrap(), 596 });
599 path,
600 },
601 ));
602 collector(self, None); 597 collector(self, None);
603 return; 598 return;
604 } 599 }
@@ -606,21 +601,15 @@ impl ExprCollector<'_> {
606 601
607 match &res.err { 602 match &res.err {
608 Some(ExpandError::UnresolvedProcMacro) => { 603 Some(ExpandError::UnresolvedProcMacro) => {
609 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro( 604 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro {
610 UnresolvedProcMacro { 605 node: InFile::new(outer_file, syntax_ptr),
611 file: outer_file, 606 });
612 node: syntax_ptr.into(),
613 precise_location: None,
614 macro_name: None,
615 },
616 ));
617 } 607 }
618 Some(err) => { 608 Some(err) => {
619 self.source_map.diagnostics.push(BodyDiagnostic::MacroError(MacroError { 609 self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
620 file: outer_file, 610 node: InFile::new(outer_file, syntax_ptr),
621 node: syntax_ptr.into(),
622 message: err.to_string(), 611 message: err.to_string(),
623 })); 612 });
624 } 613 }
625 None => {} 614 None => {}
626 } 615 }
@@ -945,12 +934,14 @@ impl ExprCollector<'_> {
945 return Some(()); 934 return Some(());
946 } 935 }
947 936
948 self.source_map.diagnostics.push(BodyDiagnostic::InactiveCode(InactiveCode { 937 self.source_map.diagnostics.push(BodyDiagnostic::InactiveCode {
949 file: self.expander.current_file_id, 938 node: InFile::new(
950 node: SyntaxNodePtr::new(owner.syntax()), 939 self.expander.current_file_id,
940 SyntaxNodePtr::new(owner.syntax()),
941 ),
951 cfg, 942 cfg,
952 opts: self.expander.cfg_options().clone(), 943 opts: self.expander.cfg_options().clone(),
953 })); 944 });
954 945
955 None 946 None
956 } 947 }
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index 3e8f16306..d4fae05a6 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -96,26 +96,26 @@ fn f() {
96 // The three g̶e̶n̶d̶e̶r̶s̶ statements: 96 // The three g̶e̶n̶d̶e̶r̶s̶ statements:
97 97
98 #[cfg(a)] fn f() {} // Item statement 98 #[cfg(a)] fn f() {} // Item statement
99 //^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 99 //^^^^^^^^^^^^^^^^^^^ InactiveCode
100 #[cfg(a)] {} // Expression statement 100 #[cfg(a)] {} // Expression statement
101 //^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 101 //^^^^^^^^^^^^ InactiveCode
102 #[cfg(a)] let x = 0; // let statement 102 #[cfg(a)] let x = 0; // let statement
103 //^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 103 //^^^^^^^^^^^^^^^^^^^^ InactiveCode
104 104
105 abc(#[cfg(a)] 0); 105 abc(#[cfg(a)] 0);
106 //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 106 //^^^^^^^^^^^ InactiveCode
107 let x = Struct { 107 let x = Struct {
108 #[cfg(a)] f: 0, 108 #[cfg(a)] f: 0,
109 //^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 109 //^^^^^^^^^^^^^^ InactiveCode
110 }; 110 };
111 match () { 111 match () {
112 () => (), 112 () => (),
113 #[cfg(a)] () => (), 113 #[cfg(a)] () => (),
114 //^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 114 //^^^^^^^^^^^^^^^^^^ InactiveCode
115 } 115 }
116 116
117 #[cfg(a)] 0 // Trailing expression of block 117 #[cfg(a)] 0 // Trailing expression of block
118 //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 118 //^^^^^^^^^^^ InactiveCode
119} 119}
120 ", 120 ",
121 ); 121 );
@@ -188,7 +188,7 @@ fn unresolved_macro_diag() {
188 r#" 188 r#"
189fn f() { 189fn f() {
190 m!(); 190 m!();
191 //^^^^ unresolved macro `m!` 191 //^^^^ UnresolvedMacroCall
192} 192}
193 "#, 193 "#,
194 ); 194 );
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index 135a6698e..d2bb381be 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -22,6 +22,7 @@ pub struct FunctionData {
22 pub name: Name, 22 pub name: Name,
23 pub params: Vec<Interned<TypeRef>>, 23 pub params: Vec<Interned<TypeRef>>,
24 pub ret_type: Interned<TypeRef>, 24 pub ret_type: Interned<TypeRef>,
25 pub async_ret_type: Option<Interned<TypeRef>>,
25 pub attrs: Attrs, 26 pub attrs: Attrs,
26 pub visibility: RawVisibility, 27 pub visibility: RawVisibility,
27 pub abi: Option<Interned<str>>, 28 pub abi: Option<Interned<str>>,
@@ -63,6 +64,7 @@ impl FunctionData {
63 }) 64 })
64 .collect(), 65 .collect(),
65 ret_type: func.ret_type.clone(), 66 ret_type: func.ret_type.clone(),
67 async_ret_type: func.async_ret_type.clone(),
66 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), 68 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
67 visibility: item_tree[func.visibility].clone(), 69 visibility: item_tree[func.visibility].clone(),
68 abi: func.abi.clone(), 70 abi: func.abi.clone(),
@@ -112,7 +114,7 @@ pub struct TypeAliasData {
112 pub visibility: RawVisibility, 114 pub visibility: RawVisibility,
113 pub is_extern: bool, 115 pub is_extern: bool,
114 /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). 116 /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
115 pub bounds: Vec<TypeBound>, 117 pub bounds: Vec<Interned<TypeBound>>,
116} 118}
117 119
118impl TypeAliasData { 120impl TypeAliasData {
@@ -141,7 +143,6 @@ pub struct TraitData {
141 pub is_auto: bool, 143 pub is_auto: bool,
142 pub is_unsafe: bool, 144 pub is_unsafe: bool,
143 pub visibility: RawVisibility, 145 pub visibility: RawVisibility,
144 pub bounds: Box<[TypeBound]>,
145} 146}
146 147
147impl TraitData { 148impl TraitData {
@@ -155,7 +156,6 @@ impl TraitData {
155 let module_id = tr_loc.container; 156 let module_id = tr_loc.container;
156 let container = AssocContainerId::TraitId(tr); 157 let container = AssocContainerId::TraitId(tr);
157 let visibility = item_tree[tr_def.visibility].clone(); 158 let visibility = item_tree[tr_def.visibility].clone();
158 let bounds = tr_def.bounds.clone();
159 let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id); 159 let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
160 160
161 let items = collect_items( 161 let items = collect_items(
@@ -168,7 +168,7 @@ impl TraitData {
168 100, 168 100,
169 ); 169 );
170 170
171 Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility, bounds }) 171 Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility })
172 } 172 }
173 173
174 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { 174 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs
deleted file mode 100644
index a71ae2668..000000000
--- a/crates/hir_def/src/diagnostics.rs
+++ /dev/null
@@ -1,227 +0,0 @@
1//! Diagnostics produced by `hir_def`.
2
3use std::any::Any;
4use stdx::format_to;
5
6use cfg::{CfgExpr, CfgOptions, DnfExpr};
7use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink};
8use hir_expand::{HirFileId, InFile};
9use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
10
11use crate::{db::DefDatabase, path::ModPath, DefWithBodyId};
12
13pub fn validate_body(db: &dyn DefDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) {
14 let source_map = db.body_with_source_map(owner).1;
15 source_map.add_diagnostics(db, sink);
16}
17
18// Diagnostic: unresolved-module
19//
20// This diagnostic is triggered if rust-analyzer is unable to discover referred module.
21#[derive(Debug)]
22pub struct UnresolvedModule {
23 pub file: HirFileId,
24 pub decl: AstPtr<ast::Module>,
25 pub candidate: String,
26}
27
28impl Diagnostic for UnresolvedModule {
29 fn code(&self) -> DiagnosticCode {
30 DiagnosticCode("unresolved-module")
31 }
32 fn message(&self) -> String {
33 "unresolved module".to_string()
34 }
35 fn display_source(&self) -> InFile<SyntaxNodePtr> {
36 InFile::new(self.file, self.decl.clone().into())
37 }
38 fn as_any(&self) -> &(dyn Any + Send + 'static) {
39 self
40 }
41}
42
43// Diagnostic: unresolved-extern-crate
44//
45// This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate.
46#[derive(Debug)]
47pub struct UnresolvedExternCrate {
48 pub file: HirFileId,
49 pub item: AstPtr<ast::ExternCrate>,
50}
51
52impl Diagnostic for UnresolvedExternCrate {
53 fn code(&self) -> DiagnosticCode {
54 DiagnosticCode("unresolved-extern-crate")
55 }
56 fn message(&self) -> String {
57 "unresolved extern crate".to_string()
58 }
59 fn display_source(&self) -> InFile<SyntaxNodePtr> {
60 InFile::new(self.file, self.item.clone().into())
61 }
62 fn as_any(&self) -> &(dyn Any + Send + 'static) {
63 self
64 }
65}
66
67// Diagnostic: unresolved-import
68//
69// This diagnostic is triggered if rust-analyzer is unable to discover imported module.
70#[derive(Debug)]
71pub struct UnresolvedImport {
72 pub file: HirFileId,
73 pub node: AstPtr<ast::UseTree>,
74}
75
76impl Diagnostic for UnresolvedImport {
77 fn code(&self) -> DiagnosticCode {
78 DiagnosticCode("unresolved-import")
79 }
80 fn message(&self) -> String {
81 "unresolved import".to_string()
82 }
83 fn display_source(&self) -> InFile<SyntaxNodePtr> {
84 InFile::new(self.file, self.node.clone().into())
85 }
86 fn as_any(&self) -> &(dyn Any + Send + 'static) {
87 self
88 }
89 fn is_experimental(&self) -> bool {
90 // This currently results in false positives in the following cases:
91 // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly)
92 // - `core::arch` (we don't handle `#[path = "../<path>"]` correctly)
93 // - proc macros and/or proc macro generated code
94 true
95 }
96}
97
98// Diagnostic: unresolved-macro-call
99//
100// This diagnostic is triggered if rust-analyzer is unable to resolve the path to a
101// macro in a macro invocation.
102#[derive(Debug, Clone, Eq, PartialEq)]
103pub struct UnresolvedMacroCall {
104 pub file: HirFileId,
105 pub node: AstPtr<ast::MacroCall>,
106 pub path: ModPath,
107}
108
109impl Diagnostic for UnresolvedMacroCall {
110 fn code(&self) -> DiagnosticCode {
111 DiagnosticCode("unresolved-macro-call")
112 }
113 fn message(&self) -> String {
114 format!("unresolved macro `{}!`", self.path)
115 }
116 fn display_source(&self) -> InFile<SyntaxNodePtr> {
117 InFile::new(self.file, self.node.clone().into())
118 }
119 fn as_any(&self) -> &(dyn Any + Send + 'static) {
120 self
121 }
122 fn is_experimental(&self) -> bool {
123 true
124 }
125}
126
127// Diagnostic: inactive-code
128//
129// This diagnostic is shown for code with inactive `#[cfg]` attributes.
130#[derive(Debug, Clone, Eq, PartialEq)]
131pub struct InactiveCode {
132 pub file: HirFileId,
133 pub node: SyntaxNodePtr,
134 pub cfg: CfgExpr,
135 pub opts: CfgOptions,
136}
137
138impl Diagnostic for InactiveCode {
139 fn code(&self) -> DiagnosticCode {
140 DiagnosticCode("inactive-code")
141 }
142 fn message(&self) -> String {
143 let inactive = DnfExpr::new(self.cfg.clone()).why_inactive(&self.opts);
144 let mut buf = "code is inactive due to #[cfg] directives".to_string();
145
146 if let Some(inactive) = inactive {
147 format_to!(buf, ": {}", inactive);
148 }
149
150 buf
151 }
152 fn display_source(&self) -> InFile<SyntaxNodePtr> {
153 InFile::new(self.file, self.node.clone())
154 }
155 fn as_any(&self) -> &(dyn Any + Send + 'static) {
156 self
157 }
158}
159
160// Diagnostic: unresolved-proc-macro
161//
162// This diagnostic is shown when a procedural macro can not be found. This usually means that
163// procedural macro support is simply disabled (and hence is only a weak hint instead of an error),
164// but can also indicate project setup problems.
165//
166// If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the
167// `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can
168// enable support for procedural macros (see `rust-analyzer.procMacro.enable`).
169#[derive(Debug, Clone, Eq, PartialEq)]
170pub struct UnresolvedProcMacro {
171 pub file: HirFileId,
172 pub node: SyntaxNodePtr,
173 /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange`
174 /// to use instead.
175 pub precise_location: Option<TextRange>,
176 pub macro_name: Option<String>,
177}
178
179impl Diagnostic for UnresolvedProcMacro {
180 fn code(&self) -> DiagnosticCode {
181 DiagnosticCode("unresolved-proc-macro")
182 }
183
184 fn message(&self) -> String {
185 match &self.macro_name {
186 Some(name) => format!("proc macro `{}` not expanded", name),
187 None => "proc macro not expanded".to_string(),
188 }
189 }
190
191 fn display_source(&self) -> InFile<SyntaxNodePtr> {
192 InFile::new(self.file, self.node.clone())
193 }
194
195 fn as_any(&self) -> &(dyn Any + Send + 'static) {
196 self
197 }
198}
199
200// Diagnostic: macro-error
201//
202// This diagnostic is shown for macro expansion errors.
203#[derive(Debug, Clone, Eq, PartialEq)]
204pub struct MacroError {
205 pub file: HirFileId,
206 pub node: SyntaxNodePtr,
207 pub message: String,
208}
209
210impl Diagnostic for MacroError {
211 fn code(&self) -> DiagnosticCode {
212 DiagnosticCode("macro-error")
213 }
214 fn message(&self) -> String {
215 self.message.clone()
216 }
217 fn display_source(&self) -> InFile<SyntaxNodePtr> {
218 InFile::new(self.file, self.node.clone())
219 }
220 fn as_any(&self) -> &(dyn Any + Send + 'static) {
221 self
222 }
223 fn is_experimental(&self) -> bool {
224 // Newly added and not very well-tested, might contain false positives.
225 true
226 }
227}
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index de5acced8..44d22b918 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -68,9 +68,19 @@ pub struct GenericParams {
68/// associated type bindings like `Iterator<Item = u32>`. 68/// associated type bindings like `Iterator<Item = u32>`.
69#[derive(Clone, PartialEq, Eq, Debug, Hash)] 69#[derive(Clone, PartialEq, Eq, Debug, Hash)]
70pub enum WherePredicate { 70pub enum WherePredicate {
71 TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, 71 TypeBound {
72 Lifetime { target: LifetimeRef, bound: LifetimeRef }, 72 target: WherePredicateTypeTarget,
73 ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, 73 bound: Interned<TypeBound>,
74 },
75 Lifetime {
76 target: LifetimeRef,
77 bound: LifetimeRef,
78 },
79 ForLifetime {
80 lifetimes: Box<[Name]>,
81 target: WherePredicateTypeTarget,
82 bound: Interned<TypeBound>,
83 },
74} 84}
75 85
76#[derive(Clone, PartialEq, Eq, Debug, Hash)] 86#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -339,11 +349,11 @@ impl GenericParams {
339 Some(hrtb_lifetimes) => WherePredicate::ForLifetime { 349 Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
340 lifetimes: hrtb_lifetimes.clone(), 350 lifetimes: hrtb_lifetimes.clone(),
341 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), 351 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
342 bound, 352 bound: Interned::new(bound),
343 }, 353 },
344 None => WherePredicate::TypeBound { 354 None => WherePredicate::TypeBound {
345 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), 355 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
346 bound, 356 bound: Interned::new(bound),
347 }, 357 },
348 }, 358 },
349 (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { 359 (Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
diff --git a/crates/hir_def/src/intern.rs b/crates/hir_def/src/intern.rs
index 5cc7f2df6..79ba970e7 100644
--- a/crates/hir_def/src/intern.rs
+++ b/crates/hir_def/src/intern.rs
@@ -216,7 +216,10 @@ pub use crate::_impl_internable as impl_internable;
216impl_internable!( 216impl_internable!(
217 crate::type_ref::TypeRef, 217 crate::type_ref::TypeRef,
218 crate::type_ref::TraitRef, 218 crate::type_ref::TraitRef,
219 crate::type_ref::TypeBound,
219 crate::path::ModPath, 220 crate::path::ModPath,
221 crate::path::GenericArgs,
222 crate::attr::AttrInput,
220 GenericParams, 223 GenericParams,
221 str, 224 str,
222); 225);
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 4a5f44027..227337a8d 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -523,21 +523,38 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
523 } 523 }
524} 524}
525 525
526/// A desugared `use` import.
527#[derive(Debug, Clone, Eq, PartialEq)] 526#[derive(Debug, Clone, Eq, PartialEq)]
528pub struct Import { 527pub struct Import {
529 pub path: Interned<ModPath>,
530 pub alias: Option<ImportAlias>,
531 pub visibility: RawVisibilityId, 528 pub visibility: RawVisibilityId,
532 pub is_glob: bool,
533 /// AST ID of the `use` item this import was derived from. Note that many `Import`s can map to
534 /// the same `use` item.
535 pub ast_id: FileAstId<ast::Use>, 529 pub ast_id: FileAstId<ast::Use>,
536 /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`. 530 pub use_tree: UseTree,
537 /// 531}
538 /// This can be used to get the `UseTree` this `Import` corresponds to and allows emitting 532
539 /// precise diagnostics. 533#[derive(Debug, Clone, Eq, PartialEq)]
540 pub index: usize, 534pub struct UseTree {
535 pub index: Idx<ast::UseTree>,
536 kind: UseTreeKind,
537}
538
539#[derive(Debug, Clone, Eq, PartialEq)]
540pub enum UseTreeKind {
541 /// ```
542 /// use path::to::Item;
543 /// use path::to::Item as Renamed;
544 /// use path::to::Trait as _;
545 /// ```
546 Single { path: Interned<ModPath>, alias: Option<ImportAlias> },
547
548 /// ```
549 /// use *; // (invalid, but can occur in nested tree)
550 /// use path::*;
551 /// ```
552 Glob { path: Option<Interned<ModPath>> },
553
554 /// ```
555 /// use prefix::{self, Item, ...};
556 /// ```
557 Prefixed { prefix: Option<Interned<ModPath>>, list: Box<[UseTree]> },
541} 558}
542 559
543#[derive(Debug, Clone, Eq, PartialEq)] 560#[derive(Debug, Clone, Eq, PartialEq)]
@@ -563,6 +580,7 @@ pub struct Function {
563 pub abi: Option<Interned<str>>, 580 pub abi: Option<Interned<str>>,
564 pub params: IdRange<Param>, 581 pub params: IdRange<Param>,
565 pub ret_type: Interned<TypeRef>, 582 pub ret_type: Interned<TypeRef>,
583 pub async_ret_type: Option<Interned<TypeRef>>,
566 pub ast_id: FileAstId<ast::Fn>, 584 pub ast_id: FileAstId<ast::Fn>,
567 pub(crate) flags: FnFlags, 585 pub(crate) flags: FnFlags,
568} 586}
@@ -644,7 +662,6 @@ pub struct Trait {
644 pub generic_params: Interned<GenericParams>, 662 pub generic_params: Interned<GenericParams>,
645 pub is_auto: bool, 663 pub is_auto: bool,
646 pub is_unsafe: bool, 664 pub is_unsafe: bool,
647 pub bounds: Box<[TypeBound]>,
648 pub items: Box<[AssocItem]>, 665 pub items: Box<[AssocItem]>,
649 pub ast_id: FileAstId<ast::Trait>, 666 pub ast_id: FileAstId<ast::Trait>,
650} 667}
@@ -664,7 +681,7 @@ pub struct TypeAlias {
664 pub name: Name, 681 pub name: Name,
665 pub visibility: RawVisibilityId, 682 pub visibility: RawVisibilityId,
666 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. 683 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
667 pub bounds: Box<[TypeBound]>, 684 pub bounds: Box<[Interned<TypeBound>]>,
668 pub generic_params: Interned<GenericParams>, 685 pub generic_params: Interned<GenericParams>,
669 pub type_ref: Option<Interned<TypeRef>>, 686 pub type_ref: Option<Interned<TypeRef>>,
670 pub is_extern: bool, 687 pub is_extern: bool,
@@ -711,6 +728,97 @@ pub struct MacroDef {
711 pub ast_id: FileAstId<ast::MacroDef>, 728 pub ast_id: FileAstId<ast::MacroDef>,
712} 729}
713 730
731impl Import {
732 /// Maps a `UseTree` contained in this import back to its AST node.
733 pub fn use_tree_to_ast(
734 &self,
735 db: &dyn DefDatabase,
736 file_id: HirFileId,
737 index: Idx<ast::UseTree>,
738 ) -> ast::UseTree {
739 // Re-lower the AST item and get the source map.
740 // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
741 let ast = InFile::new(file_id, self.ast_id).to_node(db.upcast());
742 let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
743 let hygiene = Hygiene::new(db.upcast(), file_id);
744 let (_, source_map) =
745 lower::lower_use_tree(db, &hygiene, ast_use_tree).expect("failed to lower use tree");
746 source_map[index].clone()
747 }
748}
749
750impl UseTree {
751 /// Expands the `UseTree` into individually imported `ModPath`s.
752 pub fn expand(
753 &self,
754 mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, /* is_glob */ bool, Option<ImportAlias>),
755 ) {
756 self.expand_impl(None, &mut cb)
757 }
758
759 fn expand_impl(
760 &self,
761 prefix: Option<ModPath>,
762 cb: &mut dyn FnMut(
763 Idx<ast::UseTree>,
764 ModPath,
765 /* is_glob */ bool,
766 Option<ImportAlias>,
767 ),
768 ) {
769 fn concat_mod_paths(prefix: Option<ModPath>, path: &ModPath) -> Option<ModPath> {
770 match (prefix, &path.kind) {
771 (None, _) => Some(path.clone()),
772 (Some(mut prefix), PathKind::Plain) => {
773 for segment in path.segments() {
774 prefix.push_segment(segment.clone());
775 }
776 Some(prefix)
777 }
778 (Some(prefix), PathKind::Super(0)) => {
779 // `some::path::self` == `some::path`
780 if path.segments().is_empty() {
781 Some(prefix)
782 } else {
783 None
784 }
785 }
786 (Some(_), _) => None,
787 }
788 }
789
790 match &self.kind {
791 UseTreeKind::Single { path, alias } => {
792 if let Some(path) = concat_mod_paths(prefix, path) {
793 cb(self.index, path, false, alias.clone());
794 }
795 }
796 UseTreeKind::Glob { path: Some(path) } => {
797 if let Some(path) = concat_mod_paths(prefix, path) {
798 cb(self.index, path, true, None);
799 }
800 }
801 UseTreeKind::Glob { path: None } => {
802 if let Some(prefix) = prefix {
803 cb(self.index, prefix, true, None);
804 }
805 }
806 UseTreeKind::Prefixed { prefix: additional_prefix, list } => {
807 let prefix = match additional_prefix {
808 Some(path) => match concat_mod_paths(prefix, path) {
809 Some(path) => Some(path),
810 None => return,
811 },
812 None => prefix,
813 };
814 for tree in &**list {
815 tree.expand_impl(prefix.clone(), cb);
816 }
817 }
818 }
819 }
820}
821
714macro_rules! impl_froms { 822macro_rules! impl_froms {
715 ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { 823 ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
716 $( 824 $(
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 91cf75371..6208facd5 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -3,7 +3,6 @@
3use std::{collections::hash_map::Entry, mem, sync::Arc}; 3use std::{collections::hash_map::Entry, mem, sync::Arc};
4 4
5use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId}; 5use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId};
6use smallvec::SmallVec;
7use syntax::{ 6use syntax::{
8 ast::{self, ModuleItemOwner}, 7 ast::{self, ModuleItemOwner},
9 SyntaxNode, WalkEvent, 8 SyntaxNode, WalkEvent,
@@ -20,22 +19,10 @@ fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
20 FileItemTreeId { index, _p: PhantomData } 19 FileItemTreeId { index, _p: PhantomData }
21} 20}
22 21
23struct ModItems(SmallVec<[ModItem; 1]>);
24
25impl<T> From<T> for ModItems
26where
27 T: Into<ModItem>,
28{
29 fn from(t: T) -> Self {
30 ModItems(SmallVec::from_buf([t.into(); 1]))
31 }
32}
33
34pub(super) struct Ctx<'a> { 22pub(super) struct Ctx<'a> {
35 db: &'a dyn DefDatabase, 23 db: &'a dyn DefDatabase,
36 tree: ItemTree, 24 tree: ItemTree,
37 hygiene: Hygiene, 25 hygiene: Hygiene,
38 file: HirFileId,
39 source_ast_id_map: Arc<AstIdMap>, 26 source_ast_id_map: Arc<AstIdMap>,
40 body_ctx: crate::body::LowerCtx<'a>, 27 body_ctx: crate::body::LowerCtx<'a>,
41 forced_visibility: Option<RawVisibilityId>, 28 forced_visibility: Option<RawVisibilityId>,
@@ -47,7 +34,6 @@ impl<'a> Ctx<'a> {
47 db, 34 db,
48 tree: ItemTree::default(), 35 tree: ItemTree::default(),
49 hygiene, 36 hygiene,
50 file,
51 source_ast_id_map: db.ast_id_map(file), 37 source_ast_id_map: db.ast_id_map(file),
52 body_ctx: crate::body::LowerCtx::new(db, file), 38 body_ctx: crate::body::LowerCtx::new(db, file),
53 forced_visibility: None, 39 forced_visibility: None,
@@ -55,11 +41,8 @@ impl<'a> Ctx<'a> {
55 } 41 }
56 42
57 pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { 43 pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree {
58 self.tree.top_level = item_owner 44 self.tree.top_level =
59 .items() 45 item_owner.items().flat_map(|item| self.lower_mod_item(&item, false)).collect();
60 .flat_map(|item| self.lower_mod_item(&item, false))
61 .flat_map(|items| items.0)
62 .collect();
63 self.tree 46 self.tree
64 } 47 }
65 48
@@ -71,7 +54,6 @@ impl<'a> Ctx<'a> {
71 _ => None, 54 _ => None,
72 }) 55 })
73 .flat_map(|item| self.lower_mod_item(&item, false)) 56 .flat_map(|item| self.lower_mod_item(&item, false))
74 .flat_map(|items| items.0)
75 .collect(); 57 .collect();
76 58
77 // Non-items need to have their inner items collected. 59 // Non-items need to have their inner items collected.
@@ -98,7 +80,7 @@ impl<'a> Ctx<'a> {
98 self.tree.data_mut() 80 self.tree.data_mut()
99 } 81 }
100 82
101 fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems> { 83 fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItem> {
102 // Collect inner items for 1-to-1-lowered items. 84 // Collect inner items for 1-to-1-lowered items.
103 match item { 85 match item {
104 ast::Item::Struct(_) 86 ast::Item::Struct(_)
@@ -129,34 +111,28 @@ impl<'a> Ctx<'a> {
129 }; 111 };
130 112
131 let attrs = RawAttrs::new(self.db, item, &self.hygiene); 113 let attrs = RawAttrs::new(self.db, item, &self.hygiene);
132 let items = match item { 114 let item: ModItem = match item {
133 ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), 115 ast::Item::Struct(ast) => self.lower_struct(ast)?.into(),
134 ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), 116 ast::Item::Union(ast) => self.lower_union(ast)?.into(),
135 ast::Item::Enum(ast) => self.lower_enum(ast).map(Into::into), 117 ast::Item::Enum(ast) => self.lower_enum(ast)?.into(),
136 ast::Item::Fn(ast) => self.lower_function(ast).map(Into::into), 118 ast::Item::Fn(ast) => self.lower_function(ast)?.into(),
137 ast::Item::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into), 119 ast::Item::TypeAlias(ast) => self.lower_type_alias(ast)?.into(),
138 ast::Item::Static(ast) => self.lower_static(ast).map(Into::into), 120 ast::Item::Static(ast) => self.lower_static(ast)?.into(),
139 ast::Item::Const(ast) => Some(self.lower_const(ast).into()), 121 ast::Item::Const(ast) => self.lower_const(ast).into(),
140 ast::Item::Module(ast) => self.lower_module(ast).map(Into::into), 122 ast::Item::Module(ast) => self.lower_module(ast)?.into(),
141 ast::Item::Trait(ast) => self.lower_trait(ast).map(Into::into), 123 ast::Item::Trait(ast) => self.lower_trait(ast)?.into(),
142 ast::Item::Impl(ast) => self.lower_impl(ast).map(Into::into), 124 ast::Item::Impl(ast) => self.lower_impl(ast)?.into(),
143 ast::Item::Use(ast) => Some(ModItems( 125 ast::Item::Use(ast) => self.lower_use(ast)?.into(),
144 self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(), 126 ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(),
145 )), 127 ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(),
146 ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into), 128 ast::Item::MacroRules(ast) => self.lower_macro_rules(ast)?.into(),
147 ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), 129 ast::Item::MacroDef(ast) => self.lower_macro_def(ast)?.into(),
148 ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into), 130 ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(),
149 ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into),
150 ast::Item::ExternBlock(ast) => Some(self.lower_extern_block(ast).into()),
151 }; 131 };
152 132
153 if !attrs.is_empty() { 133 self.add_attrs(item.into(), attrs.clone());
154 for item in items.iter().flat_map(|items| &items.0) {
155 self.add_attrs((*item).into(), attrs.clone());
156 }
157 }
158 134
159 items 135 Some(item)
160 } 136 }
161 137
162 fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) { 138 fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
@@ -190,12 +166,10 @@ impl<'a> Ctx<'a> {
190 }, 166 },
191 ast::Item(item) => { 167 ast::Item(item) => {
192 // FIXME: This triggers for macro calls in expression/pattern/type position 168 // FIXME: This triggers for macro calls in expression/pattern/type position
193 let mod_items = self.lower_mod_item(&item, true); 169 let mod_item = self.lower_mod_item(&item, true);
194 let current_block = block_stack.last(); 170 let current_block = block_stack.last();
195 if let (Some(mod_items), Some(block)) = (mod_items, current_block) { 171 if let (Some(mod_item), Some(block)) = (mod_item, current_block) {
196 if !mod_items.0.is_empty() { 172 self.data().inner_items.entry(*block).or_default().push(mod_item);
197 self.data().inner_items.entry(*block).or_default().extend(mod_items.0.iter().copied());
198 }
199 } 173 }
200 }, 174 },
201 _ => {} 175 _ => {}
@@ -382,12 +356,13 @@ impl<'a> Ctx<'a> {
382 _ => TypeRef::unit(), 356 _ => TypeRef::unit(),
383 }; 357 };
384 358
385 let ret_type = if func.async_token().is_some() { 359 let (ret_type, async_ret_type) = if func.async_token().is_some() {
360 let async_ret_type = ret_type.clone();
386 let future_impl = desugar_future_path(ret_type); 361 let future_impl = desugar_future_path(ret_type);
387 let ty_bound = TypeBound::Path(future_impl); 362 let ty_bound = Interned::new(TypeBound::Path(future_impl));
388 TypeRef::ImplTrait(vec![ty_bound]) 363 (TypeRef::ImplTrait(vec![ty_bound]), Some(async_ret_type))
389 } else { 364 } else {
390 ret_type 365 (ret_type, None)
391 }; 366 };
392 367
393 let abi = func.abi().map(lower_abi); 368 let abi = func.abi().map(lower_abi);
@@ -421,6 +396,7 @@ impl<'a> Ctx<'a> {
421 abi, 396 abi,
422 params, 397 params,
423 ret_type: Interned::new(ret_type), 398 ret_type: Interned::new(ret_type),
399 async_ret_type: async_ret_type.map(Interned::new),
424 ast_id, 400 ast_id,
425 flags, 401 flags,
426 }; 402 };
@@ -480,10 +456,7 @@ impl<'a> Ctx<'a> {
480 items: module 456 items: module
481 .item_list() 457 .item_list()
482 .map(|list| { 458 .map(|list| {
483 list.items() 459 list.items().flat_map(|item| self.lower_mod_item(&item, false)).collect()
484 .flat_map(|item| self.lower_mod_item(&item, false))
485 .flat_map(|items| items.0)
486 .collect()
487 }) 460 })
488 .unwrap_or_else(|| { 461 .unwrap_or_else(|| {
489 cov_mark::hit!(name_res_works_for_broken_modules); 462 cov_mark::hit!(name_res_works_for_broken_modules);
@@ -503,7 +476,6 @@ impl<'a> Ctx<'a> {
503 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); 476 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
504 let is_auto = trait_def.auto_token().is_some(); 477 let is_auto = trait_def.auto_token().is_some();
505 let is_unsafe = trait_def.unsafe_token().is_some(); 478 let is_unsafe = trait_def.unsafe_token().is_some();
506 let bounds = self.lower_type_bounds(trait_def);
507 let items = trait_def.assoc_item_list().map(|list| { 479 let items = trait_def.assoc_item_list().map(|list| {
508 let db = self.db; 480 let db = self.db;
509 self.with_inherited_visibility(visibility, |this| { 481 self.with_inherited_visibility(visibility, |this| {
@@ -526,7 +498,6 @@ impl<'a> Ctx<'a> {
526 generic_params, 498 generic_params,
527 is_auto, 499 is_auto,
528 is_unsafe, 500 is_unsafe,
529 bounds: bounds.into(),
530 items: items.unwrap_or_default(), 501 items: items.unwrap_or_default(),
531 ast_id, 502 ast_id,
532 }; 503 };
@@ -561,30 +532,13 @@ impl<'a> Ctx<'a> {
561 Some(id(self.data().impls.alloc(res))) 532 Some(id(self.data().impls.alloc(res)))
562 } 533 }
563 534
564 fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> { 535 fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Import>> {
565 let visibility = self.lower_visibility(use_item); 536 let visibility = self.lower_visibility(use_item);
566 let ast_id = self.source_ast_id_map.ast_id(use_item); 537 let ast_id = self.source_ast_id_map.ast_id(use_item);
538 let (use_tree, _) = lower_use_tree(self.db, &self.hygiene, use_item.use_tree()?)?;
567 539
568 // Every use item can expand to many `Import`s. 540 let res = Import { visibility, ast_id, use_tree };
569 let mut imports = Vec::new(); 541 Some(id(self.data().imports.alloc(res)))
570 let tree = self.tree.data_mut();
571 ModPath::expand_use_item(
572 self.db,
573 InFile::new(self.file, use_item.clone()),
574 &self.hygiene,
575 |path, _use_tree, is_glob, alias| {
576 imports.push(id(tree.imports.alloc(Import {
577 path: Interned::new(path),
578 alias,
579 visibility,
580 is_glob,
581 ast_id,
582 index: imports.len(),
583 })));
584 },
585 );
586
587 imports
588 } 542 }
589 543
590 fn lower_extern_crate( 544 fn lower_extern_crate(
@@ -738,11 +692,12 @@ impl<'a> Ctx<'a> {
738 Interned::new(generics) 692 Interned::new(generics)
739 } 693 }
740 694
741 fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> { 695 fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<Interned<TypeBound>> {
742 match node.type_bound_list() { 696 match node.type_bound_list() {
743 Some(bound_list) => { 697 Some(bound_list) => bound_list
744 bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect() 698 .bounds()
745 } 699 .map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it)))
700 .collect(),
746 None => Vec::new(), 701 None => Vec::new(),
747 } 702 }
748 } 703 }
@@ -810,7 +765,7 @@ fn desugar_future_path(orig: TypeRef) -> Path {
810 let binding = 765 let binding =
811 AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() }; 766 AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() };
812 last.bindings.push(binding); 767 last.bindings.push(binding);
813 generic_args.push(Some(Arc::new(last))); 768 generic_args.push(Some(Interned::new(last)));
814 769
815 Path::from_known_path(path, generic_args) 770 Path::from_known_path(path, generic_args)
816} 771}
@@ -883,3 +838,81 @@ fn lower_abi(abi: ast::Abi) -> Interned<str> {
883 } 838 }
884 } 839 }
885} 840}
841
842struct UseTreeLowering<'a> {
843 db: &'a dyn DefDatabase,
844 hygiene: &'a Hygiene,
845 mapping: Arena<ast::UseTree>,
846}
847
848impl UseTreeLowering<'_> {
849 fn lower_use_tree(&mut self, tree: ast::UseTree) -> Option<UseTree> {
850 if let Some(use_tree_list) = tree.use_tree_list() {
851 let prefix = match tree.path() {
852 // E.g. use something::{{{inner}}};
853 None => None,
854 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
855 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
856 Some(path) => {
857 match ModPath::from_src(self.db, path, &self.hygiene) {
858 Some(it) => Some(it),
859 None => return None, // FIXME: report errors somewhere
860 }
861 }
862 };
863
864 let list =
865 use_tree_list.use_trees().filter_map(|tree| self.lower_use_tree(tree)).collect();
866
867 Some(
868 self.use_tree(
869 UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
870 tree,
871 ),
872 )
873 } else {
874 let is_glob = tree.star_token().is_some();
875 let path = match tree.path() {
876 Some(path) => Some(ModPath::from_src(self.db, path, &self.hygiene)?),
877 None => None,
878 };
879 let alias = tree.rename().map(|a| {
880 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
881 });
882 if alias.is_some() && is_glob {
883 return None;
884 }
885
886 match (path, alias, is_glob) {
887 (path, None, true) => {
888 if path.is_none() {
889 cov_mark::hit!(glob_enum_group);
890 }
891 Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree))
892 }
893 // Globs can't be renamed
894 (_, Some(_), true) | (None, None, false) => None,
895 // `bla::{ as Name}` is invalid
896 (None, Some(_), false) => None,
897 (Some(path), alias, false) => Some(
898 self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree),
899 ),
900 }
901 }
902 }
903
904 fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree {
905 let index = self.mapping.alloc(ast);
906 UseTree { index, kind }
907 }
908}
909
910pub(super) fn lower_use_tree(
911 db: &dyn DefDatabase,
912 hygiene: &Hygiene,
913 tree: ast::UseTree,
914) -> Option<(UseTree, Arena<ast::UseTree>)> {
915 let mut lowering = UseTreeLowering { db, hygiene, mapping: Arena::new() };
916 let tree = lowering.lower_use_tree(tree)?;
917 Some((tree, lowering.mapping))
918}
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 4bc87a0e2..cc9944a22 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -163,21 +163,46 @@ impl<'a> Printer<'a> {
163 } 163 }
164 } 164 }
165 165
166 fn print_use_tree(&mut self, use_tree: &UseTree) {
167 match &use_tree.kind {
168 UseTreeKind::Single { path, alias } => {
169 w!(self, "{}", path);
170 if let Some(alias) = alias {
171 w!(self, " as {}", alias);
172 }
173 }
174 UseTreeKind::Glob { path } => {
175 if let Some(path) = path {
176 w!(self, "{}::", path);
177 }
178 w!(self, "*");
179 }
180 UseTreeKind::Prefixed { prefix, list } => {
181 if let Some(prefix) = prefix {
182 w!(self, "{}::", prefix);
183 }
184 w!(self, "{{");
185 for (i, tree) in list.iter().enumerate() {
186 if i != 0 {
187 w!(self, ", ");
188 }
189 self.print_use_tree(tree);
190 }
191 w!(self, "}}");
192 }
193 }
194 }
195
166 fn print_mod_item(&mut self, item: ModItem) { 196 fn print_mod_item(&mut self, item: ModItem) {
167 self.print_attrs_of(item); 197 self.print_attrs_of(item);
168 198
169 match item { 199 match item {
170 ModItem::Import(it) => { 200 ModItem::Import(it) => {
171 let Import { visibility, path, is_glob, alias, ast_id: _, index } = &self.tree[it]; 201 let Import { visibility, use_tree, ast_id: _ } = &self.tree[it];
172 self.print_visibility(*visibility); 202 self.print_visibility(*visibility);
173 w!(self, "use {}", path); 203 w!(self, "use ");
174 if *is_glob { 204 self.print_use_tree(use_tree);
175 w!(self, "::*"); 205 wln!(self, ";");
176 }
177 if let Some(alias) = alias {
178 w!(self, " as {}", alias);
179 }
180 wln!(self, "; // {}", index);
181 } 206 }
182 ModItem::ExternCrate(it) => { 207 ModItem::ExternCrate(it) => {
183 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it]; 208 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
@@ -210,6 +235,7 @@ impl<'a> Printer<'a> {
210 abi, 235 abi,
211 params, 236 params,
212 ret_type, 237 ret_type,
238 async_ret_type: _,
213 ast_id: _, 239 ast_id: _,
214 flags, 240 flags,
215 } = &self.tree[it]; 241 } = &self.tree[it];
@@ -320,7 +346,6 @@ impl<'a> Printer<'a> {
320 visibility, 346 visibility,
321 is_auto, 347 is_auto,
322 is_unsafe, 348 is_unsafe,
323 bounds,
324 items, 349 items,
325 generic_params, 350 generic_params,
326 ast_id: _, 351 ast_id: _,
@@ -334,10 +359,6 @@ impl<'a> Printer<'a> {
334 } 359 }
335 w!(self, "trait {}", name); 360 w!(self, "trait {}", name);
336 self.print_generic_params(generic_params); 361 self.print_generic_params(generic_params);
337 if !bounds.is_empty() {
338 w!(self, ": ");
339 self.print_type_bounds(bounds);
340 }
341 self.print_where_clause_and_opening_brace(generic_params); 362 self.print_where_clause_and_opening_brace(generic_params);
342 self.indented(|this| { 363 self.indented(|this| {
343 for item in &**items { 364 for item in &**items {
@@ -513,13 +534,13 @@ impl<'a> Printer<'a> {
513 } 534 }
514 } 535 }
515 536
516 fn print_type_bounds(&mut self, bounds: &[TypeBound]) { 537 fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
517 for (i, bound) in bounds.iter().enumerate() { 538 for (i, bound) in bounds.iter().enumerate() {
518 if i != 0 { 539 if i != 0 {
519 w!(self, " + "); 540 w!(self, " + ");
520 } 541 }
521 542
522 match bound { 543 match bound.as_ref() {
523 TypeBound::Path(path) => self.print_path(path), 544 TypeBound::Path(path) => self.print_path(path),
524 TypeBound::Lifetime(lt) => w!(self, "{}", lt.name), 545 TypeBound::Lifetime(lt) => w!(self, "{}", lt.name),
525 TypeBound::Error => w!(self, "{{unknown}}"), 546 TypeBound::Error => w!(self, "{{unknown}}"),
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index 6407871b5..b362add5c 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -26,6 +26,8 @@ use globs::*;
26 26
27/// docs on import 27/// docs on import
28use crate::{A, B}; 28use crate::{A, B};
29
30use a::{c, d::{e}};
29 "#, 31 "#,
30 expect![[r##" 32 expect![[r##"
31 #![doc = " file comment"] // AttrId { is_doc_comment: true, ast_index: 0 } 33 #![doc = " file comment"] // AttrId { is_doc_comment: true, ast_index: 0 }
@@ -36,19 +38,14 @@ use crate::{A, B};
36 38
37 pub(super) extern crate bli; 39 pub(super) extern crate bli;
38 40
39 pub use crate::path::nested; // 0 41 pub use crate::path::{nested, items as renamed, Trait as _};
40
41 pub use crate::path::items as renamed; // 1
42 42
43 pub use crate::path::Trait as _; // 2 43 pub(self) use globs::*;
44
45 pub(self) use globs::*; // 0
46 44
47 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 } 45 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 }
48 pub(self) use crate::A; // 0 46 pub(self) use crate::{A, B};
49 47
50 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 } 48 pub(self) use a::{c, d::{e}};
51 pub(self) use crate::B; // 1
52 "##]], 49 "##]],
53 ); 50 );
54} 51}
@@ -183,7 +180,7 @@ trait Tr: SuperTrait + 'lifetime {
183 _: (), 180 _: (),
184 ) -> (); 181 ) -> ();
185 182
186 pub(self) trait Tr<Self>: SuperTrait + 'lifetime 183 pub(self) trait Tr<Self>
187 where 184 where
188 Self: SuperTrait, 185 Self: SuperTrait,
189 Self: 'lifetime 186 Self: 'lifetime
@@ -218,7 +215,7 @@ mod outline;
218 #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 } 215 #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 }
219 #[doc = " inner"] // AttrId { is_doc_comment: true, ast_index: 1 } 216 #[doc = " inner"] // AttrId { is_doc_comment: true, ast_index: 1 }
220 pub(self) mod inline { 217 pub(self) mod inline {
221 pub(self) use super::*; // 0 218 pub(self) use super::*;
222 219
223 // flags = 0x2 220 // flags = 0x2
224 pub(self) fn fn_in_module() -> (); 221 pub(self) fn fn_in_module() -> ();
@@ -353,7 +350,7 @@ trait Tr<'a, T: 'a>: Super {}
353 pub(self) union Union<'a, T, const U: u8> { 350 pub(self) union Union<'a, T, const U: u8> {
354 } 351 }
355 352
356 pub(self) trait Tr<'a, Self, T>: Super 353 pub(self) trait Tr<'a, Self, T>
357 where 354 where
358 Self: Super, 355 Self: Super,
359 T: 'a 356 T: 'a
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 70001cac8..9aa95720a 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -19,7 +19,6 @@ pub mod path;
19pub mod type_ref; 19pub mod type_ref;
20pub mod builtin_type; 20pub mod builtin_type;
21pub mod builtin_attr; 21pub mod builtin_attr;
22pub mod diagnostics;
23pub mod per_ns; 22pub mod per_ns;
24pub mod item_scope; 23pub mod item_scope;
25 24
@@ -56,7 +55,6 @@ use std::{
56 sync::Arc, 55 sync::Arc,
57}; 56};
58 57
59use adt::VariantData;
60use base_db::{impl_intern_key, salsa, CrateId}; 58use base_db::{impl_intern_key, salsa, CrateId};
61use hir_expand::{ 59use hir_expand::{
62 ast_id_map::FileAstId, 60 ast_id_map::FileAstId,
@@ -67,15 +65,18 @@ use hir_expand::{
67use la_arena::Idx; 65use la_arena::Idx;
68use nameres::DefMap; 66use nameres::DefMap;
69use path::ModPath; 67use path::ModPath;
68use stdx::impl_from;
70use syntax::ast; 69use syntax::ast;
71 70
72use crate::attr::AttrId; 71use crate::{
73use crate::builtin_type::BuiltinType; 72 adt::VariantData,
74use item_tree::{ 73 attr::AttrId,
75 Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait, 74 builtin_type::BuiltinType,
76 TypeAlias, Union, 75 item_tree::{
76 Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait,
77 TypeAlias, Union,
78 },
77}; 79};
78use stdx::impl_from;
79 80
80#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 81#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
81pub struct ModuleId { 82pub struct ModuleId {
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 249af6fc8..ebfcc26c4 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -47,18 +47,19 @@
47//! path and, upon success, we run macro expansion and "collect module" phase on 47//! path and, upon success, we run macro expansion and "collect module" phase on
48//! the result 48//! the result
49 49
50pub mod diagnostics;
50mod collector; 51mod collector;
51mod mod_resolution; 52mod mod_resolution;
52mod path_resolution; 53mod path_resolution;
54mod proc_macro;
53 55
54#[cfg(test)] 56#[cfg(test)]
55mod tests; 57mod tests;
56mod proc_macro;
57 58
58use std::sync::Arc; 59use std::sync::Arc;
59 60
60use base_db::{CrateId, Edition, FileId}; 61use base_db::{CrateId, Edition, FileId};
61use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile, MacroDefId}; 62use hir_expand::{name::Name, InFile, MacroDefId};
62use la_arena::Arena; 63use la_arena::Arena;
63use profile::Count; 64use profile::Count;
64use rustc_hash::FxHashMap; 65use rustc_hash::FxHashMap;
@@ -254,15 +255,6 @@ impl DefMap {
254 } 255 }
255 } 256 }
256 257
257 pub fn add_diagnostics(
258 &self,
259 db: &dyn DefDatabase,
260 module: LocalModuleId,
261 sink: &mut DiagnosticSink,
262 ) {
263 self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
264 }
265
266 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ { 258 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ {
267 self.modules 259 self.modules
268 .iter() 260 .iter()
@@ -448,6 +440,11 @@ impl DefMap {
448 module.scope.shrink_to_fit(); 440 module.scope.shrink_to_fit();
449 } 441 }
450 } 442 }
443
444 /// Get a reference to the def map's diagnostics.
445 pub fn diagnostics(&self) -> &[DefDiagnostic] {
446 self.diagnostics.as_slice()
447 }
451} 448}
452 449
453impl ModuleData { 450impl ModuleData {
@@ -471,236 +468,3 @@ pub enum ModuleSource {
471 Module(ast::Module), 468 Module(ast::Module),
472 BlockExpr(ast::BlockExpr), 469 BlockExpr(ast::BlockExpr),
473} 470}
474
475mod diagnostics {
476 use cfg::{CfgExpr, CfgOptions};
477 use hir_expand::diagnostics::DiagnosticSink;
478 use hir_expand::hygiene::Hygiene;
479 use hir_expand::{InFile, MacroCallKind};
480 use syntax::ast::AttrsOwner;
481 use syntax::{ast, AstNode, AstPtr, SyntaxKind, SyntaxNodePtr};
482
483 use crate::path::ModPath;
484 use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId};
485
486 #[derive(Debug, PartialEq, Eq)]
487 enum DiagnosticKind {
488 UnresolvedModule { declaration: AstId<ast::Module>, candidate: String },
489
490 UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
491
492 UnresolvedImport { ast: AstId<ast::Use>, index: usize },
493
494 UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions },
495
496 UnresolvedProcMacro { ast: MacroCallKind },
497
498 UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
499
500 MacroError { ast: MacroCallKind, message: String },
501 }
502
503 #[derive(Debug, PartialEq, Eq)]
504 pub(super) struct DefDiagnostic {
505 in_module: LocalModuleId,
506 kind: DiagnosticKind,
507 }
508
509 impl DefDiagnostic {
510 pub(super) fn unresolved_module(
511 container: LocalModuleId,
512 declaration: AstId<ast::Module>,
513 candidate: String,
514 ) -> Self {
515 Self {
516 in_module: container,
517 kind: DiagnosticKind::UnresolvedModule { declaration, candidate },
518 }
519 }
520
521 pub(super) fn unresolved_extern_crate(
522 container: LocalModuleId,
523 declaration: AstId<ast::ExternCrate>,
524 ) -> Self {
525 Self {
526 in_module: container,
527 kind: DiagnosticKind::UnresolvedExternCrate { ast: declaration },
528 }
529 }
530
531 pub(super) fn unresolved_import(
532 container: LocalModuleId,
533 ast: AstId<ast::Use>,
534 index: usize,
535 ) -> Self {
536 Self { in_module: container, kind: DiagnosticKind::UnresolvedImport { ast, index } }
537 }
538
539 pub(super) fn unconfigured_code(
540 container: LocalModuleId,
541 ast: AstId<ast::Item>,
542 cfg: CfgExpr,
543 opts: CfgOptions,
544 ) -> Self {
545 Self { in_module: container, kind: DiagnosticKind::UnconfiguredCode { ast, cfg, opts } }
546 }
547
548 pub(super) fn unresolved_proc_macro(container: LocalModuleId, ast: MacroCallKind) -> Self {
549 Self { in_module: container, kind: DiagnosticKind::UnresolvedProcMacro { ast } }
550 }
551
552 pub(super) fn macro_error(
553 container: LocalModuleId,
554 ast: MacroCallKind,
555 message: String,
556 ) -> Self {
557 Self { in_module: container, kind: DiagnosticKind::MacroError { ast, message } }
558 }
559
560 pub(super) fn unresolved_macro_call(
561 container: LocalModuleId,
562 ast: AstId<ast::MacroCall>,
563 path: ModPath,
564 ) -> Self {
565 Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast, path } }
566 }
567
568 pub(super) fn add_to(
569 &self,
570 db: &dyn DefDatabase,
571 target_module: LocalModuleId,
572 sink: &mut DiagnosticSink,
573 ) {
574 if self.in_module != target_module {
575 return;
576 }
577
578 match &self.kind {
579 DiagnosticKind::UnresolvedModule { declaration, candidate } => {
580 let decl = declaration.to_node(db.upcast());
581 sink.push(UnresolvedModule {
582 file: declaration.file_id,
583 decl: AstPtr::new(&decl),
584 candidate: candidate.clone(),
585 })
586 }
587
588 DiagnosticKind::UnresolvedExternCrate { ast } => {
589 let item = ast.to_node(db.upcast());
590 sink.push(UnresolvedExternCrate {
591 file: ast.file_id,
592 item: AstPtr::new(&item),
593 });
594 }
595
596 DiagnosticKind::UnresolvedImport { ast, index } => {
597 let use_item = ast.to_node(db.upcast());
598 let hygiene = Hygiene::new(db.upcast(), ast.file_id);
599 let mut cur = 0;
600 let mut tree = None;
601 ModPath::expand_use_item(
602 db,
603 InFile::new(ast.file_id, use_item),
604 &hygiene,
605 |_mod_path, use_tree, _is_glob, _alias| {
606 if cur == *index {
607 tree = Some(use_tree.clone());
608 }
609
610 cur += 1;
611 },
612 );
613
614 if let Some(tree) = tree {
615 sink.push(UnresolvedImport { file: ast.file_id, node: AstPtr::new(&tree) });
616 }
617 }
618
619 DiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
620 let item = ast.to_node(db.upcast());
621 sink.push(InactiveCode {
622 file: ast.file_id,
623 node: AstPtr::new(&item).into(),
624 cfg: cfg.clone(),
625 opts: opts.clone(),
626 });
627 }
628
629 DiagnosticKind::UnresolvedProcMacro { ast } => {
630 let mut precise_location = None;
631 let (file, ast, name) = match ast {
632 MacroCallKind::FnLike { ast_id, .. } => {
633 let node = ast_id.to_node(db.upcast());
634 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
635 }
636 MacroCallKind::Derive { ast_id, derive_name, .. } => {
637 let node = ast_id.to_node(db.upcast());
638
639 // Compute the precise location of the macro name's token in the derive
640 // list.
641 // FIXME: This does not handle paths to the macro, but neither does the
642 // rest of r-a.
643 let derive_attrs =
644 node.attrs().filter_map(|attr| match attr.as_simple_call() {
645 Some((name, args)) if name == "derive" => Some(args),
646 _ => None,
647 });
648 'outer: for attr in derive_attrs {
649 let tokens =
650 attr.syntax().children_with_tokens().filter_map(|elem| {
651 match elem {
652 syntax::NodeOrToken::Node(_) => None,
653 syntax::NodeOrToken::Token(tok) => Some(tok),
654 }
655 });
656 for token in tokens {
657 if token.kind() == SyntaxKind::IDENT
658 && token.text() == derive_name.as_str()
659 {
660 precise_location = Some(token.text_range());
661 break 'outer;
662 }
663 }
664 }
665
666 (
667 ast_id.file_id,
668 SyntaxNodePtr::from(AstPtr::new(&node)),
669 Some(derive_name.clone()),
670 )
671 }
672 };
673 sink.push(UnresolvedProcMacro {
674 file,
675 node: ast,
676 precise_location,
677 macro_name: name,
678 });
679 }
680
681 DiagnosticKind::UnresolvedMacroCall { ast, path } => {
682 let node = ast.to_node(db.upcast());
683 sink.push(UnresolvedMacroCall {
684 file: ast.file_id,
685 node: AstPtr::new(&node),
686 path: path.clone(),
687 });
688 }
689
690 DiagnosticKind::MacroError { ast, message } => {
691 let (file, ast) = match ast {
692 MacroCallKind::FnLike { ast_id, .. } => {
693 let node = ast_id.to_node(db.upcast());
694 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
695 }
696 MacroCallKind::Derive { ast_id, .. } => {
697 let node = ast_id.to_node(db.upcast());
698 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
699 }
700 };
701 sink.push(MacroError { file, node: ast, message: message.clone() });
702 }
703 }
704 }
705 }
706}
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 014ea4de4..d9d6c91a8 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -17,6 +17,7 @@ use hir_expand::{
17}; 17};
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use itertools::Itertools; 19use itertools::Itertools;
20use la_arena::Idx;
20use rustc_hash::{FxHashMap, FxHashSet}; 21use rustc_hash::{FxHashMap, FxHashSet};
21use syntax::ast; 22use syntax::ast;
22 23
@@ -33,7 +34,10 @@ use crate::{
33 }, 34 },
34 macro_call_as_call_id, 35 macro_call_as_call_id,
35 nameres::{ 36 nameres::{
36 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, 37 diagnostics::DefDiagnostic,
38 mod_resolution::ModDir,
39 path_resolution::ReachedFixedPoint,
40 proc_macro::{ProcMacroDef, ProcMacroKind},
37 BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode, 41 BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode,
38 }, 42 },
39 path::{ImportAlias, ModPath, PathKind}, 43 path::{ImportAlias, ModPath, PathKind},
@@ -44,8 +48,6 @@ use crate::{
44 UnresolvedMacro, 48 UnresolvedMacro,
45}; 49};
46 50
47use super::proc_macro::{ProcMacroDef, ProcMacroKind};
48
49const GLOB_RECURSION_LIMIT: usize = 100; 51const GLOB_RECURSION_LIMIT: usize = 100;
50const EXPANSION_DEPTH_LIMIT: usize = 128; 52const EXPANSION_DEPTH_LIMIT: usize = 128;
51const FIXED_POINT_LIMIT: usize = 8192; 53const FIXED_POINT_LIMIT: usize = 8192;
@@ -142,7 +144,7 @@ impl PartialResolvedImport {
142 144
143#[derive(Clone, Debug, Eq, PartialEq)] 145#[derive(Clone, Debug, Eq, PartialEq)]
144enum ImportSource { 146enum ImportSource {
145 Import(ItemTreeId<item_tree::Import>), 147 Import { id: ItemTreeId<item_tree::Import>, use_tree: Idx<ast::UseTree> },
146 ExternCrate(ItemTreeId<item_tree::ExternCrate>), 148 ExternCrate(ItemTreeId<item_tree::ExternCrate>),
147} 149}
148 150
@@ -164,20 +166,26 @@ impl Import {
164 krate: CrateId, 166 krate: CrateId,
165 tree: &ItemTree, 167 tree: &ItemTree,
166 id: ItemTreeId<item_tree::Import>, 168 id: ItemTreeId<item_tree::Import>,
167 ) -> Self { 169 ) -> Vec<Self> {
168 let it = &tree[id.value]; 170 let it = &tree[id.value];
169 let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); 171 let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
170 let visibility = &tree[it.visibility]; 172 let visibility = &tree[it.visibility];
171 Self { 173 let is_prelude = attrs.by_key("prelude_import").exists();
172 path: it.path.clone(), 174
173 alias: it.alias.clone(), 175 let mut res = Vec::new();
174 visibility: visibility.clone(), 176 it.use_tree.expand(|idx, path, is_glob, alias| {
175 is_glob: it.is_glob, 177 res.push(Self {
176 is_prelude: attrs.by_key("prelude_import").exists(), 178 path: Interned::new(path), // FIXME this makes little sense
177 is_extern_crate: false, 179 alias,
178 is_macro_use: false, 180 visibility: visibility.clone(),
179 source: ImportSource::Import(id), 181 is_glob,
180 } 182 is_prelude,
183 is_extern_crate: false,
184 is_macro_use: false,
185 source: ImportSource::Import { id, use_tree: idx },
186 });
187 });
188 res
181 } 189 }
182 190
183 fn from_extern_crate( 191 fn from_extern_crate(
@@ -285,7 +293,7 @@ impl DefCollector<'_> {
285 let registered_name = if *attr_name == hir_expand::name![register_attr] 293 let registered_name = if *attr_name == hir_expand::name![register_attr]
286 || *attr_name == hir_expand::name![register_tool] 294 || *attr_name == hir_expand::name![register_tool]
287 { 295 {
288 match &attr.input { 296 match attr.input.as_deref() {
289 Some(AttrInput::TokenTree(subtree)) => match &*subtree.token_trees { 297 Some(AttrInput::TokenTree(subtree)) => match &*subtree.token_trees {
290 [tt::TokenTree::Leaf(tt::Leaf::Ident(name))] => name.as_name(), 298 [tt::TokenTree::Leaf(tt::Leaf::Ident(name))] => name.as_name(),
291 _ => continue, 299 _ => continue,
@@ -469,16 +477,21 @@ impl DefCollector<'_> {
469 /// going out of sync with what the build system sees (since we resolve using VFS state, but 477 /// going out of sync with what the build system sees (since we resolve using VFS state, but
470 /// Cargo builds only on-disk files). We could and probably should add diagnostics for that. 478 /// Cargo builds only on-disk files). We could and probably should add diagnostics for that.
471 fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>) { 479 fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>) {
480 let kind = def.kind.to_basedb_kind();
472 self.exports_proc_macros = true; 481 self.exports_proc_macros = true;
473 let macro_def = match self.proc_macros.iter().find(|(n, _)| n == &def.name) { 482 let macro_def = match self.proc_macros.iter().find(|(n, _)| n == &def.name) {
474 Some((_, expander)) => MacroDefId { 483 Some((_, expander)) => MacroDefId {
475 krate: self.def_map.krate, 484 krate: self.def_map.krate,
476 kind: MacroDefKind::ProcMacro(*expander, ast_id), 485 kind: MacroDefKind::ProcMacro(*expander, kind, ast_id),
477 local_inner: false, 486 local_inner: false,
478 }, 487 },
479 None => MacroDefId { 488 None => MacroDefId {
480 krate: self.def_map.krate, 489 krate: self.def_map.krate,
481 kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate), ast_id), 490 kind: MacroDefKind::ProcMacro(
491 ProcMacroExpander::dummy(self.def_map.krate),
492 kind,
493 ast_id,
494 ),
482 local_inner: false, 495 local_inner: false,
483 }, 496 },
484 }; 497 };
@@ -1129,11 +1142,8 @@ impl DefCollector<'_> {
1129 } 1142 }
1130 1143
1131 for directive in &self.unresolved_imports { 1144 for directive in &self.unresolved_imports {
1132 if let ImportSource::Import(import) = &directive.import.source { 1145 if let ImportSource::Import { id: import, use_tree } = &directive.import.source {
1133 let item_tree = import.item_tree(self.db); 1146 match (directive.import.path.segments().first(), &directive.import.path.kind) {
1134 let import_data = &item_tree[import.value];
1135
1136 match (import_data.path.segments().first(), &import_data.path.kind) {
1137 (Some(krate), PathKind::Plain) | (Some(krate), PathKind::Abs) => { 1147 (Some(krate), PathKind::Plain) | (Some(krate), PathKind::Abs) => {
1138 if diagnosed_extern_crates.contains(krate) { 1148 if diagnosed_extern_crates.contains(krate) {
1139 continue; 1149 continue;
@@ -1144,8 +1154,8 @@ impl DefCollector<'_> {
1144 1154
1145 self.def_map.diagnostics.push(DefDiagnostic::unresolved_import( 1155 self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
1146 directive.module_id, 1156 directive.module_id,
1147 InFile::new(import.file_id(), import_data.ast_id), 1157 *import,
1148 import_data.index, 1158 *use_tree,
1149 )); 1159 ));
1150 } 1160 }
1151 } 1161 }
@@ -1221,16 +1231,20 @@ impl ModCollector<'_, '_> {
1221 match item { 1231 match item {
1222 ModItem::Mod(m) => self.collect_module(&self.item_tree[m], &attrs), 1232 ModItem::Mod(m) => self.collect_module(&self.item_tree[m], &attrs),
1223 ModItem::Import(import_id) => { 1233 ModItem::Import(import_id) => {
1224 self.def_collector.unresolved_imports.push(ImportDirective { 1234 let module_id = self.module_id;
1225 module_id: self.module_id, 1235 let imports = Import::from_use(
1226 import: Import::from_use( 1236 self.def_collector.db,
1227 self.def_collector.db, 1237 krate,
1228 krate, 1238 &self.item_tree,
1229 &self.item_tree, 1239 ItemTreeId::new(self.file_id, import_id),
1230 ItemTreeId::new(self.file_id, import_id), 1240 );
1231 ), 1241 self.def_collector.unresolved_imports.extend(imports.into_iter().map(
1232 status: PartialResolvedImport::Unresolved, 1242 |import| ImportDirective {
1233 }) 1243 module_id,
1244 import,
1245 status: PartialResolvedImport::Unresolved,
1246 },
1247 ));
1234 } 1248 }
1235 ModItem::ExternCrate(import_id) => { 1249 ModItem::ExternCrate(import_id) => {
1236 self.def_collector.unresolved_imports.push(ImportDirective { 1250 self.def_collector.unresolved_imports.push(ImportDirective {
diff --git a/crates/hir_def/src/nameres/diagnostics.rs b/crates/hir_def/src/nameres/diagnostics.rs
new file mode 100644
index 000000000..57c36c3c6
--- /dev/null
+++ b/crates/hir_def/src/nameres/diagnostics.rs
@@ -0,0 +1,96 @@
1//! Diagnostics emitted during DefMap construction.
2
3use cfg::{CfgExpr, CfgOptions};
4use hir_expand::MacroCallKind;
5use la_arena::Idx;
6use syntax::ast;
7
8use crate::{
9 item_tree::{self, ItemTreeId},
10 nameres::LocalModuleId,
11 path::ModPath,
12 AstId,
13};
14
15#[derive(Debug, PartialEq, Eq)]
16pub enum DefDiagnosticKind {
17 UnresolvedModule { ast: AstId<ast::Module>, candidate: String },
18
19 UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
20
21 UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> },
22
23 UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions },
24
25 UnresolvedProcMacro { ast: MacroCallKind },
26
27 UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
28
29 MacroError { ast: MacroCallKind, message: String },
30}
31
32#[derive(Debug, PartialEq, Eq)]
33pub struct DefDiagnostic {
34 pub in_module: LocalModuleId,
35 pub kind: DefDiagnosticKind,
36}
37
38impl DefDiagnostic {
39 pub(super) fn unresolved_module(
40 container: LocalModuleId,
41 declaration: AstId<ast::Module>,
42 candidate: String,
43 ) -> Self {
44 Self {
45 in_module: container,
46 kind: DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate },
47 }
48 }
49
50 pub(super) fn unresolved_extern_crate(
51 container: LocalModuleId,
52 declaration: AstId<ast::ExternCrate>,
53 ) -> Self {
54 Self {
55 in_module: container,
56 kind: DefDiagnosticKind::UnresolvedExternCrate { ast: declaration },
57 }
58 }
59
60 pub(super) fn unresolved_import(
61 container: LocalModuleId,
62 id: ItemTreeId<item_tree::Import>,
63 index: Idx<ast::UseTree>,
64 ) -> Self {
65 Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } }
66 }
67
68 pub(super) fn unconfigured_code(
69 container: LocalModuleId,
70 ast: AstId<ast::Item>,
71 cfg: CfgExpr,
72 opts: CfgOptions,
73 ) -> Self {
74 Self { in_module: container, kind: DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } }
75 }
76
77 pub(super) fn unresolved_proc_macro(container: LocalModuleId, ast: MacroCallKind) -> Self {
78 Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast } }
79 }
80
81 pub(super) fn macro_error(
82 container: LocalModuleId,
83 ast: MacroCallKind,
84 message: String,
85 ) -> Self {
86 Self { in_module: container, kind: DefDiagnosticKind::MacroError { ast, message } }
87 }
88
89 pub(super) fn unresolved_macro_call(
90 container: LocalModuleId,
91 ast: AstId<ast::MacroCall>,
92 path: ModPath,
93 ) -> Self {
94 Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } }
95 }
96}
diff --git a/crates/hir_def/src/nameres/proc_macro.rs b/crates/hir_def/src/nameres/proc_macro.rs
index 156598f19..3f095d623 100644
--- a/crates/hir_def/src/nameres/proc_macro.rs
+++ b/crates/hir_def/src/nameres/proc_macro.rs
@@ -18,6 +18,16 @@ pub(super) enum ProcMacroKind {
18 Attr, 18 Attr,
19} 19}
20 20
21impl ProcMacroKind {
22 pub(super) fn to_basedb_kind(&self) -> base_db::ProcMacroKind {
23 match self {
24 ProcMacroKind::CustomDerive { .. } => base_db::ProcMacroKind::CustomDerive,
25 ProcMacroKind::FnLike => base_db::ProcMacroKind::FuncLike,
26 ProcMacroKind::Attr => base_db::ProcMacroKind::Attr,
27 }
28 }
29}
30
21impl Attrs { 31impl Attrs {
22 #[rustfmt::skip] 32 #[rustfmt::skip]
23 pub(super) fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> { 33 pub(super) fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> {
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index 75147d973..ec6670952 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -18,7 +18,7 @@ fn unresolved_import() {
18 r" 18 r"
19 use does_exist; 19 use does_exist;
20 use does_not_exist; 20 use does_not_exist;
21 //^^^^^^^^^^^^^^ unresolved import 21 //^^^^^^^^^^^^^^^^^^^ UnresolvedImport
22 22
23 mod does_exist {} 23 mod does_exist {}
24 ", 24 ",
@@ -26,40 +26,13 @@ fn unresolved_import() {
26} 26}
27 27
28#[test] 28#[test]
29fn unresolved_import_in_use_tree() {
30 // Only the relevant part of a nested `use` item should be highlighted.
31 check_diagnostics(
32 r"
33 use does_exist::{Exists, DoesntExist};
34 //^^^^^^^^^^^ unresolved import
35
36 use {does_not_exist::*, does_exist};
37 //^^^^^^^^^^^^^^^^^ unresolved import
38
39 use does_not_exist::{
40 a,
41 //^ unresolved import
42 b,
43 //^ unresolved import
44 c,
45 //^ unresolved import
46 };
47
48 mod does_exist {
49 pub struct Exists;
50 }
51 ",
52 );
53}
54
55#[test]
56fn unresolved_extern_crate() { 29fn unresolved_extern_crate() {
57 check_diagnostics( 30 check_diagnostics(
58 r" 31 r"
59 //- /main.rs crate:main deps:core 32 //- /main.rs crate:main deps:core
60 extern crate core; 33 extern crate core;
61 extern crate doesnotexist; 34 extern crate doesnotexist;
62 //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate 35 //^^^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedExternCrate
63 //- /lib.rs crate:core 36 //- /lib.rs crate:core
64 ", 37 ",
65 ); 38 );
@@ -72,7 +45,7 @@ fn extern_crate_self_as() {
72 r" 45 r"
73 //- /lib.rs 46 //- /lib.rs
74 extern crate doesnotexist; 47 extern crate doesnotexist;
75 //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate 48 //^^^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedExternCrate
76 // Should not error. 49 // Should not error.
77 extern crate self as foo; 50 extern crate self as foo;
78 struct Foo; 51 struct Foo;
@@ -88,18 +61,18 @@ fn dedup_unresolved_import_from_unresolved_crate() {
88 //- /main.rs crate:main 61 //- /main.rs crate:main
89 mod a { 62 mod a {
90 extern crate doesnotexist; 63 extern crate doesnotexist;
91 //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate 64 //^^^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedExternCrate
92 65
93 // Should not error, since we already errored for the missing crate. 66 // Should not error, since we already errored for the missing crate.
94 use doesnotexist::{self, bla, *}; 67 use doesnotexist::{self, bla, *};
95 68
96 use crate::doesnotexist; 69 use crate::doesnotexist;
97 //^^^^^^^^^^^^^^^^^^^ unresolved import 70 //^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedImport
98 } 71 }
99 72
100 mod m { 73 mod m {
101 use super::doesnotexist; 74 use super::doesnotexist;
102 //^^^^^^^^^^^^^^^^^^^ unresolved import 75 //^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedImport
103 } 76 }
104 ", 77 ",
105 ); 78 );
@@ -112,7 +85,7 @@ fn unresolved_module() {
112 //- /lib.rs 85 //- /lib.rs
113 mod foo; 86 mod foo;
114 mod bar; 87 mod bar;
115 //^^^^^^^^ unresolved module 88 //^^^^^^^^ UnresolvedModule
116 mod baz {} 89 mod baz {}
117 //- /foo.rs 90 //- /foo.rs
118 ", 91 ",
@@ -127,16 +100,16 @@ fn inactive_item() {
127 r#" 100 r#"
128 //- /lib.rs 101 //- /lib.rs
129 #[cfg(no)] pub fn f() {} 102 #[cfg(no)] pub fn f() {}
130 //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled 103 //^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
131 104
132 #[cfg(no)] #[cfg(no2)] mod m; 105 #[cfg(no)] #[cfg(no2)] mod m;
133 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled 106 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
134 107
135 #[cfg(all(not(a), b))] enum E {} 108 #[cfg(all(not(a), b))] enum E {}
136 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled 109 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
137 110
138 #[cfg(feature = "std")] use std; 111 #[cfg(feature = "std")] use std;
139 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled 112 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
140 "#, 113 "#,
141 ); 114 );
142} 115}
@@ -149,14 +122,14 @@ fn inactive_via_cfg_attr() {
149 r#" 122 r#"
150 //- /lib.rs 123 //- /lib.rs
151 #[cfg_attr(not(never), cfg(no))] fn f() {} 124 #[cfg_attr(not(never), cfg(no))] fn f() {}
152 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled 125 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
153 126
154 #[cfg_attr(not(never), cfg(not(no)))] fn f() {} 127 #[cfg_attr(not(never), cfg(not(no)))] fn f() {}
155 128
156 #[cfg_attr(never, cfg(no))] fn g() {} 129 #[cfg_attr(never, cfg(no))] fn g() {}
157 130
158 #[cfg_attr(not(never), inline, cfg(no))] fn h() {} 131 #[cfg_attr(not(never), inline, cfg(no))] fn h() {}
159 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled 132 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
160 "#, 133 "#,
161 ); 134 );
162} 135}
@@ -170,7 +143,7 @@ fn unresolved_legacy_scope_macro() {
170 143
171 m!(); 144 m!();
172 m2!(); 145 m2!();
173 //^^^^^^ unresolved macro `self::m2!` 146 //^^^^^^ UnresolvedMacroCall
174 "#, 147 "#,
175 ); 148 );
176} 149}
@@ -187,7 +160,7 @@ fn unresolved_module_scope_macro() {
187 160
188 self::m!(); 161 self::m!();
189 self::m2!(); 162 self::m2!();
190 //^^^^^^^^^^^^ unresolved macro `self::m2!` 163 //^^^^^^^^^^^^ UnresolvedMacroCall
191 "#, 164 "#,
192 ); 165 );
193} 166}
diff --git a/crates/hir_def/src/nameres/tests/incremental.rs b/crates/hir_def/src/nameres/tests/incremental.rs
index d884a6eb4..7bf152e26 100644
--- a/crates/hir_def/src/nameres/tests/incremental.rs
+++ b/crates/hir_def/src/nameres/tests/incremental.rs
@@ -1,6 +1,8 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use base_db::SourceDatabaseExt; 3use base_db::{salsa::SweepStrategy, SourceDatabaseExt};
4
5use crate::{AdtId, ModuleDefId};
4 6
5use super::*; 7use super::*;
6 8
@@ -163,3 +165,73 @@ m!(Z);
163 assert_eq!(n_reparsed_macros, 0); 165 assert_eq!(n_reparsed_macros, 0);
164 } 166 }
165} 167}
168
169#[test]
170fn item_tree_prevents_reparsing() {
171 // The `ItemTree` is used by both name resolution and the various queries in `adt.rs` and
172 // `data.rs`. After computing the `ItemTree` and deleting the parse tree, we should be able to
173 // run those other queries without triggering a reparse.
174
175 let (db, pos) = TestDB::with_position(
176 r#"
177pub struct S;
178pub union U {}
179pub enum E {
180 Variant,
181}
182pub fn f(_: S) { $0 }
183pub trait Tr {}
184impl Tr for () {}
185pub const C: u8 = 0;
186pub static ST: u8 = 0;
187pub type Ty = ();
188"#,
189 );
190 let krate = db.test_crate();
191 {
192 let events = db.log_executed(|| {
193 db.file_item_tree(pos.file_id.into());
194 });
195 let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
196 assert_eq!(n_calculated_item_trees, 1);
197 let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count();
198 assert_eq!(n_parsed_files, 1);
199 }
200
201 // Delete the parse tree.
202 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
203 base_db::ParseQuery.in_db(&db).sweep(sweep);
204
205 {
206 let events = db.log_executed(|| {
207 let crate_def_map = db.crate_def_map(krate);
208 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
209 assert_eq!(module_data.scope.resolutions().count(), 8);
210 assert_eq!(module_data.scope.impls().count(), 1);
211
212 for imp in module_data.scope.impls() {
213 db.impl_data(imp);
214 }
215
216 for (_, res) in module_data.scope.resolutions() {
217 match res.values.or(res.types).unwrap().0 {
218 ModuleDefId::FunctionId(f) => drop(db.function_data(f)),
219 ModuleDefId::AdtId(adt) => match adt {
220 AdtId::StructId(it) => drop(db.struct_data(it)),
221 AdtId::UnionId(it) => drop(db.union_data(it)),
222 AdtId::EnumId(it) => drop(db.enum_data(it)),
223 },
224 ModuleDefId::ConstId(it) => drop(db.const_data(it)),
225 ModuleDefId::StaticId(it) => drop(db.static_data(it)),
226 ModuleDefId::TraitId(it) => drop(db.trait_data(it)),
227 ModuleDefId::TypeAliasId(it) => drop(db.type_alias_data(it)),
228 ModuleDefId::EnumVariantId(_)
229 | ModuleDefId::ModuleId(_)
230 | ModuleDefId::BuiltinType(_) => unreachable!(),
231 }
232 }
233 });
234 let n_reparsed_files = events.iter().filter(|it| it.contains("parse(")).count();
235 assert_eq!(n_reparsed_files, 0);
236 }
237}
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 9b8873fd2..16440041d 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -4,7 +4,6 @@ mod lower;
4use std::{ 4use std::{
5 fmt::{self, Display}, 5 fmt::{self, Display},
6 iter, 6 iter,
7 sync::Arc,
8}; 7};
9 8
10use crate::{body::LowerCtx, db::DefDatabase, intern::Interned, type_ref::LifetimeRef}; 9use crate::{body::LowerCtx, db::DefDatabase, intern::Interned, type_ref::LifetimeRef};
@@ -15,10 +14,7 @@ use hir_expand::{
15}; 14};
16use syntax::ast; 15use syntax::ast;
17 16
18use crate::{ 17use crate::type_ref::{TypeBound, TypeRef};
19 type_ref::{TypeBound, TypeRef},
20 InFile,
21};
22 18
23#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 19#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub struct ModPath { 20pub struct ModPath {
@@ -57,8 +53,7 @@ impl Display for ImportAlias {
57 53
58impl ModPath { 54impl ModPath {
59 pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { 55 pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
60 let ctx = LowerCtx::with_hygiene(db, hygiene); 56 lower::convert_path(db, None, path, hygiene)
61 lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone())
62 } 57 }
63 58
64 pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { 59 pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
@@ -71,18 +66,6 @@ impl ModPath {
71 ModPath { kind, segments: Vec::new() } 66 ModPath { kind, segments: Vec::new() }
72 } 67 }
73 68
74 /// Calls `cb` with all paths, represented by this use item.
75 pub(crate) fn expand_use_item(
76 db: &dyn DefDatabase,
77 item_src: InFile<ast::Use>,
78 hygiene: &Hygiene,
79 mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>),
80 ) {
81 if let Some(tree) = item_src.value.use_tree() {
82 lower::lower_use_tree(db, None, tree, hygiene, &mut cb);
83 }
84 }
85
86 pub fn segments(&self) -> &[Name] { 69 pub fn segments(&self) -> &[Name] {
87 &self.segments 70 &self.segments
88 } 71 }
@@ -136,7 +119,7 @@ pub struct Path {
136 type_anchor: Option<Interned<TypeRef>>, 119 type_anchor: Option<Interned<TypeRef>>,
137 mod_path: Interned<ModPath>, 120 mod_path: Interned<ModPath>,
138 /// Invariant: the same len as `self.mod_path.segments` 121 /// Invariant: the same len as `self.mod_path.segments`
139 generic_args: Vec<Option<Arc<GenericArgs>>>, 122 generic_args: Vec<Option<Interned<GenericArgs>>>,
140} 123}
141 124
142/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This 125/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
@@ -165,7 +148,7 @@ pub struct AssociatedTypeBinding {
165 /// Bounds for the associated type, like in `Iterator<Item: 148 /// Bounds for the associated type, like in `Iterator<Item:
166 /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds` 149 /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
167 /// feature.) 150 /// feature.)
168 pub bounds: Vec<TypeBound>, 151 pub bounds: Vec<Interned<TypeBound>>,
169} 152}
170 153
171/// A single generic argument. 154/// A single generic argument.
@@ -185,7 +168,7 @@ impl Path {
185 /// Converts a known mod path to `Path`. 168 /// Converts a known mod path to `Path`.
186 pub(crate) fn from_known_path( 169 pub(crate) fn from_known_path(
187 path: ModPath, 170 path: ModPath,
188 generic_args: Vec<Option<Arc<GenericArgs>>>, 171 generic_args: Vec<Option<Interned<GenericArgs>>>,
189 ) -> Path { 172 ) -> Path {
190 Path { type_anchor: None, mod_path: Interned::new(path), generic_args } 173 Path { type_anchor: None, mod_path: Interned::new(path), generic_args }
191 } 174 }
@@ -239,7 +222,7 @@ pub struct PathSegment<'a> {
239 222
240pub struct PathSegments<'a> { 223pub struct PathSegments<'a> {
241 segments: &'a [Name], 224 segments: &'a [Name],
242 generic_args: &'a [Option<Arc<GenericArgs>>], 225 generic_args: &'a [Option<Interned<GenericArgs>>],
243} 226}
244 227
245impl<'a> PathSegments<'a> { 228impl<'a> PathSegments<'a> {
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index a873325b2..f6220aa92 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -3,7 +3,6 @@
3mod lower_use; 3mod lower_use;
4 4
5use crate::intern::Interned; 5use crate::intern::Interned;
6use std::sync::Arc;
7 6
8use either::Either; 7use either::Either;
9use hir_expand::name::{name, AsName}; 8use hir_expand::name::{name, AsName};
@@ -16,7 +15,7 @@ use crate::{
16 type_ref::{LifetimeRef, TypeBound, TypeRef}, 15 type_ref::{LifetimeRef, TypeBound, TypeRef},
17}; 16};
18 17
19pub(super) use lower_use::lower_use_tree; 18pub(super) use lower_use::convert_path;
20 19
21/// Converts an `ast::Path` to `Path`. Works with use trees. 20/// Converts an `ast::Path` to `Path`. Works with use trees.
22/// It correctly handles `$crate` based path from macro call. 21/// It correctly handles `$crate` based path from macro call.
@@ -48,7 +47,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
48 segment.ret_type(), 47 segment.ret_type(),
49 ) 48 )
50 }) 49 })
51 .map(Arc::new); 50 .map(Interned::new);
52 segments.push(name); 51 segments.push(name);
53 generic_args.push(args) 52 generic_args.push(args)
54 } 53 }
@@ -87,13 +86,13 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
87 // Insert the type reference (T in the above example) as Self parameter for the trait 86 // Insert the type reference (T in the above example) as Self parameter for the trait
88 let last_segment = 87 let last_segment =
89 generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?; 88 generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?;
90 if last_segment.is_none() { 89 let mut args_inner = match last_segment {
91 *last_segment = Some(Arc::new(GenericArgs::empty())); 90 Some(it) => it.as_ref().clone(),
91 None => GenericArgs::empty(),
92 }; 92 };
93 let args = last_segment.as_mut().unwrap();
94 let mut args_inner = Arc::make_mut(args);
95 args_inner.has_self_type = true; 93 args_inner.has_self_type = true;
96 args_inner.args.insert(0, GenericArg::Type(self_type)); 94 args_inner.args.insert(0, GenericArg::Type(self_type));
95 *last_segment = Some(Interned::new(args_inner));
97 } 96 }
98 } 97 }
99 } 98 }
@@ -171,7 +170,9 @@ pub(super) fn lower_generic_args(
171 let name = name_ref.as_name(); 170 let name = name_ref.as_name();
172 let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); 171 let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
173 let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { 172 let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
174 l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() 173 l.bounds()
174 .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
175 .collect()
175 } else { 176 } else {
176 Vec::new() 177 Vec::new()
177 }; 178 };
@@ -204,15 +205,14 @@ fn lower_generic_args_from_fn_path(
204) -> Option<GenericArgs> { 205) -> Option<GenericArgs> {
205 let mut args = Vec::new(); 206 let mut args = Vec::new();
206 let mut bindings = Vec::new(); 207 let mut bindings = Vec::new();
207 if let Some(params) = params { 208 let params = params?;
208 let mut param_types = Vec::new(); 209 let mut param_types = Vec::new();
209 for param in params.params() { 210 for param in params.params() {
210 let type_ref = TypeRef::from_ast_opt(&ctx, param.ty()); 211 let type_ref = TypeRef::from_ast_opt(&ctx, param.ty());
211 param_types.push(type_ref); 212 param_types.push(type_ref);
212 }
213 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
214 args.push(arg);
215 } 213 }
214 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
215 args.push(arg);
216 if let Some(ret_type) = ret_type { 216 if let Some(ret_type) = ret_type {
217 let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.ty()); 217 let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.ty());
218 bindings.push(AssociatedTypeBinding { 218 bindings.push(AssociatedTypeBinding {
@@ -220,10 +220,14 @@ fn lower_generic_args_from_fn_path(
220 type_ref: Some(type_ref), 220 type_ref: Some(type_ref),
221 bounds: Vec::new(), 221 bounds: Vec::new(),
222 }); 222 });
223 }
224 if args.is_empty() && bindings.is_empty() {
225 None
226 } else { 223 } else {
227 Some(GenericArgs { args, has_self_type: false, bindings }) 224 // -> ()
225 let type_ref = TypeRef::Tuple(Vec::new());
226 bindings.push(AssociatedTypeBinding {
227 name: name![Output],
228 type_ref: Some(type_ref),
229 bounds: Vec::new(),
230 });
228 } 231 }
232 Some(GenericArgs { args, has_self_type: false, bindings })
229} 233}
diff --git a/crates/hir_def/src/path/lower/lower_use.rs b/crates/hir_def/src/path/lower/lower_use.rs
index ee80e3df3..0ee406f63 100644
--- a/crates/hir_def/src/path/lower/lower_use.rs
+++ b/crates/hir_def/src/path/lower/lower_use.rs
@@ -4,68 +4,15 @@
4use std::iter; 4use std::iter;
5 5
6use either::Either; 6use either::Either;
7use hir_expand::{hygiene::Hygiene, name::AsName}; 7use hir_expand::hygiene::Hygiene;
8use syntax::ast::{self, NameOwner}; 8use syntax::{ast, AstNode};
9 9
10use crate::{ 10use crate::{
11 db::DefDatabase, 11 db::DefDatabase,
12 path::{ImportAlias, ModPath, PathKind}, 12 path::{ModPath, PathKind},
13}; 13};
14 14
15pub(crate) fn lower_use_tree( 15pub(crate) fn convert_path(
16 db: &dyn DefDatabase,
17 prefix: Option<ModPath>,
18 tree: ast::UseTree,
19 hygiene: &Hygiene,
20 cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, Option<ImportAlias>),
21) {
22 if let Some(use_tree_list) = tree.use_tree_list() {
23 let prefix = match tree.path() {
24 // E.g. use something::{{{inner}}};
25 None => prefix,
26 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
27 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
28 Some(path) => match convert_path(db, prefix, path, hygiene) {
29 Some(it) => Some(it),
30 None => return, // FIXME: report errors somewhere
31 },
32 };
33 for child_tree in use_tree_list.use_trees() {
34 lower_use_tree(db, prefix.clone(), child_tree, hygiene, cb);
35 }
36 } else {
37 let alias = tree.rename().map(|a| {
38 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
39 });
40 let is_glob = tree.star_token().is_some();
41 if let Some(ast_path) = tree.path() {
42 // Handle self in a path.
43 // E.g. `use something::{self, <...>}`
44 if ast_path.qualifier().is_none() {
45 if let Some(segment) = ast_path.segment() {
46 if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
47 if let Some(prefix) = prefix {
48 cb(prefix, &tree, false, alias);
49 return;
50 }
51 }
52 }
53 }
54 if let Some(path) = convert_path(db, prefix, ast_path, hygiene) {
55 cb(path, &tree, is_glob, alias)
56 }
57 // FIXME: report errors somewhere
58 // We get here if we do
59 } else if is_glob {
60 cov_mark::hit!(glob_enum_group);
61 if let Some(prefix) = prefix {
62 cb(prefix, &tree, is_glob, None)
63 }
64 }
65 }
66}
67
68fn convert_path(
69 db: &dyn DefDatabase, 16 db: &dyn DefDatabase,
70 prefix: Option<ModPath>, 17 prefix: Option<ModPath>,
71 path: ast::Path, 18 path: ast::Path,
@@ -78,7 +25,7 @@ fn convert_path(
78 }; 25 };
79 26
80 let segment = path.segment()?; 27 let segment = path.segment()?;
81 let res = match segment.kind()? { 28 let mut mod_path = match segment.kind()? {
82 ast::PathSegmentKind::Name(name_ref) => { 29 ast::PathSegmentKind::Name(name_ref) => {
83 match hygiene.name_ref_to_name(db.upcast(), name_ref) { 30 match hygiene.name_ref_to_name(db.upcast(), name_ref) {
84 Either::Left(name) => { 31 Either::Left(name) => {
@@ -125,5 +72,18 @@ fn convert_path(
125 return None; 72 return None;
126 } 73 }
127 }; 74 };
128 Some(res) 75
76 // handle local_inner_macros :
77 // Basically, even in rustc it is quite hacky:
78 // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456
79 // We follow what it did anyway :)
80 if mod_path.segments.len() == 1 && mod_path.kind == PathKind::Plain {
81 if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
82 if let Some(crate_id) = hygiene.local_inner_macros(db.upcast(), path) {
83 mod_path.kind = PathKind::DollarCrate(crate_id);
84 }
85 }
86 }
87
88 Some(mod_path)
129} 89}
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 0391cc49b..fb8a6f260 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -337,22 +337,34 @@ impl Resolver {
337 pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> { 337 pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> {
338 let mut traits = FxHashSet::default(); 338 let mut traits = FxHashSet::default();
339 for scope in &self.scopes { 339 for scope in &self.scopes {
340 if let Scope::ModuleScope(m) = scope { 340 match scope {
341 if let Some(prelude) = m.def_map.prelude() { 341 Scope::ModuleScope(m) => {
342 let prelude_def_map = prelude.def_map(db); 342 if let Some(prelude) = m.def_map.prelude() {
343 traits.extend(prelude_def_map[prelude.local_id].scope.traits());
344 }
345 traits.extend(m.def_map[m.module_id].scope.traits());
346
347 // Add all traits that are in scope because of the containing DefMaps
348 m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| {
349 if let Some(prelude) = def_map.prelude() {
350 let prelude_def_map = prelude.def_map(db); 343 let prelude_def_map = prelude.def_map(db);
351 traits.extend(prelude_def_map[prelude.local_id].scope.traits()); 344 traits.extend(prelude_def_map[prelude.local_id].scope.traits());
352 } 345 }
353 traits.extend(def_map[module].scope.traits()); 346 traits.extend(m.def_map[m.module_id].scope.traits());
354 None::<()> 347
355 }); 348 // Add all traits that are in scope because of the containing DefMaps
349 m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| {
350 if let Some(prelude) = def_map.prelude() {
351 let prelude_def_map = prelude.def_map(db);
352 traits.extend(prelude_def_map[prelude.local_id].scope.traits());
353 }
354 traits.extend(def_map[module].scope.traits());
355 None::<()>
356 });
357 }
358 &Scope::ImplDefScope(impl_) => {
359 if let Some(target_trait) = &db.impl_data(impl_).target_trait {
360 if let Some(TypeNs::TraitId(trait_)) =
361 self.resolve_path_in_type_ns_fully(db, target_trait.path.mod_path())
362 {
363 traits.insert(trait_);
364 }
365 }
366 }
367 _ => (),
356 } 368 }
357 } 369 }
358 traits 370 traits
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs
index 8fa703a57..a9c1e13e2 100644
--- a/crates/hir_def/src/test_db.rs
+++ b/crates/hir_def/src/test_db.rs
@@ -5,19 +5,20 @@ use std::{
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
8use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, Upcast}; 8use base_db::{
9 salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, FileRange, Upcast,
10};
9use base_db::{AnchoredPath, SourceDatabase}; 11use base_db::{AnchoredPath, SourceDatabase};
10use hir_expand::diagnostics::Diagnostic;
11use hir_expand::diagnostics::DiagnosticSinkBuilder;
12use hir_expand::{db::AstDatabase, InFile}; 12use hir_expand::{db::AstDatabase, InFile};
13use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
14use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
15use syntax::{algo, ast, AstNode, TextRange, TextSize}; 15use syntax::{algo, ast, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize};
16use test_utils::extract_annotations; 16use test_utils::extract_annotations;
17 17
18use crate::{ 18use crate::{
19 body::BodyDiagnostic,
19 db::DefDatabase, 20 db::DefDatabase,
20 nameres::{DefMap, ModuleSource}, 21 nameres::{diagnostics::DefDiagnosticKind, DefMap, ModuleSource},
21 src::HasSource, 22 src::HasSource,
22 LocalModuleId, Lookup, ModuleDefId, ModuleId, 23 LocalModuleId, Lookup, ModuleDefId, ModuleId,
23}; 24};
@@ -262,19 +263,72 @@ impl TestDB {
262 .collect() 263 .collect()
263 } 264 }
264 265
265 pub(crate) fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) { 266 pub(crate) fn diagnostics(&self, cb: &mut dyn FnMut(FileRange, String)) {
266 let crate_graph = self.crate_graph(); 267 let crate_graph = self.crate_graph();
267 for krate in crate_graph.iter() { 268 for krate in crate_graph.iter() {
268 let crate_def_map = self.crate_def_map(krate); 269 let crate_def_map = self.crate_def_map(krate);
269 270
270 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); 271 for diag in crate_def_map.diagnostics() {
271 for (module_id, module) in crate_def_map.modules() { 272 let (node, message): (InFile<SyntaxNode>, &str) = match &diag.kind {
272 crate_def_map.add_diagnostics(self, module_id, &mut sink); 273 DefDiagnosticKind::UnresolvedModule { ast, .. } => {
274 let node = ast.to_node(self.upcast());
275 (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedModule")
276 }
277 DefDiagnosticKind::UnresolvedExternCrate { ast, .. } => {
278 let node = ast.to_node(self.upcast());
279 (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedExternCrate")
280 }
281 DefDiagnosticKind::UnresolvedImport { id, .. } => {
282 let item_tree = id.item_tree(self.upcast());
283 let import = &item_tree[id.value];
284 let node = InFile::new(id.file_id(), import.ast_id).to_node(self.upcast());
285 (InFile::new(id.file_id(), node.syntax().clone()), "UnresolvedImport")
286 }
287 DefDiagnosticKind::UnconfiguredCode { ast, .. } => {
288 let node = ast.to_node(self.upcast());
289 (InFile::new(ast.file_id, node.syntax().clone()), "UnconfiguredCode")
290 }
291 DefDiagnosticKind::UnresolvedProcMacro { ast, .. } => {
292 (ast.to_node(self.upcast()), "UnresolvedProcMacro")
293 }
294 DefDiagnosticKind::UnresolvedMacroCall { ast, .. } => {
295 let node = ast.to_node(self.upcast());
296 (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedMacroCall")
297 }
298 DefDiagnosticKind::MacroError { ast, message } => {
299 (ast.to_node(self.upcast()), message.as_str())
300 }
301 };
302
303 let frange = node.as_ref().original_file_range(self);
304 cb(frange, message.to_string())
305 }
273 306
307 for (_module_id, module) in crate_def_map.modules() {
274 for decl in module.scope.declarations() { 308 for decl in module.scope.declarations() {
275 if let ModuleDefId::FunctionId(it) = decl { 309 if let ModuleDefId::FunctionId(it) = decl {
276 let source_map = self.body_with_source_map(it.into()).1; 310 let source_map = self.body_with_source_map(it.into()).1;
277 source_map.add_diagnostics(self, &mut sink); 311 for diag in source_map.diagnostics() {
312 let (ptr, message): (InFile<SyntaxNodePtr>, &str) = match diag {
313 BodyDiagnostic::InactiveCode { node, .. } => {
314 (node.clone().map(|it| it.into()), "InactiveCode")
315 }
316 BodyDiagnostic::MacroError { node, message } => {
317 (node.clone().map(|it| it.into()), message.as_str())
318 }
319 BodyDiagnostic::UnresolvedProcMacro { node } => {
320 (node.clone().map(|it| it.into()), "UnresolvedProcMacro")
321 }
322 BodyDiagnostic::UnresolvedMacroCall { node, .. } => {
323 (node.clone().map(|it| it.into()), "UnresolvedMacroCall")
324 }
325 };
326
327 let root = self.parse_or_expand(ptr.file_id).unwrap();
328 let node = ptr.map(|ptr| ptr.to_node(&root));
329 let frange = node.as_ref().original_file_range(self);
330 cb(frange, message.to_string())
331 }
278 } 332 }
279 } 333 }
280 } 334 }
@@ -287,14 +341,7 @@ impl TestDB {
287 assert!(!annotations.is_empty()); 341 assert!(!annotations.is_empty());
288 342
289 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); 343 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
290 db.diagnostics(|d| { 344 db.diagnostics(&mut |frange, message| {
291 let src = d.display_source();
292 let root = db.parse_or_expand(src.file_id).unwrap();
293
294 let node = src.map(|ptr| ptr.to_node(&root));
295 let frange = node.as_ref().original_file_range(db);
296
297 let message = d.message();
298 actual.entry(frange.file_id).or_default().push((frange.range, message)); 345 actual.entry(frange.file_id).or_default().push((frange.range, message));
299 }); 346 });
300 347
@@ -319,7 +366,7 @@ impl TestDB {
319 assert!(annotations.is_empty()); 366 assert!(annotations.is_empty());
320 367
321 let mut has_diagnostics = false; 368 let mut has_diagnostics = false;
322 db.diagnostics(|_| { 369 db.diagnostics(&mut |_, _| {
323 has_diagnostics = true; 370 has_diagnostics = true;
324 }); 371 });
325 372
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index cdcab7110..cbde6b940 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -5,7 +5,7 @@ use hir_expand::{name::Name, AstId, InFile};
5use std::convert::TryInto; 5use std::convert::TryInto;
6use syntax::ast; 6use syntax::ast;
7 7
8use crate::{body::LowerCtx, path::Path}; 8use crate::{body::LowerCtx, intern::Interned, path::Path};
9 9
10#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] 10#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
11pub enum Mutability { 11pub enum Mutability {
@@ -91,8 +91,8 @@ pub enum TypeRef {
91 /// A fn pointer. Last element of the vector is the return type. 91 /// A fn pointer. Last element of the vector is the return type.
92 Fn(Vec<TypeRef>, bool /*varargs*/), 92 Fn(Vec<TypeRef>, bool /*varargs*/),
93 // For 93 // For
94 ImplTrait(Vec<TypeBound>), 94 ImplTrait(Vec<Interned<TypeBound>>),
95 DynTrait(Vec<TypeBound>), 95 DynTrait(Vec<Interned<TypeBound>>),
96 Macro(AstId<ast::MacroCall>), 96 Macro(AstId<ast::MacroCall>),
97 Error, 97 Error,
98} 98}
@@ -232,7 +232,7 @@ impl TypeRef {
232 | TypeRef::Slice(type_ref) => go(&type_ref, f), 232 | TypeRef::Slice(type_ref) => go(&type_ref, f),
233 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { 233 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
234 for bound in bounds { 234 for bound in bounds {
235 match bound { 235 match bound.as_ref() {
236 TypeBound::Path(path) => go_path(path, f), 236 TypeBound::Path(path) => go_path(path, f),
237 TypeBound::Lifetime(_) | TypeBound::Error => (), 237 TypeBound::Lifetime(_) | TypeBound::Error => (),
238 } 238 }
@@ -262,7 +262,7 @@ impl TypeRef {
262 go(type_ref, f); 262 go(type_ref, f);
263 } 263 }
264 for bound in &binding.bounds { 264 for bound in &binding.bounds {
265 match bound { 265 match bound.as_ref() {
266 TypeBound::Path(path) => go_path(path, f), 266 TypeBound::Path(path) => go_path(path, f),
267 TypeBound::Lifetime(_) | TypeBound::Error => (), 267 TypeBound::Lifetime(_) | TypeBound::Error => (),
268 } 268 }
@@ -277,9 +277,9 @@ impl TypeRef {
277pub(crate) fn type_bounds_from_ast( 277pub(crate) fn type_bounds_from_ast(
278 lower_ctx: &LowerCtx, 278 lower_ctx: &LowerCtx,
279 type_bounds_opt: Option<ast::TypeBoundList>, 279 type_bounds_opt: Option<ast::TypeBoundList>,
280) -> Vec<TypeBound> { 280) -> Vec<Interned<TypeBound>> {
281 if let Some(type_bounds) = type_bounds_opt { 281 if let Some(type_bounds) = type_bounds_opt {
282 type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() 282 type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect()
283 } else { 283 } else {
284 vec![] 284 vec![]
285 } 285 }