aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/nameres
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/nameres')
-rw-r--r--crates/hir_def/src/nameres/collector.rs136
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs59
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs26
3 files changed, 147 insertions, 74 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index d58135ec9..05ceb1efb 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -13,7 +13,7 @@ use hir_expand::{
13 builtin_macro::find_builtin_macro, 13 builtin_macro::find_builtin_macro,
14 name::{AsName, Name}, 14 name::{AsName, Name},
15 proc_macro::ProcMacroExpander, 15 proc_macro::ProcMacroExpander,
16 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 16 AttrId, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
17}; 17};
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use rustc_hash::{FxHashMap, FxHashSet}; 19use rustc_hash::{FxHashMap, FxHashSet};
@@ -23,6 +23,7 @@ use crate::{
23 attr::Attrs, 23 attr::Attrs,
24 db::DefDatabase, 24 db::DefDatabase,
25 derive_macro_as_call_id, 25 derive_macro_as_call_id,
26 intern::Interned,
26 item_scope::{ImportType, PerNsGlobImports}, 27 item_scope::{ImportType, PerNsGlobImports},
27 item_tree::{ 28 item_tree::{
28 self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod, ModItem, 29 self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod, ModItem,
@@ -54,20 +55,22 @@ pub(super) fn collect_defs(
54) -> DefMap { 55) -> DefMap {
55 let crate_graph = db.crate_graph(); 56 let crate_graph = db.crate_graph();
56 57
57 // populate external prelude 58 if block.is_none() {
58 for dep in &crate_graph[def_map.krate].dependencies { 59 // populate external prelude
59 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); 60 for dep in &crate_graph[def_map.krate].dependencies {
60 let dep_def_map = db.crate_def_map(dep.crate_id); 61 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
61 def_map 62 let dep_def_map = db.crate_def_map(dep.crate_id);
62 .extern_prelude 63 def_map
63 .insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into()); 64 .extern_prelude
64 65 .insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into());
65 // look for the prelude 66
66 // If the dependency defines a prelude, we overwrite an already defined 67 // look for the prelude
67 // prelude. This is necessary to import the "std" prelude if a crate 68 // If the dependency defines a prelude, we overwrite an already defined
68 // depends on both "core" and "std". 69 // prelude. This is necessary to import the "std" prelude if a crate
69 if dep_def_map.prelude.is_some() { 70 // depends on both "core" and "std".
70 def_map.prelude = dep_def_map.prelude; 71 if dep_def_map.prelude.is_some() {
72 def_map.prelude = dep_def_map.prelude;
73 }
71 } 74 }
72 } 75 }
73 76
@@ -106,7 +109,9 @@ pub(super) fn collect_defs(
106 } 109 }
107 } 110 }
108 collector.collect(); 111 collector.collect();
109 collector.finish() 112 let mut def_map = collector.finish();
113 def_map.shrink_to_fit();
114 def_map
110} 115}
111 116
112#[derive(Copy, Clone, Debug, Eq, PartialEq)] 117#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -137,7 +142,7 @@ enum ImportSource {
137 142
138#[derive(Clone, Debug, Eq, PartialEq)] 143#[derive(Clone, Debug, Eq, PartialEq)]
139struct Import { 144struct Import {
140 path: ModPath, 145 path: Interned<ModPath>,
141 alias: Option<ImportAlias>, 146 alias: Option<ImportAlias>,
142 visibility: RawVisibility, 147 visibility: RawVisibility,
143 is_glob: bool, 148 is_glob: bool,
@@ -179,7 +184,10 @@ impl Import {
179 let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); 184 let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
180 let visibility = &tree[it.visibility]; 185 let visibility = &tree[it.visibility];
181 Self { 186 Self {
182 path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())), 187 path: Interned::new(ModPath::from_segments(
188 PathKind::Plain,
189 iter::once(it.name.clone()),
190 )),
183 alias: it.alias.clone(), 191 alias: it.alias.clone(),
184 visibility: visibility.clone(), 192 visibility: visibility.clone(),
185 is_glob: false, 193 is_glob: false,
@@ -207,8 +215,8 @@ struct MacroDirective {
207 215
208#[derive(Clone, Debug, Eq, PartialEq)] 216#[derive(Clone, Debug, Eq, PartialEq)]
209enum MacroDirectiveKind { 217enum MacroDirectiveKind {
210 FnLike { ast_id: AstIdWithPath<ast::MacroCall>, legacy: Option<MacroCallId> }, 218 FnLike { ast_id: AstIdWithPath<ast::MacroCall> },
211 Derive { ast_id: AstIdWithPath<ast::Item> }, 219 Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId },
212} 220}
213 221
214struct DefData<'a> { 222struct DefData<'a> {
@@ -470,7 +478,7 @@ impl DefCollector<'_> {
470 self.def_map.edition, 478 self.def_map.edition,
471 ); 479 );
472 480
473 let res = self.def_map.resolve_name_in_extern_prelude(&extern_crate.name); 481 let res = self.def_map.resolve_name_in_extern_prelude(self.db, &extern_crate.name);
474 482
475 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { 483 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
476 cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); 484 cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
@@ -526,6 +534,7 @@ impl DefCollector<'_> {
526 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 534 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
527 if import.is_extern_crate { 535 if import.is_extern_crate {
528 let res = self.def_map.resolve_name_in_extern_prelude( 536 let res = self.def_map.resolve_name_in_extern_prelude(
537 self.db,
529 &import 538 &import
530 .path 539 .path
531 .as_ident() 540 .as_ident()
@@ -798,13 +807,7 @@ impl DefCollector<'_> {
798 let mut res = ReachedFixedPoint::Yes; 807 let mut res = ReachedFixedPoint::Yes;
799 macros.retain(|directive| { 808 macros.retain(|directive| {
800 match &directive.kind { 809 match &directive.kind {
801 MacroDirectiveKind::FnLike { ast_id, legacy } => { 810 MacroDirectiveKind::FnLike { ast_id } => {
802 if let Some(call_id) = legacy {
803 res = ReachedFixedPoint::No;
804 resolved.push((directive.module_id, *call_id, directive.depth));
805 return false;
806 }
807
808 match macro_call_as_call_id( 811 match macro_call_as_call_id(
809 ast_id, 812 ast_id,
810 self.db, 813 self.db,
@@ -826,19 +829,23 @@ impl DefCollector<'_> {
826 res = ReachedFixedPoint::No; 829 res = ReachedFixedPoint::No;
827 return false; 830 return false;
828 } 831 }
829 Err(UnresolvedMacro) | Ok(Err(_)) => {} 832 Err(UnresolvedMacro { .. }) | Ok(Err(_)) => {}
830 } 833 }
831 } 834 }
832 MacroDirectiveKind::Derive { ast_id } => { 835 MacroDirectiveKind::Derive { ast_id, derive_attr } => {
833 match derive_macro_as_call_id(ast_id, self.db, self.def_map.krate, |path| { 836 match derive_macro_as_call_id(
834 self.resolve_derive_macro(directive.module_id, &path) 837 ast_id,
835 }) { 838 *derive_attr,
839 self.db,
840 self.def_map.krate,
841 |path| self.resolve_derive_macro(directive.module_id, &path),
842 ) {
836 Ok(call_id) => { 843 Ok(call_id) => {
837 resolved.push((directive.module_id, call_id, 0)); 844 resolved.push((directive.module_id, call_id, directive.depth));
838 res = ReachedFixedPoint::No; 845 res = ReachedFixedPoint::No;
839 return false; 846 return false;
840 } 847 }
841 Err(UnresolvedMacro) => (), 848 Err(UnresolvedMacro { .. }) => (),
842 } 849 }
843 } 850 }
844 } 851 }
@@ -936,10 +943,11 @@ impl DefCollector<'_> {
936 &mut |_| (), 943 &mut |_| (),
937 ) { 944 ) {
938 Ok(_) => (), 945 Ok(_) => (),
939 Err(UnresolvedMacro) => { 946 Err(UnresolvedMacro { path }) => {
940 self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( 947 self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
941 directive.module_id, 948 directive.module_id,
942 ast_id.ast_id, 949 ast_id.ast_id,
950 path,
943 )); 951 ));
944 } 952 }
945 }, 953 },
@@ -1161,19 +1169,27 @@ impl ModCollector<'_, '_> {
1161 } 1169 }
1162 ModItem::Const(id) => { 1170 ModItem::Const(id) => {
1163 let it = &self.item_tree[id]; 1171 let it = &self.item_tree[id];
1164 1172 let const_id = ConstLoc {
1165 if let Some(name) = &it.name { 1173 container: module.into(),
1166 def = Some(DefData { 1174 id: ItemTreeId::new(self.file_id, id),
1167 id: ConstLoc { 1175 }
1168 container: module.into(), 1176 .intern(self.def_collector.db);
1169 id: ItemTreeId::new(self.file_id, id), 1177
1170 } 1178 match &it.name {
1171 .intern(self.def_collector.db) 1179 Some(name) => {
1172 .into(), 1180 def = Some(DefData {
1173 name, 1181 id: const_id.into(),
1174 visibility: &self.item_tree[it.visibility], 1182 name,
1175 has_constructor: false, 1183 visibility: &self.item_tree[it.visibility],
1176 }); 1184 has_constructor: false,
1185 });
1186 }
1187 None => {
1188 // const _: T = ...;
1189 self.def_collector.def_map.modules[self.module_id]
1190 .scope
1191 .define_unnamed_const(const_id);
1192 }
1177 } 1193 }
1178 } 1194 }
1179 ModItem::Static(id) => { 1195 ModItem::Static(id) => {
@@ -1358,7 +1374,7 @@ impl ModCollector<'_, '_> {
1358 self.def_collector.unexpanded_macros.push(MacroDirective { 1374 self.def_collector.unexpanded_macros.push(MacroDirective {
1359 module_id: self.module_id, 1375 module_id: self.module_id,
1360 depth: self.macro_depth + 1, 1376 depth: self.macro_depth + 1,
1361 kind: MacroDirectiveKind::Derive { ast_id }, 1377 kind: MacroDirectiveKind::Derive { ast_id, derive_attr: derive.id },
1362 }); 1378 });
1363 } 1379 }
1364 } 1380 }
@@ -1400,8 +1416,18 @@ impl ModCollector<'_, '_> {
1400 1416
1401 // Case 1: builtin macros 1417 // Case 1: builtin macros
1402 if attrs.by_key("rustc_builtin_macro").exists() { 1418 if attrs.by_key("rustc_builtin_macro").exists() {
1419 // `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name.
1420 let name;
1421 let name = match attrs.by_key("rustc_builtin_macro").string_value() {
1422 Some(it) => {
1423 // FIXME: a hacky way to create a Name from string.
1424 name = tt::Ident { text: it.clone(), id: tt::TokenId::unspecified() }.as_name();
1425 &name
1426 }
1427 None => &mac.name,
1428 };
1403 let krate = self.def_collector.def_map.krate; 1429 let krate = self.def_collector.def_map.krate;
1404 if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) { 1430 if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) {
1405 self.def_collector.define_macro_rules( 1431 self.def_collector.define_macro_rules(
1406 self.module_id, 1432 self.module_id,
1407 mac.name.clone(), 1433 mac.name.clone(),
@@ -1464,7 +1490,7 @@ impl ModCollector<'_, '_> {
1464 } 1490 }
1465 1491
1466 fn collect_macro_call(&mut self, mac: &MacroCall) { 1492 fn collect_macro_call(&mut self, mac: &MacroCall) {
1467 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); 1493 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, (*mac.path).clone());
1468 1494
1469 // Case 1: try to resolve in legacy scope and expand macro_rules 1495 // Case 1: try to resolve in legacy scope and expand macro_rules
1470 let mut error = None; 1496 let mut error = None;
@@ -1500,12 +1526,12 @@ impl ModCollector<'_, '_> {
1500 // Built-in macro failed eager expansion. 1526 // Built-in macro failed eager expansion.
1501 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( 1527 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
1502 self.module_id, 1528 self.module_id,
1503 MacroCallKind::FnLike(ast_id.ast_id), 1529 MacroCallKind::FnLike { ast_id: ast_id.ast_id },
1504 error.unwrap().to_string(), 1530 error.unwrap().to_string(),
1505 )); 1531 ));
1506 return; 1532 return;
1507 } 1533 }
1508 Err(UnresolvedMacro) => (), 1534 Err(UnresolvedMacro { .. }) => (),
1509 } 1535 }
1510 1536
1511 // Case 2: resolve in module scope, expand during name resolution. 1537 // Case 2: resolve in module scope, expand during name resolution.
@@ -1517,7 +1543,7 @@ impl ModCollector<'_, '_> {
1517 self.def_collector.unexpanded_macros.push(MacroDirective { 1543 self.def_collector.unexpanded_macros.push(MacroDirective {
1518 module_id: self.module_id, 1544 module_id: self.module_id,
1519 depth: self.macro_depth + 1, 1545 depth: self.macro_depth + 1,
1520 kind: MacroDirectiveKind::FnLike { ast_id, legacy: None }, 1546 kind: MacroDirectiveKind::FnLike { ast_id },
1521 }); 1547 });
1522 } 1548 }
1523 1549
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index 60471937c..c984148c3 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -60,12 +60,26 @@ impl ResolvePathResult {
60} 60}
61 61
62impl DefMap { 62impl DefMap {
63 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { 63 pub(super) fn resolve_name_in_extern_prelude(
64 &self,
65 db: &dyn DefDatabase,
66 name: &Name,
67 ) -> PerNs {
64 if name == &name!(self) { 68 if name == &name!(self) {
65 cov_mark::hit!(extern_crate_self_as); 69 cov_mark::hit!(extern_crate_self_as);
66 return PerNs::types(self.module_id(self.root).into(), Visibility::Public); 70 return PerNs::types(self.module_id(self.root).into(), Visibility::Public);
67 } 71 }
68 self.extern_prelude 72
73 let arc;
74 let root = match self.block {
75 Some(_) => {
76 arc = self.crate_root(db).def_map(db);
77 &*arc
78 }
79 None => self,
80 };
81
82 root.extern_prelude
69 .get(name) 83 .get(name)
70 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)) 84 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public))
71 } 85 }
@@ -191,7 +205,7 @@ impl DefMap {
191 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 205 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
192 }; 206 };
193 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 207 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
194 self.resolve_name_in_crate_root_or_extern_prelude(&segment) 208 self.resolve_name_in_crate_root_or_extern_prelude(db, &segment)
195 } 209 }
196 PathKind::Plain => { 210 PathKind::Plain => {
197 let (_, segment) = match segments.next() { 211 let (_, segment) = match segments.next() {
@@ -373,7 +387,13 @@ impl DefMap {
373 .get_legacy_macro(name) 387 .get_legacy_macro(name)
374 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public)); 388 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
375 let from_scope = self[module].scope.get(name); 389 let from_scope = self[module].scope.get(name);
376 let from_builtin = BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none); 390 let from_builtin = match self.block {
391 Some(_) => {
392 // Only resolve to builtins in the root `DefMap`.
393 PerNs::none()
394 }
395 None => BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none),
396 };
377 let from_scope_or_builtin = match shadow { 397 let from_scope_or_builtin = match shadow {
378 BuiltinShadowMode::Module => from_scope.or(from_builtin), 398 BuiltinShadowMode::Module => from_scope.or(from_builtin),
379 BuiltinShadowMode::Other => { 399 BuiltinShadowMode::Other => {
@@ -384,24 +404,31 @@ impl DefMap {
384 } 404 }
385 } 405 }
386 }; 406 };
387 // Give precedence to names in outer `DefMap`s over the extern prelude; only check prelude 407 let from_extern_prelude = self
388 // from the crate DefMap. 408 .extern_prelude
389 let from_extern_prelude = match self.block { 409 .get(name)
390 Some(_) => PerNs::none(), 410 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public));
391 None => self
392 .extern_prelude
393 .get(name)
394 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)),
395 };
396 411
397 let from_prelude = self.resolve_in_prelude(db, name); 412 let from_prelude = self.resolve_in_prelude(db, name);
398 413
399 from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude) 414 from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude)
400 } 415 }
401 416
402 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { 417 fn resolve_name_in_crate_root_or_extern_prelude(
403 let from_crate_root = self[self.root].scope.get(name); 418 &self,
404 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 419 db: &dyn DefDatabase,
420 name: &Name,
421 ) -> PerNs {
422 let arc;
423 let crate_def_map = match self.block {
424 Some(_) => {
425 arc = self.crate_root(db).def_map(db);
426 &arc
427 }
428 None => self,
429 };
430 let from_crate_root = crate_def_map[crate_def_map.root].scope.get(name);
431 let from_extern_prelude = self.resolve_name_in_extern_prelude(db, name);
405 432
406 from_crate_root.or(from_extern_prelude) 433 from_crate_root.or(from_extern_prelude)
407 } 434 }
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index a89061c2e..543975e07 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -7,6 +7,11 @@ fn check_diagnostics(ra_fixture: &str) {
7 db.check_diagnostics(); 7 db.check_diagnostics();
8} 8}
9 9
10fn check_no_diagnostics(ra_fixture: &str) {
11 let db: TestDB = TestDB::with_files(ra_fixture);
12 db.check_no_diagnostics();
13}
14
10#[test] 15#[test]
11fn unresolved_import() { 16fn unresolved_import() {
12 check_diagnostics( 17 check_diagnostics(
@@ -165,7 +170,7 @@ fn unresolved_legacy_scope_macro() {
165 170
166 m!(); 171 m!();
167 m2!(); 172 m2!();
168 //^^^^^^ unresolved macro call 173 //^^^^^^ unresolved macro `self::m2!`
169 "#, 174 "#,
170 ); 175 );
171} 176}
@@ -182,7 +187,7 @@ fn unresolved_module_scope_macro() {
182 187
183 self::m!(); 188 self::m!();
184 self::m2!(); 189 self::m2!();
185 //^^^^^^^^^^^^ unresolved macro call 190 //^^^^^^^^^^^^ unresolved macro `self::m2!`
186 "#, 191 "#,
187 ); 192 );
188} 193}
@@ -202,6 +207,21 @@ fn builtin_macro_fails_expansion() {
202} 207}
203 208
204#[test] 209#[test]
210fn include_macro_should_allow_empty_content() {
211 check_no_diagnostics(
212 r#"
213 //- /lib.rs
214 #[rustc_builtin_macro]
215 macro_rules! include { () => {} }
216
217 include!("bar.rs");
218 //- /bar.rs
219 // empty
220 "#,
221 );
222}
223
224#[test]
205fn good_out_dir_diagnostic() { 225fn good_out_dir_diagnostic() {
206 check_diagnostics( 226 check_diagnostics(
207 r#" 227 r#"
@@ -213,7 +233,7 @@ fn good_out_dir_diagnostic() {
213 macro_rules! concat { () => {} } 233 macro_rules! concat { () => {} }
214 234
215 include!(concat!(env!("OUT_DIR"), "/out.rs")); 235 include!(concat!(env!("OUT_DIR"), "/out.rs"));
216 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 236 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
217 "#, 237 "#,
218 ); 238 );
219} 239}