aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/db.rs4
-rw-r--r--crates/hir_def/src/intern.rs8
-rw-r--r--crates/hir_def/src/nameres/collector.rs259
-rw-r--r--crates/hir_def/src/nameres/tests/macros.rs51
-rw-r--r--crates/hir_expand/src/builtin_derive.rs25
-rw-r--r--crates/hir_expand/src/builtin_macro.rs81
-rw-r--r--crates/hir_expand/src/db.rs120
-rw-r--r--crates/hir_expand/src/eager.rs32
-rw-r--r--crates/hir_expand/src/hygiene.rs34
-rw-r--r--crates/hir_expand/src/input.rs4
-rw-r--r--crates/hir_expand/src/lib.rs126
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs22
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs12
-rw-r--r--crates/hir_ty/src/infer.rs23
-rw-r--r--crates/hir_ty/src/infer/expr.rs9
-rw-r--r--crates/hir_ty/src/infer/pat.rs7
-rw-r--r--crates/hir_ty/src/tests.rs5
-rw-r--r--crates/hir_ty/src/tests/patterns.rs58
-rw-r--r--crates/ide/src/references/rename.rs12
-rw-r--r--crates/ide_assists/src/handlers/add_explicit_type.rs25
-rw-r--r--crates/ide_db/src/apply_change.rs1
-rw-r--r--crates/ide_db/src/symbol_index.rs5
-rw-r--r--crates/rust-analyzer/src/caps.rs1
-rw-r--r--crates/rust-analyzer/src/config.rs63
-rw-r--r--crates/rust-analyzer/src/handlers.rs48
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs42
-rw-r--r--crates/rust-analyzer/src/main_loop.rs2
-rw-r--r--docs/dev/lsp-extensions.md36
-rw-r--r--docs/user/generated_config.adoc10
-rw-r--r--editors/code/package.json26
30 files changed, 788 insertions, 363 deletions
diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs
index df5758342..ffc8155b9 100644
--- a/crates/hir/src/db.rs
+++ b/crates/hir/src/db.rs
@@ -2,8 +2,8 @@
2 2
3pub use hir_def::db::*; 3pub use hir_def::db::*;
4pub use hir_expand::db::{ 4pub use hir_expand::db::{
5 AstDatabase, AstDatabaseStorage, AstIdMapQuery, HygieneFrameQuery, InternEagerExpansionQuery, 5 AstDatabase, AstDatabaseStorage, AstIdMapQuery, HygieneFrameQuery, InternMacroQuery,
6 InternMacroQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroExpansionQuery, 6 MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroExpansionQuery,
7}; 7};
8pub use hir_ty::db::*; 8pub use hir_ty::db::*;
9 9
diff --git a/crates/hir_def/src/intern.rs b/crates/hir_def/src/intern.rs
index abc304ef0..5cc7f2df6 100644
--- a/crates/hir_def/src/intern.rs
+++ b/crates/hir_def/src/intern.rs
@@ -4,7 +4,7 @@
4 4
5use std::{ 5use std::{
6 collections::HashMap, 6 collections::HashMap,
7 fmt::{self, Debug}, 7 fmt::{self, Debug, Display},
8 hash::{BuildHasherDefault, Hash, Hasher}, 8 hash::{BuildHasherDefault, Hash, Hasher},
9 ops::Deref, 9 ops::Deref,
10 sync::Arc, 10 sync::Arc,
@@ -171,6 +171,12 @@ impl<T: Debug + Internable + ?Sized> Debug for Interned<T> {
171 } 171 }
172} 172}
173 173
174impl<T: Display + Internable + ?Sized> Display for Interned<T> {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 (*self.arc).fmt(f)
177 }
178}
179
174pub struct InternStorage<T: ?Sized> { 180pub struct InternStorage<T: ?Sized> {
175 map: OnceCell<InternMap<T>>, 181 map: OnceCell<InternMap<T>>,
176} 182}
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 19db6cc59..3896be25d 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -21,6 +21,7 @@ use syntax::ast;
21 21
22use crate::{ 22use crate::{
23 attr::{AttrId, Attrs}, 23 attr::{AttrId, Attrs},
24 builtin_attr,
24 db::DefDatabase, 25 db::DefDatabase,
25 derive_macro_as_call_id, 26 derive_macro_as_call_id,
26 intern::Interned, 27 intern::Interned,
@@ -42,7 +43,7 @@ use crate::{
42 UnresolvedMacro, 43 UnresolvedMacro,
43}; 44};
44 45
45use super::proc_macro::ProcMacroDef; 46use super::proc_macro::{ProcMacroDef, ProcMacroKind};
46 47
47const GLOB_RECURSION_LIMIT: usize = 100; 48const GLOB_RECURSION_LIMIT: usize = 100;
48const EXPANSION_DEPTH_LIMIT: usize = 128; 49const EXPANSION_DEPTH_LIMIT: usize = 128;
@@ -99,6 +100,8 @@ pub(super) fn collect_defs(
99 proc_macros, 100 proc_macros,
100 exports_proc_macros: false, 101 exports_proc_macros: false,
101 from_glob_import: Default::default(), 102 from_glob_import: Default::default(),
103 ignore_attrs_on: FxHashSet::default(),
104 derive_helpers_in_scope: FxHashMap::default(),
102 }; 105 };
103 match block { 106 match block {
104 Some(block) => { 107 Some(block) => {
@@ -217,6 +220,7 @@ struct MacroDirective {
217enum MacroDirectiveKind { 220enum MacroDirectiveKind {
218 FnLike { ast_id: AstIdWithPath<ast::MacroCall>, fragment: FragmentKind }, 221 FnLike { ast_id: AstIdWithPath<ast::MacroCall>, fragment: FragmentKind },
219 Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId }, 222 Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId },
223 Attr { ast_id: AstIdWithPath<ast::Item>, attr: AttrId, mod_item: ModItem },
220} 224}
221 225
222struct DefData<'a> { 226struct DefData<'a> {
@@ -243,6 +247,10 @@ struct DefCollector<'a> {
243 proc_macros: Vec<(Name, ProcMacroExpander)>, 247 proc_macros: Vec<(Name, ProcMacroExpander)>,
244 exports_proc_macros: bool, 248 exports_proc_macros: bool,
245 from_glob_import: PerNsGlobImports, 249 from_glob_import: PerNsGlobImports,
250 ignore_attrs_on: FxHashSet<InFile<ModItem>>,
251 /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
252 /// attributes.
253 derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<Name>>,
246} 254}
247 255
248impl DefCollector<'_> { 256impl DefCollector<'_> {
@@ -292,16 +300,26 @@ impl DefCollector<'_> {
292 fn collect(&mut self) { 300 fn collect(&mut self) {
293 // main name resolution fixed-point loop. 301 // main name resolution fixed-point loop.
294 let mut i = 0; 302 let mut i = 0;
295 loop { 303 'outer: loop {
296 self.db.check_canceled(); 304 loop {
297 self.resolve_imports(); 305 self.db.check_canceled();
306 loop {
307 if self.resolve_imports() == ReachedFixedPoint::Yes {
308 break;
309 }
310 }
311 if self.resolve_macros() == ReachedFixedPoint::Yes {
312 break;
313 }
298 314
299 match self.resolve_macros() { 315 i += 1;
300 ReachedFixedPoint::Yes => break, 316 if i == FIXED_POINT_LIMIT {
301 ReachedFixedPoint::No => i += 1, 317 log::error!("name resolution is stuck");
318 break 'outer;
319 }
302 } 320 }
303 if i == FIXED_POINT_LIMIT { 321
304 log::error!("name resolution is stuck"); 322 if self.reseed_with_unresolved_attributes() == ReachedFixedPoint::Yes {
305 break; 323 break;
306 } 324 }
307 } 325 }
@@ -343,6 +361,54 @@ impl DefCollector<'_> {
343 } 361 }
344 } 362 }
345 363
364 /// When the fixed-point loop reaches a stable state, we might still have some unresolved
365 /// attributes (or unexpanded attribute proc macros) left over. This takes them, and feeds the
366 /// item they're applied to back into name resolution.
367 ///
368 /// This effectively ignores the fact that the macro is there and just treats the items as
369 /// normal code.
370 ///
371 /// This improves UX when proc macros are turned off or don't work, and replicates the behavior
372 /// before we supported proc. attribute macros.
373 fn reseed_with_unresolved_attributes(&mut self) -> ReachedFixedPoint {
374 cov_mark::hit!(unresolved_attribute_fallback);
375
376 let mut added_items = false;
377 let unexpanded_macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
378 for directive in &unexpanded_macros {
379 if let MacroDirectiveKind::Attr { ast_id, mod_item, .. } = &directive.kind {
380 // Make sure to only add such items once.
381 if !self.ignore_attrs_on.insert(ast_id.ast_id.with_value(*mod_item)) {
382 continue;
383 }
384
385 let file_id = self.def_map[directive.module_id].definition_source(self.db).file_id;
386 let item_tree = self.db.file_item_tree(file_id);
387 let mod_dir = self.mod_dirs[&directive.module_id].clone();
388 ModCollector {
389 def_collector: &mut *self,
390 macro_depth: directive.depth,
391 module_id: directive.module_id,
392 file_id,
393 item_tree: &item_tree,
394 mod_dir,
395 }
396 .collect(&[*mod_item]);
397 added_items = true;
398 }
399 }
400
401 // The collection above might add new unresolved macros (eg. derives), so merge the lists.
402 self.unexpanded_macros.extend(unexpanded_macros);
403
404 if added_items {
405 // Continue name resolution with the new data.
406 ReachedFixedPoint::No
407 } else {
408 ReachedFixedPoint::Yes
409 }
410 }
411
346 /// Adds a definition of procedural macro `name` to the root module. 412 /// Adds a definition of procedural macro `name` to the root module.
347 /// 413 ///
348 /// # Notes on procedural macro resolution 414 /// # Notes on procedural macro resolution
@@ -504,35 +570,35 @@ impl DefCollector<'_> {
504 } 570 }
505 } 571 }
506 572
507 /// Import resolution 573 /// Tries to resolve every currently unresolved import.
508 /// 574 fn resolve_imports(&mut self) -> ReachedFixedPoint {
509 /// This is a fix point algorithm. We resolve imports until no forward 575 let mut res = ReachedFixedPoint::Yes;
510 /// progress in resolving imports is made 576 let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
511 fn resolve_imports(&mut self) { 577 let imports = imports
512 let mut n_previous_unresolved = self.unresolved_imports.len() + 1; 578 .into_iter()
513 579 .filter_map(|mut directive| {
514 while self.unresolved_imports.len() < n_previous_unresolved {
515 n_previous_unresolved = self.unresolved_imports.len();
516 let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
517 for mut directive in imports {
518 directive.status = self.resolve_import(directive.module_id, &directive.import); 580 directive.status = self.resolve_import(directive.module_id, &directive.import);
519 match directive.status { 581 match directive.status {
520 PartialResolvedImport::Indeterminate(_) => { 582 PartialResolvedImport::Indeterminate(_) => {
521 self.record_resolved_import(&directive); 583 self.record_resolved_import(&directive);
522 // FIXME: For avoid performance regression, 584 // FIXME: For avoid performance regression,
523 // we consider an imported resolved if it is indeterminate (i.e not all namespace resolved) 585 // we consider an imported resolved if it is indeterminate (i.e not all namespace resolved)
524 self.resolved_imports.push(directive) 586 self.resolved_imports.push(directive);
587 res = ReachedFixedPoint::No;
588 None
525 } 589 }
526 PartialResolvedImport::Resolved(_) => { 590 PartialResolvedImport::Resolved(_) => {
527 self.record_resolved_import(&directive); 591 self.record_resolved_import(&directive);
528 self.resolved_imports.push(directive) 592 self.resolved_imports.push(directive);
529 } 593 res = ReachedFixedPoint::No;
530 PartialResolvedImport::Unresolved => { 594 None
531 self.unresolved_imports.push(directive);
532 } 595 }
596 PartialResolvedImport::Unresolved => Some(directive),
533 } 597 }
534 } 598 })
535 } 599 .collect();
600 self.unresolved_imports = imports;
601 res
536 } 602 }
537 603
538 fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { 604 fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport {
@@ -811,6 +877,17 @@ impl DefCollector<'_> {
811 let mut resolved = Vec::new(); 877 let mut resolved = Vec::new();
812 let mut res = ReachedFixedPoint::Yes; 878 let mut res = ReachedFixedPoint::Yes;
813 macros.retain(|directive| { 879 macros.retain(|directive| {
880 let resolver = |path| {
881 let resolved_res = self.def_map.resolve_path_fp_with_macro(
882 self.db,
883 ResolveMode::Other,
884 directive.module_id,
885 &path,
886 BuiltinShadowMode::Module,
887 );
888 resolved_res.resolved_def.take_macros()
889 };
890
814 match &directive.kind { 891 match &directive.kind {
815 MacroDirectiveKind::FnLike { ast_id, fragment } => { 892 MacroDirectiveKind::FnLike { ast_id, fragment } => {
816 match macro_call_as_call_id( 893 match macro_call_as_call_id(
@@ -818,16 +895,7 @@ impl DefCollector<'_> {
818 *fragment, 895 *fragment,
819 self.db, 896 self.db,
820 self.def_map.krate, 897 self.def_map.krate,
821 |path| { 898 &resolver,
822 let resolved_res = self.def_map.resolve_path_fp_with_macro(
823 self.db,
824 ResolveMode::Other,
825 directive.module_id,
826 &path,
827 BuiltinShadowMode::Module,
828 );
829 resolved_res.resolved_def.take_macros()
830 },
831 &mut |_err| (), 899 &mut |_err| (),
832 ) { 900 ) {
833 Ok(Ok(call_id)) => { 901 Ok(Ok(call_id)) => {
@@ -844,7 +912,7 @@ impl DefCollector<'_> {
844 *derive_attr, 912 *derive_attr,
845 self.db, 913 self.db,
846 self.def_map.krate, 914 self.def_map.krate,
847 |path| self.resolve_derive_macro(directive.module_id, &path), 915 &resolver,
848 ) { 916 ) {
849 Ok(call_id) => { 917 Ok(call_id) => {
850 resolved.push((directive.module_id, call_id, directive.depth)); 918 resolved.push((directive.module_id, call_id, directive.depth));
@@ -854,6 +922,9 @@ impl DefCollector<'_> {
854 Err(UnresolvedMacro { .. }) => (), 922 Err(UnresolvedMacro { .. }) => (),
855 } 923 }
856 } 924 }
925 MacroDirectiveKind::Attr { .. } => {
926 // not yet :)
927 }
857 } 928 }
858 929
859 true 930 true
@@ -867,18 +938,6 @@ impl DefCollector<'_> {
867 res 938 res
868 } 939 }
869 940
870 fn resolve_derive_macro(&self, module: LocalModuleId, path: &ModPath) -> Option<MacroDefId> {
871 let resolved_res = self.def_map.resolve_path_fp_with_macro(
872 self.db,
873 ResolveMode::Other,
874 module,
875 &path,
876 BuiltinShadowMode::Module,
877 );
878
879 resolved_res.resolved_def.take_macros()
880 }
881
882 fn collect_macro_expansion( 941 fn collect_macro_expansion(
883 &mut self, 942 &mut self,
884 module_id: LocalModuleId, 943 module_id: LocalModuleId,
@@ -895,22 +954,33 @@ impl DefCollector<'_> {
895 // First, fetch the raw expansion result for purposes of error reporting. This goes through 954 // First, fetch the raw expansion result for purposes of error reporting. This goes through
896 // `macro_expand_error` to avoid depending on the full expansion result (to improve 955 // `macro_expand_error` to avoid depending on the full expansion result (to improve
897 // incrementality). 956 // incrementality).
957 let loc: MacroCallLoc = self.db.lookup_intern_macro(macro_call_id);
898 let err = self.db.macro_expand_error(macro_call_id); 958 let err = self.db.macro_expand_error(macro_call_id);
899 if let Some(err) = err { 959 if let Some(err) = err {
900 if let MacroCallId::LazyMacro(id) = macro_call_id { 960 let diag = match err {
901 let loc: MacroCallLoc = self.db.lookup_intern_macro(id); 961 hir_expand::ExpandError::UnresolvedProcMacro => {
962 // Missing proc macros are non-fatal, so they are handled specially.
963 DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone())
964 }
965 _ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()),
966 };
902 967
903 let diag = match err { 968 self.def_map.diagnostics.push(diag);
904 hir_expand::ExpandError::UnresolvedProcMacro => { 969 }
905 // Missing proc macros are non-fatal, so they are handled specially.
906 DefDiagnostic::unresolved_proc_macro(module_id, loc.kind)
907 }
908 _ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()),
909 };
910 970
911 self.def_map.diagnostics.push(diag); 971 // If we've just resolved a derive, record its helper attributes.
972 if let MacroCallKind::Derive { ast_id, .. } = &loc.kind {
973 if loc.def.krate != self.def_map.krate {
974 let def_map = self.db.crate_def_map(loc.def.krate);
975 if let Some(def) = def_map.exported_proc_macros.get(&loc.def) {
976 if let ProcMacroKind::CustomDerive { helpers } = &def.kind {
977 self.derive_helpers_in_scope
978 .entry(*ast_id)
979 .or_default()
980 .extend(helpers.iter().cloned());
981 }
982 }
912 } 983 }
913 // FIXME: Handle eager macros.
914 } 984 }
915 985
916 // Then, fetch and process the item tree. This will reuse the expansion result from above. 986 // Then, fetch and process the item tree. This will reuse the expansion result from above.
@@ -958,7 +1028,7 @@ impl DefCollector<'_> {
958 )); 1028 ));
959 } 1029 }
960 }, 1030 },
961 MacroDirectiveKind::Derive { .. } => { 1031 MacroDirectiveKind::Derive { .. } | MacroDirectiveKind::Attr { .. } => {
962 // FIXME: we might want to diagnose this too 1032 // FIXME: we might want to diagnose this too
963 } 1033 }
964 } 1034 }
@@ -1066,6 +1136,13 @@ impl ModCollector<'_, '_> {
1066 continue; 1136 continue;
1067 } 1137 }
1068 } 1138 }
1139
1140 if let Err(()) = self.resolve_attributes(&attrs, item) {
1141 // Do not process the item. It has at least one non-builtin attribute, so the
1142 // fixed-point algorithm is required to resolve the rest of them.
1143 continue;
1144 }
1145
1069 let module = self.def_collector.def_map.module_id(self.module_id); 1146 let module = self.def_collector.def_map.module_id(self.module_id);
1070 1147
1071 let mut def = None; 1148 let mut def = None;
@@ -1372,6 +1449,62 @@ impl ModCollector<'_, '_> {
1372 res 1449 res
1373 } 1450 }
1374 1451
1452 /// Resolves attributes on an item.
1453 ///
1454 /// Returns `Err` when some attributes could not be resolved to builtins and have been
1455 /// registered as unresolved.
1456 fn resolve_attributes(&mut self, attrs: &Attrs, mod_item: ModItem) -> Result<(), ()> {
1457 fn is_builtin_attr(path: &ModPath) -> bool {
1458 if path.kind == PathKind::Plain {
1459 if let Some(tool_module) = path.segments().first() {
1460 let tool_module = tool_module.to_string();
1461 if builtin_attr::TOOL_MODULES.iter().any(|m| tool_module == *m) {
1462 return true;
1463 }
1464 }
1465
1466 if let Some(name) = path.as_ident() {
1467 let name = name.to_string();
1468 if builtin_attr::INERT_ATTRIBUTES
1469 .iter()
1470 .chain(builtin_attr::EXTRA_ATTRIBUTES)
1471 .any(|attr| name == *attr)
1472 {
1473 return true;
1474 }
1475 }
1476 }
1477
1478 false
1479 }
1480
1481 // We failed to resolve an attribute on this item earlier, and are falling back to treating
1482 // the item as-is.
1483 if self.def_collector.ignore_attrs_on.contains(&InFile::new(self.file_id, mod_item)) {
1484 return Ok(());
1485 }
1486
1487 match attrs.iter().find(|attr| !is_builtin_attr(&attr.path)) {
1488 Some(non_builtin_attr) => {
1489 log::debug!("non-builtin attribute {}", non_builtin_attr.path);
1490
1491 let ast_id = AstIdWithPath::new(
1492 self.file_id,
1493 mod_item.ast_id(self.item_tree),
1494 non_builtin_attr.path.as_ref().clone(),
1495 );
1496 self.def_collector.unexpanded_macros.push(MacroDirective {
1497 module_id: self.module_id,
1498 depth: self.macro_depth + 1,
1499 kind: MacroDirectiveKind::Attr { ast_id, attr: non_builtin_attr.id, mod_item },
1500 });
1501
1502 Err(())
1503 }
1504 None => Ok(()),
1505 }
1506 }
1507
1375 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) { 1508 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) {
1376 for derive in attrs.by_key("derive").attrs() { 1509 for derive in attrs.by_key("derive").attrs() {
1377 match derive.parse_derive() { 1510 match derive.parse_derive() {
@@ -1604,6 +1737,8 @@ mod tests {
1604 proc_macros: Default::default(), 1737 proc_macros: Default::default(),
1605 exports_proc_macros: false, 1738 exports_proc_macros: false,
1606 from_glob_import: Default::default(), 1739 from_glob_import: Default::default(),
1740 ignore_attrs_on: FxHashSet::default(),
1741 derive_helpers_in_scope: FxHashMap::default(),
1607 }; 1742 };
1608 collector.seed_with_top_level(); 1743 collector.seed_with_top_level();
1609 collector.collect(); 1744 collector.collect();
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs
index c37f915ab..6eb5f97be 100644
--- a/crates/hir_def/src/nameres/tests/macros.rs
+++ b/crates/hir_def/src/nameres/tests/macros.rs
@@ -686,6 +686,56 @@ pub trait Clone {}
686} 686}
687 687
688#[test] 688#[test]
689fn builtin_derive_with_unresolved_attributes_fall_back() {
690 // Tests that we still resolve derives after ignoring an unresolved attribute.
691 cov_mark::check!(unresolved_attribute_fallback);
692 let map = compute_crate_def_map(
693 r#"
694 //- /main.rs crate:main deps:core
695 use core::Clone;
696
697 #[derive(Clone)]
698 #[unresolved]
699 struct Foo;
700
701 //- /core.rs crate:core
702 #[rustc_builtin_macro]
703 pub macro Clone {}
704 "#,
705 );
706 assert_eq!(map.modules[map.root].scope.impls().len(), 1);
707}
708
709#[test]
710fn unresolved_attributes_fall_back_track_per_file_moditems() {
711 // Tests that we track per-file ModItems when ignoring an unresolved attribute.
712 // Just tracking the `ModItem` leads to `Foo` getting ignored.
713
714 check(
715 r#"
716 //- /main.rs crate:main
717
718 mod submod;
719
720 #[unresolved]
721 struct Foo;
722
723 //- /submod.rs
724 #[unresolved]
725 struct Bar;
726 "#,
727 expect![[r#"
728 crate
729 Foo: t v
730 submod: t
731
732 crate::submod
733 Bar: t v
734 "#]],
735 );
736}
737
738#[test]
689fn macro_expansion_overflow() { 739fn macro_expansion_overflow() {
690 cov_mark::check!(macro_expansion_overflow); 740 cov_mark::check!(macro_expansion_overflow);
691 check( 741 check(
@@ -842,7 +892,6 @@ fn collects_derive_helpers() {
842fn resolve_macro_def() { 892fn resolve_macro_def() {
843 check( 893 check(
844 r#" 894 r#"
845//- /lib.rs
846pub macro structs($($i:ident),*) { 895pub macro structs($($i:ident),*) {
847 $(struct $i { field: u32 } )* 896 $(struct $i { field: u32 } )*
848} 897}
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs
index b6a6d602f..fe9497b50 100644
--- a/crates/hir_expand/src/builtin_derive.rs
+++ b/crates/hir_expand/src/builtin_derive.rs
@@ -8,7 +8,7 @@ use syntax::{
8 match_ast, 8 match_ast,
9}; 9};
10 10
11use crate::{db::AstDatabase, name, quote, AstId, CrateId, LazyMacroId, MacroDefId, MacroDefKind}; 11use crate::{db::AstDatabase, name, quote, AstId, CrateId, MacroCallId, MacroDefId, MacroDefKind};
12 12
13macro_rules! register_builtin { 13macro_rules! register_builtin {
14 ( $($trait:ident => $expand:ident),* ) => { 14 ( $($trait:ident => $expand:ident),* ) => {
@@ -21,7 +21,7 @@ macro_rules! register_builtin {
21 pub fn expand( 21 pub fn expand(
22 &self, 22 &self,
23 db: &dyn AstDatabase, 23 db: &dyn AstDatabase,
24 id: LazyMacroId, 24 id: MacroCallId,
25 tt: &tt::Subtree, 25 tt: &tt::Subtree,
26 ) -> Result<tt::Subtree, mbe::ExpandError> { 26 ) -> Result<tt::Subtree, mbe::ExpandError> {
27 let expander = match *self { 27 let expander = match *self {
@@ -164,7 +164,7 @@ fn expand_simple_derive(
164 Ok(expanded) 164 Ok(expanded)
165} 165}
166 166
167fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { 167fn find_builtin_crate(db: &dyn AstDatabase, id: MacroCallId) -> tt::TokenTree {
168 // FIXME: make hygiene works for builtin derive macro 168 // FIXME: make hygiene works for builtin derive macro
169 // such that $crate can be used here. 169 // such that $crate can be used here.
170 let cg = db.crate_graph(); 170 let cg = db.crate_graph();
@@ -184,7 +184,7 @@ fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree {
184 184
185fn copy_expand( 185fn copy_expand(
186 db: &dyn AstDatabase, 186 db: &dyn AstDatabase,
187 id: LazyMacroId, 187 id: MacroCallId,
188 tt: &tt::Subtree, 188 tt: &tt::Subtree,
189) -> Result<tt::Subtree, mbe::ExpandError> { 189) -> Result<tt::Subtree, mbe::ExpandError> {
190 let krate = find_builtin_crate(db, id); 190 let krate = find_builtin_crate(db, id);
@@ -193,7 +193,7 @@ fn copy_expand(
193 193
194fn clone_expand( 194fn clone_expand(
195 db: &dyn AstDatabase, 195 db: &dyn AstDatabase,
196 id: LazyMacroId, 196 id: MacroCallId,
197 tt: &tt::Subtree, 197 tt: &tt::Subtree,
198) -> Result<tt::Subtree, mbe::ExpandError> { 198) -> Result<tt::Subtree, mbe::ExpandError> {
199 let krate = find_builtin_crate(db, id); 199 let krate = find_builtin_crate(db, id);
@@ -202,7 +202,7 @@ fn clone_expand(
202 202
203fn default_expand( 203fn default_expand(
204 db: &dyn AstDatabase, 204 db: &dyn AstDatabase,
205 id: LazyMacroId, 205 id: MacroCallId,
206 tt: &tt::Subtree, 206 tt: &tt::Subtree,
207) -> Result<tt::Subtree, mbe::ExpandError> { 207) -> Result<tt::Subtree, mbe::ExpandError> {
208 let krate = find_builtin_crate(db, id); 208 let krate = find_builtin_crate(db, id);
@@ -211,7 +211,7 @@ fn default_expand(
211 211
212fn debug_expand( 212fn debug_expand(
213 db: &dyn AstDatabase, 213 db: &dyn AstDatabase,
214 id: LazyMacroId, 214 id: MacroCallId,
215 tt: &tt::Subtree, 215 tt: &tt::Subtree,
216) -> Result<tt::Subtree, mbe::ExpandError> { 216) -> Result<tt::Subtree, mbe::ExpandError> {
217 let krate = find_builtin_crate(db, id); 217 let krate = find_builtin_crate(db, id);
@@ -220,7 +220,7 @@ fn debug_expand(
220 220
221fn hash_expand( 221fn hash_expand(
222 db: &dyn AstDatabase, 222 db: &dyn AstDatabase,
223 id: LazyMacroId, 223 id: MacroCallId,
224 tt: &tt::Subtree, 224 tt: &tt::Subtree,
225) -> Result<tt::Subtree, mbe::ExpandError> { 225) -> Result<tt::Subtree, mbe::ExpandError> {
226 let krate = find_builtin_crate(db, id); 226 let krate = find_builtin_crate(db, id);
@@ -229,7 +229,7 @@ fn hash_expand(
229 229
230fn eq_expand( 230fn eq_expand(
231 db: &dyn AstDatabase, 231 db: &dyn AstDatabase,
232 id: LazyMacroId, 232 id: MacroCallId,
233 tt: &tt::Subtree, 233 tt: &tt::Subtree,
234) -> Result<tt::Subtree, mbe::ExpandError> { 234) -> Result<tt::Subtree, mbe::ExpandError> {
235 let krate = find_builtin_crate(db, id); 235 let krate = find_builtin_crate(db, id);
@@ -238,7 +238,7 @@ fn eq_expand(
238 238
239fn partial_eq_expand( 239fn partial_eq_expand(
240 db: &dyn AstDatabase, 240 db: &dyn AstDatabase,
241 id: LazyMacroId, 241 id: MacroCallId,
242 tt: &tt::Subtree, 242 tt: &tt::Subtree,
243) -> Result<tt::Subtree, mbe::ExpandError> { 243) -> Result<tt::Subtree, mbe::ExpandError> {
244 let krate = find_builtin_crate(db, id); 244 let krate = find_builtin_crate(db, id);
@@ -247,7 +247,7 @@ fn partial_eq_expand(
247 247
248fn ord_expand( 248fn ord_expand(
249 db: &dyn AstDatabase, 249 db: &dyn AstDatabase,
250 id: LazyMacroId, 250 id: MacroCallId,
251 tt: &tt::Subtree, 251 tt: &tt::Subtree,
252) -> Result<tt::Subtree, mbe::ExpandError> { 252) -> Result<tt::Subtree, mbe::ExpandError> {
253 let krate = find_builtin_crate(db, id); 253 let krate = find_builtin_crate(db, id);
@@ -256,7 +256,7 @@ fn ord_expand(
256 256
257fn partial_ord_expand( 257fn partial_ord_expand(
258 db: &dyn AstDatabase, 258 db: &dyn AstDatabase,
259 id: LazyMacroId, 259 id: MacroCallId,
260 tt: &tt::Subtree, 260 tt: &tt::Subtree,
261) -> Result<tt::Subtree, mbe::ExpandError> { 261) -> Result<tt::Subtree, mbe::ExpandError> {
262 let krate = find_builtin_crate(db, id); 262 let krate = find_builtin_crate(db, id);
@@ -317,6 +317,7 @@ $0
317 local_inner: false, 317 local_inner: false,
318 }, 318 },
319 krate: CrateId(0), 319 krate: CrateId(0),
320 eager: None,
320 kind: MacroCallKind::Derive { 321 kind: MacroCallKind::Derive {
321 ast_id, 322 ast_id,
322 derive_name: name.to_string(), 323 derive_name: name.to_string(),
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 280c25f11..94d7aecb6 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -1,7 +1,7 @@
1//! Builtin macro 1//! Builtin macro
2use crate::{ 2use crate::{
3 db::AstDatabase, name, quote, AstId, CrateId, EagerMacroId, LazyMacroId, MacroCallId, 3 db::AstDatabase, name, quote, AstId, CrateId, MacroCallId, MacroCallLoc, MacroDefId,
4 MacroCallLoc, MacroDefId, MacroDefKind, TextSize, 4 MacroDefKind, TextSize,
5}; 5};
6 6
7use base_db::{AnchoredPath, Edition, FileId}; 7use base_db::{AnchoredPath, Edition, FileId};
@@ -27,7 +27,7 @@ macro_rules! register_builtin {
27 pub fn expand( 27 pub fn expand(
28 &self, 28 &self,
29 db: &dyn AstDatabase, 29 db: &dyn AstDatabase,
30 id: LazyMacroId, 30 id: MacroCallId,
31 tt: &tt::Subtree, 31 tt: &tt::Subtree,
32 ) -> ExpandResult<tt::Subtree> { 32 ) -> ExpandResult<tt::Subtree> {
33 let expander = match *self { 33 let expander = match *self {
@@ -41,7 +41,7 @@ macro_rules! register_builtin {
41 pub fn expand( 41 pub fn expand(
42 &self, 42 &self,
43 db: &dyn AstDatabase, 43 db: &dyn AstDatabase,
44 arg_id: EagerMacroId, 44 arg_id: MacroCallId,
45 tt: &tt::Subtree, 45 tt: &tt::Subtree,
46 ) -> ExpandResult<Option<ExpandedEager>> { 46 ) -> ExpandResult<Option<ExpandedEager>> {
47 let expander = match *self { 47 let expander = match *self {
@@ -128,7 +128,7 @@ register_builtin! {
128 128
129fn module_path_expand( 129fn module_path_expand(
130 _db: &dyn AstDatabase, 130 _db: &dyn AstDatabase,
131 _id: LazyMacroId, 131 _id: MacroCallId,
132 _tt: &tt::Subtree, 132 _tt: &tt::Subtree,
133) -> ExpandResult<tt::Subtree> { 133) -> ExpandResult<tt::Subtree> {
134 // Just return a dummy result. 134 // Just return a dummy result.
@@ -137,7 +137,7 @@ fn module_path_expand(
137 137
138fn line_expand( 138fn line_expand(
139 _db: &dyn AstDatabase, 139 _db: &dyn AstDatabase,
140 _id: LazyMacroId, 140 _id: MacroCallId,
141 _tt: &tt::Subtree, 141 _tt: &tt::Subtree,
142) -> ExpandResult<tt::Subtree> { 142) -> ExpandResult<tt::Subtree> {
143 // dummy implementation for type-checking purposes 143 // dummy implementation for type-checking purposes
@@ -151,7 +151,7 @@ fn line_expand(
151 151
152fn stringify_expand( 152fn stringify_expand(
153 db: &dyn AstDatabase, 153 db: &dyn AstDatabase,
154 id: LazyMacroId, 154 id: MacroCallId,
155 _tt: &tt::Subtree, 155 _tt: &tt::Subtree,
156) -> ExpandResult<tt::Subtree> { 156) -> ExpandResult<tt::Subtree> {
157 let loc = db.lookup_intern_macro(id); 157 let loc = db.lookup_intern_macro(id);
@@ -176,7 +176,7 @@ fn stringify_expand(
176 176
177fn column_expand( 177fn column_expand(
178 _db: &dyn AstDatabase, 178 _db: &dyn AstDatabase,
179 _id: LazyMacroId, 179 _id: MacroCallId,
180 _tt: &tt::Subtree, 180 _tt: &tt::Subtree,
181) -> ExpandResult<tt::Subtree> { 181) -> ExpandResult<tt::Subtree> {
182 // dummy implementation for type-checking purposes 182 // dummy implementation for type-checking purposes
@@ -190,7 +190,7 @@ fn column_expand(
190 190
191fn assert_expand( 191fn assert_expand(
192 _db: &dyn AstDatabase, 192 _db: &dyn AstDatabase,
193 _id: LazyMacroId, 193 _id: MacroCallId,
194 tt: &tt::Subtree, 194 tt: &tt::Subtree,
195) -> ExpandResult<tt::Subtree> { 195) -> ExpandResult<tt::Subtree> {
196 // A hacky implementation for goto def and hover 196 // A hacky implementation for goto def and hover
@@ -214,7 +214,7 @@ fn assert_expand(
214 214
215fn file_expand( 215fn file_expand(
216 _db: &dyn AstDatabase, 216 _db: &dyn AstDatabase,
217 _id: LazyMacroId, 217 _id: MacroCallId,
218 _tt: &tt::Subtree, 218 _tt: &tt::Subtree,
219) -> ExpandResult<tt::Subtree> { 219) -> ExpandResult<tt::Subtree> {
220 // FIXME: RA purposefully lacks knowledge of absolute file names 220 // FIXME: RA purposefully lacks knowledge of absolute file names
@@ -230,7 +230,7 @@ fn file_expand(
230 230
231fn format_args_expand( 231fn format_args_expand(
232 _db: &dyn AstDatabase, 232 _db: &dyn AstDatabase,
233 _id: LazyMacroId, 233 _id: MacroCallId,
234 tt: &tt::Subtree, 234 tt: &tt::Subtree,
235) -> ExpandResult<tt::Subtree> { 235) -> ExpandResult<tt::Subtree> {
236 // We expand `format_args!("", a1, a2)` to 236 // We expand `format_args!("", a1, a2)` to
@@ -265,7 +265,7 @@ fn format_args_expand(
265 265
266fn asm_expand( 266fn asm_expand(
267 _db: &dyn AstDatabase, 267 _db: &dyn AstDatabase,
268 _id: LazyMacroId, 268 _id: MacroCallId,
269 _tt: &tt::Subtree, 269 _tt: &tt::Subtree,
270) -> ExpandResult<tt::Subtree> { 270) -> ExpandResult<tt::Subtree> {
271 // both asm and llvm_asm don't return anything, so we can expand them to nothing, 271 // both asm and llvm_asm don't return anything, so we can expand them to nothing,
@@ -278,7 +278,7 @@ fn asm_expand(
278 278
279fn global_asm_expand( 279fn global_asm_expand(
280 _db: &dyn AstDatabase, 280 _db: &dyn AstDatabase,
281 _id: LazyMacroId, 281 _id: MacroCallId,
282 _tt: &tt::Subtree, 282 _tt: &tt::Subtree,
283) -> ExpandResult<tt::Subtree> { 283) -> ExpandResult<tt::Subtree> {
284 // Expand to nothing (at item-level) 284 // Expand to nothing (at item-level)
@@ -287,7 +287,7 @@ fn global_asm_expand(
287 287
288fn cfg_expand( 288fn cfg_expand(
289 db: &dyn AstDatabase, 289 db: &dyn AstDatabase,
290 id: LazyMacroId, 290 id: MacroCallId,
291 tt: &tt::Subtree, 291 tt: &tt::Subtree,
292) -> ExpandResult<tt::Subtree> { 292) -> ExpandResult<tt::Subtree> {
293 let loc = db.lookup_intern_macro(id); 293 let loc = db.lookup_intern_macro(id);
@@ -299,7 +299,7 @@ fn cfg_expand(
299 299
300fn panic_expand( 300fn panic_expand(
301 db: &dyn AstDatabase, 301 db: &dyn AstDatabase,
302 id: LazyMacroId, 302 id: MacroCallId,
303 tt: &tt::Subtree, 303 tt: &tt::Subtree,
304) -> ExpandResult<tt::Subtree> { 304) -> ExpandResult<tt::Subtree> {
305 let loc: MacroCallLoc = db.lookup_intern_macro(id); 305 let loc: MacroCallLoc = db.lookup_intern_macro(id);
@@ -324,7 +324,7 @@ fn unquote_str(lit: &tt::Literal) -> Option<String> {
324 324
325fn compile_error_expand( 325fn compile_error_expand(
326 _db: &dyn AstDatabase, 326 _db: &dyn AstDatabase,
327 _id: EagerMacroId, 327 _id: MacroCallId,
328 tt: &tt::Subtree, 328 tt: &tt::Subtree,
329) -> ExpandResult<Option<ExpandedEager>> { 329) -> ExpandResult<Option<ExpandedEager>> {
330 let err = match &*tt.token_trees { 330 let err = match &*tt.token_trees {
@@ -345,7 +345,7 @@ fn compile_error_expand(
345 345
346fn concat_expand( 346fn concat_expand(
347 _db: &dyn AstDatabase, 347 _db: &dyn AstDatabase,
348 _arg_id: EagerMacroId, 348 _arg_id: MacroCallId,
349 tt: &tt::Subtree, 349 tt: &tt::Subtree,
350) -> ExpandResult<Option<ExpandedEager>> { 350) -> ExpandResult<Option<ExpandedEager>> {
351 let mut err = None; 351 let mut err = None;
@@ -376,7 +376,7 @@ fn concat_expand(
376 376
377fn concat_idents_expand( 377fn concat_idents_expand(
378 _db: &dyn AstDatabase, 378 _db: &dyn AstDatabase,
379 _arg_id: EagerMacroId, 379 _arg_id: MacroCallId,
380 tt: &tt::Subtree, 380 tt: &tt::Subtree,
381) -> ExpandResult<Option<ExpandedEager>> { 381) -> ExpandResult<Option<ExpandedEager>> {
382 let mut err = None; 382 let mut err = None;
@@ -427,7 +427,7 @@ fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> {
427 427
428fn include_expand( 428fn include_expand(
429 db: &dyn AstDatabase, 429 db: &dyn AstDatabase,
430 arg_id: EagerMacroId, 430 arg_id: MacroCallId,
431 tt: &tt::Subtree, 431 tt: &tt::Subtree,
432) -> ExpandResult<Option<ExpandedEager>> { 432) -> ExpandResult<Option<ExpandedEager>> {
433 let res = (|| { 433 let res = (|| {
@@ -457,7 +457,7 @@ fn include_expand(
457 457
458fn include_bytes_expand( 458fn include_bytes_expand(
459 _db: &dyn AstDatabase, 459 _db: &dyn AstDatabase,
460 _arg_id: EagerMacroId, 460 _arg_id: MacroCallId,
461 tt: &tt::Subtree, 461 tt: &tt::Subtree,
462) -> ExpandResult<Option<ExpandedEager>> { 462) -> ExpandResult<Option<ExpandedEager>> {
463 if let Err(e) = parse_string(tt) { 463 if let Err(e) = parse_string(tt) {
@@ -477,7 +477,7 @@ fn include_bytes_expand(
477 477
478fn include_str_expand( 478fn include_str_expand(
479 db: &dyn AstDatabase, 479 db: &dyn AstDatabase,
480 arg_id: EagerMacroId, 480 arg_id: MacroCallId,
481 tt: &tt::Subtree, 481 tt: &tt::Subtree,
482) -> ExpandResult<Option<ExpandedEager>> { 482) -> ExpandResult<Option<ExpandedEager>> {
483 let path = match parse_string(tt) { 483 let path = match parse_string(tt) {
@@ -502,14 +502,14 @@ fn include_str_expand(
502 ExpandResult::ok(Some(ExpandedEager::new(quote!(#text), FragmentKind::Expr))) 502 ExpandResult::ok(Some(ExpandedEager::new(quote!(#text), FragmentKind::Expr)))
503} 503}
504 504
505fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { 505fn get_env_inner(db: &dyn AstDatabase, arg_id: MacroCallId, key: &str) -> Option<String> {
506 let krate = db.lookup_intern_eager_expansion(arg_id).krate; 506 let krate = db.lookup_intern_macro(arg_id).krate;
507 db.crate_graph()[krate].env.get(key) 507 db.crate_graph()[krate].env.get(key)
508} 508}
509 509
510fn env_expand( 510fn env_expand(
511 db: &dyn AstDatabase, 511 db: &dyn AstDatabase,
512 arg_id: EagerMacroId, 512 arg_id: MacroCallId,
513 tt: &tt::Subtree, 513 tt: &tt::Subtree,
514) -> ExpandResult<Option<ExpandedEager>> { 514) -> ExpandResult<Option<ExpandedEager>> {
515 let key = match parse_string(tt) { 515 let key = match parse_string(tt) {
@@ -540,7 +540,7 @@ fn env_expand(
540 540
541fn option_env_expand( 541fn option_env_expand(
542 db: &dyn AstDatabase, 542 db: &dyn AstDatabase,
543 arg_id: EagerMacroId, 543 arg_id: MacroCallId,
544 tt: &tt::Subtree, 544 tt: &tt::Subtree,
545) -> ExpandResult<Option<ExpandedEager>> { 545) -> ExpandResult<Option<ExpandedEager>> {
546 let key = match parse_string(tt) { 546 let key = match parse_string(tt) {
@@ -560,7 +560,7 @@ fn option_env_expand(
560mod tests { 560mod tests {
561 use super::*; 561 use super::*;
562 use crate::{ 562 use crate::{
563 name::AsName, test_db::TestDB, AstNode, EagerCallLoc, MacroCallId, MacroCallKind, 563 name::AsName, test_db::TestDB, AstNode, EagerCallInfo, MacroCallId, MacroCallKind,
564 MacroCallLoc, 564 MacroCallLoc,
565 }; 565 };
566 use base_db::{fixture::WithFixture, SourceDatabase}; 566 use base_db::{fixture::WithFixture, SourceDatabase};
@@ -599,6 +599,7 @@ mod tests {
599 let loc = MacroCallLoc { 599 let loc = MacroCallLoc {
600 def, 600 def,
601 krate, 601 krate,
602 eager: None,
602 kind: MacroCallKind::FnLike { 603 kind: MacroCallKind::FnLike {
603 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_call)), 604 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_call)),
604 fragment: FragmentKind::Expr, 605 fragment: FragmentKind::Expr,
@@ -620,28 +621,28 @@ mod tests {
620 let parsed_args = mbe::ast_to_token_tree(&args).0; 621 let parsed_args = mbe::ast_to_token_tree(&args).0;
621 let call_id = AstId::new(file_id.into(), ast_id_map.ast_id(&macro_call)); 622 let call_id = AstId::new(file_id.into(), ast_id_map.ast_id(&macro_call));
622 623
623 let arg_id = db.intern_eager_expansion({ 624 let arg_id = db.intern_macro(MacroCallLoc {
624 EagerCallLoc { 625 def,
625 def, 626 krate,
626 fragment: FragmentKind::Expr, 627 eager: Some(EagerCallInfo {
627 subtree: Arc::new(parsed_args.clone()), 628 arg_or_expansion: Arc::new(parsed_args.clone()),
628 krate,
629 call: call_id,
630 included_file: None, 629 included_file: None,
631 } 630 }),
631 kind: MacroCallKind::FnLike { ast_id: call_id, fragment: FragmentKind::Expr },
632 }); 632 });
633 633
634 let expanded = expander.expand(&db, arg_id, &parsed_args).value.unwrap(); 634 let expanded = expander.expand(&db, arg_id, &parsed_args).value.unwrap();
635 let eager = EagerCallLoc { 635 let loc = MacroCallLoc {
636 def, 636 def,
637 fragment: expanded.fragment,
638 subtree: Arc::new(expanded.subtree),
639 krate, 637 krate,
640 call: call_id, 638 eager: Some(EagerCallInfo {
641 included_file: expanded.included_file, 639 arg_or_expansion: Arc::new(expanded.subtree),
640 included_file: expanded.included_file,
641 }),
642 kind: MacroCallKind::FnLike { ast_id: call_id, fragment: expanded.fragment },
642 }; 643 };
643 644
644 let id: MacroCallId = db.intern_eager_expansion(eager).into(); 645 let id: MacroCallId = db.intern_macro(loc).into();
645 id.as_file() 646 id.as_file()
646 } 647 }
647 }; 648 };
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index c43d382ad..5c769c1bf 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -13,8 +13,8 @@ use syntax::{
13 13
14use crate::{ 14use crate::{
15 ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinDeriveExpander, 15 ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinDeriveExpander,
16 BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, HirFileId, HirFileIdRepr, LazyMacroId, 16 BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, MacroDefId,
17 MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, 17 MacroDefKind, MacroFile, ProcMacroExpander,
18}; 18};
19 19
20/// Total limit on the number of tokens produced by any macro invocation. 20/// Total limit on the number of tokens produced by any macro invocation.
@@ -41,7 +41,7 @@ impl TokenExpander {
41 fn expand( 41 fn expand(
42 &self, 42 &self,
43 db: &dyn AstDatabase, 43 db: &dyn AstDatabase,
44 id: LazyMacroId, 44 id: MacroCallId,
45 tt: &tt::Subtree, 45 tt: &tt::Subtree,
46 ) -> mbe::ExpandResult<tt::Subtree> { 46 ) -> mbe::ExpandResult<tt::Subtree> {
47 match self { 47 match self {
@@ -101,11 +101,7 @@ pub trait AstDatabase: SourceDatabase {
101 /// We encode macro definitions into ids of macro calls, this what allows us 101 /// We encode macro definitions into ids of macro calls, this what allows us
102 /// to be incremental. 102 /// to be incremental.
103 #[salsa::interned] 103 #[salsa::interned]
104 fn intern_macro(&self, macro_call: MacroCallLoc) -> LazyMacroId; 104 fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId;
105 /// Certain built-in macros are eager (`format!(concat!("file: ", file!(), "{}"")), 92`).
106 /// For them, we actually want to encode the whole token tree as an argument.
107 #[salsa::interned]
108 fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId;
109 105
110 /// Lowers syntactic macro call to a token tree representation. 106 /// Lowers syntactic macro call to a token tree representation.
111 #[salsa::transparent] 107 #[salsa::transparent]
@@ -146,17 +142,12 @@ pub fn expand_hypothetical(
146 token_to_map.text_range().checked_sub(hypothetical_args.syntax().text_range().start())?; 142 token_to_map.text_range().checked_sub(hypothetical_args.syntax().text_range().start())?;
147 let token_id = tmap_1.token_by_range(range)?; 143 let token_id = tmap_1.token_by_range(range)?;
148 144
149 let lazy_id = match actual_macro_call {
150 MacroCallId::LazyMacro(id) => id,
151 MacroCallId::EagerMacro(_) => return None,
152 };
153
154 let macro_def = { 145 let macro_def = {
155 let loc = db.lookup_intern_macro(lazy_id); 146 let loc: MacroCallLoc = db.lookup_intern_macro(actual_macro_call);
156 db.macro_def(loc.def)? 147 db.macro_def(loc.def)?
157 }; 148 };
158 149
159 let hypothetical_expansion = macro_def.expand(db, lazy_id, &tt); 150 let hypothetical_expansion = macro_def.expand(db, actual_macro_call, &tt);
160 151
161 let fragment_kind = macro_fragment_kind(db, actual_macro_call); 152 let fragment_kind = macro_fragment_kind(db, actual_macro_call);
162 153
@@ -194,30 +185,22 @@ fn parse_macro_expansion(
194 // Note: 185 // Note:
195 // The final goal we would like to make all parse_macro success, 186 // The final goal we would like to make all parse_macro success,
196 // such that the following log will not call anyway. 187 // such that the following log will not call anyway.
197 match macro_file.macro_call_id { 188 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
198 MacroCallId::LazyMacro(id) => { 189 let node = loc.kind.node(db);
199 let loc: MacroCallLoc = db.lookup_intern_macro(id); 190
200 let node = loc.kind.node(db); 191 // collect parent information for warning log
201 192 let parents =
202 // collect parent information for warning log 193 std::iter::successors(loc.kind.file_id().call_node(db), |it| it.file_id.call_node(db))
203 let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| {
204 it.file_id.call_node(db)
205 })
206 .map(|n| format!("{:#}", n.value)) 194 .map(|n| format!("{:#}", n.value))
207 .collect::<Vec<_>>() 195 .collect::<Vec<_>>()
208 .join("\n"); 196 .join("\n");
209 197
210 log::warn!( 198 log::warn!(
211 "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}", 199 "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}",
212 err, 200 err,
213 node.value, 201 node.value,
214 parents 202 parents
215 ); 203 );
216 }
217 _ => {
218 log::warn!("fail on macro_parse: (reason: {:?})", err);
219 }
220 }
221 } 204 }
222 let tt = match result.value { 205 let tt = match result.value {
223 Some(tt) => tt, 206 Some(tt) => tt,
@@ -269,25 +252,16 @@ fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree,
269 let arg = db.macro_arg_text(id)?; 252 let arg = db.macro_arg_text(id)?;
270 let (mut tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg)); 253 let (mut tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg));
271 254
272 if let MacroCallId::LazyMacro(id) = id { 255 let loc: MacroCallLoc = db.lookup_intern_macro(id);
273 let loc: MacroCallLoc = db.lookup_intern_macro(id); 256 if loc.def.is_proc_macro() {
274 if loc.def.is_proc_macro() { 257 // proc macros expect their inputs without parentheses, MBEs expect it with them included
275 // proc macros expect their inputs without parentheses, MBEs expect it with them included 258 tt.delimiter = None;
276 tt.delimiter = None;
277 }
278 } 259 }
279 260
280 Some(Arc::new((tt, tmap))) 261 Some(Arc::new((tt, tmap)))
281} 262}
282 263
283fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { 264fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
284 let id = match id {
285 MacroCallId::LazyMacro(id) => id,
286 MacroCallId::EagerMacro(_id) => {
287 // FIXME: support macro_arg for eager macro
288 return None;
289 }
290 };
291 let loc = db.lookup_intern_macro(id); 265 let loc = db.lookup_intern_macro(id);
292 let arg = loc.kind.arg(db)?; 266 let arg = loc.kind.arg(db)?;
293 let arg = process_macro_input(db, arg, id); 267 let arg = process_macro_input(db, arg, id);
@@ -347,24 +321,21 @@ fn macro_expand_with_arg(
347 arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, 321 arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>,
348) -> ExpandResult<Option<Arc<tt::Subtree>>> { 322) -> ExpandResult<Option<Arc<tt::Subtree>>> {
349 let _p = profile::span("macro_expand"); 323 let _p = profile::span("macro_expand");
350 let lazy_id = match id { 324 let loc: MacroCallLoc = db.lookup_intern_macro(id);
351 MacroCallId::LazyMacro(id) => id, 325 if let Some(eager) = &loc.eager {
352 MacroCallId::EagerMacro(id) => { 326 if arg.is_some() {
353 if arg.is_some() { 327 return ExpandResult::str_err(
354 return ExpandResult::str_err( 328 "hypothetical macro expansion not implemented for eager macro".to_owned(),
355 "hypothetical macro expansion not implemented for eager macro".to_owned(), 329 );
356 ); 330 } else {
357 } else { 331 return ExpandResult {
358 return ExpandResult { 332 value: Some(eager.arg_or_expansion.clone()),
359 value: Some(db.lookup_intern_eager_expansion(id).subtree), 333 // FIXME: There could be errors here!
360 // FIXME: There could be errors here! 334 err: None,
361 err: None, 335 };
362 };
363 }
364 } 336 }
365 }; 337 }
366 338
367 let loc = db.lookup_intern_macro(lazy_id);
368 let macro_arg = match arg.or_else(|| db.macro_arg(id)) { 339 let macro_arg = match arg.or_else(|| db.macro_arg(id)) {
369 Some(it) => it, 340 Some(it) => it,
370 None => return ExpandResult::str_err("Fail to args in to tt::TokenTree".into()), 341 None => return ExpandResult::str_err("Fail to args in to tt::TokenTree".into()),
@@ -374,7 +345,7 @@ fn macro_expand_with_arg(
374 Some(it) => it, 345 Some(it) => it,
375 None => return ExpandResult::str_err("Fail to find macro definition".into()), 346 None => return ExpandResult::str_err("Fail to find macro definition".into()),
376 }; 347 };
377 let ExpandResult { value: tt, err } = macro_rules.expand(db, lazy_id, &macro_arg.0); 348 let ExpandResult { value: tt, err } = macro_rules.expand(db, id, &macro_arg.0);
378 // Set a hard limit for the expanded tt 349 // Set a hard limit for the expanded tt
379 let count = tt.count(); 350 let count = tt.count();
380 if count > TOKEN_LIMIT { 351 if count > TOKEN_LIMIT {
@@ -391,12 +362,7 @@ fn expand_proc_macro(
391 db: &dyn AstDatabase, 362 db: &dyn AstDatabase,
392 id: MacroCallId, 363 id: MacroCallId,
393) -> Result<tt::Subtree, mbe::ExpandError> { 364) -> Result<tt::Subtree, mbe::ExpandError> {
394 let lazy_id = match id { 365 let loc: MacroCallLoc = db.lookup_intern_macro(id);
395 MacroCallId::LazyMacro(id) => id,
396 MacroCallId::EagerMacro(_) => unreachable!(),
397 };
398
399 let loc = db.lookup_intern_macro(lazy_id);
400 let macro_arg = match db.macro_arg(id) { 366 let macro_arg = match db.macro_arg(id) {
401 Some(it) => it, 367 Some(it) => it,
402 None => { 368 None => {
@@ -436,14 +402,6 @@ fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame>
436} 402}
437 403
438fn macro_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { 404fn macro_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
439 match id { 405 let loc: MacroCallLoc = db.lookup_intern_macro(id);
440 MacroCallId::LazyMacro(id) => { 406 loc.kind.fragment_kind()
441 let loc: MacroCallLoc = db.lookup_intern_macro(id);
442 loc.kind.fragment_kind()
443 }
444 MacroCallId::EagerMacro(id) => {
445 let loc: EagerCallLoc = db.lookup_intern_eager_expansion(id);
446 loc.fragment
447 }
448 }
449} 407}
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index 85491fe8b..e165b9c5f 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -22,7 +22,7 @@
22use crate::{ 22use crate::{
23 ast::{self, AstNode}, 23 ast::{self, AstNode},
24 db::AstDatabase, 24 db::AstDatabase,
25 EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 25 EagerCallInfo, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
26}; 26};
27 27
28use base_db::CrateId; 28use base_db::CrateId;
@@ -105,7 +105,7 @@ pub fn expand_eager_macro(
105 def: MacroDefId, 105 def: MacroDefId,
106 resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, 106 resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
107 mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError), 107 mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError),
108) -> Result<EagerMacroId, ErrorEmitted> { 108) -> Result<MacroCallId, ErrorEmitted> {
109 let parsed_args = diagnostic_sink.option_with( 109 let parsed_args = diagnostic_sink.option_with(
110 || Some(mbe::ast_to_token_tree(&macro_call.value.token_tree()?).0), 110 || Some(mbe::ast_to_token_tree(&macro_call.value.token_tree()?).0),
111 || err("malformed macro invocation"), 111 || err("malformed macro invocation"),
@@ -118,15 +118,14 @@ pub fn expand_eager_macro(
118 // When `lazy_expand` is called, its *parent* file must be already exists. 118 // When `lazy_expand` is called, its *parent* file must be already exists.
119 // Here we store an eager macro id for the argument expanded subtree here 119 // Here we store an eager macro id for the argument expanded subtree here
120 // for that purpose. 120 // for that purpose.
121 let arg_id = db.intern_eager_expansion({ 121 let arg_id = db.intern_macro(MacroCallLoc {
122 EagerCallLoc { 122 def,
123 def, 123 krate,
124 fragment: FragmentKind::Expr, 124 eager: Some(EagerCallInfo {
125 subtree: Arc::new(parsed_args.clone()), 125 arg_or_expansion: Arc::new(parsed_args.clone()),
126 krate,
127 call: call_id,
128 included_file: None, 126 included_file: None,
129 } 127 }),
128 kind: MacroCallKind::FnLike { ast_id: call_id, fragment: FragmentKind::Expr },
130 }); 129 });
131 let arg_file_id: MacroCallId = arg_id.into(); 130 let arg_file_id: MacroCallId = arg_id.into();
132 131
@@ -146,16 +145,17 @@ pub fn expand_eager_macro(
146 let res = eager.expand(db, arg_id, &subtree); 145 let res = eager.expand(db, arg_id, &subtree);
147 146
148 let expanded = diagnostic_sink.expand_result_option(res)?; 147 let expanded = diagnostic_sink.expand_result_option(res)?;
149 let eager = EagerCallLoc { 148 let loc = MacroCallLoc {
150 def, 149 def,
151 fragment: expanded.fragment,
152 subtree: Arc::new(expanded.subtree),
153 krate, 150 krate,
154 call: call_id, 151 eager: Some(EagerCallInfo {
155 included_file: expanded.included_file, 152 arg_or_expansion: Arc::new(expanded.subtree),
153 included_file: expanded.included_file,
154 }),
155 kind: MacroCallKind::FnLike { ast_id: call_id, fragment: expanded.fragment },
156 }; 156 };
157 157
158 Ok(db.intern_eager_expansion(eager)) 158 Ok(db.intern_macro(loc))
159 } else { 159 } else {
160 panic!("called `expand_eager_macro` on non-eager macro def {:?}", def); 160 panic!("called `expand_eager_macro` on non-eager macro def {:?}", def);
161 } 161 }
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index aca69e35a..38e09fdd4 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -14,7 +14,7 @@ use syntax::{ast, AstNode, SyntaxNode, TextRange, TextSize};
14use crate::{ 14use crate::{
15 db::{self, AstDatabase}, 15 db::{self, AstDatabase},
16 name::{AsName, Name}, 16 name::{AsName, Name},
17 HirFileId, HirFileIdRepr, InFile, MacroCallId, MacroCallLoc, MacroDefKind, MacroFile, 17 HirFileId, HirFileIdRepr, InFile, MacroCallLoc, MacroDefKind, MacroFile,
18}; 18};
19 19
20#[derive(Clone, Debug)] 20#[derive(Clone, Debug)]
@@ -140,10 +140,7 @@ impl HygieneInfo {
140 let (token_id, origin) = self.macro_def.map_id_up(token_id); 140 let (token_id, origin) = self.macro_def.map_id_up(token_id);
141 let (token_map, tt) = match origin { 141 let (token_map, tt) = match origin {
142 mbe::Origin::Call => { 142 mbe::Origin::Call => {
143 let call_id = match self.file.macro_call_id { 143 let call_id = self.file.macro_call_id;
144 MacroCallId::LazyMacro(lazy) => lazy,
145 MacroCallId::EagerMacro(_) => unreachable!(),
146 };
147 let loc: MacroCallLoc = db.lookup_intern_macro(call_id); 144 let loc: MacroCallLoc = db.lookup_intern_macro(call_id);
148 let arg_start = loc.kind.arg(db)?.text_range().start(); 145 let arg_start = loc.kind.arg(db)?.text_range().start();
149 (&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start)) 146 (&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start))
@@ -186,23 +183,20 @@ impl HygieneFrame {
186 pub(crate) fn new(db: &dyn AstDatabase, file_id: HirFileId) -> HygieneFrame { 183 pub(crate) fn new(db: &dyn AstDatabase, file_id: HirFileId) -> HygieneFrame {
187 let (info, krate, local_inner) = match file_id.0 { 184 let (info, krate, local_inner) = match file_id.0 {
188 HirFileIdRepr::FileId(_) => (None, None, false), 185 HirFileIdRepr::FileId(_) => (None, None, false),
189 HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { 186 HirFileIdRepr::MacroFile(macro_file) => {
190 MacroCallId::EagerMacro(_id) => (None, None, false), 187 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
191 MacroCallId::LazyMacro(id) => { 188 let info =
192 let loc = db.lookup_intern_macro(id); 189 make_hygiene_info(db, macro_file, &loc).map(|info| (loc.kind.file_id(), info));
193 let info = make_hygiene_info(db, macro_file, &loc) 190 match loc.def.kind {
194 .map(|info| (loc.kind.file_id(), info)); 191 MacroDefKind::Declarative(_) => {
195 match loc.def.kind { 192 (info, Some(loc.def.krate), loc.def.local_inner)
196 MacroDefKind::Declarative(_) => {
197 (info, Some(loc.def.krate), loc.def.local_inner)
198 }
199 MacroDefKind::BuiltIn(..) => (info, Some(loc.def.krate), false),
200 MacroDefKind::BuiltInDerive(..) => (info, None, false),
201 MacroDefKind::BuiltInEager(..) => (info, None, false),
202 MacroDefKind::ProcMacro(..) => (info, None, false),
203 } 193 }
194 MacroDefKind::BuiltIn(..) => (info, Some(loc.def.krate), false),
195 MacroDefKind::BuiltInDerive(..) => (info, None, false),
196 MacroDefKind::BuiltInEager(..) => (info, None, false),
197 MacroDefKind::ProcMacro(..) => (info, None, false),
204 } 198 }
205 }, 199 }
206 }; 200 };
207 201
208 let (calling_file, info) = match info { 202 let (calling_file, info) = match info {
diff --git a/crates/hir_expand/src/input.rs b/crates/hir_expand/src/input.rs
index 112216859..fe4790e7b 100644
--- a/crates/hir_expand/src/input.rs
+++ b/crates/hir_expand/src/input.rs
@@ -8,13 +8,13 @@ use syntax::{
8use crate::{ 8use crate::{
9 db::AstDatabase, 9 db::AstDatabase,
10 name::{name, AsName}, 10 name::{name, AsName},
11 LazyMacroId, MacroCallKind, MacroCallLoc, 11 MacroCallId, MacroCallKind, MacroCallLoc,
12}; 12};
13 13
14pub(crate) fn process_macro_input( 14pub(crate) fn process_macro_input(
15 db: &dyn AstDatabase, 15 db: &dyn AstDatabase,
16 node: SyntaxNode, 16 node: SyntaxNode,
17 id: LazyMacroId, 17 id: MacroCallId,
18) -> SyntaxNode { 18) -> SyntaxNode {
19 let loc: MacroCallLoc = db.lookup_intern_macro(id); 19 let loc: MacroCallLoc = db.lookup_intern_macro(id);
20 20
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 88cb16ca4..92c679dd2 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -80,19 +80,10 @@ impl HirFileId {
80 match self.0 { 80 match self.0 {
81 HirFileIdRepr::FileId(file_id) => file_id, 81 HirFileIdRepr::FileId(file_id) => file_id,
82 HirFileIdRepr::MacroFile(macro_file) => { 82 HirFileIdRepr::MacroFile(macro_file) => {
83 let file_id = match macro_file.macro_call_id { 83 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
84 MacroCallId::LazyMacro(id) => { 84 let file_id = match &loc.eager {
85 let loc = db.lookup_intern_macro(id); 85 Some(EagerCallInfo { included_file: Some(file), .. }) => (*file).into(),
86 loc.kind.file_id() 86 _ => loc.kind.file_id(),
87 }
88 MacroCallId::EagerMacro(id) => {
89 let loc = db.lookup_intern_eager_expansion(id);
90 if let Some(included_file) = loc.included_file {
91 return included_file;
92 } else {
93 loc.call.file_id
94 }
95 }
96 }; 87 };
97 file_id.original_file(db) 88 file_id.original_file(db)
98 } 89 }
@@ -103,17 +94,10 @@ impl HirFileId {
103 let mut level = 0; 94 let mut level = 0;
104 let mut curr = self; 95 let mut curr = self;
105 while let HirFileIdRepr::MacroFile(macro_file) = curr.0 { 96 while let HirFileIdRepr::MacroFile(macro_file) = curr.0 {
97 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
98
106 level += 1; 99 level += 1;
107 curr = match macro_file.macro_call_id { 100 curr = loc.kind.file_id();
108 MacroCallId::LazyMacro(id) => {
109 let loc = db.lookup_intern_macro(id);
110 loc.kind.file_id()
111 }
112 MacroCallId::EagerMacro(id) => {
113 let loc = db.lookup_intern_eager_expansion(id);
114 loc.call.file_id
115 }
116 };
117 } 101 }
118 level 102 level
119 } 103 }
@@ -122,16 +106,10 @@ impl HirFileId {
122 pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { 106 pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
123 match self.0 { 107 match self.0 {
124 HirFileIdRepr::FileId(_) => None, 108 HirFileIdRepr::FileId(_) => None,
125 HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { 109 HirFileIdRepr::MacroFile(macro_file) => {
126 MacroCallId::LazyMacro(lazy_id) => { 110 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
127 let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id); 111 Some(loc.kind.node(db))
128 Some(loc.kind.node(db)) 112 }
129 }
130 MacroCallId::EagerMacro(id) => {
131 let loc: EagerCallLoc = db.lookup_intern_eager_expansion(id);
132 Some(loc.call.with_value(loc.call.to_node(db).syntax().clone()))
133 }
134 },
135 } 113 }
136 } 114 }
137 115
@@ -140,14 +118,7 @@ impl HirFileId {
140 match self.0 { 118 match self.0 {
141 HirFileIdRepr::FileId(_) => None, 119 HirFileIdRepr::FileId(_) => None,
142 HirFileIdRepr::MacroFile(macro_file) => { 120 HirFileIdRepr::MacroFile(macro_file) => {
143 let lazy_id = match macro_file.macro_call_id { 121 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
144 MacroCallId::LazyMacro(id) => id,
145 MacroCallId::EagerMacro(_id) => {
146 // FIXME: handle expansion_info for eager macro
147 return None;
148 }
149 };
150 let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id);
151 122
152 let arg_tt = loc.kind.arg(db)?; 123 let arg_tt = loc.kind.arg(db)?;
153 124
@@ -180,13 +151,7 @@ impl HirFileId {
180 match self.0 { 151 match self.0 {
181 HirFileIdRepr::FileId(_) => None, 152 HirFileIdRepr::FileId(_) => None,
182 HirFileIdRepr::MacroFile(macro_file) => { 153 HirFileIdRepr::MacroFile(macro_file) => {
183 let lazy_id = match macro_file.macro_call_id { 154 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
184 MacroCallId::LazyMacro(id) => id,
185 MacroCallId::EagerMacro(_id) => {
186 return None;
187 }
188 };
189 let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id);
190 let item = match loc.def.kind { 155 let item = match loc.def.kind {
191 MacroDefKind::BuiltInDerive(..) => loc.kind.node(db), 156 MacroDefKind::BuiltInDerive(..) => loc.kind.node(db),
192 _ => return None, 157 _ => return None,
@@ -199,16 +164,12 @@ impl HirFileId {
199 /// Return whether this file is an include macro 164 /// Return whether this file is an include macro
200 pub fn is_include_macro(&self, db: &dyn db::AstDatabase) -> bool { 165 pub fn is_include_macro(&self, db: &dyn db::AstDatabase) -> bool {
201 match self.0 { 166 match self.0 {
202 HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { 167 HirFileIdRepr::MacroFile(macro_file) => {
203 MacroCallId::EagerMacro(id) => { 168 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
204 let loc = db.lookup_intern_eager_expansion(id); 169 matches!(loc.eager, Some(EagerCallInfo { included_file: Some(_), .. }))
205 return loc.included_file.is_some(); 170 }
206 } 171 _ => false,
207 _ => {}
208 },
209 _ => {}
210 } 172 }
211 false
212 } 173 }
213} 174}
214 175
@@ -220,29 +181,8 @@ pub struct MacroFile {
220/// `MacroCallId` identifies a particular macro invocation, like 181/// `MacroCallId` identifies a particular macro invocation, like
221/// `println!("Hello, {}", world)`. 182/// `println!("Hello, {}", world)`.
222#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 183#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
223pub enum MacroCallId { 184pub struct MacroCallId(salsa::InternId);
224 LazyMacro(LazyMacroId), 185impl_intern_key!(MacroCallId);
225 EagerMacro(EagerMacroId),
226}
227
228#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
229pub struct LazyMacroId(salsa::InternId);
230impl_intern_key!(LazyMacroId);
231
232#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
233pub struct EagerMacroId(salsa::InternId);
234impl_intern_key!(EagerMacroId);
235
236impl From<LazyMacroId> for MacroCallId {
237 fn from(it: LazyMacroId) -> Self {
238 MacroCallId::LazyMacro(it)
239 }
240}
241impl From<EagerMacroId> for MacroCallId {
242 fn from(it: EagerMacroId) -> Self {
243 MacroCallId::EagerMacro(it)
244 }
245}
246 186
247#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 187#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
248pub struct MacroDefId { 188pub struct MacroDefId {
@@ -258,8 +198,8 @@ impl MacroDefId {
258 db: &dyn db::AstDatabase, 198 db: &dyn db::AstDatabase,
259 krate: CrateId, 199 krate: CrateId,
260 kind: MacroCallKind, 200 kind: MacroCallKind,
261 ) -> LazyMacroId { 201 ) -> MacroCallId {
262 db.intern_macro(MacroCallLoc { def: self, krate, kind }) 202 db.intern_macro(MacroCallLoc { def: self, krate, eager: None, kind })
263 } 203 }
264 204
265 pub fn ast_id(&self) -> Either<AstId<ast::Macro>, AstId<ast::Fn>> { 205 pub fn ast_id(&self) -> Either<AstId<ast::Macro>, AstId<ast::Fn>> {
@@ -289,9 +229,17 @@ pub enum MacroDefKind {
289} 229}
290 230
291#[derive(Debug, Clone, PartialEq, Eq, Hash)] 231#[derive(Debug, Clone, PartialEq, Eq, Hash)]
232struct EagerCallInfo {
233 /// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro!
234 arg_or_expansion: Arc<tt::Subtree>,
235 included_file: Option<FileId>,
236}
237
238#[derive(Debug, Clone, PartialEq, Eq, Hash)]
292pub struct MacroCallLoc { 239pub struct MacroCallLoc {
293 pub(crate) def: MacroDefId, 240 pub def: MacroDefId,
294 pub(crate) krate: CrateId, 241 pub(crate) krate: CrateId,
242 eager: Option<EagerCallInfo>,
295 pub kind: MacroCallKind, 243 pub kind: MacroCallKind,
296} 244}
297 245
@@ -313,6 +261,7 @@ pub enum MacroCallKind {
313} 261}
314 262
315impl MacroCallKind { 263impl MacroCallKind {
264 /// Returns the file containing the macro invocation.
316 fn file_id(&self) -> HirFileId { 265 fn file_id(&self) -> HirFileId {
317 match self { 266 match self {
318 MacroCallKind::FnLike { ast_id, .. } => ast_id.file_id, 267 MacroCallKind::FnLike { ast_id, .. } => ast_id.file_id,
@@ -354,17 +303,6 @@ impl MacroCallId {
354 } 303 }
355} 304}
356 305
357#[derive(Debug, Clone, PartialEq, Eq, Hash)]
358pub struct EagerCallLoc {
359 pub(crate) def: MacroDefId,
360 pub(crate) fragment: FragmentKind,
361 pub(crate) subtree: Arc<tt::Subtree>,
362 pub(crate) krate: CrateId,
363 pub(crate) call: AstId<ast::MacroCall>,
364 // The included file ID of the include macro.
365 pub(crate) included_file: Option<FileId>,
366}
367
368/// ExpansionInfo mainly describes how to map text range between src and expanded macro 306/// ExpansionInfo mainly describes how to map text range between src and expanded macro
369#[derive(Debug, Clone, PartialEq, Eq)] 307#[derive(Debug, Clone, PartialEq, Eq)]
370pub struct ExpansionInfo { 308pub struct ExpansionInfo {
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 47709c1e8..b9a69b79c 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -211,7 +211,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
211 211
212 // FIXME: Due to shortcomings in the current type system implementation, only emit this 212 // FIXME: Due to shortcomings in the current type system implementation, only emit this
213 // diagnostic if there are no type mismatches in the containing function. 213 // diagnostic if there are no type mismatches in the containing function.
214 if self.infer.type_mismatches.iter().next().is_some() { 214 if self.infer.expr_type_mismatches().next().is_some() {
215 return; 215 return;
216 } 216 }
217 217
@@ -311,11 +311,12 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
311 // necessary. 311 // necessary.
312 // 312 //
313 // FIXME we should use the type checker for this. 313 // FIXME we should use the type checker for this.
314 if pat_ty == match_expr_ty 314 if (pat_ty == match_expr_ty
315 || match_expr_ty 315 || match_expr_ty
316 .as_reference() 316 .as_reference()
317 .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty) 317 .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
318 .unwrap_or(false) 318 .unwrap_or(false))
319 && types_of_subpatterns_do_match(pat, &cx.body, &infer)
319 { 320 {
320 // If we had a NotUsefulMatchArm diagnostic, we could 321 // If we had a NotUsefulMatchArm diagnostic, we could
321 // check the usefulness of each pattern as we added it 322 // check the usefulness of each pattern as we added it
@@ -496,6 +497,21 @@ pub fn record_pattern_missing_fields(
496 Some((variant_def, missed_fields, exhaustive)) 497 Some((variant_def, missed_fields, exhaustive))
497} 498}
498 499
500fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult) -> bool {
501 fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) {
502 match infer.type_mismatch_for_pat(pat) {
503 Some(_) => *has_type_mismatches = true,
504 None => {
505 body[pat].walk_child_pats(|subpat| walk(subpat, body, infer, has_type_mismatches))
506 }
507 }
508 }
509
510 let mut has_type_mismatches = false;
511 walk(pat, body, infer, &mut has_type_mismatches);
512 !has_type_mismatches
513}
514
499#[cfg(test)] 515#[cfg(test)]
500mod tests { 516mod tests {
501 use crate::diagnostics::tests::check_diagnostics; 517 use crate::diagnostics::tests::check_diagnostics;
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index 6ee0529c6..e8dd669bf 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -1128,6 +1128,18 @@ fn main() {
1128 } 1128 }
1129 1129
1130 #[test] 1130 #[test]
1131 fn mismatched_types_in_or_patterns() {
1132 check_diagnostics(
1133 r#"
1134fn main() {
1135 match false { true | () => {} }
1136 match (false,) { (true | (),) => {} }
1137}
1138"#,
1139 );
1140 }
1141
1142 #[test]
1131 fn malformed_match_arm_tuple_enum_missing_pattern() { 1143 fn malformed_match_arm_tuple_enum_missing_pattern() {
1132 // We are testing to be sure we don't panic here when the match 1144 // We are testing to be sure we don't panic here when the match
1133 // arm `Either::B` is missing its pattern. 1145 // arm `Either::B` is missing its pattern.
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index bf2da2d4a..0ee851a74 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -137,8 +137,12 @@ pub struct InferenceResult {
137 assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>, 137 assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
138 diagnostics: Vec<InferenceDiagnostic>, 138 diagnostics: Vec<InferenceDiagnostic>,
139 pub type_of_expr: ArenaMap<ExprId, Ty>, 139 pub type_of_expr: ArenaMap<ExprId, Ty>,
140 /// For each pattern record the type it resolves to.
141 ///
142 /// **Note**: When a pattern type is resolved it may still contain
143 /// unresolved or missing subpatterns or subpatterns of mismatched types.
140 pub type_of_pat: ArenaMap<PatId, Ty>, 144 pub type_of_pat: ArenaMap<PatId, Ty>,
141 pub(super) type_mismatches: ArenaMap<ExprId, TypeMismatch>, 145 type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
142 /// Interned Unknown to return references to. 146 /// Interned Unknown to return references to.
143 standard_types: InternedStandardTypes, 147 standard_types: InternedStandardTypes,
144} 148}
@@ -163,7 +167,22 @@ impl InferenceResult {
163 self.assoc_resolutions.get(&id.into()).copied() 167 self.assoc_resolutions.get(&id.into()).copied()
164 } 168 }
165 pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> { 169 pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
166 self.type_mismatches.get(expr) 170 self.type_mismatches.get(&expr.into())
171 }
172 pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> {
173 self.type_mismatches.get(&pat.into())
174 }
175 pub fn expr_type_mismatches(&self) -> impl Iterator<Item = (ExprId, &TypeMismatch)> {
176 self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
177 ExprOrPatId::ExprId(expr) => Some((expr, mismatch)),
178 _ => None,
179 })
180 }
181 pub fn pat_type_mismatches(&self) -> impl Iterator<Item = (PatId, &TypeMismatch)> {
182 self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
183 ExprOrPatId::PatId(pat) => Some((pat, mismatch)),
184 _ => None,
185 })
167 } 186 }
168 pub fn add_diagnostics( 187 pub fn add_diagnostics(
169 &self, 188 &self,
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index b6b5a1b75..7278faeec 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -42,7 +42,7 @@ impl<'a> InferenceContext<'a> {
42 let could_unify = self.unify(&ty, &expected.ty); 42 let could_unify = self.unify(&ty, &expected.ty);
43 if !could_unify { 43 if !could_unify {
44 self.result.type_mismatches.insert( 44 self.result.type_mismatches.insert(
45 tgt_expr, 45 tgt_expr.into(),
46 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, 46 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
47 ); 47 );
48 } 48 }
@@ -54,9 +54,10 @@ impl<'a> InferenceContext<'a> {
54 pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { 54 pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
55 let ty = self.infer_expr_inner(expr, &expected); 55 let ty = self.infer_expr_inner(expr, &expected);
56 let ty = if !self.coerce(&ty, &expected.coercion_target()) { 56 let ty = if !self.coerce(&ty, &expected.coercion_target()) {
57 self.result 57 self.result.type_mismatches.insert(
58 .type_mismatches 58 expr.into(),
59 .insert(expr, TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }); 59 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
60 );
60 // Return actual type when type mismatch. 61 // Return actual type when type mismatch.
61 // This is needed for diagnostic when return type mismatch. 62 // This is needed for diagnostic when return type mismatch.
62 ty 63 ty
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index 60b94a642..b15f4977d 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -10,7 +10,7 @@ use hir_def::{
10}; 10};
11use hir_expand::name::Name; 11use hir_expand::name::Name;
12 12
13use super::{BindingMode, Expectation, InferenceContext}; 13use super::{BindingMode, Expectation, InferenceContext, TypeMismatch};
14use crate::{ 14use crate::{
15 lower::lower_to_chalk_mutability, static_lifetime, Interner, Substitution, Ty, TyBuilder, 15 lower::lower_to_chalk_mutability, static_lifetime, Interner, Substitution, Ty, TyBuilder,
16 TyExt, TyKind, 16 TyExt, TyKind,
@@ -266,7 +266,10 @@ impl<'a> InferenceContext<'a> {
266 // use a new type variable if we got error type here 266 // use a new type variable if we got error type here
267 let ty = self.insert_type_vars_shallow(ty); 267 let ty = self.insert_type_vars_shallow(ty);
268 if !self.unify(&ty, expected) { 268 if !self.unify(&ty, expected) {
269 // FIXME record mismatch, we need to change the type of self.type_mismatches for that 269 self.result.type_mismatches.insert(
270 pat.into(),
271 TypeMismatch { expected: expected.clone(), actual: ty.clone() },
272 );
270 } 273 }
271 let ty = self.resolve_ty_as_possible(ty); 274 let ty = self.resolve_ty_as_possible(ty);
272 self.write_pat_ty(pat, ty.clone()); 275 self.write_pat_ty(pat, ty.clone());
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index ccfb88c52..cc819373c 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -130,7 +130,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
130 } 130 }
131 Err(SyntheticSyntax) => continue, 131 Err(SyntheticSyntax) => continue,
132 }; 132 };
133 types.push((syntax_ptr, ty)); 133 types.push((syntax_ptr.clone(), ty));
134 if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat) {
135 mismatches.push((syntax_ptr, mismatch));
136 }
134 } 137 }
135 138
136 for (expr, ty) in inference_result.type_of_expr.iter() { 139 for (expr, ty) in inference_result.type_of_expr.iter() {
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index 787647e9f..ddbadbe40 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -546,7 +546,9 @@ fn infer_const_pattern() {
546 273..276 'Bar': usize 546 273..276 'Bar': usize
547 280..283 'Bar': usize 547 280..283 'Bar': usize
548 200..223: expected (), got Foo 548 200..223: expected (), got Foo
549 211..214: expected (), got Foo
549 262..285: expected (), got usize 550 262..285: expected (), got usize
551 273..276: expected (), got usize
550 "#]], 552 "#]],
551 ); 553 );
552} 554}
@@ -703,7 +705,7 @@ fn box_pattern() {
703 705
704#[test] 706#[test]
705fn tuple_ellipsis_pattern() { 707fn tuple_ellipsis_pattern() {
706 check_infer( 708 check_infer_with_mismatches(
707 r#" 709 r#"
708fn foo(tuple: (u8, i16, f32)) { 710fn foo(tuple: (u8, i16, f32)) {
709 match tuple { 711 match tuple {
@@ -744,6 +746,8 @@ fn foo(tuple: (u8, i16, f32)) {
744 186..200 '{/*too long*/}': () 746 186..200 '{/*too long*/}': ()
745 209..210 '_': (u8, i16, f32) 747 209..210 '_': (u8, i16, f32)
746 214..216 '{}': () 748 214..216 '{}': ()
749 136..142: expected (u8, i16, f32), got (u8, i16)
750 170..182: expected (u8, i16, f32), got (u8, i16, f32, _)
747 "#]], 751 "#]],
748 ); 752 );
749} 753}
@@ -851,3 +855,55 @@ fn f(e: Enum) {
851 "#, 855 "#,
852 ) 856 )
853} 857}
858
859#[test]
860fn type_mismatch_in_or_pattern() {
861 check_infer_with_mismatches(
862 r#"
863fn main() {
864 match (false,) {
865 (true | (),) => {}
866 (() | true,) => {}
867 (_ | (),) => {}
868 (() | _,) => {}
869 }
870}
871"#,
872 expect![[r#"
873 10..142 '{ ... } }': ()
874 16..140 'match ... }': ()
875 22..30 '(false,)': (bool,)
876 23..28 'false': bool
877 41..53 '(true | (),)': (bool,)
878 42..46 'true': bool
879 42..46 'true': bool
880 42..51 'true | ()': bool
881 49..51 '()': ()
882 57..59 '{}': ()
883 68..80 '(() | true,)': ((),)
884 69..71 '()': ()
885 69..78 '() | true': ()
886 74..78 'true': bool
887 74..78 'true': bool
888 84..86 '{}': ()
889 95..104 '(_ | (),)': (bool,)
890 96..97 '_': bool
891 96..102 '_ | ()': bool
892 100..102 '()': ()
893 108..110 '{}': ()
894 119..128 '(() | _,)': ((),)
895 120..122 '()': ()
896 120..126 '() | _': ()
897 125..126 '_': bool
898 132..134 '{}': ()
899 49..51: expected bool, got ()
900 68..80: expected (bool,), got ((),)
901 69..71: expected bool, got ()
902 69..78: expected bool, got ()
903 100..102: expected bool, got ()
904 119..128: expected (bool,), got ((),)
905 120..122: expected bool, got ()
906 120..126: expected bool, got ()
907 "#]],
908 );
909}
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 2bf953305..01fe3a1a1 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -55,12 +55,14 @@ pub(crate) fn prepare_rename(
55 match def { 55 match def {
56 Definition::SelfType(_) => bail!("Cannot rename `Self`"), 56 Definition::SelfType(_) => bail!("Cannot rename `Self`"),
57 Definition::ModuleDef(ModuleDef::BuiltinType(_)) => bail!("Cannot rename builtin type"), 57 Definition::ModuleDef(ModuleDef::BuiltinType(_)) => bail!("Cannot rename builtin type"),
58 _ => {} 58 Definition::ModuleDef(ModuleDef::Module(_)) => (),
59 _ => {
60 let nav = def
61 .try_to_nav(sema.db)
62 .ok_or_else(|| format_err!("No references found at position"))?;
63 nav.focus_range.ok_or_else(|| format_err!("No identifier available to rename"))?;
64 }
59 }; 65 };
60 let nav =
61 def.try_to_nav(sema.db).ok_or_else(|| format_err!("No references found at position"))?;
62 nav.focus_range.ok_or_else(|| format_err!("No identifier available to rename"))?;
63
64 let name_like = sema 66 let name_like = sema
65 .find_node_at_offset_with_descend(&syntax, position.offset) 67 .find_node_at_offset_with_descend(&syntax, position.offset)
66 .ok_or_else(|| format_err!("No references found at position"))?; 68 .ok_or_else(|| format_err!("No references found at position"))?;
diff --git a/crates/ide_assists/src/handlers/add_explicit_type.rs b/crates/ide_assists/src/handlers/add_explicit_type.rs
index 36589203d..b7617ca3d 100644
--- a/crates/ide_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ide_assists/src/handlers/add_explicit_type.rs
@@ -1,6 +1,6 @@
1use hir::HirDisplay; 1use hir::HirDisplay;
2use syntax::{ 2use syntax::{
3 ast::{self, AstNode, LetStmt, NameOwner}, 3 ast::{self, AstNode, LetStmt},
4 TextRange, 4 TextRange,
5}; 5};
6 6
@@ -31,9 +31,6 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio
31 _ => return None, 31 _ => return None,
32 }; 32 };
33 let pat_range = pat.syntax().text_range(); 33 let pat_range = pat.syntax().text_range();
34 // The binding must have a name
35 let name = pat.name()?;
36 let name_range = name.syntax().text_range();
37 34
38 // Assist should only be applicable if cursor is between 'let' and '=' 35 // Assist should only be applicable if cursor is between 'let' and '='
39 let cursor_in_range = { 36 let cursor_in_range = {
@@ -74,7 +71,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio
74 builder.replace(ascribed_ty.syntax().text_range(), inferred_type); 71 builder.replace(ascribed_ty.syntax().text_range(), inferred_type);
75 } 72 }
76 None => { 73 None => {
77 builder.insert(name_range.end(), format!(": {}", inferred_type)); 74 builder.insert(pat_range.end(), format!(": {}", inferred_type));
78 } 75 }
79 }, 76 },
80 ) 77 )
@@ -246,4 +243,22 @@ fn main() {
246"#, 243"#,
247 ); 244 );
248 } 245 }
246
247 #[test]
248 fn type_should_be_added_after_pattern() {
249 // LetStmt = Attr* 'let' Pat (':' Type)? '=' initializer:Expr ';'
250 check_assist(
251 add_explicit_type,
252 r#"
253fn main() {
254 let $0test @ () = ();
255}
256"#,
257 r#"
258fn main() {
259 let test @ (): () = ();
260}
261"#,
262 );
263 }
249} 264}
diff --git a/crates/ide_db/src/apply_change.rs b/crates/ide_db/src/apply_change.rs
index eac5ef6b9..f988572ae 100644
--- a/crates/ide_db/src/apply_change.rs
+++ b/crates/ide_db/src/apply_change.rs
@@ -222,7 +222,6 @@ impl RootDatabase {
222 sweep_each_query![ 222 sweep_each_query![
223 // AstDatabase 223 // AstDatabase
224 hir::db::InternMacroQuery 224 hir::db::InternMacroQuery
225 hir::db::InternEagerExpansionQuery
226 225
227 // InternDatabase 226 // InternDatabase
228 hir::db::InternFunctionQuery 227 hir::db::InternFunctionQuery
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index da427d686..0f5c4abc4 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -161,6 +161,11 @@ impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
161// That is, `#` switches from "types" to all symbols, `*` switches from the current 161// That is, `#` switches from "types" to all symbols, `*` switches from the current
162// workspace to dependencies. 162// workspace to dependencies.
163// 163//
164// Note that filtering does not currently work in VSCode due to the editor never
165// sending the special symbols to the language server. Instead, you can configure
166// the filtering via the `rust-analyzer.workspace.symbol.search.scope` and
167// `rust-analyzer.workspace.symbol.search.kind` settings.
168//
164// |=== 169// |===
165// | Editor | Shortcut 170// | Editor | Shortcut
166// 171//
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index 3c87782f2..b2317618a 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -122,6 +122,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
122 "runnables": { 122 "runnables": {
123 "kinds": [ "cargo" ], 123 "kinds": [ "cargo" ],
124 }, 124 },
125 "workspaceSymbolScopeKindFiltering": true,
125 })), 126 })),
126 } 127 }
127} 128}
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 867d72ea4..b700d025f 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -23,7 +23,8 @@ use vfs::AbsPathBuf;
23 23
24use crate::{ 24use crate::{
25 caps::completion_item_edit_resolve, diagnostics::DiagnosticsMapConfig, 25 caps::completion_item_edit_resolve, diagnostics::DiagnosticsMapConfig,
26 line_index::OffsetEncoding, lsp_ext::supports_utf8, 26 line_index::OffsetEncoding, lsp_ext::supports_utf8, lsp_ext::WorkspaceSymbolSearchKind,
27 lsp_ext::WorkspaceSymbolSearchScope,
27}; 28};
28 29
29// Defines the server-side configuration of the rust-analyzer. We generate 30// Defines the server-side configuration of the rust-analyzer. We generate
@@ -217,6 +218,11 @@ config_data! {
217 /// Advanced option, fully override the command rust-analyzer uses for 218 /// Advanced option, fully override the command rust-analyzer uses for
218 /// formatting. 219 /// formatting.
219 rustfmt_overrideCommand: Option<Vec<String>> = "null", 220 rustfmt_overrideCommand: Option<Vec<String>> = "null",
221
222 /// Workspace symbol search scope.
223 workspace_symbol_search_scope: WorskpaceSymbolSearchScopeDef = "\"workspace\"",
224 /// Workspace symbol search kind.
225 workspace_symbol_search_kind: WorskpaceSymbolSearchKindDef = "\"only_types\"",
220 } 226 }
221} 227}
222 228
@@ -311,6 +317,15 @@ pub struct RunnablesConfig {
311 pub cargo_extra_args: Vec<String>, 317 pub cargo_extra_args: Vec<String>,
312} 318}
313 319
320/// Configuration for workspace symbol search requests.
321#[derive(Debug, Clone)]
322pub struct WorkspaceSymbolConfig {
323 /// In what scope should the symbol be searched in.
324 pub search_scope: WorkspaceSymbolSearchScope,
325 /// What kind of symbol is being search for.
326 pub search_kind: WorkspaceSymbolSearchKind,
327}
328
314impl Config { 329impl Config {
315 pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self { 330 pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self {
316 Config { caps, data: ConfigData::default(), discovered_projects: None, root_path } 331 Config { caps, data: ConfigData::default(), discovered_projects: None, root_path }
@@ -691,6 +706,22 @@ impl Config {
691 .contains(&MarkupKind::Markdown), 706 .contains(&MarkupKind::Markdown),
692 } 707 }
693 } 708 }
709
710 pub fn workspace_symbol(&self) -> WorkspaceSymbolConfig {
711 WorkspaceSymbolConfig {
712 search_scope: match self.data.workspace_symbol_search_scope {
713 WorskpaceSymbolSearchScopeDef::Workspace => WorkspaceSymbolSearchScope::Workspace,
714 WorskpaceSymbolSearchScopeDef::WorkspaceAndDependencies => {
715 WorkspaceSymbolSearchScope::WorkspaceAndDependencies
716 }
717 },
718 search_kind: match self.data.workspace_symbol_search_kind {
719 WorskpaceSymbolSearchKindDef::OnlyTypes => WorkspaceSymbolSearchKind::OnlyTypes,
720 WorskpaceSymbolSearchKindDef::AllSymbols => WorkspaceSymbolSearchKind::AllSymbols,
721 },
722 }
723 }
724
694 pub fn semantic_tokens_refresh(&self) -> bool { 725 pub fn semantic_tokens_refresh(&self) -> bool {
695 try_or!(self.caps.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support?, false) 726 try_or!(self.caps.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support?, false)
696 } 727 }
@@ -739,6 +770,20 @@ enum ImportPrefixDef {
739 ByCrate, 770 ByCrate,
740} 771}
741 772
773#[derive(Deserialize, Debug, Clone)]
774#[serde(rename_all = "snake_case")]
775enum WorskpaceSymbolSearchScopeDef {
776 Workspace,
777 WorkspaceAndDependencies,
778}
779
780#[derive(Deserialize, Debug, Clone)]
781#[serde(rename_all = "snake_case")]
782enum WorskpaceSymbolSearchKindDef {
783 OnlyTypes,
784 AllSymbols,
785}
786
742macro_rules! _config_data { 787macro_rules! _config_data {
743 (struct $name:ident { 788 (struct $name:ident {
744 $( 789 $(
@@ -919,6 +964,22 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
919 "type": "array", 964 "type": "array",
920 "items": { "type": ["string", "object"] }, 965 "items": { "type": ["string", "object"] },
921 }, 966 },
967 "WorskpaceSymbolSearchScopeDef" => set! {
968 "type": "string",
969 "enum": ["workspace", "workspace_and_dependencies"],
970 "enumDescriptions": [
971 "Search in current workspace only",
972 "Search in current workspace and dependencies"
973 ],
974 },
975 "WorskpaceSymbolSearchKindDef" => set! {
976 "type": "string",
977 "enum": ["only_types", "all_symbols"],
978 "enumDescriptions": [
979 "Search for types only",
980 "Search for all symbols kinds"
981 ],
982 },
922 _ => panic!("{}: {}", ty, default), 983 _ => panic!("{}: {}", ty, default),
923 } 984 }
924 985
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 8fe97fd7c..51041d7a0 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -38,7 +38,7 @@ use crate::{
38 from_proto, 38 from_proto,
39 global_state::{GlobalState, GlobalStateSnapshot}, 39 global_state::{GlobalState, GlobalStateSnapshot},
40 line_index::LineEndings, 40 line_index::LineEndings,
41 lsp_ext::{self, InlayHint, InlayHintsParams}, 41 lsp_ext::{self, InlayHint, InlayHintsParams, WorkspaceSymbolParams},
42 lsp_utils::all_edits_are_disjoint, 42 lsp_utils::all_edits_are_disjoint,
43 to_proto, LspError, Result, 43 to_proto, LspError, Result,
44}; 44};
@@ -380,11 +380,12 @@ pub(crate) fn handle_document_symbol(
380 380
381pub(crate) fn handle_workspace_symbol( 381pub(crate) fn handle_workspace_symbol(
382 snap: GlobalStateSnapshot, 382 snap: GlobalStateSnapshot,
383 params: lsp_types::WorkspaceSymbolParams, 383 params: WorkspaceSymbolParams,
384) -> Result<Option<Vec<SymbolInformation>>> { 384) -> Result<Option<Vec<SymbolInformation>>> {
385 let _p = profile::span("handle_workspace_symbol"); 385 let _p = profile::span("handle_workspace_symbol");
386 let all_symbols = params.query.contains('#'); 386
387 let libs = params.query.contains('*'); 387 let (all_symbols, libs) = decide_search_scope_and_kind(&params, &snap);
388
388 let query = { 389 let query = {
389 let query: String = params.query.chars().filter(|&c| c != '#' && c != '*').collect(); 390 let query: String = params.query.chars().filter(|&c| c != '#' && c != '*').collect();
390 let mut q = Query::new(query); 391 let mut q = Query::new(query);
@@ -406,6 +407,45 @@ pub(crate) fn handle_workspace_symbol(
406 407
407 return Ok(Some(res)); 408 return Ok(Some(res));
408 409
410 fn decide_search_scope_and_kind(
411 params: &WorkspaceSymbolParams,
412 snap: &GlobalStateSnapshot,
413 ) -> (bool, bool) {
414 // Support old-style parsing of markers in the query.
415 let mut all_symbols = params.query.contains('#');
416 let mut libs = params.query.contains('*');
417
418 let config = snap.config.workspace_symbol();
419
420 // If no explicit marker was set, check request params. If that's also empty
421 // use global config.
422 if !all_symbols {
423 let search_kind = if let Some(ref search_kind) = params.search_kind {
424 search_kind
425 } else {
426 &config.search_kind
427 };
428 all_symbols = match search_kind {
429 lsp_ext::WorkspaceSymbolSearchKind::OnlyTypes => false,
430 lsp_ext::WorkspaceSymbolSearchKind::AllSymbols => true,
431 }
432 }
433
434 if !libs {
435 let search_scope = if let Some(ref search_scope) = params.search_scope {
436 search_scope
437 } else {
438 &config.search_scope
439 };
440 libs = match search_scope {
441 lsp_ext::WorkspaceSymbolSearchScope::Workspace => false,
442 lsp_ext::WorkspaceSymbolSearchScope::WorkspaceAndDependencies => true,
443 }
444 }
445
446 (all_symbols, libs)
447 }
448
409 fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> { 449 fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> {
410 let mut res = Vec::new(); 450 let mut res = Vec::new();
411 for nav in snap.analysis.symbol_search(query)? { 451 for nav in snap.analysis.symbol_search(query)? {
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 3bd098058..34b53a7a8 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -4,7 +4,8 @@ use std::{collections::HashMap, path::PathBuf};
4 4
5use lsp_types::request::Request; 5use lsp_types::request::Request;
6use lsp_types::{ 6use lsp_types::{
7 notification::Notification, CodeActionKind, Position, Range, TextDocumentIdentifier, 7 notification::Notification, CodeActionKind, PartialResultParams, Position, Range,
8 TextDocumentIdentifier, WorkDoneProgressParams,
8}; 9};
9use serde::{Deserialize, Serialize}; 10use serde::{Deserialize, Serialize};
10 11
@@ -438,3 +439,42 @@ pub enum MoveItemDirection {
438 Up, 439 Up,
439 Down, 440 Down,
440} 441}
442
443#[derive(Debug)]
444pub enum WorkspaceSymbol {}
445
446impl Request for WorkspaceSymbol {
447 type Params = WorkspaceSymbolParams;
448 type Result = Option<Vec<lsp_types::SymbolInformation>>;
449 const METHOD: &'static str = "workspace/symbol";
450}
451
452#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
453pub struct WorkspaceSymbolParams {
454 #[serde(flatten)]
455 pub partial_result_params: PartialResultParams,
456
457 #[serde(flatten)]
458 pub work_done_progress_params: WorkDoneProgressParams,
459
460 /// A non-empty query string
461 pub query: String,
462
463 pub search_scope: Option<WorkspaceSymbolSearchScope>,
464
465 pub search_kind: Option<WorkspaceSymbolSearchKind>,
466}
467
468#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
469#[serde(rename_all = "camelCase")]
470pub enum WorkspaceSymbolSearchScope {
471 Workspace,
472 WorkspaceAndDependencies,
473}
474
475#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
476#[serde(rename_all = "camelCase")]
477pub enum WorkspaceSymbolSearchKind {
478 OnlyTypes,
479 AllSymbols,
480}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index c7bd7eee1..4e0791611 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -525,9 +525,9 @@ impl GlobalState {
525 .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs) 525 .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs)
526 .on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml) 526 .on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
527 .on::<lsp_ext::MoveItem>(handlers::handle_move_item) 527 .on::<lsp_ext::MoveItem>(handlers::handle_move_item)
528 .on::<lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
528 .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting) 529 .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting)
529 .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol) 530 .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)
530 .on::<lsp_types::request::WorkspaceSymbol>(handlers::handle_workspace_symbol)
531 .on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition) 531 .on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition)
532 .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation) 532 .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)
533 .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition) 533 .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 8fcd72d5d..3c4eacfeb 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
1<!--- 1<!---
2lsp_ext.rs hash: 6e57fc1b345b00e9 2lsp_ext.rs hash: 10a8988e6893e6b2
3 3
4If you need to change the above hash to make the test pass, please check if you 4If you need to change the above hash to make the test pass, please check if you
5need to adjust this doc as well and ping this issue: 5need to adjust this doc as well and ping this issue:
@@ -650,3 +650,37 @@ export const enum Direction {
650 Down = "Down" 650 Down = "Down"
651} 651}
652``` 652```
653
654## Workspace Symbols Filtering
655
656**Issue:** https://github.com/rust-analyzer/rust-analyzer/pull/7698
657
658**Experimental Server Capability:** `{ "workspaceSymbolScopeKindFiltering": boolean }`
659
660Extends the existing `workspace/symbol` request with ability to filter symbols by broad scope and kind of symbol.
661If this capability is set, `workspace/symbol` parameter gains two new optional fields:
662
663
664```typescript
665interface WorkspaceSymbolParams {
666 /**
667 * Return only the symbols defined in the specified scope.
668 */
669 searchScope?: WorkspaceSymbolSearchScope;
670 /**
671 * Return only the symbols of specified kinds.
672 */
673 searchKind?: WorkspaceSymbolSearchKind;
674 ...
675}
676
677const enum WorkspaceSymbolSearchScope {
678 Workspace = "workspace",
679 WorkspaceAndDependencies = "workspaceAndDependencies"
680}
681
682const enum WorkspaceSymbolSearchKind {
683 OnlyTypes = "onlyTypes",
684 AllSymbols = "allSymbols"
685}
686```
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index b2c1f6261..c02bab7cc 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -346,3 +346,13 @@ Additional arguments to `rustfmt`.
346Advanced option, fully override the command rust-analyzer uses for 346Advanced option, fully override the command rust-analyzer uses for
347formatting. 347formatting.
348-- 348--
349[[rust-analyzer.workspace.symbol.search.scope]]rust-analyzer.workspace.symbol.search.scope (default: `"workspace"`)::
350+
351--
352Workspace symbol search scope.
353--
354[[rust-analyzer.workspace.symbol.search.kind]]rust-analyzer.workspace.symbol.search.kind (default: `"only_types"`)::
355+
356--
357Workspace symbol search kind.
358--
diff --git a/editors/code/package.json b/editors/code/package.json
index 48d12b35a..1743b374c 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -790,6 +790,32 @@
790 "type": "string" 790 "type": "string"
791 } 791 }
792 }, 792 },
793 "rust-analyzer.workspace.symbol.search.scope": {
794 "markdownDescription": "Workspace symbol search scope.",
795 "default": "workspace",
796 "type": "string",
797 "enum": [
798 "workspace",
799 "workspace_and_dependencies"
800 ],
801 "enumDescriptions": [
802 "Search in current workspace only",
803 "Search in current workspace and dependencies"
804 ]
805 },
806 "rust-analyzer.workspace.symbol.search.kind": {
807 "markdownDescription": "Workspace symbol search kind.",
808 "default": "only_types",
809 "type": "string",
810 "enum": [
811 "only_types",
812 "all_symbols"
813 ],
814 "enumDescriptions": [
815 "Search for types only",
816 "Search for all symbols kinds"
817 ]
818 },
793 "$generated-end": false 819 "$generated-end": false
794 } 820 }
795 }, 821 },