aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorMarcus Klaas de Vries <[email protected]>2019-01-10 15:03:15 +0000
committerMarcus Klaas de Vries <[email protected]>2019-01-14 12:52:57 +0000
commit5f5dc20d85dead5fbd51d163451f796255c9faea (patch)
tree2027553e671ee8c94dd1b6e5045868fd479cd682 /crates
parenta6146d35b1615cf5fb908b29f34e58bfde3bf96d (diff)
Try implementing integer type inference (WIP)
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/expr.rs58
-rw-r--r--crates/ra_hir/src/ty.rs53
-rw-r--r--crates/ra_hir/src/ty/primitive.rs50
-rw-r--r--crates/ra_hir/src/ty/tests/data/basics.txt4
-rw-r--r--crates/ra_hir/src/ty/tests/data/binary_op.txt2
-rw-r--r--crates/ra_hir/src/ty/tests/data/let.txt4
-rw-r--r--crates/ra_hir/src/ty/tests/data/literals.txt2
-rw-r--r--crates/ra_syntax/src/yellow.rs2
8 files changed, 129 insertions, 46 deletions
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index e07725d05..bc8515836 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -11,6 +11,7 @@ use ra_syntax::{
11}; 11};
12 12
13use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; 13use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName};
14use crate::ty::primitive::{UintTy, IntTy, FloatTy, UncertainIntTy, UncertainFloatTy};
14 15
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub struct ExprId(RawId); 17pub struct ExprId(RawId);
@@ -112,9 +113,8 @@ pub enum Literal {
112 ByteString(Vec<u8>), 113 ByteString(Vec<u8>),
113 Char(char), 114 Char(char),
114 Bool(bool), 115 Bool(bool),
115 Byte(u8), 116 Int(u64, UncertainIntTy),
116 Int, // this and float need additional information 117 Float(u64, UncertainFloatTy), // FIXME: f64 is not Eq
117 Float,
118 Tuple { values: Vec<ExprId> }, 118 Tuple { values: Vec<ExprId> },
119 Array { values: Vec<ExprId> }, 119 Array { values: Vec<ExprId> },
120} 120}
@@ -328,13 +328,7 @@ impl Expr {
328 f(val); 328 f(val);
329 } 329 }
330 } 330 }
331 Literal::String(..) 331 _ => {}
332 | Literal::ByteString(..)
333 | Literal::Byte(..)
334 | Literal::Bool(..)
335 | Literal::Char(..)
336 | Literal::Int
337 | Literal::Float => {}
338 }, 332 },
339 } 333 }
340 } 334 }
@@ -669,8 +663,43 @@ impl ExprCollector {
669 663
670 if let Some(c) = child { 664 if let Some(c) = child {
671 let lit = match c.kind() { 665 let lit = match c.kind() {
672 SyntaxKind::INT_NUMBER => Literal::Int, 666 SyntaxKind::INT_NUMBER => {
673 SyntaxKind::FLOAT_NUMBER => Literal::Float, 667 let text = c.text().to_string();
668
669 // FIXME: don't do it like this. maybe use something like
670 // the IntTy::from_name functions
671 let ty = if text.ends_with("isize") {
672 UncertainIntTy::Signed(IntTy::Isize)
673 } else if text.ends_with("i128") {
674 UncertainIntTy::Signed(IntTy::I128)
675 } else if text.ends_with("i64") {
676 UncertainIntTy::Signed(IntTy::I64)
677 } else if text.ends_with("i32") {
678 UncertainIntTy::Signed(IntTy::I32)
679 } else if text.ends_with("i16") {
680 UncertainIntTy::Signed(IntTy::I16)
681 } else if text.ends_with("i8") {
682 UncertainIntTy::Signed(IntTy::I8)
683 } else if text.ends_with("usize") {
684 UncertainIntTy::Unsigned(UintTy::Usize)
685 } else if text.ends_with("u128") {
686 UncertainIntTy::Unsigned(UintTy::U128)
687 } else if text.ends_with("u64") {
688 UncertainIntTy::Unsigned(UintTy::U64)
689 } else if text.ends_with("u32") {
690 UncertainIntTy::Unsigned(UintTy::U32)
691 } else if text.ends_with("u16") {
692 UncertainIntTy::Unsigned(UintTy::U16)
693 } else if text.ends_with("u8") {
694 UncertainIntTy::Unsigned(UintTy::U8)
695 } else {
696 UncertainIntTy::Unknown
697 };
698
699 // TODO: actually parse integer
700 Literal::Int(0u64, ty)
701 }
702 SyntaxKind::FLOAT_NUMBER => Literal::Float(0, UncertainFloatTy::Unknown),
674 SyntaxKind::STRING => { 703 SyntaxKind::STRING => {
675 // FIXME: this likely includes the " characters 704 // FIXME: this likely includes the " characters
676 let text = c.text().to_string(); 705 let text = c.text().to_string();
@@ -698,7 +727,10 @@ impl ExprCollector {
698 } 727 }
699 SyntaxKind::BYTE => { 728 SyntaxKind::BYTE => {
700 let character = c.text().char_at(1).unwrap_or('X'); 729 let character = c.text().char_at(1).unwrap_or('X');
701 Literal::Byte(character as u8) 730 Literal::Int(
731 character as u8 as u64,
732 UncertainIntTy::Unsigned(UintTy::U8),
733 )
702 } 734 }
703 _ => return self.alloc_expr(Expr::Missing, syntax_ptr), 735 _ => return self.alloc_expr(Expr::Missing, syntax_ptr),
704 }; 736 };
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 0baa205a1..13a1c2907 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -14,7 +14,7 @@
14//! rustc. 14//! rustc.
15 15
16mod autoderef; 16mod autoderef;
17mod primitive; 17pub(crate) mod primitive;
18#[cfg(test)] 18#[cfg(test)]
19mod tests; 19mod tests;
20pub(crate) mod method_resolution; 20pub(crate) mod method_resolution;
@@ -151,14 +151,13 @@ pub enum Ty {
151 /// (a non-surrogate code point). Written as `char`. 151 /// (a non-surrogate code point). Written as `char`.
152 Char, 152 Char,
153 153
154 /// A primitive signed integer type. For example, `i32`. 154 /// A primitive integer type. For example, `i32`.
155 Int(primitive::IntTy), 155 Int(primitive::UncertainIntTy),
156
157 /// A primitive unsigned integer type. For example, `u32`.
158 Uint(primitive::UintTy),
159 156
157 // /// A primitive unsigned integer type. For example, `u32`.
158 // Uint(primitive::UintTy),
160 /// A primitive floating-point type. For example, `f64`. 159 /// A primitive floating-point type. For example, `f64`.
161 Float(primitive::FloatTy), 160 Float(primitive::UncertainFloatTy),
162 161
163 /// Structures, enumerations and unions. 162 /// Structures, enumerations and unions.
164 Adt { 163 Adt {
@@ -318,11 +317,9 @@ impl Ty {
318 return Ok(Ty::Char); 317 return Ok(Ty::Char);
319 } else if let Some(KnownName::Str) = name.as_known_name() { 318 } else if let Some(KnownName::Str) = name.as_known_name() {
320 return Ok(Ty::Str); 319 return Ok(Ty::Str);
321 } else if let Some(int_ty) = primitive::IntTy::from_name(name) { 320 } else if let Some(int_ty) = primitive::UncertainIntTy::from_name(name) {
322 return Ok(Ty::Int(int_ty)); 321 return Ok(Ty::Int(int_ty));
323 } else if let Some(uint_ty) = primitive::UintTy::from_name(name) { 322 } 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)); 323 return Ok(Ty::Float(float_ty));
327 } else if name.as_known_name() == Some(KnownName::SelfType) { 324 } 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())); 325 return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type()));
@@ -392,7 +389,6 @@ impl fmt::Display for Ty {
392 Ty::Bool => write!(f, "bool"), 389 Ty::Bool => write!(f, "bool"),
393 Ty::Char => write!(f, "char"), 390 Ty::Char => write!(f, "char"),
394 Ty::Int(t) => write!(f, "{}", t.ty_to_string()), 391 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()), 392 Ty::Float(t) => write!(f, "{}", t.ty_to_string()),
397 Ty::Str => write!(f, "str"), 393 Ty::Str => write!(f, "str"),
398 Ty::Slice(t) => write!(f, "[{}]", t), 394 Ty::Slice(t) => write!(f, "[{}]", t),
@@ -587,7 +583,7 @@ fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
587 | BinaryOp::BitwiseAnd 583 | BinaryOp::BitwiseAnd
588 | BinaryOp::BitwiseOr 584 | BinaryOp::BitwiseOr
589 | BinaryOp::BitwiseXor => match rhs_ty { 585 | BinaryOp::BitwiseXor => match rhs_ty {
590 Ty::Uint(..) | Ty::Int(..) | Ty::Float(..) => rhs_ty, 586 Ty::Int(..) | Ty::Float(..) => rhs_ty,
591 _ => Ty::Unknown, 587 _ => Ty::Unknown,
592 }, 588 },
593 BinaryOp::RangeRightOpen | BinaryOp::RangeRightClosed => Ty::Unknown, 589 BinaryOp::RangeRightOpen | BinaryOp::RangeRightClosed => Ty::Unknown,
@@ -598,7 +594,7 @@ fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
598 match op { 594 match op {
599 BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::Bool, 595 BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::Bool,
600 BinaryOp::Assignment | BinaryOp::EqualityTest => match lhs_ty { 596 BinaryOp::Assignment | BinaryOp::EqualityTest => match lhs_ty {
601 Ty::Uint(..) | Ty::Int(..) | Ty::Float(..) | Ty::Str | Ty::Char | Ty::Bool => lhs_ty, 597 Ty::Int(..) | Ty::Float(..) | Ty::Str | Ty::Char | Ty::Bool => lhs_ty,
602 _ => Ty::Unknown, 598 _ => Ty::Unknown,
603 }, 599 },
604 BinaryOp::LesserEqualTest 600 BinaryOp::LesserEqualTest
@@ -625,7 +621,7 @@ fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
625 | BinaryOp::BitwiseAnd 621 | BinaryOp::BitwiseAnd
626 | BinaryOp::BitwiseOr 622 | BinaryOp::BitwiseOr
627 | BinaryOp::BitwiseXor => match lhs_ty { 623 | BinaryOp::BitwiseXor => match lhs_ty {
628 Ty::Uint(..) | Ty::Int(..) | Ty::Float(..) => lhs_ty, 624 Ty::Int(..) | Ty::Float(..) => lhs_ty,
629 _ => Ty::Unknown, 625 _ => Ty::Unknown,
630 }, 626 },
631 _ => Ty::Unknown, 627 _ => Ty::Unknown,
@@ -695,13 +691,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
695 match (&*ty1, &*ty2) { 691 match (&*ty1, &*ty2) {
696 (Ty::Unknown, ..) => true, 692 (Ty::Unknown, ..) => true,
697 (.., Ty::Unknown) => true, 693 (.., Ty::Unknown) => true,
698 (Ty::Bool, _) 694 (Ty::Int(t1), Ty::Int(t2)) => match (t1, t2) {
699 | (Ty::Str, _) 695 (primitive::UncertainIntTy::Unknown, _)
700 | (Ty::Never, _) 696 | (_, primitive::UncertainIntTy::Unknown) => true,
701 | (Ty::Char, _) 697 _ => t1 == t2,
702 | (Ty::Int(..), Ty::Int(..)) 698 },
703 | (Ty::Uint(..), Ty::Uint(..)) 699 (Ty::Float(t1), Ty::Float(t2)) => match (t1, t2) {
704 | (Ty::Float(..), Ty::Float(..)) => ty1 == ty2, 700 (primitive::UncertainFloatTy::Unknown, _)
701 | (_, primitive::UncertainFloatTy::Unknown) => true,
702 _ => t1 == t2,
703 },
704 (Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2,
705 ( 705 (
706 Ty::Adt { 706 Ty::Adt {
707 def_id: def_id1, .. 707 def_id: def_id1, ..
@@ -1071,11 +1071,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1071 Literal::Bool(..) => Ty::Bool, 1071 Literal::Bool(..) => Ty::Bool,
1072 Literal::String(..) => Ty::Ref(Arc::new(Ty::Str), Mutability::Shared), 1072 Literal::String(..) => Ty::Ref(Arc::new(Ty::Str), Mutability::Shared),
1073 Literal::ByteString(..) => { 1073 Literal::ByteString(..) => {
1074 let byte_type = Arc::new(Ty::Uint(primitive::UintTy::U8)); 1074 let byte_type = Arc::new(Ty::Int(primitive::UncertainIntTy::Unsigned(
1075 primitive::UintTy::U8,
1076 )));
1075 let slice_type = Arc::new(Ty::Slice(byte_type)); 1077 let slice_type = Arc::new(Ty::Slice(byte_type));
1076 Ty::Ref(slice_type, Mutability::Shared) 1078 Ty::Ref(slice_type, Mutability::Shared)
1077 } 1079 }
1078 Literal::Byte(..) => Ty::Uint(primitive::UintTy::U8),
1079 Literal::Char(..) => Ty::Char, 1080 Literal::Char(..) => Ty::Char,
1080 Literal::Tuple { values } => { 1081 Literal::Tuple { values } => {
1081 let mut inner_tys = Vec::new(); 1082 let mut inner_tys = Vec::new();
@@ -1095,8 +1096,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1095 // available 1096 // available
1096 Ty::Slice(Arc::new(inner_ty)) 1097 Ty::Slice(Arc::new(inner_ty))
1097 } 1098 }
1098 // TODO 1099 Literal::Int(_v, ty) => Ty::Int(*ty),
1099 Literal::Int | Literal::Float => Ty::Unknown, 1100 Literal::Float(_v, ty) => Ty::Float(*ty),
1100 }, 1101 },
1101 }; 1102 };
1102 // use a new type variable if we got Ty::Unknown here 1103 // use a new type variable if we got Ty::Unknown here
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs
index 498d42d52..5741ca90d 100644
--- a/crates/ra_hir/src/ty/primitive.rs
+++ b/crates/ra_hir/src/ty/primitive.rs
@@ -2,6 +2,56 @@ use std::fmt;
2 2
3use crate::{Name, KnownName}; 3use crate::{Name, KnownName};
4 4
5#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)]
6pub enum UncertainIntTy {
7 Unknown,
8 Unsigned(UintTy),
9 Signed(IntTy),
10}
11
12impl UncertainIntTy {
13 pub fn ty_to_string(&self) -> &'static str {
14 match *self {
15 UncertainIntTy::Unknown => "{integer}",
16 UncertainIntTy::Signed(ty) => ty.ty_to_string(),
17 UncertainIntTy::Unsigned(ty) => ty.ty_to_string(),
18 }
19 }
20
21 pub fn from_name(name: &Name) -> Option<UncertainIntTy> {
22 if let Some(ty) = IntTy::from_name(name) {
23 Some(UncertainIntTy::Signed(ty))
24 } else if let Some(ty) = UintTy::from_name(name) {
25 Some(UncertainIntTy::Unsigned(ty))
26 } else {
27 None
28 }
29 }
30}
31
32#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)]
33pub enum UncertainFloatTy {
34 Unknown,
35 Known(FloatTy),
36}
37
38impl UncertainFloatTy {
39 pub fn ty_to_string(&self) -> &'static str {
40 match *self {
41 UncertainFloatTy::Unknown => "{float}",
42 UncertainFloatTy::Known(ty) => ty.ty_to_string(),
43 }
44 }
45
46 pub fn from_name(name: &Name) -> Option<UncertainFloatTy> {
47 if let Some(ty) = FloatTy::from_name(name) {
48 Some(UncertainFloatTy::Known(ty))
49 } else {
50 None
51 }
52 }
53}
54
5#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] 55#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
6pub enum IntTy { 56pub enum IntTy {
7 Isize, 57 Isize,
diff --git a/crates/ra_hir/src/ty/tests/data/basics.txt b/crates/ra_hir/src/ty/tests/data/basics.txt
index e02947ba8..4a3b69b7e 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"': &str 12[100; 106) '"test"': &str
13[112; 118) '1.0f32': [unknown] 13[112; 118) '1.0f32': [unknown]
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..7fdb8a900 100644
--- a/crates/ra_hir/src/ty/tests/data/binary_op.txt
+++ b/crates/ra_hir/src/ty/tests/data/binary_op.txt
@@ -16,7 +16,7 @@
16[112; 113) 'y': bool 16[112; 113) 'y': bool
17[123; 134) 'minus_forty': isize 17[123; 134) 'minus_forty': isize
18[144; 152) '-40isize': isize 18[144; 152) '-40isize': isize
19[145; 152) '40isize': [unknown] 19[145; 152) '40isize': isize
20[162; 163) 'h': bool 20[162; 163) 'h': bool
21[166; 177) 'minus_forty': isize 21[166; 177) 'minus_forty': isize
22[166; 188) 'minus_...ONST_2': bool 22[166; 188) 'minus_...ONST_2': bool
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
index 8b22eee31..e139d57a8 100644
--- a/crates/ra_hir/src/ty/tests/data/literals.txt
+++ b/crates/ra_hir/src/ty/tests/data/literals.txt
@@ -1,5 +1,5 @@
1[11; 135) '{ ...lse] }': () 1[11; 135) '{ ...lse] }': ()
2[17; 21) '5i32': [unknown] 2[17; 21) '5i32': i32
3[27; 34) '"hello"': &str 3[27; 34) '"hello"': &str
4[40; 48) 'b"bytes"': &[u8] 4[40; 48) 'b"bytes"': &[u8]
5[54; 57) ''c'': char 5[54; 57) ''c'': char
diff --git a/crates/ra_syntax/src/yellow.rs b/crates/ra_syntax/src/yellow.rs
index 03df00fc6..9b93945cc 100644
--- a/crates/ra_syntax/src/yellow.rs
+++ b/crates/ra_syntax/src/yellow.rs
@@ -128,7 +128,7 @@ 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
132 pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { 132 pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode {
133 self.0.replace_self(replacement) 133 self.0.replace_self(replacement)
134 } 134 }