aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_ty/src/infer.rs11
-rw-r--r--crates/ra_hir_ty/src/lower.rs5
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs38
-rw-r--r--crates/ra_ide/src/hover.rs31
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs66
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs11
-rw-r--r--crates/ra_ide/test_data/highlight_unsafe.html11
-rw-r--r--crates/rust-analyzer/src/handlers.rs2
-rw-r--r--crates/rust-analyzer/src/main_loop.rs12
-rw-r--r--crates/rust-analyzer/src/to_proto.rs3
-rw-r--r--editors/code/src/util.ts6
11 files changed, 170 insertions, 26 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 28f32a0a4..3d12039a6 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -440,6 +440,12 @@ impl<'a> InferenceContext<'a> {
440 let ty = self.insert_type_vars(ty.subst(&substs)); 440 let ty = self.insert_type_vars(ty.subst(&substs));
441 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) 441 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
442 } 442 }
443 TypeNs::AdtId(AdtId::UnionId(u)) => {
444 let substs = Ty::substs_from_path(&ctx, path, u.into(), true);
445 let ty = self.db.ty(u.into());
446 let ty = self.insert_type_vars(ty.subst(&substs));
447 forbid_unresolved_segments((ty, Some(u.into())), unresolved)
448 }
443 TypeNs::EnumVariantId(var) => { 449 TypeNs::EnumVariantId(var) => {
444 let substs = Ty::substs_from_path(&ctx, path, var.into(), true); 450 let substs = Ty::substs_from_path(&ctx, path, var.into(), true);
445 let ty = self.db.ty(var.parent.into()); 451 let ty = self.db.ty(var.parent.into());
@@ -490,10 +496,7 @@ impl<'a> InferenceContext<'a> {
490 // FIXME potentially resolve assoc type 496 // FIXME potentially resolve assoc type
491 (Ty::Unknown, None) 497 (Ty::Unknown, None)
492 } 498 }
493 TypeNs::AdtId(AdtId::EnumId(_)) 499 TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => {
494 | TypeNs::AdtId(AdtId::UnionId(_))
495 | TypeNs::BuiltinType(_)
496 | TypeNs::TraitId(_) => {
497 // FIXME diagnostic 500 // FIXME diagnostic
498 (Ty::Unknown, None) 501 (Ty::Unknown, None)
499 } 502 }
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 1eacc6f95..7638f167b 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -518,6 +518,7 @@ impl Ty {
518 let (segment, generic_def) = match resolved { 518 let (segment, generic_def) = match resolved {
519 ValueTyDefId::FunctionId(it) => (last, Some(it.into())), 519 ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
520 ValueTyDefId::StructId(it) => (last, Some(it.into())), 520 ValueTyDefId::StructId(it) => (last, Some(it.into())),
521 ValueTyDefId::UnionId(it) => (last, Some(it.into())),
521 ValueTyDefId::ConstId(it) => (last, Some(it.into())), 522 ValueTyDefId::ConstId(it) => (last, Some(it.into())),
522 ValueTyDefId::StaticId(_) => (last, None), 523 ValueTyDefId::StaticId(_) => (last, None),
523 ValueTyDefId::EnumVariantId(var) => { 524 ValueTyDefId::EnumVariantId(var) => {
@@ -1148,11 +1149,12 @@ impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefI
1148pub enum ValueTyDefId { 1149pub enum ValueTyDefId {
1149 FunctionId(FunctionId), 1150 FunctionId(FunctionId),
1150 StructId(StructId), 1151 StructId(StructId),
1152 UnionId(UnionId),
1151 EnumVariantId(EnumVariantId), 1153 EnumVariantId(EnumVariantId),
1152 ConstId(ConstId), 1154 ConstId(ConstId),
1153 StaticId(StaticId), 1155 StaticId(StaticId),
1154} 1156}
1155impl_from!(FunctionId, StructId, EnumVariantId, ConstId, StaticId for ValueTyDefId); 1157impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
1156 1158
1157/// Build the declared type of an item. This depends on the namespace; e.g. for 1159/// Build the declared type of an item. This depends on the namespace; e.g. for
1158/// `struct Foo(usize)`, we have two types: The type of the struct itself, and 1160/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
@@ -1179,6 +1181,7 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders
1179 match def { 1181 match def {
1180 ValueTyDefId::FunctionId(it) => type_for_fn(db, it), 1182 ValueTyDefId::FunctionId(it) => type_for_fn(db, it),
1181 ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), 1183 ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
1184 ValueTyDefId::UnionId(it) => type_for_adt(db, it.into()),
1182 ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), 1185 ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
1183 ValueTyDefId::ConstId(it) => type_for_const(db, it), 1186 ValueTyDefId::ConstId(it) => type_for_const(db, it),
1184 ValueTyDefId::StaticId(it) => type_for_static(db, it), 1187 ValueTyDefId::StaticId(it) => type_for_static(db, it),
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 3fd7d5cd4..5a7cf9455 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -334,16 +334,44 @@ fn infer_union() {
334 bar: f32, 334 bar: f32,
335 } 335 }
336 336
337 fn test() {
338 let u = MyUnion { foo: 0 };
339 unsafe { baz(u); }
340 let u = MyUnion { bar: 0.0 };
341 unsafe { baz(u); }
342 }
343
337 unsafe fn baz(u: MyUnion) { 344 unsafe fn baz(u: MyUnion) {
338 let inner = u.foo; 345 let inner = u.foo;
346 let inner = u.bar;
339 } 347 }
340 "#, 348 "#,
341 expect![[r#" 349 expect![[r#"
342 61..62 'u': MyUnion 350 57..172 '{ ...); } }': ()
343 73..99 '{ ...foo; }': () 351 67..68 'u': MyUnion
344 83..88 'inner': u32 352 71..89 'MyUnio...o: 0 }': MyUnion
345 91..92 'u': MyUnion 353 86..87 '0': u32
346 91..96 'u.foo': u32 354 95..113 'unsafe...(u); }': ()
355 102..113 '{ baz(u); }': ()
356 104..107 'baz': fn baz(MyUnion)
357 104..110 'baz(u)': ()
358 108..109 'u': MyUnion
359 122..123 'u': MyUnion
360 126..146 'MyUnio... 0.0 }': MyUnion
361 141..144 '0.0': f32
362 152..170 'unsafe...(u); }': ()
363 159..170 '{ baz(u); }': ()
364 161..164 'baz': fn baz(MyUnion)
365 161..167 'baz(u)': ()
366 165..166 'u': MyUnion
367 188..189 'u': MyUnion
368 200..249 '{ ...bar; }': ()
369 210..215 'inner': u32
370 218..219 'u': MyUnion
371 218..223 'u.foo': u32
372 233..238 'inner': f32
373 241..242 'u': MyUnion
374 241..246 'u.bar': f32
347 "#]], 375 "#]],
348 ); 376 );
349} 377}
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index f6e493817..9c7348898 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -512,6 +512,37 @@ fn main() { }
512 } 512 }
513 513
514 #[test] 514 #[test]
515 fn hover_shows_fn_doc() {
516 check(
517 r#"
518/// # Example
519/// ```
520/// # use std::path::Path;
521/// #
522/// foo(Path::new("hello, world!"))
523/// ```
524pub fn foo<|>(_: &Path) {}
525
526fn main() { }
527"#,
528 expect![[r#"
529 *foo*
530 ```rust
531 pub fn foo(_: &Path)
532 ```
533 ___
534
535 # Example
536 ```
537 # use std::path::Path;
538 #
539 foo(Path::new("hello, world!"))
540 ```
541 "#]],
542 );
543 }
544
545 #[test]
515 fn hover_shows_struct_field_info() { 546 fn hover_shows_struct_field_info() {
516 // Hovering over the field when instantiating 547 // Hovering over the field when instantiating
517 check( 548 check(
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index ec442bcd8..6b7874460 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -4,7 +4,7 @@ mod injection;
4#[cfg(test)] 4#[cfg(test)]
5mod tests; 5mod tests;
6 6
7use hir::{Name, Semantics}; 7use hir::{Name, Semantics, VariantDef};
8use ra_ide_db::{ 8use ra_ide_db::{
9 defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, 9 defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass},
10 RootDatabase, 10 RootDatabase,
@@ -455,6 +455,18 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> {
455 Some(TextRange::new(range_start, range_end)) 455 Some(TextRange::new(range_start, range_end))
456} 456}
457 457
458fn is_possibly_unsafe(name_ref: &ast::NameRef) -> bool {
459 name_ref
460 .syntax()
461 .parent()
462 .and_then(|parent| {
463 ast::FieldExpr::cast(parent.clone())
464 .map(|_| true)
465 .or_else(|| ast::RecordPatField::cast(parent).map(|_| true))
466 })
467 .unwrap_or(false)
468}
469
458fn highlight_element( 470fn highlight_element(
459 sema: &Semantics<RootDatabase>, 471 sema: &Semantics<RootDatabase>,
460 bindings_shadow_count: &mut FxHashMap<Name, u32>, 472 bindings_shadow_count: &mut FxHashMap<Name, u32>,
@@ -485,10 +497,19 @@ fn highlight_element(
485 match name_kind { 497 match name_kind {
486 Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(), 498 Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(),
487 Some(NameClass::Definition(def)) => { 499 Some(NameClass::Definition(def)) => {
488 highlight_name(db, def) | HighlightModifier::Definition 500 highlight_name(db, def, false) | HighlightModifier::Definition
501 }
502 Some(NameClass::ConstReference(def)) => highlight_name(db, def, false),
503 Some(NameClass::FieldShorthand { field, .. }) => {
504 let mut h = HighlightTag::Field.into();
505 if let Definition::Field(field) = field {
506 if let VariantDef::Union(_) = field.parent_def(db) {
507 h |= HighlightModifier::Unsafe;
508 }
509 }
510
511 h
489 } 512 }
490 Some(NameClass::ConstReference(def)) => highlight_name(db, def),
491 Some(NameClass::FieldShorthand { .. }) => HighlightTag::Field.into(),
492 None => highlight_name_by_syntax(name) | HighlightModifier::Definition, 513 None => highlight_name_by_syntax(name) | HighlightModifier::Definition,
493 } 514 }
494 } 515 }
@@ -499,6 +520,7 @@ fn highlight_element(
499 } 520 }
500 NAME_REF => { 521 NAME_REF => {
501 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); 522 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
523 let possibly_unsafe = is_possibly_unsafe(&name_ref);
502 match classify_name_ref(sema, &name_ref) { 524 match classify_name_ref(sema, &name_ref) {
503 Some(name_kind) => match name_kind { 525 Some(name_kind) => match name_kind {
504 NameRefClass::ExternCrate(_) => HighlightTag::Module.into(), 526 NameRefClass::ExternCrate(_) => HighlightTag::Module.into(),
@@ -510,11 +532,13 @@ fn highlight_element(
510 binding_hash = Some(calc_binding_hash(&name, *shadow_count)) 532 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
511 } 533 }
512 }; 534 };
513 highlight_name(db, def) 535 highlight_name(db, def, possibly_unsafe)
514 } 536 }
515 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), 537 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(),
516 }, 538 },
517 None if syntactic_name_ref_highlighting => highlight_name_ref_by_syntax(name_ref), 539 None if syntactic_name_ref_highlighting => {
540 highlight_name_ref_by_syntax(name_ref, sema)
541 }
518 None => HighlightTag::UnresolvedReference.into(), 542 None => HighlightTag::UnresolvedReference.into(),
519 } 543 }
520 } 544 }
@@ -654,10 +678,19 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool {
654 } 678 }
655} 679}
656 680
657fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { 681fn highlight_name(db: &RootDatabase, def: Definition, possibly_unsafe: bool) -> Highlight {
658 match def { 682 match def {
659 Definition::Macro(_) => HighlightTag::Macro, 683 Definition::Macro(_) => HighlightTag::Macro,
660 Definition::Field(_) => HighlightTag::Field, 684 Definition::Field(field) => {
685 let mut h = HighlightTag::Field.into();
686 if possibly_unsafe {
687 if let VariantDef::Union(_) = field.parent_def(db) {
688 h |= HighlightModifier::Unsafe;
689 }
690 }
691
692 return h;
693 }
661 Definition::ModuleDef(def) => match def { 694 Definition::ModuleDef(def) => match def {
662 hir::ModuleDef::Module(_) => HighlightTag::Module, 695 hir::ModuleDef::Module(_) => HighlightTag::Module,
663 hir::ModuleDef::Function(func) => { 696 hir::ModuleDef::Function(func) => {
@@ -727,7 +760,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
727 tag.into() 760 tag.into()
728} 761}
729 762
730fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight { 763fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight {
731 let default = HighlightTag::UnresolvedReference; 764 let default = HighlightTag::UnresolvedReference;
732 765
733 let parent = match name.syntax().parent() { 766 let parent = match name.syntax().parent() {
@@ -737,7 +770,20 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight {
737 770
738 let tag = match parent.kind() { 771 let tag = match parent.kind() {
739 METHOD_CALL_EXPR => HighlightTag::Function, 772 METHOD_CALL_EXPR => HighlightTag::Function,
740 FIELD_EXPR => HighlightTag::Field, 773 FIELD_EXPR => {
774 let h = HighlightTag::Field;
775 let is_union = ast::FieldExpr::cast(parent)
776 .and_then(|field_expr| {
777 let field = sema.resolve_field(&field_expr)?;
778 Some(if let VariantDef::Union(_) = field.parent_def(sema.db) {
779 true
780 } else {
781 false
782 })
783 })
784 .unwrap_or(false);
785 return if is_union { h | HighlightModifier::Unsafe } else { h.into() };
786 }
741 PATH_SEGMENT => { 787 PATH_SEGMENT => {
742 let path = match parent.parent().and_then(ast::Path::cast) { 788 let path = match parent.parent().and_then(ast::Path::cast) {
743 Some(it) => it, 789 Some(it) => it,
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index b8d60bdc6..09062c38e 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -275,6 +275,11 @@ fn test_unsafe_highlighting() {
275 r#" 275 r#"
276unsafe fn unsafe_fn() {} 276unsafe fn unsafe_fn() {}
277 277
278union Union {
279 a: u32,
280 b: f32,
281}
282
278struct HasUnsafeFn; 283struct HasUnsafeFn;
279 284
280impl HasUnsafeFn { 285impl HasUnsafeFn {
@@ -289,8 +294,14 @@ static mut global_mut: TypeForStaticMut = TypeForStaticMut { a: 0 };
289 294
290fn main() { 295fn main() {
291 let x = &5 as *const usize; 296 let x = &5 as *const usize;
297 let u = Union { b: 0 };
292 unsafe { 298 unsafe {
293 unsafe_fn(); 299 unsafe_fn();
300 let b = u.b;
301 match u {
302 Union { b: 0 } => (),
303 Union { a } => (),
304 }
294 HasUnsafeFn.unsafe_method(); 305 HasUnsafeFn.unsafe_method();
295 let y = *(x); 306 let y = *(x);
296 let z = -x; 307 let z = -x;
diff --git a/crates/ra_ide/test_data/highlight_unsafe.html b/crates/ra_ide/test_data/highlight_unsafe.html
index 87d8c1556..79409fe81 100644
--- a/crates/ra_ide/test_data/highlight_unsafe.html
+++ b/crates/ra_ide/test_data/highlight_unsafe.html
@@ -37,6 +37,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
37</style> 37</style>
38<pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> 38<pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
39 39
40<span class="keyword">union</span> <span class="union declaration">Union</span> <span class="punctuation">{</span>
41 <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u32</span><span class="punctuation">,</span>
42 <span class="field declaration">b</span><span class="punctuation">:</span> <span class="builtin_type">f32</span><span class="punctuation">,</span>
43<span class="punctuation">}</span>
44
40<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span> 45<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span>
41 46
42<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span> 47<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span>
@@ -51,8 +56,14 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
51 56
52<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> 57<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
53 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="punctuation">;</span> 58 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="punctuation">;</span>
59 <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="punctuation">{</span> <span class="field">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span>
54 <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> 60 <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span>
55 <span class="function unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 61 <span class="function unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
62 <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="punctuation">.</span><span class="field unsafe">b</span><span class="punctuation">;</span>
63 <span class="keyword control">match</span> <span class="variable">u</span> <span class="punctuation">{</span>
64 <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span> <span class="operator">=&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span>
65 <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">a</span> <span class="punctuation">}</span> <span class="operator">=&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span>
66 <span class="punctuation">}</span>
56 <span class="struct">HasUnsafeFn</span><span class="punctuation">.</span><span class="function unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> 67 <span class="struct">HasUnsafeFn</span><span class="punctuation">.</span><span class="function unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
57 <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="punctuation">(</span><span class="variable">x</span><span class="punctuation">)</span><span class="punctuation">;</span> 68 <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="punctuation">(</span><span class="variable">x</span><span class="punctuation">)</span><span class="punctuation">;</span>
58 <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="variable">x</span><span class="punctuation">;</span> 69 <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="variable">x</span><span class="punctuation">;</span>
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 067259e24..895af1dd7 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -892,7 +892,7 @@ pub(crate) fn handle_code_lens(
892 } 892 }
893 893
894 let action = runnable.action(); 894 let action = runnable.action();
895 let range = to_proto::range(&line_index, runnable.nav.focus_or_full_range()); 895 let range = to_proto::range(&line_index, runnable.nav.full_range);
896 let r = to_proto::runnable(&snap, file_id, runnable)?; 896 let r = to_proto::runnable(&snap, file_id, runnable)?;
897 if snap.config.lens.run { 897 if snap.config.lens.run {
898 let lens = CodeLens { 898 let lens = CodeLens {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index ceddb2b05..0ac6434dd 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -47,7 +47,7 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
47 SetThreadPriority(thread, thread_priority_above_normal); 47 SetThreadPriority(thread, thread_priority_above_normal);
48 } 48 }
49 49
50 GlobalState::new(connection.sender.clone(), config).run(connection.receiver) 50 GlobalState::new(connection.sender, config).run(connection.receiver)
51} 51}
52 52
53enum Event { 53enum Event {
@@ -337,6 +337,16 @@ impl GlobalState {
337 fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> { 337 fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> {
338 self.register_request(&req, request_received); 338 self.register_request(&req, request_received);
339 339
340 if self.status == Status::Loading && req.method != "shutdown" {
341 self.respond(lsp_server::Response::new_err(
342 req.id,
343 // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion)
344 lsp_server::ErrorCode::ContentModified as i32,
345 "Rust Analyzer is still loading...".to_owned(),
346 ));
347 return Ok(());
348 }
349
340 RequestDispatcher { req: Some(req), global_state: self } 350 RequestDispatcher { req: Some(req), global_state: self }
341 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces()))? 351 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces()))?
342 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? 352 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 5eba1f155..27460db78 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -755,7 +755,8 @@ pub(crate) fn runnable(
755} 755}
756 756
757pub(crate) fn markup_content(markup: Markup) -> lsp_types::MarkupContent { 757pub(crate) fn markup_content(markup: Markup) -> lsp_types::MarkupContent {
758 lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value: markup.into() } 758 let value = crate::markdown::format_docs(markup.as_str());
759 lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value }
759} 760}
760 761
761#[cfg(test)] 762#[cfg(test)]
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts
index 970fedb37..49d2d1c6f 100644
--- a/editors/code/src/util.ts
+++ b/editors/code/src/util.ts
@@ -64,7 +64,8 @@ export async function sendRequestWithRetry<TParam, TRet>(
64 param: TParam, 64 param: TParam,
65 token?: vscode.CancellationToken, 65 token?: vscode.CancellationToken,
66): Promise<TRet> { 66): Promise<TRet> {
67 for (const delay of [2, 4, 6, 8, 10, null]) { 67 // The sequence is `10 * (2 ** (2 * n))` where n is 1, 2, 3...
68 for (const delay of [40, 160, 640, 2560, 10240, null]) {
68 try { 69 try {
69 return await (token 70 return await (token
70 ? client.sendRequest(reqType, param, token) 71 ? client.sendRequest(reqType, param, token)
@@ -84,8 +85,7 @@ export async function sendRequestWithRetry<TParam, TRet>(
84 log.warn("LSP request failed", { method: reqType.method, param, error }); 85 log.warn("LSP request failed", { method: reqType.method, param, error });
85 throw error; 86 throw error;
86 } 87 }
87 88 await sleep(delay);
88 await sleep(10 * (1 << delay));
89 } 89 }
90 } 90 }
91 throw 'unreachable'; 91 throw 'unreachable';