aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--crates/ra_assists/src/test_db.rs2
-rw-r--r--crates/ra_hir/src/code_model.rs8
-rw-r--r--crates/ra_hir/src/debug.rs94
-rw-r--r--crates/ra_hir/src/has_source.rs (renamed from crates/ra_hir/src/code_model/src.rs)0
-rw-r--r--crates/ra_hir/src/lib.rs14
-rw-r--r--crates/ra_hir/src/source_binder.rs4
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs206
-rw-r--r--crates/ra_hir_ty/src/infer/coerce.rs6
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs37
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs2
-rw-r--r--crates/ra_ide/src/db.rs14
-rw-r--r--docs/user/README.md17
-rw-r--r--editors/code/package-lock.json5
-rw-r--r--editors/code/package.json1
-rw-r--r--editors/code/src/extension.ts12
-rw-r--r--editors/code/src/server.ts11
-rw-r--r--xtask/src/lib.rs4
18 files changed, 153 insertions, 287 deletions
diff --git a/README.md b/README.md
index 74c971c0d..979e4ef88 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,8 @@ $ cargo xtask install
37$ cargo xtask install --server 37$ cargo xtask install --server
38``` 38```
39 39
40For non-standard setup of VS Code and other editors, see [./docs/user](./docs/user). 40For non-standard setup of VS Code and other editors, or if the language server
41cannot start, see [./docs/user](./docs/user).
41 42
42## Documentation 43## Documentation
43 44
diff --git a/crates/ra_assists/src/test_db.rs b/crates/ra_assists/src/test_db.rs
index 523259fd4..d5249f308 100644
--- a/crates/ra_assists/src/test_db.rs
+++ b/crates/ra_assists/src/test_db.rs
@@ -43,5 +43,3 @@ impl FileLoader for TestDB {
43 FileLoaderDelegate(self).relevant_crates(file_id) 43 FileLoaderDelegate(self).relevant_crates(file_id)
44 } 44 }
45} 45}
46
47impl hir::debug::HirDebugHelper for TestDB {}
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 7ac1bf461..c013ff99b 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1,7 +1,4 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2
3pub(crate) mod src;
4
5use std::sync::Arc; 2use std::sync::Arc;
6 3
7use either::Either; 4use either::Either;
@@ -989,11 +986,6 @@ impl Type {
989 None 986 None
990 } 987 }
991 988
992 // FIXME: remove
993 pub fn into_ty(self) -> Ty {
994 self.ty.value
995 }
996
997 pub fn as_adt(&self) -> Option<Adt> { 989 pub fn as_adt(&self) -> Option<Adt> {
998 let (adt, _subst) = self.ty.value.as_adt()?; 990 let (adt, _subst) = self.ty.value.as_adt()?;
999 Some(adt.into()) 991 Some(adt.into())
diff --git a/crates/ra_hir/src/debug.rs b/crates/ra_hir/src/debug.rs
deleted file mode 100644
index 6cd5c8cb9..000000000
--- a/crates/ra_hir/src/debug.rs
+++ /dev/null
@@ -1,94 +0,0 @@
1//! XXX: This does not work at the moment.
2//!
3//! printf debugging infrastructure for rust-analyzer.
4//!
5//! When you print a hir type, like a module, using `eprintln!("{:?}", module)`,
6//! you usually get back a numeric ID, which doesn't tell you much:
7//! `Module(92)`.
8//!
9//! This module adds convenience `debug` methods to various types, which resolve
10//! the id to a human-readable location info:
11//!
12//! ```not_rust
13//! eprintln!("{:?}", module.debug(db));
14//! =>
15//! Module { name: collections, path: "liballoc/collections/mod.rs" }
16//! ```
17//!
18//! Note that to get this info, we might need to execute queries! So
19//!
20//! * don't use the `debug` methods for logging
21//! * when debugging, be aware that interference is possible.
22
23use std::fmt;
24
25use hir_expand::HirFileId;
26use ra_db::{CrateId, FileId};
27
28use crate::{db::HirDatabase, Crate, Module, Name};
29
30impl Crate {
31 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
32 debug_fn(move |fmt| db.debug_crate(self, fmt))
33 }
34}
35
36impl Module {
37 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
38 debug_fn(move |fmt| db.debug_module(self, fmt))
39 }
40}
41
42pub trait HirDebugHelper: HirDatabase {
43 fn crate_name(&self, _krate: CrateId) -> Option<String> {
44 None
45 }
46 fn file_path(&self, _file_id: FileId) -> Option<String> {
47 None
48 }
49}
50
51pub trait HirDebugDatabase {
52 fn debug_crate(&self, krate: Crate, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
53 fn debug_module(&self, module: Module, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
54 fn debug_hir_file_id(&self, file_id: HirFileId, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
55}
56
57impl<DB: HirDebugHelper> HirDebugDatabase for DB {
58 fn debug_crate(&self, krate: Crate, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
59 let mut builder = fmt.debug_tuple("Crate");
60 match self.crate_name(krate.id) {
61 Some(name) => builder.field(&name),
62 None => builder.field(&krate.id),
63 }
64 .finish()
65 }
66
67 fn debug_module(&self, module: Module, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
68 let file_id = module.definition_source(self).file_id.original_file(self);
69 let path = self.file_path(file_id).unwrap_or_else(|| "N/A".to_string());
70 fmt.debug_struct("Module")
71 .field("name", &module.name(self).unwrap_or_else(Name::missing))
72 .field("path", &path)
73 .finish()
74 }
75
76 fn debug_hir_file_id(&self, file_id: HirFileId, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
77 let original = file_id.original_file(self);
78 let path = self.file_path(original).unwrap_or_else(|| "N/A".to_string());
79 let is_macro = file_id != original.into();
80 fmt.debug_struct("HirFileId").field("path", &path).field("macro", &is_macro).finish()
81 }
82}
83
84fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
85 struct DebugFn<F>(F);
86
87 impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for DebugFn<F> {
88 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
89 (&self.0)(fmt)
90 }
91 }
92
93 DebugFn(f)
94}
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/has_source.rs
index b09582f93..b09582f93 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/has_source.rs
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index bb22882b1..e7602ee30 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -26,8 +26,6 @@ macro_rules! impl_froms {
26 } 26 }
27} 27}
28 28
29pub mod debug;
30
31pub mod db; 29pub mod db;
32pub mod source_binder; 30pub mod source_binder;
33 31
@@ -36,16 +34,18 @@ pub mod diagnostics;
36mod from_id; 34mod from_id;
37mod code_model; 35mod code_model;
38 36
39pub mod from_source; 37mod has_source;
38mod from_source;
40 39
41pub use crate::{ 40pub use crate::{
42 code_model::{ 41 code_model::{
43 src::HasSource, Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency, 42 Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency, DefWithBody, Docs, Enum,
44 DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, HasAttrs, 43 EnumVariant, FieldSource, Function, GenericDef, HasAttrs, ImplBlock, Import, Local,
45 ImplBlock, Import, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, 44 MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, StructField, Trait, Type, TypeAlias,
46 StructField, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, 45 TypeParam, Union, VariantDef,
47 }, 46 },
48 from_source::FromSource, 47 from_source::FromSource,
48 has_source::HasSource,
49 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 49 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
50}; 50};
51 51
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 9efd0477c..44d185003 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -427,7 +427,7 @@ impl SourceAnalyzer {
427 427
428 /// Checks that particular type `ty` implements `std::future::Future`. 428 /// Checks that particular type `ty` implements `std::future::Future`.
429 /// This function is used in `.await` syntax completion. 429 /// This function is used in `.await` syntax completion.
430 pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { 430 pub fn impls_future(&self, db: &impl HirDatabase, ty: Type) -> bool {
431 let std_future_path = known::std_future_future(); 431 let std_future_path = known::std_future_future();
432 432
433 let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) { 433 let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) {
@@ -440,7 +440,7 @@ impl SourceAnalyzer {
440 _ => return false, 440 _ => return false,
441 }; 441 };
442 442
443 let canonical_ty = Canonical { value: ty, num_vars: 0 }; 443 let canonical_ty = Canonical { value: ty.ty.value, num_vars: 0 };
444 implements_trait(&canonical_ty, db, &self.resolver, krate.into(), std_future_trait) 444 implements_trait(&canonical_ty, db, &self.resolver, krate.into(), std_future_trait)
445 } 445 }
446 446
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 3ff071f9e..a80067979 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -12,7 +12,7 @@ use hir_expand::{
12use ra_cfg::CfgOptions; 12use ra_cfg::CfgOptions;
13use ra_db::{CrateId, FileId}; 13use ra_db::{CrateId, FileId};
14use ra_syntax::ast; 14use ra_syntax::ast;
15use rustc_hash::{FxHashMap, FxHashSet}; 15use rustc_hash::FxHashMap;
16use test_utils::tested_by; 16use test_utils::tested_by;
17 17
18use crate::{ 18use crate::{
@@ -63,42 +63,12 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
63 unexpanded_macros: Vec::new(), 63 unexpanded_macros: Vec::new(),
64 unexpanded_attribute_macros: Vec::new(), 64 unexpanded_attribute_macros: Vec::new(),
65 mod_dirs: FxHashMap::default(), 65 mod_dirs: FxHashMap::default(),
66 macro_stack_monitor: MacroStackMonitor::default(),
67 poison_macros: FxHashSet::default(),
68 cfg_options, 66 cfg_options,
69 }; 67 };
70 collector.collect(); 68 collector.collect();
71 collector.finish() 69 collector.finish()
72} 70}
73 71
74#[derive(Default)]
75struct MacroStackMonitor {
76 counts: FxHashMap<MacroDefId, u32>,
77
78 /// Mainly use for test
79 validator: Option<Box<dyn Fn(u32) -> bool>>,
80}
81
82impl MacroStackMonitor {
83 fn increase(&mut self, macro_def_id: MacroDefId) {
84 *self.counts.entry(macro_def_id).or_default() += 1;
85 }
86
87 fn decrease(&mut self, macro_def_id: MacroDefId) {
88 *self.counts.entry(macro_def_id).or_default() -= 1;
89 }
90
91 fn is_poison(&self, macro_def_id: MacroDefId) -> bool {
92 let cur = *self.counts.get(&macro_def_id).unwrap_or(&0);
93
94 if let Some(validator) = &self.validator {
95 validator(cur)
96 } else {
97 cur > 100
98 }
99 }
100}
101
102#[derive(Copy, Clone, Debug, Eq, PartialEq)] 72#[derive(Copy, Clone, Debug, Eq, PartialEq)]
103enum PartialResolvedImport { 73enum PartialResolvedImport {
104 /// None of any namespaces is resolved 74 /// None of any namespaces is resolved
@@ -127,6 +97,14 @@ struct ImportDirective {
127 status: PartialResolvedImport, 97 status: PartialResolvedImport,
128} 98}
129 99
100#[derive(Clone, Debug, Eq, PartialEq)]
101struct MacroDirective {
102 module_id: LocalModuleId,
103 ast_id: AstId<ast::MacroCall>,
104 path: Path,
105 legacy: Option<MacroCallId>,
106}
107
130/// Walks the tree of module recursively 108/// Walks the tree of module recursively
131struct DefCollector<'a, DB> { 109struct DefCollector<'a, DB> {
132 db: &'a DB, 110 db: &'a DB,
@@ -134,25 +112,9 @@ struct DefCollector<'a, DB> {
134 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, LocalImportId)>>, 112 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, LocalImportId)>>,
135 unresolved_imports: Vec<ImportDirective>, 113 unresolved_imports: Vec<ImportDirective>,
136 resolved_imports: Vec<ImportDirective>, 114 resolved_imports: Vec<ImportDirective>,
137 unexpanded_macros: Vec<(LocalModuleId, AstId<ast::MacroCall>, Path)>, 115 unexpanded_macros: Vec<MacroDirective>,
138 unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, Path)>, 116 unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, Path)>,
139 mod_dirs: FxHashMap<LocalModuleId, ModDir>, 117 mod_dirs: FxHashMap<LocalModuleId, ModDir>,
140
141 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
142 /// To prevent stack overflow, we add a deep counter here for prevent that.
143 macro_stack_monitor: MacroStackMonitor,
144 /// Some macros are not well-behavior, which leads to infinite loop
145 /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
146 /// We mark it down and skip it in collector
147 ///
148 /// FIXME:
149 /// Right now it only handle a poison macro in a single crate,
150 /// such that if other crate try to call that macro,
151 /// the whole process will do again until it became poisoned in that crate.
152 /// We should handle this macro set globally
153 /// However, do we want to put it as a global variable?
154 poison_macros: FxHashSet<MacroDefId>,
155
156 cfg_options: &'a CfgOptions, 118 cfg_options: &'a CfgOptions,
157} 119}
158 120
@@ -556,18 +518,24 @@ where
556 std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new()); 518 std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new());
557 let mut resolved = Vec::new(); 519 let mut resolved = Vec::new();
558 let mut res = ReachedFixedPoint::Yes; 520 let mut res = ReachedFixedPoint::Yes;
559 macros.retain(|(module_id, ast_id, path)| { 521 macros.retain(|directive| {
522 if let Some(call_id) = directive.legacy {
523 res = ReachedFixedPoint::No;
524 resolved.push((directive.module_id, call_id));
525 return false;
526 }
527
560 let resolved_res = self.def_map.resolve_path_fp_with_macro( 528 let resolved_res = self.def_map.resolve_path_fp_with_macro(
561 self.db, 529 self.db,
562 ResolveMode::Other, 530 ResolveMode::Other,
563 *module_id, 531 directive.module_id,
564 path, 532 &directive.path,
565 BuiltinShadowMode::Module, 533 BuiltinShadowMode::Module,
566 ); 534 );
567 535
568 if let Some(def) = resolved_res.resolved_def.take_macros() { 536 if let Some(def) = resolved_res.resolved_def.take_macros() {
569 let call_id = def.as_call_id(self.db, MacroCallKind::FnLike(*ast_id)); 537 let call_id = def.as_call_id(self.db, MacroCallKind::FnLike(directive.ast_id));
570 resolved.push((*module_id, call_id, def)); 538 resolved.push((directive.module_id, call_id));
571 res = ReachedFixedPoint::No; 539 res = ReachedFixedPoint::No;
572 return false; 540 return false;
573 } 541 }
@@ -579,7 +547,7 @@ where
579 547
580 if let Some(def) = resolved_res { 548 if let Some(def) = resolved_res {
581 let call_id = def.as_call_id(self.db, MacroCallKind::Attr(*ast_id)); 549 let call_id = def.as_call_id(self.db, MacroCallKind::Attr(*ast_id));
582 resolved.push((*module_id, call_id, def)); 550 resolved.push((*module_id, call_id));
583 res = ReachedFixedPoint::No; 551 res = ReachedFixedPoint::No;
584 return false; 552 return false;
585 } 553 }
@@ -590,8 +558,8 @@ where
590 self.unexpanded_macros = macros; 558 self.unexpanded_macros = macros;
591 self.unexpanded_attribute_macros = attribute_macros; 559 self.unexpanded_attribute_macros = attribute_macros;
592 560
593 for (module_id, macro_call_id, macro_def_id) in resolved { 561 for (module_id, macro_call_id) in resolved {
594 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id); 562 self.collect_macro_expansion(module_id, macro_call_id);
595 } 563 }
596 564
597 res 565 res
@@ -611,36 +579,18 @@ where
611 None 579 None
612 } 580 }
613 581
614 fn collect_macro_expansion( 582 fn collect_macro_expansion(&mut self, module_id: LocalModuleId, macro_call_id: MacroCallId) {
615 &mut self, 583 let file_id: HirFileId = macro_call_id.as_file();
616 module_id: LocalModuleId, 584 let raw_items = self.db.raw_items(file_id);
617 macro_call_id: MacroCallId, 585 let mod_dir = self.mod_dirs[&module_id].clone();
618 macro_def_id: MacroDefId, 586 ModCollector {
619 ) { 587 def_collector: &mut *self,
620 if self.poison_macros.contains(&macro_def_id) { 588 file_id,
621 return; 589 module_id,
622 } 590 raw_items: &raw_items,
623 591 mod_dir,
624 self.macro_stack_monitor.increase(macro_def_id);
625
626 if !self.macro_stack_monitor.is_poison(macro_def_id) {
627 let file_id: HirFileId = macro_call_id.as_file();
628 let raw_items = self.db.raw_items(file_id);
629 let mod_dir = self.mod_dirs[&module_id].clone();
630 ModCollector {
631 def_collector: &mut *self,
632 file_id,
633 module_id,
634 raw_items: &raw_items,
635 mod_dir,
636 }
637 .collect(raw_items.items());
638 } else {
639 log::error!("Too deep macro expansion: {:?}", macro_call_id);
640 self.poison_macros.insert(macro_def_id);
641 } 592 }
642 593 .collect(raw_items.items());
643 self.macro_stack_monitor.decrease(macro_def_id);
644 } 594 }
645 595
646 fn finish(self) -> CrateDefMap { 596 fn finish(self) -> CrateDefMap {
@@ -908,15 +858,20 @@ where
908 return; 858 return;
909 } 859 }
910 860
911 // Case 2: try to resolve in legacy scope and expand macro_rules, triggering 861 // Case 2: try to resolve in legacy scope and expand macro_rules
912 // recursive item collection.
913 if let Some(macro_def) = mac.path.as_ident().and_then(|name| { 862 if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
914 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) 863 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
915 }) { 864 }) {
916 let macro_call_id = 865 let macro_call_id =
917 macro_def.as_call_id(self.def_collector.db, MacroCallKind::FnLike(ast_id)); 866 macro_def.as_call_id(self.def_collector.db, MacroCallKind::FnLike(ast_id));
918 867
919 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_def); 868 self.def_collector.unexpanded_macros.push(MacroDirective {
869 module_id: self.module_id,
870 path: mac.path.clone(),
871 ast_id,
872 legacy: Some(macro_call_id),
873 });
874
920 return; 875 return;
921 } 876 }
922 877
@@ -926,7 +881,13 @@ where
926 if path.is_ident() { 881 if path.is_ident() {
927 path.kind = PathKind::Self_; 882 path.kind = PathKind::Self_;
928 } 883 }
929 self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path)); 884
885 self.def_collector.unexpanded_macros.push(MacroDirective {
886 module_id: self.module_id,
887 path,
888 ast_id,
889 legacy: None,
890 });
930 } 891 }
931 892
932 fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { 893 fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
@@ -951,19 +912,13 @@ fn is_macro_rules(path: &Path) -> bool {
951 912
952#[cfg(test)] 913#[cfg(test)]
953mod tests { 914mod tests {
915 use crate::{db::DefDatabase, test_db::TestDB};
954 use ra_arena::Arena; 916 use ra_arena::Arena;
955 use ra_db::{fixture::WithFixture, SourceDatabase}; 917 use ra_db::{fixture::WithFixture, SourceDatabase};
956 use rustc_hash::FxHashSet;
957
958 use crate::{db::DefDatabase, test_db::TestDB};
959 918
960 use super::*; 919 use super::*;
961 920
962 fn do_collect_defs( 921 fn do_collect_defs(db: &impl DefDatabase, def_map: CrateDefMap) -> CrateDefMap {
963 db: &impl DefDatabase,
964 def_map: CrateDefMap,
965 monitor: MacroStackMonitor,
966 ) -> (CrateDefMap, FxHashSet<MacroDefId>) {
967 let mut collector = DefCollector { 922 let mut collector = DefCollector {
968 db, 923 db,
969 def_map, 924 def_map,
@@ -973,19 +928,13 @@ mod tests {
973 unexpanded_macros: Vec::new(), 928 unexpanded_macros: Vec::new(),
974 unexpanded_attribute_macros: Vec::new(), 929 unexpanded_attribute_macros: Vec::new(),
975 mod_dirs: FxHashMap::default(), 930 mod_dirs: FxHashMap::default(),
976 macro_stack_monitor: monitor,
977 poison_macros: FxHashSet::default(),
978 cfg_options: &CfgOptions::default(), 931 cfg_options: &CfgOptions::default(),
979 }; 932 };
980 collector.collect(); 933 collector.collect();
981 (collector.def_map, collector.poison_macros) 934 collector.def_map
982 } 935 }
983 936
984 fn do_limited_resolve( 937 fn do_resolve(code: &str) -> CrateDefMap {
985 code: &str,
986 limit: u32,
987 poison_limit: u32,
988 ) -> (CrateDefMap, FxHashSet<MacroDefId>) {
989 let (db, _file_id) = TestDB::with_single_file(&code); 938 let (db, _file_id) = TestDB::with_single_file(&code);
990 let krate = db.test_crate(); 939 let krate = db.test_crate();
991 940
@@ -1003,59 +952,18 @@ mod tests {
1003 diagnostics: Vec::new(), 952 diagnostics: Vec::new(),
1004 } 953 }
1005 }; 954 };
1006 955 do_collect_defs(&db, def_map)
1007 let mut monitor = MacroStackMonitor::default();
1008 monitor.validator = Some(Box::new(move |count| {
1009 assert!(count < limit);
1010 count >= poison_limit
1011 }));
1012
1013 do_collect_defs(&db, def_map, monitor)
1014 } 956 }
1015 957
1016 #[test] 958 #[test]
1017 fn test_macro_expand_limit_width() { 959 fn test_macro_expand_will_stop() {
1018 do_limited_resolve( 960 do_resolve(
1019 r#" 961 r#"
1020 macro_rules! foo { 962 macro_rules! foo {
1021 ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); } 963 ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); }
1022 } 964 }
1023foo!(KABOOM); 965foo!(KABOOM);
1024 "#, 966 "#,
1025 16,
1026 1000,
1027 ); 967 );
1028 } 968 }
1029
1030 #[test]
1031 fn test_macro_expand_poisoned() {
1032 let (_, poison_macros) = do_limited_resolve(
1033 r#"
1034 macro_rules! foo {
1035 ($ty:ty) => { foo!($ty); }
1036 }
1037foo!(KABOOM);
1038 "#,
1039 100,
1040 16,
1041 );
1042
1043 assert_eq!(poison_macros.len(), 1);
1044 }
1045
1046 #[test]
1047 fn test_macro_expand_normal() {
1048 let (_, poison_macros) = do_limited_resolve(
1049 r#"
1050 macro_rules! foo {
1051 ($ident:ident) => { struct $ident {} }
1052 }
1053foo!(Bar);
1054 "#,
1055 16,
1056 16,
1057 );
1058
1059 assert_eq!(poison_macros.len(), 0);
1060 }
1061} 969}
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs
index 9daa77cfa..0f4dac45e 100644
--- a/crates/ra_hir_ty/src/infer/coerce.rs
+++ b/crates/ra_hir_ty/src/infer/coerce.rs
@@ -332,7 +332,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
332 // It will not recurse to `coerce`. 332 // It will not recurse to `coerce`.
333 return self.table.unify_substs(st1, st2, 0); 333 return self.table.unify_substs(st1, st2, 0);
334 } 334 }
335 _ => {} 335 _ => {
336 if self.table.unify_inner_trivial(&derefed_ty, &to_ty) {
337 return true;
338 }
339 }
336 } 340 }
337 } 341 }
338 342
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index 58b22396f..ac9e3872a 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -403,3 +403,40 @@ fn test() {
403 "### 403 "###
404 ); 404 );
405} 405}
406
407#[test]
408fn coerce_autoderef_generic() {
409 assert_snapshot!(
410 infer_with_mismatches(r#"
411struct Foo;
412fn takes_ref<T>(x: &T) -> T { *x }
413fn test() {
414 takes_ref(&Foo);
415 takes_ref(&&Foo);
416 takes_ref(&&&Foo);
417}
418"#, true),
419 @r###"
420 [29; 30) 'x': &T
421 [41; 47) '{ *x }': T
422 [43; 45) '*x': T
423 [44; 45) 'x': &T
424 [58; 127) '{ ...oo); }': ()
425 [64; 73) 'takes_ref': fn takes_ref<Foo>(&T) -> T
426 [64; 79) 'takes_ref(&Foo)': Foo
427 [74; 78) '&Foo': &Foo
428 [75; 78) 'Foo': Foo
429 [85; 94) 'takes_ref': fn takes_ref<&Foo>(&T) -> T
430 [85; 101) 'takes_...&&Foo)': &Foo
431 [95; 100) '&&Foo': &&Foo
432 [96; 100) '&Foo': &Foo
433 [97; 100) 'Foo': Foo
434 [107; 116) 'takes_ref': fn takes_ref<&&Foo>(&T) -> T
435 [107; 124) 'takes_...&&Foo)': &&Foo
436 [117; 123) '&&&Foo': &&&Foo
437 [118; 123) '&&Foo': &&Foo
438 [119; 123) '&Foo': &Foo
439 [120; 123) 'Foo': Foo
440 "###
441 );
442}
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index a52eb0ee4..294964887 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -27,7 +27,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
27 complete_methods(acc, ctx, &receiver_ty); 27 complete_methods(acc, ctx, &receiver_ty);
28 28
29 // Suggest .await syntax for types that implement Future trait 29 // Suggest .await syntax for types that implement Future trait
30 if ctx.analyzer.impls_future(ctx.db, receiver_ty.into_ty()) { 30 if ctx.analyzer.impls_future(ctx.db, receiver_ty) {
31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") 31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
32 .detail("expr.await") 32 .detail("expr.await")
33 .insert_text("await") 33 .insert_text("await")
diff --git a/crates/ra_ide/src/db.rs b/crates/ra_ide/src/db.rs
index f739ebecd..47d0aed6f 100644
--- a/crates/ra_ide/src/db.rs
+++ b/crates/ra_ide/src/db.rs
@@ -5,7 +5,7 @@ use std::sync::Arc;
5use ra_db::{ 5use ra_db::{
6 salsa::{self, Database, Durability}, 6 salsa::{self, Database, Durability},
7 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, 7 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath,
8 SourceDatabase, SourceDatabaseExt, SourceRootId, 8 SourceDatabase, SourceRootId,
9}; 9};
10use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
11 11
@@ -49,18 +49,6 @@ impl FileLoader for RootDatabase {
49 } 49 }
50} 50}
51 51
52impl hir::debug::HirDebugHelper for RootDatabase {
53 fn crate_name(&self, krate: CrateId) -> Option<String> {
54 self.debug_data.crate_names.get(&krate).cloned()
55 }
56 fn file_path(&self, file_id: FileId) -> Option<String> {
57 let source_root_id = self.file_source_root(file_id);
58 let source_root_path = self.debug_data.root_paths.get(&source_root_id)?;
59 let file_path = self.file_relative_path(file_id);
60 Some(format!("{}/{}", source_root_path, file_path))
61 }
62}
63
64impl salsa::Database for RootDatabase { 52impl salsa::Database for RootDatabase {
65 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> { 53 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> {
66 &self.runtime 54 &self.runtime
diff --git a/docs/user/README.md b/docs/user/README.md
index 5ec8fb25d..04c349342 100644
--- a/docs/user/README.md
+++ b/docs/user/README.md
@@ -204,4 +204,19 @@ Installation:
204 204
205* You can now invoke the command palette and type LSP enable to locally/globally enable the rust-analyzer LSP (type LSP enable, then choose either locally or globally, then select rust-analyzer) 205* You can now invoke the command palette and type LSP enable to locally/globally enable the rust-analyzer LSP (type LSP enable, then choose either locally or globally, then select rust-analyzer)
206 206
207* Note that `ra_lsp_server` binary must be in `$PATH` for this to work. If it's not the case, you can specify full path to the binary, which is typically `.cargo/bin/ra_lsp_server`. 207### Setting up the `PATH` variable
208
209On Unix systems, `rustup` adds `~/.cargo/bin` to `PATH` by modifying the shell's
210startup file. Depending on your configuration, your Desktop Environment might not
211actually load it. If you find that `rust-analyzer` only runs when starting the
212editor from the terminal, you will have to set up your `PATH` variable manually.
213
214There are a couple of ways to do that:
215
216- for Code, set `rust-analyzer.raLspServerPath` to `~/.cargo/bin` (the `~` is
217 automatically resolved by the extension)
218- copy the binary to a location that is already in `PATH`, e.g. `/usr/local/bin`
219- on Linux, use PAM to configure the `PATH` variable, by e.g. putting
220 `PATH DEFAULT=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:@{HOME}/.cargo/bin:@{HOME}/.local/bin`
221 in your `~/.pam_environment` file; note that this might interfere with other
222 defaults set by the system administrator via `/etc/environment`.
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 2ceac60a0..099aaaaa2 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -763,6 +763,11 @@
763 "chalk": "^2.0.1" 763 "chalk": "^2.0.1"
764 } 764 }
765 }, 765 },
766 "lookpath": {
767 "version": "1.0.3",
768 "resolved": "https://registry.npmjs.org/lookpath/-/lookpath-1.0.3.tgz",
769 "integrity": "sha512-XIdgzlX26g10XnzyZdO/4obybEmfGnZyWQZ2DgmmEfVB79X+n3lhUoIzMe501C6s7RmCpAo66OPegWc+CsxYMg=="
770 },
766 "magic-string": { 771 "magic-string": {
767 "version": "0.25.3", 772 "version": "0.25.3",
768 "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz", 773 "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz",
diff --git a/editors/code/package.json b/editors/code/package.json
index 94887674b..5dea8fac0 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -31,6 +31,7 @@
31 "singleQuote": true 31 "singleQuote": true
32 }, 32 },
33 "dependencies": { 33 "dependencies": {
34 "lookpath": "^1.0.3",
34 "seedrandom": "^3.0.1", 35 "seedrandom": "^3.0.1",
35 "vscode-languageclient": "^5.3.0-next.4" 36 "vscode-languageclient": "^5.3.0-next.4"
36 }, 37 },
diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts
index 683497dfd..6637c3bf0 100644
--- a/editors/code/src/extension.ts
+++ b/editors/code/src/extension.ts
@@ -14,7 +14,7 @@ import * as events from './events';
14import * as notifications from './notifications'; 14import * as notifications from './notifications';
15import { Server } from './server'; 15import { Server } from './server';
16 16
17export function activate(context: vscode.ExtensionContext) { 17export async function activate(context: vscode.ExtensionContext) {
18 function disposeOnDeactivation(disposable: vscode.Disposable) { 18 function disposeOnDeactivation(disposable: vscode.Disposable) {
19 context.subscriptions.push(disposable); 19 context.subscriptions.push(disposable);
20 } 20 }
@@ -159,7 +159,11 @@ export function activate(context: vscode.ExtensionContext) {
159 }); 159 });
160 160
161 // Start the language server, finally! 161 // Start the language server, finally!
162 startServer(); 162 try {
163 await startServer();
164 } catch (e) {
165 vscode.window.showErrorMessage(e.message);
166 }
163 167
164 if (Server.config.displayInlayHints) { 168 if (Server.config.displayInlayHints) {
165 const hintsUpdater = new HintsUpdater(); 169 const hintsUpdater = new HintsUpdater();
@@ -204,10 +208,10 @@ export function deactivate(): Thenable<void> {
204 return Server.client.stop(); 208 return Server.client.stop();
205} 209}
206 210
207async function reloadServer(startServer: () => void) { 211async function reloadServer(startServer: () => Promise<void>) {
208 if (Server.client != null) { 212 if (Server.client != null) {
209 vscode.window.showInformationMessage('Reloading rust-analyzer...'); 213 vscode.window.showInformationMessage('Reloading rust-analyzer...');
210 await Server.client.stop(); 214 await Server.client.stop();
211 startServer(); 215 await startServer();
212 } 216 }
213} 217}
diff --git a/editors/code/src/server.ts b/editors/code/src/server.ts
index 7907b70bc..e717ab294 100644
--- a/editors/code/src/server.ts
+++ b/editors/code/src/server.ts
@@ -1,3 +1,4 @@
1import { lookpath } from 'lookpath';
1import { homedir } from 'os'; 2import { homedir } from 'os';
2import * as lc from 'vscode-languageclient'; 3import * as lc from 'vscode-languageclient';
3 4
@@ -17,7 +18,7 @@ export class Server {
17 public static config = new Config(); 18 public static config = new Config();
18 public static client: lc.LanguageClient; 19 public static client: lc.LanguageClient;
19 20
20 public static start( 21 public static async start(
21 notificationHandlers: Iterable<[string, lc.GenericNotificationHandler]> 22 notificationHandlers: Iterable<[string, lc.GenericNotificationHandler]>
22 ) { 23 ) {
23 // '.' Is the fallback if no folder is open 24 // '.' Is the fallback if no folder is open
@@ -27,8 +28,14 @@ export class Server {
27 folder = workspace.workspaceFolders[0].uri.fsPath.toString(); 28 folder = workspace.workspaceFolders[0].uri.fsPath.toString();
28 } 29 }
29 30
31 const command = expandPathResolving(this.config.raLspServerPath);
32 if (!(await lookpath(command))) {
33 throw new Error(
34 `Cannot find rust-analyzer server \`${command}\` in PATH.`
35 );
36 }
30 const run: lc.Executable = { 37 const run: lc.Executable = {
31 command: expandPathResolving(this.config.raLspServerPath), 38 command,
32 options: { cwd: folder } 39 options: { cwd: folder }
33 }; 40 };
34 const serverOptions: lc.ServerOptions = { 41 const serverOptions: lc.ServerOptions = {
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index 7332a4072..190baeddf 100644
--- a/xtask/src/lib.rs
+++ b/xtask/src/lib.rs
@@ -79,7 +79,7 @@ pub fn run_rustfmt(mode: Mode) -> Result<()> {
79} 79}
80 80
81pub fn install_rustfmt() -> Result<()> { 81pub fn install_rustfmt() -> Result<()> {
82 run(&format!("rustup install {}", TOOLCHAIN), ".")?; 82 run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?;
83 run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".") 83 run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".")
84} 84}
85 85
@@ -125,7 +125,7 @@ pub fn run_clippy() -> Result<()> {
125} 125}
126 126
127pub fn install_clippy() -> Result<()> { 127pub fn install_clippy() -> Result<()> {
128 run(&format!("rustup install {}", TOOLCHAIN), ".")?; 128 run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?;
129 run(&format!("rustup component add clippy --toolchain {}", TOOLCHAIN), ".") 129 run(&format!("rustup component add clippy --toolchain {}", TOOLCHAIN), ".")
130} 130}
131 131