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_ide/src/syntax_highlighting/tests.rs59
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs37
-rw-r--r--docs/dev/README.md83
-rw-r--r--editors/code/package.json5
12 files changed, 170 insertions, 157 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_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index 36a1aa419..5e42c5b55 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -7,9 +7,21 @@ use crate::{
7 FileRange, TextRange, 7 FileRange, TextRange,
8}; 8};
9 9
10/// Highlights the code given by the `ra_fixture` argument, renders the
11/// result as HTML, and compares it with the HTML file given as `snapshot`.
12/// Note that the `snapshot` file is overwritten by the rendered HTML.
13fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) {
14 let (analysis, file_id) = single_file(ra_fixture);
15 let dst_file = project_dir().join(snapshot);
16 let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap();
17 let expected_html = &read_text(&dst_file);
18 fs::write(dst_file, &actual_html).unwrap();
19 assert_eq_text!(expected_html, actual_html);
20}
21
10#[test] 22#[test]
11fn test_highlighting() { 23fn test_highlighting() {
12 let (analysis, file_id) = single_file( 24 check_highlighting(
13 r#" 25 r#"
14#[derive(Clone, Debug)] 26#[derive(Clone, Debug)]
15struct Foo { 27struct Foo {
@@ -84,17 +96,14 @@ impl<T> Option<T> {
84} 96}
85"# 97"#
86 .trim(), 98 .trim(),
99 "crates/ra_ide/src/snapshots/highlighting.html",
100 false,
87 ); 101 );
88 let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlighting.html");
89 let actual_html = &analysis.highlight_as_html(file_id, false).unwrap();
90 let expected_html = &read_text(&dst_file);
91 fs::write(dst_file, &actual_html).unwrap();
92 assert_eq_text!(expected_html, actual_html);
93} 102}
94 103
95#[test] 104#[test]
96fn test_rainbow_highlighting() { 105fn test_rainbow_highlighting() {
97 let (analysis, file_id) = single_file( 106 check_highlighting(
98 r#" 107 r#"
99fn main() { 108fn main() {
100 let hello = "hello"; 109 let hello = "hello";
@@ -110,12 +119,9 @@ fn bar() {
110} 119}
111"# 120"#
112 .trim(), 121 .trim(),
122 "crates/ra_ide/src/snapshots/rainbow_highlighting.html",
123 true,
113 ); 124 );
114 let dst_file = project_dir().join("crates/ra_ide/src/snapshots/rainbow_highlighting.html");
115 let actual_html = &analysis.highlight_as_html(file_id, true).unwrap();
116 let expected_html = &read_text(&dst_file);
117 fs::write(dst_file, &actual_html).unwrap();
118 assert_eq_text!(expected_html, actual_html);
119} 125}
120 126
121#[test] 127#[test]
@@ -153,7 +159,7 @@ fn test_ranges() {
153 159
154#[test] 160#[test]
155fn test_flattening() { 161fn test_flattening() {
156 let (analysis, file_id) = single_file( 162 check_highlighting(
157 r##" 163 r##"
158fn fixture(ra_fixture: &str) {} 164fn fixture(ra_fixture: &str) {}
159 165
@@ -167,13 +173,9 @@ fn main() {
167 ); 173 );
168}"## 174}"##
169 .trim(), 175 .trim(),
176 "crates/ra_ide/src/snapshots/highlight_injection.html",
177 false,
170 ); 178 );
171
172 let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_injection.html");
173 let actual_html = &analysis.highlight_as_html(file_id, false).unwrap();
174 let expected_html = &read_text(&dst_file);
175 fs::write(dst_file, &actual_html).unwrap();
176 assert_eq_text!(expected_html, actual_html);
177} 179}
178 180
179#[test] 181#[test]
@@ -192,7 +194,7 @@ macro_rules! test {}
192fn test_string_highlighting() { 194fn test_string_highlighting() {
193 // The format string detection is based on macro-expansion, 195 // The format string detection is based on macro-expansion,
194 // thus, we have to copy the macro definition from `std` 196 // thus, we have to copy the macro definition from `std`
195 let (analysis, file_id) = single_file( 197 check_highlighting(
196 r#" 198 r#"
197macro_rules! println { 199macro_rules! println {
198 ($($arg:tt)*) => ({ 200 ($($arg:tt)*) => ({
@@ -250,18 +252,14 @@ fn main() {
250 println!("{ничоси}", ничоси = 92); 252 println!("{ничоси}", ничоси = 92);
251}"# 253}"#
252 .trim(), 254 .trim(),
255 "crates/ra_ide/src/snapshots/highlight_strings.html",
256 false,
253 ); 257 );
254
255 let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_strings.html");
256 let actual_html = &analysis.highlight_as_html(file_id, false).unwrap();
257 let expected_html = &read_text(&dst_file);
258 fs::write(dst_file, &actual_html).unwrap();
259 assert_eq_text!(expected_html, actual_html);
260} 258}
261 259
262#[test] 260#[test]
263fn test_unsafe_highlighting() { 261fn test_unsafe_highlighting() {
264 let (analysis, file_id) = single_file( 262 check_highlighting(
265 r#" 263 r#"
266unsafe fn unsafe_fn() {} 264unsafe fn unsafe_fn() {}
267 265
@@ -282,10 +280,7 @@ fn main() {
282} 280}
283"# 281"#
284 .trim(), 282 .trim(),
283 "crates/ra_ide/src/snapshots/highlight_unsafe.html",
284 false,
285 ); 285 );
286 let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_unsafe.html");
287 let actual_html = &analysis.highlight_as_html(file_id, false).unwrap();
288 let expected_html = &read_text(&dst_file);
289 fs::write(dst_file, &actual_html).unwrap();
290 assert_eq_text!(expected_html, actual_html);
291} 286}
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/docs/dev/README.md b/docs/dev/README.md
index 194a40e15..46ee030fc 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -184,6 +184,27 @@ use crate::{}
184use super::{} // but prefer `use crate::` 184use super::{} // but prefer `use crate::`
185``` 185```
186 186
187## Import Style
188
189Items from `hir` and `ast` should be used qualified:
190
191```rust
192// Good
193use ra_syntax::ast;
194
195fn frobnicate(func: hir::Function, strukt: ast::StructDef) {}
196
197// Not as good
198use hir::Function;
199use ra_syntax::ast::StructDef;
200
201fn frobnicate(func: Function, strukt: StructDef) {}
202```
203
204Avoid local `use MyEnum::*` imports.
205
206Prefer `use crate::foo::bar` to `use super::bar`.
207
187## Order of Items 208## Order of Items
188 209
189Optimize for the reader who sees the file for the first time, and wants to get the general idea about what's going on. 210Optimize for the reader who sees the file for the first time, and wants to get the general idea about what's going on.
@@ -220,6 +241,68 @@ struct Foo {
220For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines. 241For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines.
221If the line is too long, you want to split the sentence in two :-) 242If the line is too long, you want to split the sentence in two :-)
222 243
244## Preconditions
245
246Function preconditions should generally be expressed in types and provided by the caller (rather than checked by callee):
247
248```rust
249// Good
250fn frbonicate(walrus: Walrus) {
251 ...
252}
253
254// Not as good
255fn frobnicate(walrus: Option<Walrus>) {
256 let walrus = match walrus {
257 Some(it) => it,
258 None => return,
259 };
260 ...
261}
262```
263
264## Commit Style
265
266We don't have specific rules around git history hygiene.
267Maintaining clean git history is encouraged, but not enforced.
268We use rebase workflow, it's OK to rewrite history during PR review process.
269
270Avoid @mentioning people in commit messages, as such messages create a lot of duplicate notification traffic during rebases.
271
272# Architecture Invariants
273
274This section tries to document high-level design constraints, which are not
275always obvious from the low-level code.
276
277## Incomplete syntax trees
278
279Syntax trees are by design incomplete and do not enforce well-formedness.
280If ast method returns an `Option`, it *can* be `None` at runtime, even if this is forbidden by the grammar.
281
282## LSP indenpendence
283
284rust-analyzer is independent from LSP.
285It provides features for a hypothetical perfect Rust-specific IDE client.
286Internal representations are lowered to LSP in the `rust-analyzer` crate (the only crate which is allowed to use LSP types).
287
288## IDE/Compiler split
289
290There's a semi-hard split between "compiler" and "IDE", at the `ra_hir` crate.
291Compiler derives new facts about source code.
292It explicitly acknowledges that not all info is available (ie, you can't look at types during name resolution).
293
294IDE assumes that all information is available at all times.
295
296IDE should use only types from `ra_hir`, and should not depend on the underling compiler types.
297`ra_hir` is a facade.
298
299## IDE API
300
301The main IDE crate (`ra_ide`) uses "Plain Old Data" for the API.
302Rather than talking in definitions and references, it talks in Strings and textual offsets.
303In general, API is centered around UI concerns -- the result of the call is what the user sees in the editor, and not what the compiler sees underneath.
304The results are 100% Rust specific though.
305
223# Logging 306# Logging
224 307
225Logging is done by both rust-analyzer and VS Code, so it might be tricky to 308Logging is done by both rust-analyzer and VS Code, so it might be tricky to
diff --git a/editors/code/package.json b/editors/code/package.json
index 7fdb5c27d..779d7e1b8 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -497,10 +497,7 @@
497 "default": true 497 "default": true
498 }, 498 },
499 "rust-analyzer.linkedProjects": { 499 "rust-analyzer.linkedProjects": {
500 "markdownDescription": [ 500 "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",
501 "Disable project auto-discovery in favor of explicitly specified set of projects.",
502 "Elements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format"
503 ],
504 "type": "array", 501 "type": "array",
505 "items": { 502 "items": {
506 "type": [ 503 "type": [