aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock4
-rw-r--r--crates/ra_hir_ty/src/infer.rs13
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs28
-rw-r--r--crates/ra_hir_ty/src/lib.rs6
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs12
-rw-r--r--crates/ra_hir_ty/src/primitive.rs54
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/mapping.rs24
-rw-r--r--crates/ra_ide/src/snapshots/highlight_strings.html2
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs37
-rw-r--r--editors/code/package.json5
10 files changed, 60 insertions, 125 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2e86b3fee..df79334c9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -884,9 +884,9 @@ dependencies = [
884 884
885[[package]] 885[[package]]
886name = "quote" 886name = "quote"
887version = "1.0.6" 887version = "1.0.7"
888source = "registry+https://github.com/rust-lang/crates.io-index" 888source = "registry+https://github.com/rust-lang/crates.io-index"
889checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" 889checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
890dependencies = [ 890dependencies = [
891 "proc-macro2", 891 "proc-macro2",
892] 892]
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 2e16e5120..f965eb2b5 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -39,8 +39,7 @@ use ra_syntax::SmolStr;
39use super::{ 39use super::{
40 primitive::{FloatTy, IntTy}, 40 primitive::{FloatTy, IntTy},
41 traits::{Guidance, Obligation, ProjectionPredicate, Solution}, 41 traits::{Guidance, Obligation, ProjectionPredicate, Solution},
42 ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, 42 InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
43 TypeWalk, Uncertain,
44}; 43};
45use crate::{ 44use crate::{
46 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, 45 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
@@ -312,12 +311,6 @@ impl<'a> InferenceContext<'a> {
312 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { 311 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
313 match ty { 312 match ty {
314 Ty::Unknown => self.table.new_type_var(), 313 Ty::Unknown => self.table.new_type_var(),
315 Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(Uncertain::Unknown), .. }) => {
316 self.table.new_integer_var()
317 }
318 Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(Uncertain::Unknown), .. }) => {
319 self.table.new_float_var()
320 }
321 _ => ty, 314 _ => ty,
322 } 315 }
323 } 316 }
@@ -664,8 +657,8 @@ impl InferTy {
664 fn fallback_value(self) -> Ty { 657 fn fallback_value(self) -> Ty {
665 match self { 658 match self {
666 InferTy::TypeVar(..) => Ty::Unknown, 659 InferTy::TypeVar(..) => Ty::Unknown,
667 InferTy::IntVar(..) => Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::i32()))), 660 InferTy::IntVar(..) => Ty::simple(TypeCtor::Int(IntTy::i32())),
668 InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(Uncertain::Known(FloatTy::f64()))), 661 InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(FloatTy::f64())),
669 InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never), 662 InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never),
670 } 663 }
671 } 664 }
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 4a98e2deb..9fd310f69 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -18,7 +18,7 @@ use crate::{
18 traits::InEnvironment, 18 traits::InEnvironment,
19 utils::{generics, variant_data, Generics}, 19 utils::{generics, variant_data, Generics},
20 ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, 20 ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs,
21 TraitRef, Ty, TypeCtor, Uncertain, 21 TraitRef, Ty, TypeCtor,
22}; 22};
23 23
24use super::{ 24use super::{
@@ -426,15 +426,7 @@ impl<'a> InferenceContext<'a> {
426 match &inner_ty { 426 match &inner_ty {
427 // Fast path for builtins 427 // Fast path for builtins
428 Ty::Apply(ApplicationTy { 428 Ty::Apply(ApplicationTy {
429 ctor: 429 ctor: TypeCtor::Int(IntTy { signedness: Signedness::Signed, .. }),
430 TypeCtor::Int(Uncertain::Known(IntTy {
431 signedness: Signedness::Signed,
432 ..
433 })),
434 ..
435 })
436 | Ty::Apply(ApplicationTy {
437 ctor: TypeCtor::Int(Uncertain::Unknown),
438 .. 430 ..
439 }) 431 })
440 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. }) 432 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. })
@@ -577,9 +569,7 @@ impl<'a> InferenceContext<'a> {
577 ); 569 );
578 self.infer_expr( 570 self.infer_expr(
579 *repeat, 571 *repeat,
580 &Expectation::has_type(Ty::simple(TypeCtor::Int(Uncertain::Known( 572 &Expectation::has_type(Ty::simple(TypeCtor::Int(IntTy::usize()))),
581 IntTy::usize(),
582 )))),
583 ); 573 );
584 } 574 }
585 } 575 }
@@ -592,13 +582,19 @@ impl<'a> InferenceContext<'a> {
592 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) 582 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str))
593 } 583 }
594 Literal::ByteString(..) => { 584 Literal::ByteString(..) => {
595 let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); 585 let byte_type = Ty::simple(TypeCtor::Int(IntTy::u8()));
596 let array_type = Ty::apply_one(TypeCtor::Array, byte_type); 586 let array_type = Ty::apply_one(TypeCtor::Array, byte_type);
597 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type) 587 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type)
598 } 588 }
599 Literal::Char(..) => Ty::simple(TypeCtor::Char), 589 Literal::Char(..) => Ty::simple(TypeCtor::Char),
600 Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), 590 Literal::Int(_v, ty) => match ty {
601 Literal::Float(_v, ty) => Ty::simple(TypeCtor::Float((*ty).into())), 591 Some(int_ty) => Ty::simple(TypeCtor::Int((*int_ty).into())),
592 None => self.table.new_integer_var(),
593 },
594 Literal::Float(_v, ty) => match ty {
595 Some(float_ty) => Ty::simple(TypeCtor::Float((*float_ty).into())),
596 None => self.table.new_float_var(),
597 },
602 }, 598 },
603 }; 599 };
604 // use a new type variable if we got Ty::Unknown here 600 // use a new type variable if we got Ty::Unknown here
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 135976fcd..2b9372b4b 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -58,7 +58,7 @@ use ra_db::{impl_intern_key, salsa, CrateId};
58 58
59use crate::{ 59use crate::{
60 db::HirDatabase, 60 db::HirDatabase,
61 primitive::{FloatTy, IntTy, Uncertain}, 61 primitive::{FloatTy, IntTy},
62 utils::{generics, make_mut_slice, Generics}, 62 utils::{generics, make_mut_slice, Generics},
63}; 63};
64use display::HirDisplay; 64use display::HirDisplay;
@@ -87,10 +87,10 @@ pub enum TypeCtor {
87 Char, 87 Char,
88 88
89 /// A primitive integer type. For example, `i32`. 89 /// A primitive integer type. For example, `i32`.
90 Int(Uncertain<IntTy>), 90 Int(IntTy),
91 91
92 /// A primitive floating-point type. For example, `f64`. 92 /// A primitive floating-point type. For example, `f64`.
93 Float(Uncertain<FloatTy>), 93 Float(FloatTy),
94 94
95 /// Structures, enumerations and unions. 95 /// Structures, enumerations and unions.
96 Adt(AdtId), 96 Adt(AdtId),
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index e19628fdf..e83b39456 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -16,12 +16,8 @@ use rustc_hash::{FxHashMap, FxHashSet};
16 16
17use super::Substs; 17use super::Substs;
18use crate::{ 18use crate::{
19 autoderef, 19 autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy,
20 db::HirDatabase, 20 Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
21 primitive::{FloatBitness, Uncertain},
22 utils::all_super_traits,
23 ApplicationTy, Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty,
24 TypeCtor, TypeWalk,
25}; 21};
26 22
27/// This is used as a key for indexing impls. 23/// This is used as a key for indexing impls.
@@ -147,12 +143,12 @@ impl Ty {
147 } 143 }
148 TypeCtor::Bool => lang_item_crate!("bool"), 144 TypeCtor::Bool => lang_item_crate!("bool"),
149 TypeCtor::Char => lang_item_crate!("char"), 145 TypeCtor::Char => lang_item_crate!("char"),
150 TypeCtor::Float(Uncertain::Known(f)) => match f.bitness { 146 TypeCtor::Float(f) => match f.bitness {
151 // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) 147 // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
152 FloatBitness::X32 => lang_item_crate!("f32", "f32_runtime"), 148 FloatBitness::X32 => lang_item_crate!("f32", "f32_runtime"),
153 FloatBitness::X64 => lang_item_crate!("f64", "f64_runtime"), 149 FloatBitness::X64 => lang_item_crate!("f64", "f64_runtime"),
154 }, 150 },
155 TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(i.ty_to_string()), 151 TypeCtor::Int(i) => lang_item_crate!(i.ty_to_string()),
156 TypeCtor::Str => lang_item_crate!("str_alloc", "str"), 152 TypeCtor::Str => lang_item_crate!("str_alloc", "str"),
157 TypeCtor::Slice => lang_item_crate!("slice_alloc", "slice"), 153 TypeCtor::Slice => lang_item_crate!("slice_alloc", "slice"),
158 TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!("const_ptr"), 154 TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!("const_ptr"),
diff --git a/crates/ra_hir_ty/src/primitive.rs b/crates/ra_hir_ty/src/primitive.rs
index 02a8179d9..37966b709 100644
--- a/crates/ra_hir_ty/src/primitive.rs
+++ b/crates/ra_hir_ty/src/primitive.rs
@@ -7,42 +7,6 @@ use std::fmt;
7 7
8pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, FloatBitness, IntBitness, Signedness}; 8pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, FloatBitness, IntBitness, Signedness};
9 9
10#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
11pub enum Uncertain<T> {
12 Unknown,
13 Known(T),
14}
15
16impl From<IntTy> for Uncertain<IntTy> {
17 fn from(ty: IntTy) -> Self {
18 Uncertain::Known(ty)
19 }
20}
21
22impl fmt::Display for Uncertain<IntTy> {
23 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 match *self {
25 Uncertain::Unknown => write!(f, "{{integer}}"),
26 Uncertain::Known(ty) => write!(f, "{}", ty),
27 }
28 }
29}
30
31impl From<FloatTy> for Uncertain<FloatTy> {
32 fn from(ty: FloatTy) -> Self {
33 Uncertain::Known(ty)
34 }
35}
36
37impl fmt::Display for Uncertain<FloatTy> {
38 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39 match *self {
40 Uncertain::Unknown => write!(f, "{{float}}"),
41 Uncertain::Known(ty) => write!(f, "{}", ty),
42 }
43 }
44}
45
46#[derive(Copy, Clone, Eq, PartialEq, Hash)] 10#[derive(Copy, Clone, Eq, PartialEq, Hash)]
47pub struct IntTy { 11pub struct IntTy {
48 pub signedness: Signedness, 12 pub signedness: Signedness,
@@ -173,21 +137,3 @@ impl From<BuiltinFloat> for FloatTy {
173 FloatTy { bitness: t.bitness } 137 FloatTy { bitness: t.bitness }
174 } 138 }
175} 139}
176
177impl From<Option<BuiltinInt>> for Uncertain<IntTy> {
178 fn from(t: Option<BuiltinInt>) -> Self {
179 match t {
180 None => Uncertain::Unknown,
181 Some(t) => Uncertain::Known(t.into()),
182 }
183 }
184}
185
186impl From<Option<BuiltinFloat>> for Uncertain<FloatTy> {
187 fn from(t: Option<BuiltinFloat>) -> Self {
188 match t {
189 None => Uncertain::Unknown,
190 Some(t) => Uncertain::Known(t.into()),
191 }
192 }
193}
diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
index 28a5fbe3e..18e5c9c16 100644
--- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
@@ -14,7 +14,7 @@ use ra_db::salsa::InternKey;
14 14
15use crate::{ 15use crate::{
16 db::HirDatabase, 16 db::HirDatabase,
17 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, 17 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness},
18 traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, 18 traits::{builtin, AssocTyValue, Canonical, Impl, Obligation},
19 ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId, 19 ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId,
20 ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, 20 ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
@@ -249,11 +249,11 @@ impl ToChalk for TypeCtor {
249 249
250 TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), 250 TypeCtor::Bool => TypeName::Scalar(Scalar::Bool),
251 TypeCtor::Char => TypeName::Scalar(Scalar::Char), 251 TypeCtor::Char => TypeName::Scalar(Scalar::Char),
252 TypeCtor::Int(Uncertain::Known(int_ty)) => TypeName::Scalar(int_ty_to_chalk(int_ty)), 252 TypeCtor::Int(int_ty) => TypeName::Scalar(int_ty_to_chalk(int_ty)),
253 TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) => { 253 TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 }) => {
254 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) 254 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32))
255 } 255 }
256 TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) => { 256 TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 }) => {
257 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) 257 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64))
258 } 258 }
259 259
@@ -268,9 +268,7 @@ impl ToChalk for TypeCtor {
268 } 268 }
269 TypeCtor::Never => TypeName::Never, 269 TypeCtor::Never => TypeName::Never,
270 270
271 TypeCtor::Int(Uncertain::Unknown) 271 TypeCtor::Adt(_)
272 | TypeCtor::Float(Uncertain::Unknown)
273 | TypeCtor::Adt(_)
274 | TypeCtor::Array 272 | TypeCtor::Array
275 | TypeCtor::FnPtr { .. } 273 | TypeCtor::FnPtr { .. }
276 | TypeCtor::Closure { .. } => { 274 | TypeCtor::Closure { .. } => {
@@ -291,19 +289,19 @@ impl ToChalk for TypeCtor {
291 289
292 TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool, 290 TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool,
293 TypeName::Scalar(Scalar::Char) => TypeCtor::Char, 291 TypeName::Scalar(Scalar::Char) => TypeCtor::Char,
294 TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(Uncertain::Known(IntTy { 292 TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(IntTy {
295 signedness: Signedness::Signed, 293 signedness: Signedness::Signed,
296 bitness: bitness_from_chalk_int(int_ty), 294 bitness: bitness_from_chalk_int(int_ty),
297 })), 295 }),
298 TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(Uncertain::Known(IntTy { 296 TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(IntTy {
299 signedness: Signedness::Unsigned, 297 signedness: Signedness::Unsigned,
300 bitness: bitness_from_chalk_uint(uint_ty), 298 bitness: bitness_from_chalk_uint(uint_ty),
301 })), 299 }),
302 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) => { 300 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) => {
303 TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) 301 TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 })
304 } 302 }
305 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) => { 303 TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) => {
306 TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) 304 TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 })
307 } 305 }
308 TypeName::Tuple(cardinality) => TypeCtor::Tuple { cardinality: cardinality as u16 }, 306 TypeName::Tuple(cardinality) => TypeCtor::Tuple { cardinality: cardinality as u16 },
309 TypeName::Raw(mutability) => TypeCtor::RawPtr(from_chalk(db, mutability)), 307 TypeName::Raw(mutability) => TypeCtor::RawPtr(from_chalk(db, mutability)),
diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html
index e97192b61..6a5cf0e74 100644
--- a/crates/ra_ide/src/snapshots/highlight_strings.html
+++ b/crates/ra_ide/src/snapshots/highlight_strings.html
@@ -63,7 +63,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
63 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); 63 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>);
64 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); 64 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>);
65 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>); 65 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>);
66 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="string_literal">}!"</span>, <span class="numeric_literal">27</span>); 66 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">27</span>);
67 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>); 67 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>);
68 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, -<span class="numeric_literal">5</span>); 68 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, -<span class="numeric_literal">5</span>);
69 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">27</span>); 69 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">27</span>);
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs
index 04b0a4480..56378385a 100644
--- a/crates/ra_syntax/src/ast/tokens.rs
+++ b/crates/ra_syntax/src/ast/tokens.rs
@@ -335,16 +335,26 @@ pub trait HasFormatSpecifier: AstToken {
335 } 335 }
336 c if c == '_' || c.is_alphabetic() => { 336 c if c == '_' || c.is_alphabetic() => {
337 read_identifier(&mut chars, &mut callback); 337 read_identifier(&mut chars, &mut callback);
338 if chars.peek().and_then(|next| next.1.as_ref().ok()).copied() 338 // can be either width (indicated by dollar sign, or type in which case
339 != Some('$') 339 // the next sign has to be `}`)
340 { 340 let next =
341 continue; 341 chars.peek().and_then(|next| next.1.as_ref().ok()).copied();
342 } 342 match next {
343 skip_char_and_emit( 343 Some('$') => skip_char_and_emit(
344 &mut chars, 344 &mut chars,
345 FormatSpecifier::DollarSign, 345 FormatSpecifier::DollarSign,
346 &mut callback, 346 &mut callback,
347 ); 347 ),
348 Some('}') => {
349 skip_char_and_emit(
350 &mut chars,
351 FormatSpecifier::Close,
352 &mut callback,
353 );
354 continue;
355 }
356 _ => continue,
357 };
348 } 358 }
349 _ => {} 359 _ => {}
350 } 360 }
@@ -416,12 +426,11 @@ pub trait HasFormatSpecifier: AstToken {
416 } 426 }
417 } 427 }
418 428
419 let mut cloned = chars.clone().take(2); 429 if let Some((_, Ok('}'))) = chars.peek() {
420 let first = cloned.next().and_then(|next| next.1.as_ref().ok()).copied(); 430 skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback);
421 if first != Some('}') { 431 } else {
422 continue; 432 continue;
423 } 433 }
424 skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback);
425 } 434 }
426 _ => { 435 _ => {
427 while let Some((_, Ok(next_char))) = chars.peek() { 436 while let Some((_, Ok(next_char))) = chars.peek() {
diff --git a/editors/code/package.json b/editors/code/package.json
index b9c57db3b..859ab4477 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -487,10 +487,7 @@
487 "default": true 487 "default": true
488 }, 488 },
489 "rust-analyzer.linkedProjects": { 489 "rust-analyzer.linkedProjects": {
490 "markdownDescription": [ 490 "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects. \nElements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format",
491 "Disable project auto-discovery in favor of explicitly specified set of projects.",
492 "Elements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format"
493 ],
494 "type": "array", 491 "type": "array",
495 "items": { 492 "items": {
496 "type": [ 493 "type": [