aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock8
-rw-r--r--Cargo.toml1
-rw-r--r--crates/ra_hir/src/expr.rs56
-rw-r--r--crates/ra_hir/src/name.rs2
-rw-r--r--crates/ra_hir/src/ty.rs148
-rw-r--r--crates/ra_hir/src/ty/primitive.rs50
-rw-r--r--crates/ra_hir/src/ty/tests.rs30
-rw-r--r--crates/ra_hir/src/ty/tests/data/basics.txt8
-rw-r--r--crates/ra_hir/src/ty/tests/data/binary_op.txt86
-rw-r--r--crates/ra_hir/src/ty/tests/data/let.txt4
-rw-r--r--crates/ra_hir/src/ty/tests/data/literals.txt12
-rw-r--r--crates/ra_hir/src/ty/tests/data/struct.txt4
-rw-r--r--crates/ra_hir/src/ty/tests/data/tuple.txt18
-rw-r--r--crates/ra_ide_api/src/hover.rs5
-rw-r--r--crates/ra_lsp_server/Cargo.toml2
-rw-r--r--crates/ra_lsp_server/src/project_model/cargo_workspace.rs7
-rw-r--r--crates/ra_syntax/src/ast.rs46
-rw-r--r--crates/ra_syntax/src/ast/generated.rs220
-rw-r--r--crates/ra_syntax/src/grammar.ron23
-rw-r--r--crates/ra_syntax/src/lexer/strings.rs15
-rw-r--r--crates/ra_syntax/src/lib.rs5
-rw-r--r--crates/ra_syntax/src/yellow.rs12
-rw-r--r--crates/ra_syntax/src/yellow/syntax_text.rs11
23 files changed, 635 insertions, 138 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2c4337a70..e5830574f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -111,8 +111,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
111 111
112[[package]] 112[[package]]
113name = "cargo_metadata" 113name = "cargo_metadata"
114version = "0.6.4" 114version = "0.7.0"
115source = "git+https://github.com/oli-obk/cargo_metadata.git?rev=f73e27b24e#f73e27b24e92cd9b520a78497cd1017b70a6c99a" 115source = "registry+https://github.com/rust-lang/crates.io-index"
116dependencies = [ 116dependencies = [
117 "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 117 "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
118 "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 118 "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -771,7 +771,7 @@ dependencies = [
771name = "ra_lsp_server" 771name = "ra_lsp_server"
772version = "0.1.0" 772version = "0.1.0"
773dependencies = [ 773dependencies = [
774 "cargo_metadata 0.6.4 (git+https://github.com/oli-obk/cargo_metadata.git?rev=f73e27b24e)", 774 "cargo_metadata 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
775 "crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 775 "crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
776 "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 776 "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
777 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 777 "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1546,7 +1546,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1546"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" 1546"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
1547"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" 1547"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
1548"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" 1548"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
1549"checksum cargo_metadata 0.6.4 (git+https://github.com/oli-obk/cargo_metadata.git?rev=f73e27b24e)" = "<none>" 1549"checksum cargo_metadata 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "95932a7ed5f2308fc00a46d2aa8eb1b06b402c896c2df424916ee730ba610c2e"
1550"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" 1550"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
1551"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" 1551"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
1552"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" 1552"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
diff --git a/Cargo.toml b/Cargo.toml
index 85aaa23b9..59ce6b23d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,5 +6,4 @@ incremental = true
6debug = true 6debug = true
7 7
8[patch.'crates-io'] 8[patch.'crates-io']
9cargo_metadata = { git = "https://github.com/oli-obk/cargo_metadata.git", rev="f73e27b24e" }
10salsa = { git = "https://github.com/matklad/salsa", branch = "panic-hooks" } 9salsa = { git = "https://github.com/matklad/salsa", branch = "panic-hooks" }
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index f0936e9f3..5081466a2 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -5,9 +5,12 @@ use rustc_hash::FxHashMap;
5 5
6use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 6use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
7use ra_db::{LocalSyntaxPtr, Cancelable}; 7use ra_db::{LocalSyntaxPtr, Cancelable};
8use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner}; 8use ra_syntax::{
9 ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner, LiteralFlavor}
10};
9 11
10use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; 12use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName};
13use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy};
11 14
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct ExprId(RawId); 16pub struct ExprId(RawId);
@@ -104,6 +107,16 @@ impl BodySyntaxMapping {
104} 107}
105 108
106#[derive(Debug, Clone, Eq, PartialEq)] 109#[derive(Debug, Clone, Eq, PartialEq)]
110pub enum Literal {
111 String(String),
112 ByteString(Vec<u8>),
113 Char(char),
114 Bool(bool),
115 Int(u64, UncertainIntTy),
116 Float(u64, UncertainFloatTy), // FIXME: f64 is not Eq
117}
118
119#[derive(Debug, Clone, Eq, PartialEq)]
107pub enum Expr { 120pub enum Expr {
108 /// This is produced if syntax tree does not have a required expression piece. 121 /// This is produced if syntax tree does not have a required expression piece.
109 Missing, 122 Missing,
@@ -186,6 +199,7 @@ pub enum Expr {
186 Tuple { 199 Tuple {
187 exprs: Vec<ExprId>, 200 exprs: Vec<ExprId>,
188 }, 201 },
202 Literal(Literal),
189} 203}
190 204
191pub use ra_syntax::ast::PrefixOp as UnaryOp; 205pub use ra_syntax::ast::PrefixOp as UnaryOp;
@@ -305,6 +319,7 @@ impl Expr {
305 f(*expr); 319 f(*expr);
306 } 320 }
307 } 321 }
322 Expr::Literal(_) => {}
308 } 323 }
309 } 324 }
310} 325}
@@ -633,13 +648,50 @@ impl ExprCollector {
633 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect(); 648 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect();
634 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr) 649 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
635 } 650 }
651 ast::ExprKind::Literal(e) => {
652 let child = if let Some(child) = e.literal_expr() {
653 child
654 } else {
655 return self.alloc_expr(Expr::Missing, syntax_ptr);
656 };
657
658 let lit = match child.flavor() {
659 LiteralFlavor::IntNumber { suffix } => {
660 let known_name = suffix
661 .map(|s| Name::new(s))
662 .and_then(|name| UncertainIntTy::from_name(&name));
663
664 Literal::Int(
665 Default::default(),
666 known_name.unwrap_or(UncertainIntTy::Unknown),
667 )
668 }
669 LiteralFlavor::FloatNumber { suffix } => {
670 let known_name = suffix
671 .map(|s| Name::new(s))
672 .and_then(|name| UncertainFloatTy::from_name(&name));
673
674 Literal::Float(
675 Default::default(),
676 known_name.unwrap_or(UncertainFloatTy::Unknown),
677 )
678 }
679 LiteralFlavor::ByteString => Literal::ByteString(Default::default()),
680 LiteralFlavor::String => Literal::String(Default::default()),
681 LiteralFlavor::Byte => {
682 Literal::Int(Default::default(), UncertainIntTy::Unsigned(UintTy::U8))
683 }
684 LiteralFlavor::Bool => Literal::Bool(Default::default()),
685 LiteralFlavor::Char => Literal::Char(Default::default()),
686 };
687 self.alloc_expr(Expr::Literal(lit), syntax_ptr)
688 }
636 689
637 // TODO implement HIR for these: 690 // TODO implement HIR for these:
638 ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 691 ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
639 ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 692 ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
640 ast::ExprKind::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 693 ast::ExprKind::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
641 ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 694 ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
642 ast::ExprKind::Literal(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
643 } 695 }
644 } 696 }
645 697
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
index d9683549c..8d786d2ac 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -23,7 +23,7 @@ impl fmt::Debug for Name {
23} 23}
24 24
25impl Name { 25impl Name {
26 fn new(text: SmolStr) -> Name { 26 pub(crate) fn new(text: SmolStr) -> Name {
27 Name { text } 27 Name { text }
28 } 28 }
29 29
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index fa46ddfe9..5579db8fb 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -14,7 +14,7 @@
14//! rustc. 14//! rustc.
15 15
16mod autoderef; 16mod autoderef;
17mod primitive; 17pub(crate) mod primitive;
18#[cfg(test)] 18#[cfg(test)]
19mod tests; 19mod tests;
20pub(crate) mod method_resolution; 20pub(crate) mod method_resolution;
@@ -38,7 +38,7 @@ use crate::{
38 db::HirDatabase, 38 db::HirDatabase,
39 type_ref::{TypeRef, Mutability}, 39 type_ref::{TypeRef, Mutability},
40 name::KnownName, 40 name::KnownName,
41 expr::{Body, Expr, ExprId, PatId, UnaryOp, BinaryOp, Statement}, 41 expr::{Body, Expr, Literal, ExprId, PatId, UnaryOp, BinaryOp, Statement},
42}; 42};
43 43
44fn transpose<T>(x: Cancelable<Option<T>>) -> Option<Cancelable<T>> { 44fn transpose<T>(x: Cancelable<Option<T>>) -> Option<Cancelable<T>> {
@@ -107,13 +107,35 @@ impl UnifyValue for TypeVarValue {
107 } 107 }
108} 108}
109 109
110/// The kinds of placeholders we need during type inference. Currently, we only 110/// The kinds of placeholders we need during type inference. There's separate
111/// have type variables; in the future, we will probably also need int and float 111/// values for general types, and for integer and float variables. The latter
112/// variables, for inference of literal values (e.g. `100` could be one of 112/// two are used for inference of literal values (e.g. `100` could be one of
113/// several integer types). 113/// several integer types).
114#[derive(Clone, PartialEq, Eq, Hash, Debug)] 114#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
115pub enum InferTy { 115pub enum InferTy {
116 TypeVar(TypeVarId), 116 TypeVar(TypeVarId),
117 IntVar(TypeVarId),
118 FloatVar(TypeVarId),
119}
120
121impl InferTy {
122 fn to_inner(self) -> TypeVarId {
123 match self {
124 InferTy::TypeVar(ty) | InferTy::IntVar(ty) | InferTy::FloatVar(ty) => ty,
125 }
126 }
127
128 fn fallback_value(self) -> Ty {
129 match self {
130 InferTy::TypeVar(..) => Ty::Unknown,
131 InferTy::IntVar(..) => {
132 Ty::Int(primitive::UncertainIntTy::Signed(primitive::IntTy::I32))
133 }
134 InferTy::FloatVar(..) => {
135 Ty::Float(primitive::UncertainFloatTy::Known(primitive::FloatTy::F64))
136 }
137 }
138 }
117} 139}
118 140
119/// When inferring an expression, we propagate downward whatever type hint we 141/// When inferring an expression, we propagate downward whatever type hint we
@@ -151,14 +173,11 @@ pub enum Ty {
151 /// (a non-surrogate code point). Written as `char`. 173 /// (a non-surrogate code point). Written as `char`.
152 Char, 174 Char,
153 175
154 /// A primitive signed integer type. For example, `i32`. 176 /// A primitive integer type. For example, `i32`.
155 Int(primitive::IntTy), 177 Int(primitive::UncertainIntTy),
156
157 /// A primitive unsigned integer type. For example, `u32`.
158 Uint(primitive::UintTy),
159 178
160 /// A primitive floating-point type. For example, `f64`. 179 /// A primitive floating-point type. For example, `f64`.
161 Float(primitive::FloatTy), 180 Float(primitive::UncertainFloatTy),
162 181
163 /// Structures, enumerations and unions. 182 /// Structures, enumerations and unions.
164 Adt { 183 Adt {
@@ -198,8 +217,9 @@ pub enum Ty {
198 // above function pointer type. Once we implement generics, we will probably 217 // above function pointer type. Once we implement generics, we will probably
199 // need this as well. 218 // need this as well.
200 219
201 // A trait, defined with `dyn trait`. 220 // A trait, defined with `dyn Trait`.
202 // Dynamic(), 221 // Dynamic(),
222
203 // The anonymous type of a closure. Used to represent the type of 223 // The anonymous type of a closure. Used to represent the type of
204 // `|a| a`. 224 // `|a| a`.
205 // Closure(DefId, ClosureSubsts<'tcx>), 225 // Closure(DefId, ClosureSubsts<'tcx>),
@@ -312,20 +332,19 @@ impl Ty {
312 path: &Path, 332 path: &Path,
313 ) -> Cancelable<Self> { 333 ) -> Cancelable<Self> {
314 if let Some(name) = path.as_ident() { 334 if let Some(name) = path.as_ident() {
315 if let Some(KnownName::Bool) = name.as_known_name() { 335 if let Some(int_ty) = primitive::UncertainIntTy::from_name(name) {
316 return Ok(Ty::Bool);
317 } else if let Some(KnownName::Char) = name.as_known_name() {
318 return Ok(Ty::Char);
319 } else if let Some(KnownName::Str) = name.as_known_name() {
320 return Ok(Ty::Str);
321 } else if let Some(int_ty) = primitive::IntTy::from_name(name) {
322 return Ok(Ty::Int(int_ty)); 336 return Ok(Ty::Int(int_ty));
323 } else if let Some(uint_ty) = primitive::UintTy::from_name(name) { 337 } else if let Some(float_ty) = primitive::UncertainFloatTy::from_name(name) {
324 return Ok(Ty::Uint(uint_ty));
325 } else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
326 return Ok(Ty::Float(float_ty)); 338 return Ok(Ty::Float(float_ty));
327 } else if name.as_known_name() == Some(KnownName::SelfType) { 339 } else if name.as_known_name() == Some(KnownName::SelfType) {
328 return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type())); 340 return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type()));
341 } else if let Some(known) = name.as_known_name() {
342 match known {
343 KnownName::Bool => return Ok(Ty::Bool),
344 KnownName::Char => return Ok(Ty::Char),
345 KnownName::Str => return Ok(Ty::Str),
346 _ => {}
347 }
329 } 348 }
330 } 349 }
331 350
@@ -392,7 +411,6 @@ impl fmt::Display for Ty {
392 Ty::Bool => write!(f, "bool"), 411 Ty::Bool => write!(f, "bool"),
393 Ty::Char => write!(f, "char"), 412 Ty::Char => write!(f, "char"),
394 Ty::Int(t) => write!(f, "{}", t.ty_to_string()), 413 Ty::Int(t) => write!(f, "{}", t.ty_to_string()),
395 Ty::Uint(t) => write!(f, "{}", t.ty_to_string()),
396 Ty::Float(t) => write!(f, "{}", t.ty_to_string()), 414 Ty::Float(t) => write!(f, "{}", t.ty_to_string()),
397 Ty::Str => write!(f, "str"), 415 Ty::Str => write!(f, "str"),
398 Ty::Slice(t) => write!(f, "[{}]", t), 416 Ty::Slice(t) => write!(f, "[{}]", t),
@@ -587,7 +605,7 @@ fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
587 | BinaryOp::BitwiseAnd 605 | BinaryOp::BitwiseAnd
588 | BinaryOp::BitwiseOr 606 | BinaryOp::BitwiseOr
589 | BinaryOp::BitwiseXor => match rhs_ty { 607 | BinaryOp::BitwiseXor => match rhs_ty {
590 Ty::Uint(..) | Ty::Int(..) | Ty::Float(..) => rhs_ty, 608 Ty::Int(..) | Ty::Float(..) => rhs_ty,
591 _ => Ty::Unknown, 609 _ => Ty::Unknown,
592 }, 610 },
593 BinaryOp::RangeRightOpen | BinaryOp::RangeRightClosed => Ty::Unknown, 611 BinaryOp::RangeRightOpen | BinaryOp::RangeRightClosed => Ty::Unknown,
@@ -598,7 +616,7 @@ fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
598 match op { 616 match op {
599 BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::Bool, 617 BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::Bool,
600 BinaryOp::Assignment | BinaryOp::EqualityTest => match lhs_ty { 618 BinaryOp::Assignment | BinaryOp::EqualityTest => match lhs_ty {
601 Ty::Uint(..) | Ty::Int(..) | Ty::Float(..) | Ty::Str | Ty::Char | Ty::Bool => lhs_ty, 619 Ty::Int(..) | Ty::Float(..) | Ty::Str | Ty::Char | Ty::Bool => lhs_ty,
602 _ => Ty::Unknown, 620 _ => Ty::Unknown,
603 }, 621 },
604 BinaryOp::LesserEqualTest 622 BinaryOp::LesserEqualTest
@@ -625,7 +643,7 @@ fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
625 | BinaryOp::BitwiseAnd 643 | BinaryOp::BitwiseAnd
626 | BinaryOp::BitwiseOr 644 | BinaryOp::BitwiseOr
627 | BinaryOp::BitwiseXor => match lhs_ty { 645 | BinaryOp::BitwiseXor => match lhs_ty {
628 Ty::Uint(..) | Ty::Int(..) | Ty::Float(..) => lhs_ty, 646 Ty::Int(..) | Ty::Float(..) => lhs_ty,
629 _ => Ty::Unknown, 647 _ => Ty::Unknown,
630 }, 648 },
631 _ => Ty::Unknown, 649 _ => Ty::Unknown,
@@ -695,13 +713,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
695 match (&*ty1, &*ty2) { 713 match (&*ty1, &*ty2) {
696 (Ty::Unknown, ..) => true, 714 (Ty::Unknown, ..) => true,
697 (.., Ty::Unknown) => true, 715 (.., Ty::Unknown) => true,
698 (Ty::Bool, _) 716 (Ty::Int(t1), Ty::Int(t2)) => match (t1, t2) {
699 | (Ty::Str, _) 717 (primitive::UncertainIntTy::Unknown, _)
700 | (Ty::Never, _) 718 | (_, primitive::UncertainIntTy::Unknown) => true,
701 | (Ty::Char, _) 719 _ => t1 == t2,
702 | (Ty::Int(..), Ty::Int(..)) 720 },
703 | (Ty::Uint(..), Ty::Uint(..)) 721 (Ty::Float(t1), Ty::Float(t2)) => match (t1, t2) {
704 | (Ty::Float(..), Ty::Float(..)) => ty1 == ty2, 722 (primitive::UncertainFloatTy::Unknown, _)
723 | (_, primitive::UncertainFloatTy::Unknown) => true,
724 _ => t1 == t2,
725 },
726 (Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2,
705 ( 727 (
706 Ty::Adt { 728 Ty::Adt {
707 def_id: def_id1, .. 729 def_id: def_id1, ..
@@ -718,12 +740,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
718 .iter() 740 .iter()
719 .zip(ts2.iter()) 741 .zip(ts2.iter())
720 .all(|(t1, t2)| self.unify(t1, t2)), 742 .all(|(t1, t2)| self.unify(t1, t2)),
721 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) => { 743 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
744 | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
745 | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) => {
722 // both type vars are unknown since we tried to resolve them 746 // both type vars are unknown since we tried to resolve them
723 self.var_unification_table.union(*tv1, *tv2); 747 self.var_unification_table.union(*tv1, *tv2);
724 true 748 true
725 } 749 }
726 (Ty::Infer(InferTy::TypeVar(tv)), other) | (other, Ty::Infer(InferTy::TypeVar(tv))) => { 750 (Ty::Infer(InferTy::TypeVar(tv)), other)
751 | (other, Ty::Infer(InferTy::TypeVar(tv)))
752 | (Ty::Infer(InferTy::IntVar(tv)), other)
753 | (other, Ty::Infer(InferTy::IntVar(tv)))
754 | (Ty::Infer(InferTy::FloatVar(tv)), other)
755 | (other, Ty::Infer(InferTy::FloatVar(tv))) => {
727 // the type var is unknown since we tried to resolve it 756 // the type var is unknown since we tried to resolve it
728 self.var_unification_table 757 self.var_unification_table
729 .union_value(*tv, TypeVarValue::Known(other.clone())); 758 .union_value(*tv, TypeVarValue::Known(other.clone()));
@@ -739,10 +768,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
739 )) 768 ))
740 } 769 }
741 770
771 fn new_integer_var(&mut self) -> Ty {
772 Ty::Infer(InferTy::IntVar(
773 self.var_unification_table.new_key(TypeVarValue::Unknown),
774 ))
775 }
776
777 fn new_float_var(&mut self) -> Ty {
778 Ty::Infer(InferTy::FloatVar(
779 self.var_unification_table.new_key(TypeVarValue::Unknown),
780 ))
781 }
782
742 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. 783 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
743 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { 784 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
744 match ty { 785 match ty {
745 Ty::Unknown => self.new_type_var(), 786 Ty::Unknown => self.new_type_var(),
787 Ty::Int(primitive::UncertainIntTy::Unknown) => self.new_integer_var(),
788 Ty::Float(primitive::UncertainFloatTy::Unknown) => self.new_float_var(),
746 _ => ty, 789 _ => ty,
747 } 790 }
748 } 791 }
@@ -757,12 +800,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
757 /// known type. 800 /// known type.
758 fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { 801 fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty {
759 ty.fold(&mut |ty| match ty { 802 ty.fold(&mut |ty| match ty {
760 Ty::Infer(InferTy::TypeVar(tv)) => { 803 Ty::Infer(tv) => {
761 if let Some(known_ty) = self.var_unification_table.probe_value(tv).known() { 804 let inner = tv.to_inner();
805 if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() {
762 // known_ty may contain other variables that are known by now 806 // known_ty may contain other variables that are known by now
763 self.resolve_ty_as_possible(known_ty.clone()) 807 self.resolve_ty_as_possible(known_ty.clone())
764 } else { 808 } else {
765 Ty::Infer(InferTy::TypeVar(tv)) 809 ty
766 } 810 }
767 } 811 }
768 _ => ty, 812 _ => ty,
@@ -773,8 +817,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
773 /// otherwise, return ty. 817 /// otherwise, return ty.
774 fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { 818 fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
775 match ty { 819 match ty {
776 Ty::Infer(InferTy::TypeVar(tv)) => { 820 Ty::Infer(tv) => {
777 match self.var_unification_table.probe_value(*tv).known() { 821 let inner = tv.to_inner();
822 match self.var_unification_table.probe_value(inner).known() {
778 Some(known_ty) => { 823 Some(known_ty) => {
779 // The known_ty can't be a type var itself 824 // The known_ty can't be a type var itself
780 Cow::Owned(known_ty.clone()) 825 Cow::Owned(known_ty.clone())
@@ -790,12 +835,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
790 /// replaced by Ty::Unknown. 835 /// replaced by Ty::Unknown.
791 fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { 836 fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
792 ty.fold(&mut |ty| match ty { 837 ty.fold(&mut |ty| match ty {
793 Ty::Infer(InferTy::TypeVar(tv)) => { 838 Ty::Infer(tv) => {
794 if let Some(known_ty) = self.var_unification_table.probe_value(tv).known() { 839 let inner = tv.to_inner();
840 if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() {
795 // known_ty may contain other variables that are known by now 841 // known_ty may contain other variables that are known by now
796 self.resolve_ty_completely(known_ty.clone()) 842 self.resolve_ty_completely(known_ty.clone())
797 } else { 843 } else {
798 Ty::Unknown 844 tv.fallback_value()
799 } 845 }
800 } 846 }
801 _ => ty, 847 _ => ty,
@@ -1067,6 +1113,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1067 1113
1068 Ty::Tuple(Arc::from(ty_vec)) 1114 Ty::Tuple(Arc::from(ty_vec))
1069 } 1115 }
1116 Expr::Literal(lit) => match lit {
1117 Literal::Bool(..) => Ty::Bool,
1118 Literal::String(..) => Ty::Ref(Arc::new(Ty::Str), Mutability::Shared),
1119 Literal::ByteString(..) => {
1120 let byte_type = Arc::new(Ty::Int(primitive::UncertainIntTy::Unsigned(
1121 primitive::UintTy::U8,
1122 )));
1123 let slice_type = Arc::new(Ty::Slice(byte_type));
1124 Ty::Ref(slice_type, Mutability::Shared)
1125 }
1126 Literal::Char(..) => Ty::Char,
1127 Literal::Int(_v, ty) => Ty::Int(*ty),
1128 Literal::Float(_v, ty) => Ty::Float(*ty),
1129 },
1070 }; 1130 };
1071 // use a new type variable if we got Ty::Unknown here 1131 // use a new type variable if we got Ty::Unknown here
1072 let ty = self.insert_type_vars_shallow(ty); 1132 let ty = self.insert_type_vars_shallow(ty);
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs
index 498d42d52..5741ca90d 100644
--- a/crates/ra_hir/src/ty/primitive.rs
+++ b/crates/ra_hir/src/ty/primitive.rs
@@ -2,6 +2,56 @@ use std::fmt;
2 2
3use crate::{Name, KnownName}; 3use crate::{Name, KnownName};
4 4
5#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)]
6pub enum UncertainIntTy {
7 Unknown,
8 Unsigned(UintTy),
9 Signed(IntTy),
10}
11
12impl UncertainIntTy {
13 pub fn ty_to_string(&self) -> &'static str {
14 match *self {
15 UncertainIntTy::Unknown => "{integer}",
16 UncertainIntTy::Signed(ty) => ty.ty_to_string(),
17 UncertainIntTy::Unsigned(ty) => ty.ty_to_string(),
18 }
19 }
20
21 pub fn from_name(name: &Name) -> Option<UncertainIntTy> {
22 if let Some(ty) = IntTy::from_name(name) {
23 Some(UncertainIntTy::Signed(ty))
24 } else if let Some(ty) = UintTy::from_name(name) {
25 Some(UncertainIntTy::Unsigned(ty))
26 } else {
27 None
28 }
29 }
30}
31
32#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)]
33pub enum UncertainFloatTy {
34 Unknown,
35 Known(FloatTy),
36}
37
38impl UncertainFloatTy {
39 pub fn ty_to_string(&self) -> &'static str {
40 match *self {
41 UncertainFloatTy::Unknown => "{float}",
42 UncertainFloatTy::Known(ty) => ty.ty_to_string(),
43 }
44 }
45
46 pub fn from_name(name: &Name) -> Option<UncertainFloatTy> {
47 if let Some(ty) = FloatTy::from_name(name) {
48 Some(UncertainFloatTy::Known(ty))
49 } else {
50 None
51 }
52 }
53}
54
5#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] 55#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
6pub enum IntTy { 56pub enum IntTy {
7 Isize, 57 Isize,
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 920188fc9..8aacb1a7f 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -133,6 +133,32 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
133} 133}
134 134
135#[test] 135#[test]
136fn infer_literals() {
137 check_inference(
138 r##"
139fn test() {
140 5i32;
141 "hello";
142 b"bytes";
143 'c';
144 b'b';
145 3.14;
146 5000;
147 false;
148 true;
149 r#"
150 //! doc
151 // non-doc
152 mod foo {}
153 "#;
154 br#"yolo"#;
155}
156"##,
157 "literals.txt",
158 );
159}
160
161#[test]
136fn infer_backwards() { 162fn infer_backwards() {
137 check_inference( 163 check_inference(
138 r#" 164 r#"
@@ -180,7 +206,7 @@ fn f(x: bool) -> i32 {
180 0i32 206 0i32
181} 207}
182 208
183fn test() { 209fn test() -> bool {
184 let x = a && b; 210 let x = a && b;
185 let y = true || false; 211 let y = true || false;
186 let z = x == y; 212 let z = x == y;
@@ -277,8 +303,6 @@ fn test(x: &str, y: isize) {
277 let b = (a, x); 303 let b = (a, x);
278 let c = (y, x); 304 let c = (y, x);
279 let d = (c, x); 305 let d = (c, x);
280
281 // we have not infered these case yet.
282 let e = (1, "e"); 306 let e = (1, "e");
283 let f = (e, "d"); 307 let f = (e, "d");
284} 308}
diff --git a/crates/ra_hir/src/ty/tests/data/basics.txt b/crates/ra_hir/src/ty/tests/data/basics.txt
index ac7faae0a..e65fe07aa 100644
--- a/crates/ra_hir/src/ty/tests/data/basics.txt
+++ b/crates/ra_hir/src/ty/tests/data/basics.txt
@@ -7,7 +7,7 @@
7[55; 56) 'b': isize 7[55; 56) 'b': isize
8[62; 63) 'c': ! 8[62; 63) 'c': !
9[69; 70) 'd': &str 9[69; 70) 'd': &str
10[76; 82) '1usize': [unknown] 10[76; 82) '1usize': usize
11[88; 94) '1isize': [unknown] 11[88; 94) '1isize': isize
12[100; 106) '"test"': [unknown] 12[100; 106) '"test"': &str
13[112; 118) '1.0f32': [unknown] 13[112; 118) '1.0f32': f32
diff --git a/crates/ra_hir/src/ty/tests/data/binary_op.txt b/crates/ra_hir/src/ty/tests/data/binary_op.txt
index 8a515ac5e..58a727691 100644
--- a/crates/ra_hir/src/ty/tests/data/binary_op.txt
+++ b/crates/ra_hir/src/ty/tests/data/binary_op.txt
@@ -1,46 +1,46 @@
1[6; 7) 'x': bool 1[6; 7) 'x': bool
2[22; 34) '{ 0i32 }': i32 2[22; 34) '{ 0i32 }': i32
3[28; 32) '0i32': i32 3[28; 32) '0i32': i32
4[46; 342) '{ ... < 3 }': bool 4[54; 350) '{ ... < 3 }': bool
5[56; 57) 'x': bool 5[64; 65) 'x': bool
6[60; 61) 'a': bool 6[68; 69) 'a': bool
7[60; 66) 'a && b': bool 7[68; 74) 'a && b': bool
8[65; 66) 'b': bool 8[73; 74) 'b': bool
9[76; 77) 'y': bool 9[84; 85) 'y': bool
10[80; 84) 'true': bool 10[88; 92) 'true': bool
11[80; 93) 'true || false': bool 11[88; 101) 'true || false': bool
12[88; 93) 'false': bool 12[96; 101) 'false': bool
13[103; 104) 'z': bool 13[111; 112) 'z': bool
14[107; 108) 'x': bool 14[115; 116) 'x': bool
15[107; 113) 'x == y': bool 15[115; 121) 'x == y': bool
16[112; 113) 'y': bool 16[120; 121) 'y': bool
17[123; 134) 'minus_forty': isize 17[131; 142) 'minus_forty': isize
18[144; 152) '-40isize': isize 18[152; 160) '-40isize': isize
19[145; 152) '40isize': [unknown] 19[153; 160) '40isize': isize
20[162; 163) 'h': bool 20[170; 171) 'h': bool
21[166; 177) 'minus_forty': isize 21[174; 185) 'minus_forty': isize
22[166; 188) 'minus_...ONST_2': bool 22[174; 196) 'minus_...ONST_2': bool
23[181; 188) 'CONST_2': isize 23[189; 196) 'CONST_2': isize
24[198; 199) 'c': i32 24[206; 207) 'c': i32
25[202; 203) 'f': fn(bool) -> i32 25[210; 211) 'f': fn(bool) -> i32
26[202; 211) 'f(z || y)': i32 26[210; 219) 'f(z || y)': i32
27[202; 215) 'f(z || y) + 5': i32 27[210; 223) 'f(z || y) + 5': i32
28[204; 205) 'z': bool 28[212; 213) 'z': bool
29[204; 210) 'z || y': bool 29[212; 218) 'z || y': bool
30[209; 210) 'y': bool 30[217; 218) 'y': bool
31[214; 215) '5': i32 31[222; 223) '5': i32
32[225; 226) 'd': [unknown] 32[233; 234) 'd': [unknown]
33[229; 230) 'b': [unknown] 33[237; 238) 'b': [unknown]
34[240; 241) 'g': () 34[248; 249) 'g': ()
35[244; 255) 'minus_forty': isize 35[252; 263) 'minus_forty': isize
36[244; 260) 'minus_...y ^= i': () 36[252; 268) 'minus_...y ^= i': ()
37[259; 260) 'i': isize 37[267; 268) 'i': isize
38[270; 273) 'ten': usize 38[278; 281) 'ten': usize
39[283; 285) '10': usize 39[291; 293) '10': usize
40[295; 308) 'ten_is_eleven': bool 40[303; 316) 'ten_is_eleven': bool
41[311; 314) 'ten': usize 41[319; 322) 'ten': usize
42[311; 326) 'ten == some_num': bool 42[319; 334) 'ten == some_num': bool
43[318; 326) 'some_num': usize 43[326; 334) 'some_num': usize
44[333; 336) 'ten': usize 44[341; 344) 'ten': usize
45[333; 340) 'ten < 3': bool 45[341; 348) 'ten < 3': bool
46[339; 340) '3': usize 46[347; 348) '3': usize
diff --git a/crates/ra_hir/src/ty/tests/data/let.txt b/crates/ra_hir/src/ty/tests/data/let.txt
index 30f4a2cf5..8815dba41 100644
--- a/crates/ra_hir/src/ty/tests/data/let.txt
+++ b/crates/ra_hir/src/ty/tests/data/let.txt
@@ -1,6 +1,6 @@
1[11; 71) '{ ...= b; }': () 1[11; 71) '{ ...= b; }': ()
2[21; 22) 'a': [unknown] 2[21; 22) 'a': isize
3[25; 31) '1isize': [unknown] 3[25; 31) '1isize': isize
4[41; 42) 'b': usize 4[41; 42) 'b': usize
5[52; 53) '1': usize 5[52; 53) '1': usize
6[63; 64) 'c': usize 6[63; 64) 'c': usize
diff --git a/crates/ra_hir/src/ty/tests/data/literals.txt b/crates/ra_hir/src/ty/tests/data/literals.txt
new file mode 100644
index 000000000..84ee2c11b
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/literals.txt
@@ -0,0 +1,12 @@
1[11; 201) '{ ...o"#; }': ()
2[17; 21) '5i32': i32
3[27; 34) '"hello"': &str
4[40; 48) 'b"bytes"': &[u8]
5[54; 57) ''c'': char
6[63; 67) 'b'b'': u8
7[73; 77) '3.14': f64
8[83; 87) '5000': i32
9[93; 98) 'false': bool
10[104; 108) 'true': bool
11[114; 182) 'r#" ... "#': &str
12[188; 198) 'br#"yolo"#': &[u8]
diff --git a/crates/ra_hir/src/ty/tests/data/struct.txt b/crates/ra_hir/src/ty/tests/data/struct.txt
index 7b324c82f..be9e12d02 100644
--- a/crates/ra_hir/src/ty/tests/data/struct.txt
+++ b/crates/ra_hir/src/ty/tests/data/struct.txt
@@ -2,14 +2,14 @@
2[82; 83) 'c': [unknown] 2[82; 83) 'c': [unknown]
3[86; 87) 'C': [unknown] 3[86; 87) 'C': [unknown]
4[86; 90) 'C(1)': [unknown] 4[86; 90) 'C(1)': [unknown]
5[88; 89) '1': [unknown] 5[88; 89) '1': i32
6[96; 97) 'B': [unknown] 6[96; 97) 'B': [unknown]
7[107; 108) 'a': A 7[107; 108) 'a': A
8[114; 133) 'A { b:...C(1) }': A 8[114; 133) 'A { b:...C(1) }': A
9[121; 122) 'B': B 9[121; 122) 'B': B
10[127; 128) 'C': [unknown] 10[127; 128) 'C': [unknown]
11[127; 131) 'C(1)': C 11[127; 131) 'C(1)': C
12[129; 130) '1': [unknown] 12[129; 130) '1': i32
13[139; 140) 'a': A 13[139; 140) 'a': A
14[139; 142) 'a.b': B 14[139; 142) 'a.b': B
15[148; 149) 'a': A 15[148; 149) 'a': A
diff --git a/crates/ra_hir/src/ty/tests/data/tuple.txt b/crates/ra_hir/src/ty/tests/data/tuple.txt
index 96169180d..a95d3c286 100644
--- a/crates/ra_hir/src/ty/tests/data/tuple.txt
+++ b/crates/ra_hir/src/ty/tests/data/tuple.txt
@@ -1,6 +1,6 @@
1[9; 10) 'x': &str 1[9; 10) 'x': &str
2[18; 19) 'y': isize 2[18; 19) 'y': isize
3[28; 214) '{ ...d"); }': () 3[28; 170) '{ ...d"); }': ()
4[38; 39) 'a': (u32, &str) 4[38; 39) 'a': (u32, &str)
5[55; 63) '(1, "a")': (u32, &str) 5[55; 63) '(1, "a")': (u32, &str)
6[56; 57) '1': u32 6[56; 57) '1': u32
@@ -17,11 +17,11 @@
17[117; 123) '(c, x)': ((isize, &str), &str) 17[117; 123) '(c, x)': ((isize, &str), &str)
18[118; 119) 'c': (isize, &str) 18[118; 119) 'c': (isize, &str)
19[121; 122) 'x': &str 19[121; 122) 'x': &str
20[177; 178) 'e': ([unknown], [unknown]) 20[133; 134) 'e': (i32, &str)
21[181; 189) '(1, "e")': ([unknown], [unknown]) 21[137; 145) '(1, "e")': (i32, &str)
22[182; 183) '1': [unknown] 22[138; 139) '1': i32
23[185; 188) '"e"': [unknown] 23[141; 144) '"e"': &str
24[199; 200) 'f': (([unknown], [unknown]), [unknown]) 24[155; 156) 'f': ((i32, &str), &str)
25[203; 211) '(e, "d")': (([unknown], [unknown]), [unknown]) 25[159; 167) '(e, "d")': ((i32, &str), &str)
26[204; 205) 'e': ([unknown], [unknown]) 26[160; 161) 'e': (i32, &str)
27[207; 210) '"d"': [unknown] 27[163; 166) '"d"': &str
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index d73c5bc31..107b23833 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -230,20 +230,19 @@ mod tests {
230 assert_eq!("[unknown]", &type_name); 230 assert_eq!("[unknown]", &type_name);
231 } 231 }
232 232
233 // FIXME: improve type_of to make this work
234 #[test] 233 #[test]
235 fn test_type_of_for_expr_2() { 234 fn test_type_of_for_expr_2() {
236 let (analysis, range) = single_file_with_range( 235 let (analysis, range) = single_file_with_range(
237 " 236 "
238 fn main() { 237 fn main() {
239 let foo: usize = 1; 238 let foo: usize = 1;
240 let bar = <|>1 + foo_test<|>; 239 let bar = <|>1 + foo<|>;
241 } 240 }
242 ", 241 ",
243 ); 242 );
244 243
245 let type_name = analysis.type_of(range).unwrap().unwrap(); 244 let type_name = analysis.type_of(range).unwrap().unwrap();
246 assert_eq!("[unknown]", &type_name); 245 assert_eq!("usize", &type_name);
247 } 246 }
248 247
249} 248}
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index 0557897fd..e87d311eb 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -20,7 +20,7 @@ url_serde = "0.2.0"
20lsp-types = "0.54.0" 20lsp-types = "0.54.0"
21walkdir = "2.2.7" 21walkdir = "2.2.7"
22im = "12.0.0" 22im = "12.0.0"
23cargo_metadata = "0.6.0" 23cargo_metadata = "0.7.0"
24rustc-hash = "1.0" 24rustc-hash = "1.0"
25parking_lot = "0.7.0" 25parking_lot = "0.7.0"
26 26
diff --git a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs b/crates/ra_lsp_server/src/project_model/cargo_workspace.rs
index 8f7518860..75ae78bca 100644
--- a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs
+++ b/crates/ra_lsp_server/src/project_model/cargo_workspace.rs
@@ -1,6 +1,6 @@
1use std::path::{Path, PathBuf}; 1use std::path::{Path, PathBuf};
2 2
3use cargo_metadata::{metadata_run, CargoOpt}; 3use cargo_metadata::{MetadataCommand, CargoOpt};
4use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
5use ra_arena::{Arena, RawId, impl_arena_id}; 5use ra_arena::{Arena, RawId, impl_arena_id};
6use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
@@ -117,7 +117,10 @@ impl Target {
117 117
118impl CargoWorkspace { 118impl CargoWorkspace {
119 pub fn from_cargo_metadata(cargo_toml: &Path) -> Result<CargoWorkspace> { 119 pub fn from_cargo_metadata(cargo_toml: &Path) -> Result<CargoWorkspace> {
120 let meta = metadata_run(Some(cargo_toml), true, Some(CargoOpt::AllFeatures)) 120 let meta = MetadataCommand::new()
121 .manifest_path(cargo_toml)
122 .features(CargoOpt::AllFeatures)
123 .exec()
121 .map_err(|e| format_err!("cargo metadata failed: {}", e))?; 124 .map_err(|e| format_err!("cargo metadata failed: {}", e))?;
122 let mut pkg_by_id = FxHashMap::default(); 125 let mut pkg_by_id = FxHashMap::default();
123 let mut packages = Arena::default(); 126 let mut packages = Arena::default();
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index 8bf439b60..211ba31e5 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -609,6 +609,52 @@ impl SelfParam {
609 } 609 }
610} 610}
611 611
612#[derive(Clone, Debug, PartialEq, Eq, Hash)]
613pub enum LiteralFlavor {
614 String,
615 ByteString,
616 Char,
617 Byte,
618 IntNumber { suffix: Option<SmolStr> },
619 FloatNumber { suffix: Option<SmolStr> },
620 Bool,
621}
622
623impl LiteralExpr {
624 pub fn flavor(&self) -> LiteralFlavor {
625 let syntax = self.syntax();
626 match syntax.kind() {
627 INT_NUMBER => {
628 let allowed_suffix_list = [
629 "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32",
630 "u16", "u8",
631 ];
632 let text = syntax.text().to_string();
633 let suffix = allowed_suffix_list
634 .iter()
635 .find(|&s| text.ends_with(s))
636 .map(|&suf| SmolStr::new(suf));
637 LiteralFlavor::IntNumber { suffix: suffix }
638 }
639 FLOAT_NUMBER => {
640 let allowed_suffix_list = ["f64", "f32"];
641 let text = syntax.text().to_string();
642 let suffix = allowed_suffix_list
643 .iter()
644 .find(|&s| text.ends_with(s))
645 .map(|&suf| SmolStr::new(suf));
646 LiteralFlavor::FloatNumber { suffix: suffix }
647 }
648 STRING | RAW_STRING => LiteralFlavor::String,
649 TRUE_KW | FALSE_KW => LiteralFlavor::Bool,
650 BYTE_STRING | RAW_BYTE_STRING => LiteralFlavor::ByteString,
651 CHAR => LiteralFlavor::Char,
652 BYTE => LiteralFlavor::Byte,
653 _ => unreachable!(),
654 }
655 }
656}
657
612#[test] 658#[test]
613fn test_doc_comment_of_items() { 659fn test_doc_comment_of_items() {
614 let file = SourceFile::parse( 660 let file = SourceFile::parse(
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 94842a514..3471d5226 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -793,6 +793,31 @@ impl AstNode for ExternCrateItem {
793 793
794impl ExternCrateItem {} 794impl ExternCrateItem {}
795 795
796// FalseKw
797#[derive(Debug, PartialEq, Eq, Hash)]
798#[repr(transparent)]
799pub struct FalseKw {
800 pub(crate) syntax: SyntaxNode,
801}
802unsafe impl TransparentNewType for FalseKw {
803 type Repr = rowan::SyntaxNode<RaTypes>;
804}
805
806impl AstNode for FalseKw {
807 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
808 match syntax.kind() {
809 FALSE_KW => Some(FalseKw::from_repr(syntax.into_repr())),
810 _ => None,
811 }
812 }
813 fn syntax(&self) -> &SyntaxNode { &self.syntax }
814 fn to_owned(&self) -> TreeArc<FalseKw> { TreeArc::cast(self.syntax.to_owned()) }
815}
816
817
818impl ast::AstToken for FalseKw {}
819impl FalseKw {}
820
796// FieldExpr 821// FieldExpr
797#[derive(Debug, PartialEq, Eq, Hash)] 822#[derive(Debug, PartialEq, Eq, Hash)]
798#[repr(transparent)] 823#[repr(transparent)]
@@ -849,6 +874,31 @@ impl AstNode for FieldPatList {
849 874
850impl FieldPatList {} 875impl FieldPatList {}
851 876
877// FloatNumber
878#[derive(Debug, PartialEq, Eq, Hash)]
879#[repr(transparent)]
880pub struct FloatNumber {
881 pub(crate) syntax: SyntaxNode,
882}
883unsafe impl TransparentNewType for FloatNumber {
884 type Repr = rowan::SyntaxNode<RaTypes>;
885}
886
887impl AstNode for FloatNumber {
888 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
889 match syntax.kind() {
890 FLOAT_NUMBER => Some(FloatNumber::from_repr(syntax.into_repr())),
891 _ => None,
892 }
893 }
894 fn syntax(&self) -> &SyntaxNode { &self.syntax }
895 fn to_owned(&self) -> TreeArc<FloatNumber> { TreeArc::cast(self.syntax.to_owned()) }
896}
897
898
899impl ast::AstToken for FloatNumber {}
900impl FloatNumber {}
901
852// FnDef 902// FnDef
853#[derive(Debug, PartialEq, Eq, Hash)] 903#[derive(Debug, PartialEq, Eq, Hash)]
854#[repr(transparent)] 904#[repr(transparent)]
@@ -1130,6 +1180,31 @@ impl AstNode for IndexExpr {
1130 1180
1131impl IndexExpr {} 1181impl IndexExpr {}
1132 1182
1183// IntNumber
1184#[derive(Debug, PartialEq, Eq, Hash)]
1185#[repr(transparent)]
1186pub struct IntNumber {
1187 pub(crate) syntax: SyntaxNode,
1188}
1189unsafe impl TransparentNewType for IntNumber {
1190 type Repr = rowan::SyntaxNode<RaTypes>;
1191}
1192
1193impl AstNode for IntNumber {
1194 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
1195 match syntax.kind() {
1196 INT_NUMBER => Some(IntNumber::from_repr(syntax.into_repr())),
1197 _ => None,
1198 }
1199 }
1200 fn syntax(&self) -> &SyntaxNode { &self.syntax }
1201 fn to_owned(&self) -> TreeArc<IntNumber> { TreeArc::cast(self.syntax.to_owned()) }
1202}
1203
1204
1205impl ast::AstToken for IntNumber {}
1206impl IntNumber {}
1207
1133// ItemList 1208// ItemList
1134#[derive(Debug, PartialEq, Eq, Hash)] 1209#[derive(Debug, PartialEq, Eq, Hash)]
1135#[repr(transparent)] 1210#[repr(transparent)]
@@ -1327,7 +1402,75 @@ impl AstNode for Literal {
1327} 1402}
1328 1403
1329 1404
1330impl Literal {} 1405impl Literal {
1406 pub fn literal_expr(&self) -> Option<&LiteralExpr> {
1407 super::child_opt(self)
1408 }
1409}
1410
1411// LiteralExpr
1412#[derive(Debug, PartialEq, Eq, Hash)]
1413#[repr(transparent)]
1414pub struct LiteralExpr {
1415 pub(crate) syntax: SyntaxNode,
1416}
1417unsafe impl TransparentNewType for LiteralExpr {
1418 type Repr = rowan::SyntaxNode<RaTypes>;
1419}
1420
1421#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1422pub enum LiteralExprKind<'a> {
1423 String(&'a String),
1424 ByteString(&'a ByteString),
1425 RawString(&'a RawString),
1426 RawByteString(&'a RawByteString),
1427 Char(&'a Char),
1428 Byte(&'a Byte),
1429 IntNumber(&'a IntNumber),
1430 FloatNumber(&'a FloatNumber),
1431 TrueKw(&'a TrueKw),
1432 FalseKw(&'a FalseKw),
1433}
1434
1435impl AstNode for LiteralExpr {
1436 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
1437 match syntax.kind() {
1438 | STRING
1439 | BYTE_STRING
1440 | RAW_STRING
1441 | RAW_BYTE_STRING
1442 | CHAR
1443 | BYTE
1444 | INT_NUMBER
1445 | FLOAT_NUMBER
1446 | TRUE_KW
1447 | FALSE_KW => Some(LiteralExpr::from_repr(syntax.into_repr())),
1448 _ => None,
1449 }
1450 }
1451 fn syntax(&self) -> &SyntaxNode { &self.syntax }
1452 fn to_owned(&self) -> TreeArc<LiteralExpr> { TreeArc::cast(self.syntax.to_owned()) }
1453}
1454
1455impl LiteralExpr {
1456 pub fn kind(&self) -> LiteralExprKind {
1457 match self.syntax.kind() {
1458 STRING => LiteralExprKind::String(String::cast(&self.syntax).unwrap()),
1459 BYTE_STRING => LiteralExprKind::ByteString(ByteString::cast(&self.syntax).unwrap()),
1460 RAW_STRING => LiteralExprKind::RawString(RawString::cast(&self.syntax).unwrap()),
1461 RAW_BYTE_STRING => LiteralExprKind::RawByteString(RawByteString::cast(&self.syntax).unwrap()),
1462 CHAR => LiteralExprKind::Char(Char::cast(&self.syntax).unwrap()),
1463 BYTE => LiteralExprKind::Byte(Byte::cast(&self.syntax).unwrap()),
1464 INT_NUMBER => LiteralExprKind::IntNumber(IntNumber::cast(&self.syntax).unwrap()),
1465 FLOAT_NUMBER => LiteralExprKind::FloatNumber(FloatNumber::cast(&self.syntax).unwrap()),
1466 TRUE_KW => LiteralExprKind::TrueKw(TrueKw::cast(&self.syntax).unwrap()),
1467 FALSE_KW => LiteralExprKind::FalseKw(FalseKw::cast(&self.syntax).unwrap()),
1468 _ => unreachable!(),
1469 }
1470 }
1471}
1472
1473impl LiteralExpr {}
1331 1474
1332// LoopExpr 1475// LoopExpr
1333#[derive(Debug, PartialEq, Eq, Hash)] 1476#[derive(Debug, PartialEq, Eq, Hash)]
@@ -2406,6 +2549,56 @@ impl AstNode for RangePat {
2406 2549
2407impl RangePat {} 2550impl RangePat {}
2408 2551
2552// RawByteString
2553#[derive(Debug, PartialEq, Eq, Hash)]
2554#[repr(transparent)]
2555pub struct RawByteString {
2556 pub(crate) syntax: SyntaxNode,
2557}
2558unsafe impl TransparentNewType for RawByteString {
2559 type Repr = rowan::SyntaxNode<RaTypes>;
2560}
2561
2562impl AstNode for RawByteString {
2563 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
2564 match syntax.kind() {
2565 RAW_BYTE_STRING => Some(RawByteString::from_repr(syntax.into_repr())),
2566 _ => None,
2567 }
2568 }
2569 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2570 fn to_owned(&self) -> TreeArc<RawByteString> { TreeArc::cast(self.syntax.to_owned()) }
2571}
2572
2573
2574impl ast::AstToken for RawByteString {}
2575impl RawByteString {}
2576
2577// RawString
2578#[derive(Debug, PartialEq, Eq, Hash)]
2579#[repr(transparent)]
2580pub struct RawString {
2581 pub(crate) syntax: SyntaxNode,
2582}
2583unsafe impl TransparentNewType for RawString {
2584 type Repr = rowan::SyntaxNode<RaTypes>;
2585}
2586
2587impl AstNode for RawString {
2588 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
2589 match syntax.kind() {
2590 RAW_STRING => Some(RawString::from_repr(syntax.into_repr())),
2591 _ => None,
2592 }
2593 }
2594 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2595 fn to_owned(&self) -> TreeArc<RawString> { TreeArc::cast(self.syntax.to_owned()) }
2596}
2597
2598
2599impl ast::AstToken for RawString {}
2600impl RawString {}
2601
2409// RefExpr 2602// RefExpr
2410#[derive(Debug, PartialEq, Eq, Hash)] 2603#[derive(Debug, PartialEq, Eq, Hash)]
2411#[repr(transparent)] 2604#[repr(transparent)]
@@ -2919,6 +3112,31 @@ impl ast::AttrsOwner for TraitDef {}
2919impl ast::DocCommentsOwner for TraitDef {} 3112impl ast::DocCommentsOwner for TraitDef {}
2920impl TraitDef {} 3113impl TraitDef {}
2921 3114
3115// TrueKw
3116#[derive(Debug, PartialEq, Eq, Hash)]
3117#[repr(transparent)]
3118pub struct TrueKw {
3119 pub(crate) syntax: SyntaxNode,
3120}
3121unsafe impl TransparentNewType for TrueKw {
3122 type Repr = rowan::SyntaxNode<RaTypes>;
3123}
3124
3125impl AstNode for TrueKw {
3126 fn cast(syntax: &SyntaxNode) -> Option<&Self> {
3127 match syntax.kind() {
3128 TRUE_KW => Some(TrueKw::from_repr(syntax.into_repr())),
3129 _ => None,
3130 }
3131 }
3132 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3133 fn to_owned(&self) -> TreeArc<TrueKw> { TreeArc::cast(self.syntax.to_owned()) }
3134}
3135
3136
3137impl ast::AstToken for TrueKw {}
3138impl TrueKw {}
3139
2922// TryExpr 3140// TryExpr
2923#[derive(Debug, PartialEq, Eq, Hash)] 3141#[derive(Debug, PartialEq, Eq, Hash)]
2924#[repr(transparent)] 3142#[repr(transparent)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index dfd88bd10..bd8c5b411 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -426,11 +426,32 @@ Grammar(
426 "PrefixExpr": (options: ["Expr"]), 426 "PrefixExpr": (options: ["Expr"]),
427 "RangeExpr": (), 427 "RangeExpr": (),
428 "BinExpr": (), 428 "BinExpr": (),
429
430 "IntNumber": ( traits: ["AstToken"] ),
431 "FloatNumber": ( traits: ["AstToken"] ),
429 "String": ( traits: ["AstToken"] ), 432 "String": ( traits: ["AstToken"] ),
433 "RawString": ( traits: ["AstToken"] ),
430 "Byte": ( traits: ["AstToken"] ), 434 "Byte": ( traits: ["AstToken"] ),
435 "RawByteString": ( traits: ["AstToken"] ),
431 "ByteString": ( traits: ["AstToken"] ), 436 "ByteString": ( traits: ["AstToken"] ),
432 "Char": ( traits: ["AstToken"] ), 437 "Char": ( traits: ["AstToken"] ),
433 "Literal": (), 438 "TrueKw": ( traits: ["AstToken"] ),
439 "FalseKw": ( traits: ["AstToken"] ),
440 "LiteralExpr": (
441 enum: [
442 "String",
443 "ByteString",
444 "RawString",
445 "RawByteString",
446 "Char",
447 "Byte",
448 "IntNumber",
449 "FloatNumber",
450 "TrueKw",
451 "FalseKw",
452 ]
453 ),
454 "Literal": (options: ["LiteralExpr"]),
434 455
435 "Expr": ( 456 "Expr": (
436 enum: [ 457 enum: [
diff --git a/crates/ra_syntax/src/lexer/strings.rs b/crates/ra_syntax/src/lexer/strings.rs
index 5090feae6..0865b7f3b 100644
--- a/crates/ra_syntax/src/lexer/strings.rs
+++ b/crates/ra_syntax/src/lexer/strings.rs
@@ -49,7 +49,7 @@ pub(crate) fn scan_byte_char_or_string(ptr: &mut Ptr) -> SyntaxKind {
49 BYTE_STRING 49 BYTE_STRING
50 } 50 }
51 'r' => { 51 'r' => {
52 scan_raw_byte_string(ptr); 52 scan_raw_string(ptr);
53 RAW_BYTE_STRING 53 RAW_BYTE_STRING
54 } 54 }
55 _ => unreachable!(), 55 _ => unreachable!(),
@@ -108,16 +108,3 @@ fn scan_byte(ptr: &mut Ptr) {
108fn scan_byte_string(ptr: &mut Ptr) { 108fn scan_byte_string(ptr: &mut Ptr) {
109 scan_string(ptr) 109 scan_string(ptr)
110} 110}
111
112fn scan_raw_byte_string(ptr: &mut Ptr) {
113 if !ptr.at('"') {
114 return;
115 }
116 ptr.bump();
117
118 while let Some(c) = ptr.bump() {
119 if c == '"' {
120 return;
121 }
122 }
123}
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index 2a095817a..bc311cbbc 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -59,24 +59,29 @@ impl SourceFile {
59 assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE); 59 assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
60 TreeArc::cast(root) 60 TreeArc::cast(root)
61 } 61 }
62
62 pub fn parse(text: &str) -> TreeArc<SourceFile> { 63 pub fn parse(text: &str) -> TreeArc<SourceFile> {
63 let tokens = tokenize(&text); 64 let tokens = tokenize(&text);
64 let (green, errors) = 65 let (green, errors) =
65 parser_impl::parse_with(yellow::GreenBuilder::new(), text, &tokens, grammar::root); 66 parser_impl::parse_with(yellow::GreenBuilder::new(), text, &tokens, grammar::root);
66 SourceFile::new(green, errors) 67 SourceFile::new(green, errors)
67 } 68 }
69
68 pub fn reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> { 70 pub fn reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> {
69 self.incremental_reparse(edit) 71 self.incremental_reparse(edit)
70 .unwrap_or_else(|| self.full_reparse(edit)) 72 .unwrap_or_else(|| self.full_reparse(edit))
71 } 73 }
74
72 pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<TreeArc<SourceFile>> { 75 pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<TreeArc<SourceFile>> {
73 reparsing::incremental_reparse(self.syntax(), edit, self.errors()) 76 reparsing::incremental_reparse(self.syntax(), edit, self.errors())
74 .map(|(green_node, errors)| SourceFile::new(green_node, errors)) 77 .map(|(green_node, errors)| SourceFile::new(green_node, errors))
75 } 78 }
79
76 fn full_reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> { 80 fn full_reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> {
77 let text = edit.apply(self.syntax().text().to_string()); 81 let text = edit.apply(self.syntax().text().to_string());
78 SourceFile::parse(&text) 82 SourceFile::parse(&text)
79 } 83 }
84
80 pub fn errors(&self) -> Vec<SyntaxError> { 85 pub fn errors(&self) -> Vec<SyntaxError> {
81 let mut errors = self.syntax.root_data().clone(); 86 let mut errors = self.syntax.root_data().clone();
82 errors.extend(validation::validate(self)); 87 errors.extend(validation::validate(self));
diff --git a/crates/ra_syntax/src/yellow.rs b/crates/ra_syntax/src/yellow.rs
index 93621d08a..9b93945cc 100644
--- a/crates/ra_syntax/src/yellow.rs
+++ b/crates/ra_syntax/src/yellow.rs
@@ -128,40 +128,52 @@ impl SyntaxNode {
128 pub(crate) fn root_data(&self) -> &Vec<SyntaxError> { 128 pub(crate) fn root_data(&self) -> &Vec<SyntaxError> {
129 self.0.root_data() 129 self.0.root_data()
130 } 130 }
131
131 pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { 132 pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode {
132 self.0.replace_self(replacement) 133 self.0.replace_self(replacement)
133 } 134 }
135
134 pub fn to_owned(&self) -> TreeArc<SyntaxNode> { 136 pub fn to_owned(&self) -> TreeArc<SyntaxNode> {
135 let ptr = TreeArc(self.0.to_owned()); 137 let ptr = TreeArc(self.0.to_owned());
136 TreeArc::cast(ptr) 138 TreeArc::cast(ptr)
137 } 139 }
140
138 pub fn kind(&self) -> SyntaxKind { 141 pub fn kind(&self) -> SyntaxKind {
139 self.0.kind() 142 self.0.kind()
140 } 143 }
144
141 pub fn range(&self) -> TextRange { 145 pub fn range(&self) -> TextRange {
142 self.0.range() 146 self.0.range()
143 } 147 }
148
144 pub fn text(&self) -> SyntaxText { 149 pub fn text(&self) -> SyntaxText {
145 SyntaxText::new(self) 150 SyntaxText::new(self)
146 } 151 }
152
147 pub fn is_leaf(&self) -> bool { 153 pub fn is_leaf(&self) -> bool {
148 self.0.is_leaf() 154 self.0.is_leaf()
149 } 155 }
156
150 pub fn parent(&self) -> Option<&SyntaxNode> { 157 pub fn parent(&self) -> Option<&SyntaxNode> {
151 self.0.parent().map(SyntaxNode::from_repr) 158 self.0.parent().map(SyntaxNode::from_repr)
152 } 159 }
160
153 pub fn first_child(&self) -> Option<&SyntaxNode> { 161 pub fn first_child(&self) -> Option<&SyntaxNode> {
154 self.0.first_child().map(SyntaxNode::from_repr) 162 self.0.first_child().map(SyntaxNode::from_repr)
155 } 163 }
164
156 pub fn last_child(&self) -> Option<&SyntaxNode> { 165 pub fn last_child(&self) -> Option<&SyntaxNode> {
157 self.0.last_child().map(SyntaxNode::from_repr) 166 self.0.last_child().map(SyntaxNode::from_repr)
158 } 167 }
168
159 pub fn next_sibling(&self) -> Option<&SyntaxNode> { 169 pub fn next_sibling(&self) -> Option<&SyntaxNode> {
160 self.0.next_sibling().map(SyntaxNode::from_repr) 170 self.0.next_sibling().map(SyntaxNode::from_repr)
161 } 171 }
172
162 pub fn prev_sibling(&self) -> Option<&SyntaxNode> { 173 pub fn prev_sibling(&self) -> Option<&SyntaxNode> {
163 self.0.prev_sibling().map(SyntaxNode::from_repr) 174 self.0.prev_sibling().map(SyntaxNode::from_repr)
164 } 175 }
176
165 pub fn children(&self) -> SyntaxNodeChildren { 177 pub fn children(&self) -> SyntaxNodeChildren {
166 SyntaxNodeChildren(self.0.children()) 178 SyntaxNodeChildren(self.0.children())
167 } 179 }
diff --git a/crates/ra_syntax/src/yellow/syntax_text.rs b/crates/ra_syntax/src/yellow/syntax_text.rs
index 08dbe57a2..378cd1b2e 100644
--- a/crates/ra_syntax/src/yellow/syntax_text.rs
+++ b/crates/ra_syntax/src/yellow/syntax_text.rs
@@ -15,6 +15,7 @@ impl<'a> SyntaxText<'a> {
15 range: node.range(), 15 range: node.range(),
16 } 16 }
17 } 17 }
18
18 pub fn chunks(&self) -> impl Iterator<Item = &'a str> { 19 pub fn chunks(&self) -> impl Iterator<Item = &'a str> {
19 let range = self.range; 20 let range = self.range;
20 self.node.descendants().filter_map(move |node| { 21 self.node.descendants().filter_map(move |node| {
@@ -24,15 +25,19 @@ impl<'a> SyntaxText<'a> {
24 Some(&text[range]) 25 Some(&text[range])
25 }) 26 })
26 } 27 }
28
27 pub fn push_to(&self, buf: &mut String) { 29 pub fn push_to(&self, buf: &mut String) {
28 self.chunks().for_each(|it| buf.push_str(it)); 30 self.chunks().for_each(|it| buf.push_str(it));
29 } 31 }
32
30 pub fn to_string(&self) -> String { 33 pub fn to_string(&self) -> String {
31 self.chunks().collect() 34 self.chunks().collect()
32 } 35 }
36
33 pub fn contains(&self, c: char) -> bool { 37 pub fn contains(&self, c: char) -> bool {
34 self.chunks().any(|it| it.contains(c)) 38 self.chunks().any(|it| it.contains(c))
35 } 39 }
40
36 pub fn find(&self, c: char) -> Option<TextUnit> { 41 pub fn find(&self, c: char) -> Option<TextUnit> {
37 let mut acc: TextUnit = 0.into(); 42 let mut acc: TextUnit = 0.into();
38 for chunk in self.chunks() { 43 for chunk in self.chunks() {
@@ -44,9 +49,11 @@ impl<'a> SyntaxText<'a> {
44 } 49 }
45 None 50 None
46 } 51 }
52
47 pub fn len(&self) -> TextUnit { 53 pub fn len(&self) -> TextUnit {
48 self.range.len() 54 self.range.len()
49 } 55 }
56
50 pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> { 57 pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> {
51 let range = range.restrict(self.range).unwrap_or_else(|| { 58 let range = range.restrict(self.range).unwrap_or_else(|| {
52 panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range) 59 panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range)
@@ -56,8 +63,10 @@ impl<'a> SyntaxText<'a> {
56 range, 63 range,
57 } 64 }
58 } 65 }
59 pub fn char_at(&self, offset: TextUnit) -> Option<char> { 66
67 pub fn char_at(&self, offset: impl Into<TextUnit>) -> Option<char> {
60 let mut start: TextUnit = 0.into(); 68 let mut start: TextUnit = 0.into();
69 let offset = offset.into();
61 for chunk in self.chunks() { 70 for chunk in self.chunks() {
62 let end = start + TextUnit::of_str(chunk); 71 let end = start + TextUnit::of_str(chunk);
63 if start <= offset && offset < end { 72 if start <= offset && offset < end {