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 /crates/ra_hir/src | |
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]>
Diffstat (limited to 'crates/ra_hir/src')
-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 |
11 files changed, 308 insertions, 110 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 |