aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_def/src/item_scope.rs33
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs63
-rw-r--r--crates/ra_hir_def/src/resolver.rs13
-rw-r--r--crates/ra_ide/src/completion/complete_path.rs13
-rw-r--r--crates/ra_ide/src/marks.rs1
-rw-r--r--crates/ra_mbe/src/subtree_source.rs5
-rw-r--r--crates/ra_mbe/src/tests.rs22
-rw-r--r--crates/ra_parser/src/parser.rs2
-rw-r--r--docs/user/features.md25
-rw-r--r--editors/code/.eslintrc.js1
-rw-r--r--editors/code/package-lock.json14
-rw-r--r--editors/code/src/inlay_hints.ts2
-rw-r--r--editors/code/src/installation/server.ts2
13 files changed, 114 insertions, 82 deletions
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index 6e958ca75..5e943b780 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -30,7 +30,7 @@ pub struct ItemScope {
30 legacy_macros: FxHashMap<Name, MacroDefId>, 30 legacy_macros: FxHashMap<Name, MacroDefId>,
31} 31}
32 32
33static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { 33pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
34 BuiltinType::ALL 34 BuiltinType::ALL
35 .iter() 35 .iter()
36 .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public))) 36 .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public)))
@@ -40,9 +40,9 @@ static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
40/// Shadow mode for builtin type which can be shadowed by module. 40/// Shadow mode for builtin type which can be shadowed by module.
41#[derive(Debug, Copy, Clone, PartialEq, Eq)] 41#[derive(Debug, Copy, Clone, PartialEq, Eq)]
42pub(crate) enum BuiltinShadowMode { 42pub(crate) enum BuiltinShadowMode {
43 // Prefer Module 43 /// Prefer user-defined modules (or other types) over builtins.
44 Module, 44 Module,
45 // Prefer Other Types 45 /// Prefer builtins over user-defined modules (but not other types).
46 Other, 46 Other,
47} 47}
48 48
@@ -51,7 +51,7 @@ pub(crate) enum BuiltinShadowMode {
51impl ItemScope { 51impl ItemScope {
52 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { 52 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
53 //FIXME: shadowing 53 //FIXME: shadowing
54 self.visible.iter().chain(BUILTIN_SCOPE.iter()).map(|(n, def)| (n, *def)) 54 self.visible.iter().map(|(n, def)| (n, *def))
55 } 55 }
56 56
57 pub fn entries_without_primitives<'a>( 57 pub fn entries_without_primitives<'a>(
@@ -79,29 +79,8 @@ impl ItemScope {
79 } 79 }
80 80
81 /// Get a name from current module scope, legacy macros are not included 81 /// Get a name from current module scope, legacy macros are not included
82 pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> PerNs { 82 pub(crate) fn get(&self, name: &Name) -> PerNs {
83 match shadow { 83 self.visible.get(name).copied().unwrap_or_else(PerNs::none)
84 BuiltinShadowMode::Module => self
85 .visible
86 .get(name)
87 .or_else(|| BUILTIN_SCOPE.get(name))
88 .copied()
89 .unwrap_or_else(PerNs::none),
90 BuiltinShadowMode::Other => {
91 let item = self.visible.get(name).copied();
92 if let Some(def) = item {
93 if let Some(ModuleDefId::ModuleId(_)) = def.take_types() {
94 return BUILTIN_SCOPE
95 .get(name)
96 .copied()
97 .or(item)
98 .unwrap_or_else(PerNs::none);
99 }
100 }
101
102 item.or_else(|| BUILTIN_SCOPE.get(name).copied()).unwrap_or_else(PerNs::none)
103 }
104 }
105 } 84 }
106 85
107 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { 86 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
index fd6422d60..c058e70aa 100644
--- a/crates/ra_hir_def/src/nameres/path_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -18,6 +18,7 @@ use test_utils::tested_by;
18 18
19use crate::{ 19use crate::{
20 db::DefDatabase, 20 db::DefDatabase,
21 item_scope::BUILTIN_SCOPE,
21 nameres::{BuiltinShadowMode, CrateDefMap}, 22 nameres::{BuiltinShadowMode, CrateDefMap},
22 path::{ModPath, PathKind}, 23 path::{ModPath, PathKind},
23 per_ns::PerNs, 24 per_ns::PerNs,
@@ -103,15 +104,6 @@ impl CrateDefMap {
103 path: &ModPath, 104 path: &ModPath,
104 shadow: BuiltinShadowMode, 105 shadow: BuiltinShadowMode,
105 ) -> ResolvePathResult { 106 ) -> ResolvePathResult {
106 // if it is not the last segment, we prefer the module to the builtin
107 let prefer_module = |index| {
108 if index == path.segments.len() - 1 {
109 shadow
110 } else {
111 BuiltinShadowMode::Module
112 }
113 };
114
115 let mut segments = path.segments.iter().enumerate(); 107 let mut segments = path.segments.iter().enumerate();
116 let mut curr_per_ns: PerNs = match path.kind { 108 let mut curr_per_ns: PerNs = match path.kind {
117 PathKind::DollarCrate(krate) => { 109 PathKind::DollarCrate(krate) => {
@@ -140,20 +132,29 @@ impl CrateDefMap {
140 if self.edition == Edition::Edition2015 132 if self.edition == Edition::Edition2015
141 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => 133 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
142 { 134 {
143 let (idx, segment) = match segments.next() { 135 let (_, segment) = match segments.next() {
144 Some((idx, segment)) => (idx, segment), 136 Some((idx, segment)) => (idx, segment),
145 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 137 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
146 }; 138 };
147 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 139 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
148 self.resolve_name_in_crate_root_or_extern_prelude(&segment, prefer_module(idx)) 140 self.resolve_name_in_crate_root_or_extern_prelude(&segment)
149 } 141 }
150 PathKind::Plain => { 142 PathKind::Plain => {
151 let (idx, segment) = match segments.next() { 143 let (_, segment) = match segments.next() {
152 Some((idx, segment)) => (idx, segment), 144 Some((idx, segment)) => (idx, segment),
153 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 145 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
154 }; 146 };
147 // The first segment may be a builtin type. If the path has more
148 // than one segment, we first try resolving it as a module
149 // anyway.
150 // FIXME: If the next segment doesn't resolve in the module and
151 // BuiltinShadowMode wasn't Module, then we need to try
152 // resolving it as a builtin.
153 let prefer_module =
154 if path.segments.len() == 1 { shadow } else { BuiltinShadowMode::Module };
155
155 log::debug!("resolving {:?} in module", segment); 156 log::debug!("resolving {:?} in module", segment);
156 self.resolve_name_in_module(db, original_module, &segment, prefer_module(idx)) 157 self.resolve_name_in_module(db, original_module, &segment, prefer_module)
157 } 158 }
158 PathKind::Super(lvl) => { 159 PathKind::Super(lvl) => {
159 let m = successors(Some(original_module), |m| self.modules[*m].parent) 160 let m = successors(Some(original_module), |m| self.modules[*m].parent)
@@ -216,7 +217,7 @@ impl CrateDefMap {
216 } 217 }
217 218
218 // Since it is a qualified path here, it should not contains legacy macros 219 // Since it is a qualified path here, it should not contains legacy macros
219 self[module.local_id].scope.get(&segment, prefer_module(i)) 220 self[module.local_id].scope.get(&segment)
220 } 221 }
221 ModuleDefId::AdtId(AdtId::EnumId(e)) => { 222 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
222 // enum variant 223 // enum variant
@@ -275,33 +276,35 @@ impl CrateDefMap {
275 .scope 276 .scope
276 .get_legacy_macro(name) 277 .get_legacy_macro(name)
277 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public)); 278 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
278 let from_scope = self[module].scope.get(name, shadow); 279 let from_scope = self[module].scope.get(name);
280 let from_builtin = BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none);
281 let from_scope_or_builtin = match shadow {
282 BuiltinShadowMode::Module => from_scope.or(from_builtin),
283 BuiltinShadowMode::Other => {
284 if let Some(ModuleDefId::ModuleId(_)) = from_scope.take_types() {
285 from_builtin.or(from_scope)
286 } else {
287 from_scope.or(from_builtin)
288 }
289 }
290 };
279 let from_extern_prelude = self 291 let from_extern_prelude = self
280 .extern_prelude 292 .extern_prelude
281 .get(name) 293 .get(name)
282 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)); 294 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public));
283 let from_prelude = self.resolve_in_prelude(db, name, shadow); 295 let from_prelude = self.resolve_in_prelude(db, name);
284 296
285 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) 297 from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude)
286 } 298 }
287 299
288 fn resolve_name_in_crate_root_or_extern_prelude( 300 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
289 &self, 301 let from_crate_root = self[self.root].scope.get(name);
290 name: &Name,
291 shadow: BuiltinShadowMode,
292 ) -> PerNs {
293 let from_crate_root = self[self.root].scope.get(name, shadow);
294 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 302 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
295 303
296 from_crate_root.or(from_extern_prelude) 304 from_crate_root.or(from_extern_prelude)
297 } 305 }
298 306
299 fn resolve_in_prelude( 307 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs {
300 &self,
301 db: &impl DefDatabase,
302 name: &Name,
303 shadow: BuiltinShadowMode,
304 ) -> PerNs {
305 if let Some(prelude) = self.prelude { 308 if let Some(prelude) = self.prelude {
306 let keep; 309 let keep;
307 let def_map = if prelude.krate == self.krate { 310 let def_map = if prelude.krate == self.krate {
@@ -311,7 +314,7 @@ impl CrateDefMap {
311 keep = db.crate_def_map(prelude.krate); 314 keep = db.crate_def_map(prelude.krate);
312 &keep 315 &keep
313 }; 316 };
314 def_map[prelude.local_id].scope.get(name, shadow) 317 def_map[prelude.local_id].scope.get(name)
315 } else { 318 } else {
316 PerNs::none() 319 PerNs::none()
317 } 320 }
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index 5365b80e2..9dd4fa555 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -15,7 +15,7 @@ use crate::{
15 db::DefDatabase, 15 db::DefDatabase,
16 expr::{ExprId, PatId}, 16 expr::{ExprId, PatId},
17 generics::GenericParams, 17 generics::GenericParams,
18 item_scope::BuiltinShadowMode, 18 item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
19 nameres::CrateDefMap, 19 nameres::CrateDefMap,
20 path::{ModPath, PathKind}, 20 path::{ModPath, PathKind},
21 per_ns::PerNs, 21 per_ns::PerNs,
@@ -193,7 +193,7 @@ impl Resolver {
193 return Some((res, idx)); 193 return Some((res, idx));
194 } 194 }
195 Scope::LocalItemsScope(body) => { 195 Scope::LocalItemsScope(body) => {
196 let def = body.item_scope.get(first_name, BuiltinShadowMode::Other); 196 let def = body.item_scope.get(first_name);
197 if let Some(res) = to_type_ns(def) { 197 if let Some(res) = to_type_ns(def) {
198 return Some((res, None)); 198 return Some((res, None));
199 } 199 }
@@ -335,8 +335,10 @@ impl Resolver {
335 }; 335 };
336 } 336 }
337 Scope::LocalItemsScope(body) => { 337 Scope::LocalItemsScope(body) => {
338 let def = body.item_scope.get(first_name, BuiltinShadowMode::Other); 338 // we don't bother looking in the builtin scope here because there are no builtin values
339 if let Some(res) = to_value_ns(def) { 339 let def = to_value_ns(body.item_scope.get(first_name));
340
341 if let Some(res) = def {
340 return Some(ResolveValueResult::ValueNs(res)); 342 return Some(ResolveValueResult::ValueNs(res));
341 } 343 }
342 } 344 }
@@ -476,6 +478,9 @@ impl Scope {
476 m.crate_def_map.extern_prelude.iter().for_each(|(name, &def)| { 478 m.crate_def_map.extern_prelude.iter().for_each(|(name, &def)| {
477 f(name.clone(), ScopeDef::PerNs(PerNs::types(def, Visibility::Public))); 479 f(name.clone(), ScopeDef::PerNs(PerNs::types(def, Visibility::Public)));
478 }); 480 });
481 BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
482 f(name.clone(), ScopeDef::PerNs(def));
483 });
479 if let Some(prelude) = m.crate_def_map.prelude { 484 if let Some(prelude) = m.crate_def_map.prelude {
480 let prelude_def_map = db.crate_def_map(prelude.krate); 485 let prelude_def_map = db.crate_def_map(prelude.krate);
481 prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| { 486 prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| {
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs
index af24e9f48..2d7f09a6c 100644
--- a/crates/ra_ide/src/completion/complete_path.rs
+++ b/crates/ra_ide/src/completion/complete_path.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Completion of paths, including when writing a single name.
2 2
3use hir::{Adt, PathResolution, ScopeDef}; 3use hir::{Adt, PathResolution, ScopeDef};
4use ra_syntax::AstNode; 4use ra_syntax::AstNode;
@@ -20,10 +20,6 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
20 let module_scope = module.scope(ctx.db); 20 let module_scope = module.scope(ctx.db);
21 for (name, def) in module_scope { 21 for (name, def) in module_scope {
22 if ctx.use_item_syntax.is_some() { 22 if ctx.use_item_syntax.is_some() {
23 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def {
24 tested_by!(dont_complete_primitive_in_use);
25 continue;
26 }
27 if let ScopeDef::Unknown = def { 23 if let ScopeDef::Unknown = def {
28 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { 24 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
29 if name_ref.syntax().text() == name.to_string().as_str() { 25 if name_ref.syntax().text() == name.to_string().as_str() {
@@ -125,12 +121,17 @@ mod tests {
125 121
126 #[test] 122 #[test]
127 fn dont_complete_primitive_in_use() { 123 fn dont_complete_primitive_in_use() {
128 covers!(dont_complete_primitive_in_use);
129 let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType); 124 let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType);
130 assert!(completions.is_empty()); 125 assert!(completions.is_empty());
131 } 126 }
132 127
133 #[test] 128 #[test]
129 fn dont_complete_primitive_in_module_scope() {
130 let completions = do_completion(r"fn foo() { self::<|> }", CompletionKind::BuiltinType);
131 assert!(completions.is_empty());
132 }
133
134 #[test]
134 fn completes_primitives() { 135 fn completes_primitives() {
135 let completions = 136 let completions =
136 do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType); 137 do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType);
diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs
index 5bf4d2062..bcb67e373 100644
--- a/crates/ra_ide/src/marks.rs
+++ b/crates/ra_ide/src/marks.rs
@@ -10,6 +10,5 @@ test_utils::marks!(
10 goto_def_for_field_init_shorthand 10 goto_def_for_field_init_shorthand
11 call_info_bad_offset 11 call_info_bad_offset
12 dont_complete_current_use 12 dont_complete_current_use
13 dont_complete_primitive_in_use
14 test_resolve_parent_module_on_module_decl 13 test_resolve_parent_module_on_module_decl
15); 14);
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs
index dacca8279..91e324db9 100644
--- a/crates/ra_mbe/src/subtree_source.rs
+++ b/crates/ra_mbe/src/subtree_source.rs
@@ -1,7 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_parser::{Token, TokenSource}; 3use ra_parser::{Token, TokenSource};
4use ra_syntax::{lex_single_valid_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; 4use ra_syntax::{lex_single_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T};
5use std::cell::{Cell, Ref, RefCell}; 5use std::cell::{Cell, Ref, RefCell};
6use tt::buffer::{Cursor, TokenBuffer}; 6use tt::buffer::{Cursor, TokenBuffer};
7 7
@@ -129,7 +129,8 @@ fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken {
129} 129}
130 130
131fn convert_literal(l: &tt::Literal) -> TtToken { 131fn convert_literal(l: &tt::Literal) -> TtToken {
132 let kind = lex_single_valid_syntax_kind(&l.text) 132 let kind = lex_single_syntax_kind(&l.text)
133 .map(|(kind, _error)| kind)
133 .filter(|kind| kind.is_literal()) 134 .filter(|kind| kind.is_literal())
134 .unwrap_or_else(|| match l.text.as_ref() { 135 .unwrap_or_else(|| match l.text.as_ref() {
135 "true" => T![true], 136 "true" => T![true],
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index e0d689704..cb228702f 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -1374,14 +1374,22 @@ pub(crate) struct MacroFixture {
1374 1374
1375impl MacroFixture { 1375impl MacroFixture {
1376 pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree { 1376 pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree {
1377 let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); 1377 self.try_expand_tt(invocation).unwrap()
1378 }
1379
1380 fn try_expand_tt(&self, invocation: &str) -> Result<tt::Subtree, ExpandError> {
1381 let source_file = ast::SourceFile::parse(invocation).tree();
1378 let macro_invocation = 1382 let macro_invocation =
1379 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 1383 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1380 1384
1381 let (invocation_tt, _) = 1385 let (invocation_tt, _) =
1382 ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap(); 1386 ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap();
1383 1387
1384 self.rules.expand(&invocation_tt).unwrap() 1388 self.rules.expand(&invocation_tt)
1389 }
1390
1391 fn assert_expand_err(&self, invocation: &str, err: &ExpandError) {
1392 assert_eq!(self.try_expand_tt(invocation).as_ref(), Err(err));
1385 } 1393 }
1386 1394
1387 fn expand_items(&self, invocation: &str) -> SyntaxNode { 1395 fn expand_items(&self, invocation: &str) -> SyntaxNode {
@@ -1539,3 +1547,13 @@ fn test_repeat_bad_var() {
1539 ) 1547 )
1540 .assert_expand_items("foo!(b0 b1);", "b0 b1"); 1548 .assert_expand_items("foo!(b0 b1);", "b0 b1");
1541} 1549}
1550
1551#[test]
1552fn test_expand_bad_literal() {
1553 parse_macro(
1554 r#"
1555 macro_rules! foo { ($i:literal) => {}; }
1556 "#,
1557 )
1558 .assert_expand_err(r#"foo!(&k");"#, &ExpandError::NoMatchingRule);
1559}
diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs
index 76e2d4f7d..faa63d53f 100644
--- a/crates/ra_parser/src/parser.rs
+++ b/crates/ra_parser/src/parser.rs
@@ -164,7 +164,7 @@ impl<'t> Parser<'t> {
164 assert!(self.eat(kind)); 164 assert!(self.eat(kind));
165 } 165 }
166 166
167 /// Advances the parser by one token with composite puncts handled 167 /// Advances the parser by one token
168 pub(crate) fn bump_any(&mut self) { 168 pub(crate) fn bump_any(&mut self) {
169 let kind = self.nth(0); 169 let kind = self.nth(0);
170 if kind == EOF { 170 if kind == EOF {
diff --git a/docs/user/features.md b/docs/user/features.md
index f705e5115..a9cff34d2 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -156,3 +156,28 @@ default highlighter.
156 156
157Experimental feature that, given code highlighting using rust-analyzer is 157Experimental feature that, given code highlighting using rust-analyzer is
158active, will pick unique colors for identifiers. 158active, will pick unique colors for identifiers.
159
160### Code hints
161
162Rust-analyzer has two types of hints to show the information about the code:
163
164* hover hints, appearing on hover on any element.
165
166These contain extended information on the hovered language item.
167
168* inlay hints, shown near the element hinted directly in the editor.
169
170Two types of inlay hints are displayed currently:
171
172* type hints, displaying the minimal information on the type of the expression (if the information is available)
173* parameter name hints, displaying the names of the parameters in the corresponding methods
174
175#### VS Code
176
177In VS Code, the following settings can be used to configure the inlay hints:
178
179* `rust-analyzer.displayInlayHints` — toggles inlay hints display on or off
180* `rust-analyzer.maxInlayHintLength` — shortens the hints if their length exceeds the value specified. If no value is specified (`null`), no shortening is applied.
181
182**Note:** VS Code does not have native support for inlay hints [yet](https://github.com/microsoft/vscode/issues/16221) and the hints are implemented using decorations.
183This approach has limitations: the caret movement near the end of the hint may look [weird](https://github.com/rust-analyzer/rust-analyzer/issues/1623).
diff --git a/editors/code/.eslintrc.js b/editors/code/.eslintrc.js
index 5cda886ed..d494ebce8 100644
--- a/editors/code/.eslintrc.js
+++ b/editors/code/.eslintrc.js
@@ -12,6 +12,7 @@ module.exports = {
12 "@typescript-eslint" 12 "@typescript-eslint"
13 ], 13 ],
14 "rules": { 14 "rules": {
15 "eqeqeq": ["error", "always", { "null": "ignore" }],
15 "camelcase": ["error"], 16 "camelcase": ["error"],
16 "@typescript-eslint/member-delimiter-style": [ 17 "@typescript-eslint/member-delimiter-style": [
17 "error", 18 "error",
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index d7da47089..76ef2aae4 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -5,18 +5,18 @@
5 "requires": true, 5 "requires": true,
6 "dependencies": { 6 "dependencies": {
7 "@babel/code-frame": { 7 "@babel/code-frame": {
8 "version": "7.5.5", 8 "version": "7.8.3",
9 "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", 9 "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
10 "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", 10 "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
11 "dev": true, 11 "dev": true,
12 "requires": { 12 "requires": {
13 "@babel/highlight": "^7.0.0" 13 "@babel/highlight": "^7.8.3"
14 } 14 }
15 }, 15 },
16 "@babel/highlight": { 16 "@babel/highlight": {
17 "version": "7.5.0", 17 "version": "7.8.3",
18 "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", 18 "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
19 "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", 19 "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
20 "dev": true, 20 "dev": true,
21 "requires": { 21 "requires": {
22 "chalk": "^2.0.0", 22 "chalk": "^2.0.0",
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts
index 26705067a..641ec15c6 100644
--- a/editors/code/src/inlay_hints.ts
+++ b/editors/code/src/inlay_hints.ts
@@ -73,7 +73,7 @@ class HintsUpdater {
73 async setEnabled(enabled: boolean): Promise<void> { 73 async setEnabled(enabled: boolean): Promise<void> {
74 console.log({ enabled, prev: this.enabled }); 74 console.log({ enabled, prev: this.enabled });
75 75
76 if (this.enabled == enabled) return; 76 if (this.enabled === enabled) return;
77 this.enabled = enabled; 77 this.enabled = enabled;
78 78
79 if (this.enabled) { 79 if (this.enabled) {
diff --git a/editors/code/src/installation/server.ts b/editors/code/src/installation/server.ts
index 63ab104a1..750852921 100644
--- a/editors/code/src/installation/server.ts
+++ b/editors/code/src/installation/server.ts
@@ -42,7 +42,7 @@ export async function ensureServerBinary(source: null | BinarySource): Promise<n
42 42
43 console.log("Installed version:", installedVersion, "required:", requiredVersion); 43 console.log("Installed version:", installedVersion, "required:", requiredVersion);
44 44
45 if (isBinaryAvailable(prebuiltBinaryPath) && installedVersion == requiredVersion) { 45 if (isBinaryAvailable(prebuiltBinaryPath) && installedVersion === requiredVersion) {
46 return prebuiltBinaryPath; 46 return prebuiltBinaryPath;
47 } 47 }
48 48