diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-14 20:58:20 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-14 20:58:20 +0000 |
commit | e8e82ce032f8678929b015e6f70ac060bb2cf94c (patch) | |
tree | 9fb158e9f7115bb70cf2b8623b70710c55497ed4 | |
parent | 784ff638e549a27503b719e5c2f0009b40d25364 (diff) | |
parent | 37ba237e6686d94783d1f025d23823ad7c0cb0c8 (diff) |
Merge #485
485: Add type inference for a bunch of primitives r=flodiebold a=marcusklaas
This PR adds inference for `&str`, `&[u8]`, `char`, `bool`, floats and integers. For floats and integers it uses type variables to infer the exact type, i.e. `u32`, from context when it's not annotated explicitly.
I'm not quite happy with the implementation yet, but I think it mostly works now.
Co-authored-by: Marcus Klaas de Vries <[email protected]>
-rw-r--r-- | crates/ra_hir/src/expr.rs | 56 | ||||
-rw-r--r-- | crates/ra_hir/src/name.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 148 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/primitive.rs | 50 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 30 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/basics.txt | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/binary_op.txt | 86 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/let.txt | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/literals.txt | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/struct.txt | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/tuple.txt | 18 | ||||
-rw-r--r-- | crates/ra_ide_api/src/hover.rs | 5 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast.rs | 46 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 220 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 23 | ||||
-rw-r--r-- | crates/ra_syntax/src/lexer/strings.rs | 15 | ||||
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 5 | ||||
-rw-r--r-- | crates/ra_syntax/src/yellow.rs | 12 | ||||
-rw-r--r-- | crates/ra_syntax/src/yellow/syntax_text.rs | 11 |
19 files changed, 625 insertions, 130 deletions
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 | ||
6 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; | 6 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; |
7 | use ra_db::{LocalSyntaxPtr, Cancelable}; | 7 | use ra_db::{LocalSyntaxPtr, Cancelable}; |
8 | use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner}; | 8 | use ra_syntax::{ |
9 | ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner, LiteralFlavor} | ||
10 | }; | ||
9 | 11 | ||
10 | use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; | 12 | use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; |
13 | use 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)] |
13 | pub struct ExprId(RawId); | 16 | pub 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)] |
110 | pub 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)] | ||
107 | pub enum Expr { | 120 | pub 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 | ||
191 | pub use ra_syntax::ast::PrefixOp as UnaryOp; | 205 | pub 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 | ||
25 | impl Name { | 25 | impl 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 | ||
16 | mod autoderef; | 16 | mod autoderef; |
17 | mod primitive; | 17 | pub(crate) mod primitive; |
18 | #[cfg(test)] | 18 | #[cfg(test)] |
19 | mod tests; | 19 | mod tests; |
20 | pub(crate) mod method_resolution; | 20 | pub(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 | ||
44 | fn transpose<T>(x: Cancelable<Option<T>>) -> Option<Cancelable<T>> { | 44 | fn 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)] |
115 | pub enum InferTy { | 115 | pub enum InferTy { |
116 | TypeVar(TypeVarId), | 116 | TypeVar(TypeVarId), |
117 | IntVar(TypeVarId), | ||
118 | FloatVar(TypeVarId), | ||
119 | } | ||
120 | |||
121 | impl 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 | ||
3 | use crate::{Name, KnownName}; | 3 | use crate::{Name, KnownName}; |
4 | 4 | ||
5 | #[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)] | ||
6 | pub enum UncertainIntTy { | ||
7 | Unknown, | ||
8 | Unsigned(UintTy), | ||
9 | Signed(IntTy), | ||
10 | } | ||
11 | |||
12 | impl 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)] | ||
33 | pub enum UncertainFloatTy { | ||
34 | Unknown, | ||
35 | Known(FloatTy), | ||
36 | } | ||
37 | |||
38 | impl 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)] |
6 | pub enum IntTy { | 56 | pub 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] |
136 | fn infer_literals() { | ||
137 | check_inference( | ||
138 | r##" | ||
139 | fn 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] | ||
136 | fn infer_backwards() { | 162 | fn 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 | ||
183 | fn test() { | 209 | fn 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_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)] | ||
613 | pub enum LiteralFlavor { | ||
614 | String, | ||
615 | ByteString, | ||
616 | Char, | ||
617 | Byte, | ||
618 | IntNumber { suffix: Option<SmolStr> }, | ||
619 | FloatNumber { suffix: Option<SmolStr> }, | ||
620 | Bool, | ||
621 | } | ||
622 | |||
623 | impl 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] |
613 | fn test_doc_comment_of_items() { | 659 | fn 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 | ||
794 | impl ExternCrateItem {} | 794 | impl ExternCrateItem {} |
795 | 795 | ||
796 | // FalseKw | ||
797 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
798 | #[repr(transparent)] | ||
799 | pub struct FalseKw { | ||
800 | pub(crate) syntax: SyntaxNode, | ||
801 | } | ||
802 | unsafe impl TransparentNewType for FalseKw { | ||
803 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
804 | } | ||
805 | |||
806 | impl 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 | |||
818 | impl ast::AstToken for FalseKw {} | ||
819 | impl 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 | ||
850 | impl FieldPatList {} | 875 | impl FieldPatList {} |
851 | 876 | ||
877 | // FloatNumber | ||
878 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
879 | #[repr(transparent)] | ||
880 | pub struct FloatNumber { | ||
881 | pub(crate) syntax: SyntaxNode, | ||
882 | } | ||
883 | unsafe impl TransparentNewType for FloatNumber { | ||
884 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
885 | } | ||
886 | |||
887 | impl 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 | |||
899 | impl ast::AstToken for FloatNumber {} | ||
900 | impl 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 | ||
1131 | impl IndexExpr {} | 1181 | impl IndexExpr {} |
1132 | 1182 | ||
1183 | // IntNumber | ||
1184 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1185 | #[repr(transparent)] | ||
1186 | pub struct IntNumber { | ||
1187 | pub(crate) syntax: SyntaxNode, | ||
1188 | } | ||
1189 | unsafe impl TransparentNewType for IntNumber { | ||
1190 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1191 | } | ||
1192 | |||
1193 | impl 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 | |||
1205 | impl ast::AstToken for IntNumber {} | ||
1206 | impl 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 | ||
1330 | impl Literal {} | 1405 | impl 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)] | ||
1414 | pub struct LiteralExpr { | ||
1415 | pub(crate) syntax: SyntaxNode, | ||
1416 | } | ||
1417 | unsafe impl TransparentNewType for LiteralExpr { | ||
1418 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1419 | } | ||
1420 | |||
1421 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
1422 | pub 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 | |||
1435 | impl 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 | |||
1455 | impl 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 | |||
1473 | impl 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 | ||
2407 | impl RangePat {} | 2550 | impl RangePat {} |
2408 | 2551 | ||
2552 | // RawByteString | ||
2553 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
2554 | #[repr(transparent)] | ||
2555 | pub struct RawByteString { | ||
2556 | pub(crate) syntax: SyntaxNode, | ||
2557 | } | ||
2558 | unsafe impl TransparentNewType for RawByteString { | ||
2559 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
2560 | } | ||
2561 | |||
2562 | impl 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 | |||
2574 | impl ast::AstToken for RawByteString {} | ||
2575 | impl RawByteString {} | ||
2576 | |||
2577 | // RawString | ||
2578 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
2579 | #[repr(transparent)] | ||
2580 | pub struct RawString { | ||
2581 | pub(crate) syntax: SyntaxNode, | ||
2582 | } | ||
2583 | unsafe impl TransparentNewType for RawString { | ||
2584 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
2585 | } | ||
2586 | |||
2587 | impl 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 | |||
2599 | impl ast::AstToken for RawString {} | ||
2600 | impl 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 {} | |||
2919 | impl ast::DocCommentsOwner for TraitDef {} | 3112 | impl ast::DocCommentsOwner for TraitDef {} |
2920 | impl TraitDef {} | 3113 | impl TraitDef {} |
2921 | 3114 | ||
3115 | // TrueKw | ||
3116 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3117 | #[repr(transparent)] | ||
3118 | pub struct TrueKw { | ||
3119 | pub(crate) syntax: SyntaxNode, | ||
3120 | } | ||
3121 | unsafe impl TransparentNewType for TrueKw { | ||
3122 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3123 | } | ||
3124 | |||
3125 | impl 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 | |||
3137 | impl ast::AstToken for TrueKw {} | ||
3138 | impl 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) { | |||
108 | fn scan_byte_string(ptr: &mut Ptr) { | 108 | fn scan_byte_string(ptr: &mut Ptr) { |
109 | scan_string(ptr) | 109 | scan_string(ptr) |
110 | } | 110 | } |
111 | |||
112 | fn 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 { |