diff options
30 files changed, 788 insertions, 363 deletions
diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index df5758342..ffc8155b9 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs | |||
@@ -2,8 +2,8 @@ | |||
2 | 2 | ||
3 | pub use hir_def::db::*; | 3 | pub use hir_def::db::*; |
4 | pub use hir_expand::db::{ | 4 | pub 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 | }; |
8 | pub use hir_ty::db::*; | 8 | pub 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 | ||
5 | use std::{ | 5 | use 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 | ||
174 | impl<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 | |||
174 | pub struct InternStorage<T: ?Sized> { | 180 | pub 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 | ||
22 | use crate::{ | 22 | use 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 | ||
45 | use super::proc_macro::ProcMacroDef; | 46 | use super::proc_macro::{ProcMacroDef, ProcMacroKind}; |
46 | 47 | ||
47 | const GLOB_RECURSION_LIMIT: usize = 100; | 48 | const GLOB_RECURSION_LIMIT: usize = 100; |
48 | const EXPANSION_DEPTH_LIMIT: usize = 128; | 49 | const 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 { | |||
217 | enum MacroDirectiveKind { | 220 | enum 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 | ||
222 | struct DefData<'a> { | 226 | struct 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 | ||
248 | impl DefCollector<'_> { | 256 | impl 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] |
689 | fn 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] | ||
710 | fn 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] | ||
689 | fn macro_expansion_overflow() { | 739 | fn 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() { | |||
842 | fn resolve_macro_def() { | 892 | fn resolve_macro_def() { |
843 | check( | 893 | check( |
844 | r#" | 894 | r#" |
845 | //- /lib.rs | ||
846 | pub macro structs($($i:ident),*) { | 895 | pub 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 | ||
11 | use crate::{db::AstDatabase, name, quote, AstId, CrateId, LazyMacroId, MacroDefId, MacroDefKind}; | 11 | use crate::{db::AstDatabase, name, quote, AstId, CrateId, MacroCallId, MacroDefId, MacroDefKind}; |
12 | 12 | ||
13 | macro_rules! register_builtin { | 13 | macro_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 | ||
167 | fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { | 167 | fn 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 | ||
185 | fn copy_expand( | 185 | fn 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 | ||
194 | fn clone_expand( | 194 | fn 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 | ||
203 | fn default_expand( | 203 | fn 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 | ||
212 | fn debug_expand( | 212 | fn 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 | ||
221 | fn hash_expand( | 221 | fn 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 | ||
230 | fn eq_expand( | 230 | fn 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 | ||
239 | fn partial_eq_expand( | 239 | fn 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 | ||
248 | fn ord_expand( | 248 | fn 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 | ||
257 | fn partial_ord_expand( | 257 | fn 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 |
2 | use crate::{ | 2 | use 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 | ||
7 | use base_db::{AnchoredPath, Edition, FileId}; | 7 | use 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 | ||
129 | fn module_path_expand( | 129 | fn 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 | ||
138 | fn line_expand( | 138 | fn 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 | ||
152 | fn stringify_expand( | 152 | fn 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 | ||
177 | fn column_expand( | 177 | fn 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 | ||
191 | fn assert_expand( | 191 | fn 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 | ||
215 | fn file_expand( | 215 | fn 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 | ||
231 | fn format_args_expand( | 231 | fn 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 | ||
266 | fn asm_expand( | 266 | fn 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 | ||
279 | fn global_asm_expand( | 279 | fn 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 | ||
288 | fn cfg_expand( | 288 | fn 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 | ||
300 | fn panic_expand( | 300 | fn 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 | ||
325 | fn compile_error_expand( | 325 | fn 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 | ||
346 | fn concat_expand( | 346 | fn 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 | ||
377 | fn concat_idents_expand( | 377 | fn 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 | ||
428 | fn include_expand( | 428 | fn 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 | ||
458 | fn include_bytes_expand( | 458 | fn 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 | ||
478 | fn include_str_expand( | 478 | fn 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 | ||
505 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { | 505 | fn 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 | ||
510 | fn env_expand( | 510 | fn 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 | ||
541 | fn option_env_expand( | 541 | fn 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( | |||
560 | mod tests { | 560 | mod 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(¯o_call)), | 604 | ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(¯o_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(¯o_call)); | 622 | let call_id = AstId::new(file_id.into(), ast_id_map.ast_id(¯o_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 | ||
14 | use crate::{ | 14 | use 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 | ||
283 | fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { | 264 | fn 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, ¯o_arg.0); | 348 | let ExpandResult { value: tt, err } = macro_rules.expand(db, id, ¯o_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 | ||
438 | fn macro_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { | 404 | fn 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 @@ | |||
22 | use crate::{ | 22 | use 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 | ||
28 | use base_db::CrateId; | 28 | use 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(¯o_call.value.token_tree()?).0), | 110 | || Some(mbe::ast_to_token_tree(¯o_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}; | |||
14 | use crate::{ | 14 | use 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::{ | |||
8 | use crate::{ | 8 | use 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 | ||
14 | pub(crate) fn process_macro_input( | 14 | pub(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)] |
223 | pub enum MacroCallId { | 184 | pub struct MacroCallId(salsa::InternId); |
224 | LazyMacro(LazyMacroId), | 185 | impl_intern_key!(MacroCallId); |
225 | EagerMacro(EagerMacroId), | ||
226 | } | ||
227 | |||
228 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
229 | pub struct LazyMacroId(salsa::InternId); | ||
230 | impl_intern_key!(LazyMacroId); | ||
231 | |||
232 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
233 | pub struct EagerMacroId(salsa::InternId); | ||
234 | impl_intern_key!(EagerMacroId); | ||
235 | |||
236 | impl From<LazyMacroId> for MacroCallId { | ||
237 | fn from(it: LazyMacroId) -> Self { | ||
238 | MacroCallId::LazyMacro(it) | ||
239 | } | ||
240 | } | ||
241 | impl 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)] |
248 | pub struct MacroDefId { | 188 | pub 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)] |
232 | struct 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)] | ||
292 | pub struct MacroCallLoc { | 239 | pub 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 | ||
315 | impl MacroCallKind { | 263 | impl 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)] | ||
358 | pub 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)] |
370 | pub struct ExpansionInfo { | 308 | pub 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 | ||
500 | fn 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)] |
500 | mod tests { | 516 | mod 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#" | ||
1134 | fn 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 | }; |
11 | use hir_expand::name::Name; | 11 | use hir_expand::name::Name; |
12 | 12 | ||
13 | use super::{BindingMode, Expectation, InferenceContext}; | 13 | use super::{BindingMode, Expectation, InferenceContext, TypeMismatch}; |
14 | use crate::{ | 14 | use 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] |
705 | fn tuple_ellipsis_pattern() { | 707 | fn tuple_ellipsis_pattern() { |
706 | check_infer( | 708 | check_infer_with_mismatches( |
707 | r#" | 709 | r#" |
708 | fn foo(tuple: (u8, i16, f32)) { | 710 | fn 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] | ||
860 | fn type_mismatch_in_or_pattern() { | ||
861 | check_infer_with_mismatches( | ||
862 | r#" | ||
863 | fn 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 @@ | |||
1 | use hir::HirDisplay; | 1 | use hir::HirDisplay; |
2 | use syntax::{ | 2 | use 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#" | ||
253 | fn main() { | ||
254 | let $0test @ () = (); | ||
255 | } | ||
256 | "#, | ||
257 | r#" | ||
258 | fn 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 | ||
24 | use crate::{ | 24 | use 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)] | ||
322 | pub 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 | |||
314 | impl Config { | 329 | impl 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")] | ||
775 | enum WorskpaceSymbolSearchScopeDef { | ||
776 | Workspace, | ||
777 | WorkspaceAndDependencies, | ||
778 | } | ||
779 | |||
780 | #[derive(Deserialize, Debug, Clone)] | ||
781 | #[serde(rename_all = "snake_case")] | ||
782 | enum WorskpaceSymbolSearchKindDef { | ||
783 | OnlyTypes, | ||
784 | AllSymbols, | ||
785 | } | ||
786 | |||
742 | macro_rules! _config_data { | 787 | macro_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 | ||
381 | pub(crate) fn handle_workspace_symbol( | 381 | pub(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(¶ms, &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 | ||
5 | use lsp_types::request::Request; | 5 | use lsp_types::request::Request; |
6 | use lsp_types::{ | 6 | use lsp_types::{ |
7 | notification::Notification, CodeActionKind, Position, Range, TextDocumentIdentifier, | 7 | notification::Notification, CodeActionKind, PartialResultParams, Position, Range, |
8 | TextDocumentIdentifier, WorkDoneProgressParams, | ||
8 | }; | 9 | }; |
9 | use serde::{Deserialize, Serialize}; | 10 | use 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)] | ||
444 | pub enum WorkspaceSymbol {} | ||
445 | |||
446 | impl 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)] | ||
453 | pub 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")] | ||
470 | pub enum WorkspaceSymbolSearchScope { | ||
471 | Workspace, | ||
472 | WorkspaceAndDependencies, | ||
473 | } | ||
474 | |||
475 | #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] | ||
476 | #[serde(rename_all = "camelCase")] | ||
477 | pub enum WorkspaceSymbolSearchKind { | ||
478 | OnlyTypes, | ||
479 | AllSymbols, | ||
480 | } | ||
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index c7bd7eee1..4e0791611 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -525,9 +525,9 @@ impl GlobalState { | |||
525 | .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs) | 525 | .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs) |
526 | .on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml) | 526 | .on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml) |
527 | .on::<lsp_ext::MoveItem>(handlers::handle_move_item) | 527 | .on::<lsp_ext::MoveItem>(handlers::handle_move_item) |
528 | .on::<lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol) | ||
528 | .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting) | 529 | .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting) |
529 | .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol) | 530 | .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol) |
530 | .on::<lsp_types::request::WorkspaceSymbol>(handlers::handle_workspace_symbol) | ||
531 | .on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition) | 531 | .on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition) |
532 | .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation) | 532 | .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation) |
533 | .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition) | 533 | .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition) |
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 8fcd72d5d..3c4eacfeb 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -1,5 +1,5 @@ | |||
1 | <!--- | 1 | <!--- |
2 | lsp_ext.rs hash: 6e57fc1b345b00e9 | 2 | lsp_ext.rs hash: 10a8988e6893e6b2 |
3 | 3 | ||
4 | If you need to change the above hash to make the test pass, please check if you | 4 | If you need to change the above hash to make the test pass, please check if you |
5 | need to adjust this doc as well and ping this issue: | 5 | need to adjust this doc as well and ping this issue: |
@@ -650,3 +650,37 @@ export const enum Direction { | |||
650 | Down = "Down" | 650 | Down = "Down" |
651 | } | 651 | } |
652 | ``` | 652 | ``` |
653 | |||
654 | ## Workspace Symbols Filtering | ||
655 | |||
656 | **Issue:** https://github.com/rust-analyzer/rust-analyzer/pull/7698 | ||
657 | |||
658 | **Experimental Server Capability:** `{ "workspaceSymbolScopeKindFiltering": boolean }` | ||
659 | |||
660 | Extends the existing `workspace/symbol` request with ability to filter symbols by broad scope and kind of symbol. | ||
661 | If this capability is set, `workspace/symbol` parameter gains two new optional fields: | ||
662 | |||
663 | |||
664 | ```typescript | ||
665 | interface WorkspaceSymbolParams { | ||
666 | /** | ||
667 | * Return only the symbols defined in the specified scope. | ||
668 | */ | ||
669 | searchScope?: WorkspaceSymbolSearchScope; | ||
670 | /** | ||
671 | * Return only the symbols of specified kinds. | ||
672 | */ | ||
673 | searchKind?: WorkspaceSymbolSearchKind; | ||
674 | ... | ||
675 | } | ||
676 | |||
677 | const enum WorkspaceSymbolSearchScope { | ||
678 | Workspace = "workspace", | ||
679 | WorkspaceAndDependencies = "workspaceAndDependencies" | ||
680 | } | ||
681 | |||
682 | const enum WorkspaceSymbolSearchKind { | ||
683 | OnlyTypes = "onlyTypes", | ||
684 | AllSymbols = "allSymbols" | ||
685 | } | ||
686 | ``` | ||
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index b2c1f6261..c02bab7cc 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc | |||
@@ -346,3 +346,13 @@ Additional arguments to `rustfmt`. | |||
346 | Advanced option, fully override the command rust-analyzer uses for | 346 | Advanced option, fully override the command rust-analyzer uses for |
347 | formatting. | 347 | formatting. |
348 | -- | 348 | -- |
349 | [[rust-analyzer.workspace.symbol.search.scope]]rust-analyzer.workspace.symbol.search.scope (default: `"workspace"`):: | ||
350 | + | ||
351 | -- | ||
352 | Workspace symbol search scope. | ||
353 | -- | ||
354 | [[rust-analyzer.workspace.symbol.search.kind]]rust-analyzer.workspace.symbol.search.kind (default: `"only_types"`):: | ||
355 | + | ||
356 | -- | ||
357 | Workspace symbol search kind. | ||
358 | -- | ||
diff --git a/editors/code/package.json b/editors/code/package.json index 48d12b35a..1743b374c 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -790,6 +790,32 @@ | |||
790 | "type": "string" | 790 | "type": "string" |
791 | } | 791 | } |
792 | }, | 792 | }, |
793 | "rust-analyzer.workspace.symbol.search.scope": { | ||
794 | "markdownDescription": "Workspace symbol search scope.", | ||
795 | "default": "workspace", | ||
796 | "type": "string", | ||
797 | "enum": [ | ||
798 | "workspace", | ||
799 | "workspace_and_dependencies" | ||
800 | ], | ||
801 | "enumDescriptions": [ | ||
802 | "Search in current workspace only", | ||
803 | "Search in current workspace and dependencies" | ||
804 | ] | ||
805 | }, | ||
806 | "rust-analyzer.workspace.symbol.search.kind": { | ||
807 | "markdownDescription": "Workspace symbol search kind.", | ||
808 | "default": "only_types", | ||
809 | "type": "string", | ||
810 | "enum": [ | ||
811 | "only_types", | ||
812 | "all_symbols" | ||
813 | ], | ||
814 | "enumDescriptions": [ | ||
815 | "Search for types only", | ||
816 | "Search for all symbols kinds" | ||
817 | ] | ||
818 | }, | ||
793 | "$generated-end": false | 819 | "$generated-end": false |
794 | } | 820 | } |
795 | }, | 821 | }, |