aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-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
27 files changed, 717 insertions, 362 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)