aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorMarcus Klaas de Vries <[email protected]>2019-01-10 12:54:58 +0000
committerMarcus Klaas de Vries <[email protected]>2019-01-14 12:52:55 +0000
commita6146d35b1615cf5fb908b29f34e58bfde3bf96d (patch)
tree70613ee98eee67c1df6aff1e663be75a33c348f4 /crates/ra_hir/src
parent8caff4e03475c20392f13e8c6ad469bd01a4b4ce (diff)
Implement type inference for literals (WIP)
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/expr.rs78
-rw-r--r--crates/ra_hir/src/ty.rs33
-rw-r--r--crates/ra_hir/src/ty/tests.rs20
-rw-r--r--crates/ra_hir/src/ty/tests/data/basics.txt2
-rw-r--r--crates/ra_hir/src/ty/tests/data/literals.txt10
5 files changed, 139 insertions, 4 deletions
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index f0936e9f3..e07725d05 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -5,7 +5,10 @@ use rustc_hash::FxHashMap;
5 5
6use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 6use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
7use ra_db::{LocalSyntaxPtr, Cancelable}; 7use ra_db::{LocalSyntaxPtr, Cancelable};
8use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner}; 8use ra_syntax::{
9 SyntaxKind,
10 ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner}
11};
9 12
10use 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};
11 14
@@ -104,6 +107,19 @@ impl BodySyntaxMapping {
104} 107}
105 108
106#[derive(Debug, Clone, Eq, PartialEq)] 109#[derive(Debug, Clone, Eq, PartialEq)]
110pub enum Literal {
111 String(String),
112 ByteString(Vec<u8>),
113 Char(char),
114 Bool(bool),
115 Byte(u8),
116 Int, // this and float need additional information
117 Float,
118 Tuple { values: Vec<ExprId> },
119 Array { values: Vec<ExprId> },
120}
121
122#[derive(Debug, Clone, Eq, PartialEq)]
107pub enum Expr { 123pub enum Expr {
108 /// This is produced if syntax tree does not have a required expression piece. 124 /// This is produced if syntax tree does not have a required expression piece.
109 Missing, 125 Missing,
@@ -186,6 +202,7 @@ pub enum Expr {
186 Tuple { 202 Tuple {
187 exprs: Vec<ExprId>, 203 exprs: Vec<ExprId>,
188 }, 204 },
205 Literal(Literal),
189} 206}
190 207
191pub use ra_syntax::ast::PrefixOp as UnaryOp; 208pub use ra_syntax::ast::PrefixOp as UnaryOp;
@@ -305,6 +322,20 @@ impl Expr {
305 f(*expr); 322 f(*expr);
306 } 323 }
307 } 324 }
325 Expr::Literal(l) => match l {
326 Literal::Array { values } | Literal::Tuple { values } => {
327 for &val in values {
328 f(val);
329 }
330 }
331 Literal::String(..)
332 | Literal::ByteString(..)
333 | Literal::Byte(..)
334 | Literal::Bool(..)
335 | Literal::Char(..)
336 | Literal::Int
337 | Literal::Float => {}
338 },
308 } 339 }
309 } 340 }
310} 341}
@@ -633,13 +664,56 @@ impl ExprCollector {
633 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect(); 664 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect();
634 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr) 665 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
635 } 666 }
667 ast::ExprKind::Literal(e) => {
668 let child = e.syntax().children().next();
669
670 if let Some(c) = child {
671 let lit = match c.kind() {
672 SyntaxKind::INT_NUMBER => Literal::Int,
673 SyntaxKind::FLOAT_NUMBER => Literal::Float,
674 SyntaxKind::STRING => {
675 // FIXME: this likely includes the " characters
676 let text = c.text().to_string();
677 Literal::String(text)
678 }
679 SyntaxKind::ARRAY_EXPR => {
680 // TODO: recursively call to self
681 Literal::Array { values: vec![] }
682 }
683 SyntaxKind::PAREN_EXPR => {
684 // TODO: recursively call to self
685 Literal::Tuple { values: vec![] }
686 }
687 SyntaxKind::TRUE_KW => Literal::Bool(true),
688 SyntaxKind::FALSE_KW => Literal::Bool(false),
689 SyntaxKind::BYTE_STRING => {
690 // FIXME: this is completely incorrect for a variety
691 // of reasons, but at least it gives the right type
692 let bytes = c.text().to_string().into_bytes();
693 Literal::ByteString(bytes)
694 }
695 SyntaxKind::CHAR => {
696 let character = c.text().char_at(1).unwrap_or('X');
697 Literal::Char(character)
698 }
699 SyntaxKind::BYTE => {
700 let character = c.text().char_at(1).unwrap_or('X');
701 Literal::Byte(character as u8)
702 }
703 _ => return self.alloc_expr(Expr::Missing, syntax_ptr),
704 };
705
706 self.alloc_expr(Expr::Literal(lit), syntax_ptr)
707 } else {
708 self.alloc_expr(Expr::Missing, syntax_ptr)
709 }
710 }
636 711
637 // TODO implement HIR for these: 712 // TODO implement HIR for these:
638 ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 713 ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
639 ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 714 ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
640 ast::ExprKind::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 715 ast::ExprKind::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
641 ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 716 ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
642 ast::ExprKind::Literal(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
643 } 717 }
644 } 718 }
645 719
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index fa46ddfe9..0baa205a1 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -38,7 +38,7 @@ use crate::{
38 db::HirDatabase, 38 db::HirDatabase,
39 type_ref::{TypeRef, Mutability}, 39 type_ref::{TypeRef, Mutability},
40 name::KnownName, 40 name::KnownName,
41 expr::{Body, Expr, ExprId, PatId, UnaryOp, BinaryOp, Statement}, 41 expr::{Body, Expr, Literal, ExprId, PatId, UnaryOp, BinaryOp, Statement},
42}; 42};
43 43
44fn transpose<T>(x: Cancelable<Option<T>>) -> Option<Cancelable<T>> { 44fn transpose<T>(x: Cancelable<Option<T>>) -> Option<Cancelable<T>> {
@@ -1067,6 +1067,37 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1067 1067
1068 Ty::Tuple(Arc::from(ty_vec)) 1068 Ty::Tuple(Arc::from(ty_vec))
1069 } 1069 }
1070 Expr::Literal(lit) => match lit {
1071 Literal::Bool(..) => Ty::Bool,
1072 Literal::String(..) => Ty::Ref(Arc::new(Ty::Str), Mutability::Shared),
1073 Literal::ByteString(..) => {
1074 let byte_type = Arc::new(Ty::Uint(primitive::UintTy::U8));
1075 let slice_type = Arc::new(Ty::Slice(byte_type));
1076 Ty::Ref(slice_type, Mutability::Shared)
1077 }
1078 Literal::Byte(..) => Ty::Uint(primitive::UintTy::U8),
1079 Literal::Char(..) => Ty::Char,
1080 Literal::Tuple { values } => {
1081 let mut inner_tys = Vec::new();
1082 for &expr in values {
1083 let inner_ty = self.infer_expr(expr, &Expectation::none())?;
1084 inner_tys.push(inner_ty);
1085 }
1086 Ty::Tuple(Arc::from(inner_tys))
1087 }
1088 Literal::Array { values } => {
1089 // simply take the type of the first element for now
1090 let inner_ty = match values.get(0) {
1091 Some(&expr) => self.infer_expr(expr, &Expectation::none())?,
1092 None => Ty::Unknown,
1093 };
1094 // TODO: we should return a Ty::Array when it becomes
1095 // available
1096 Ty::Slice(Arc::new(inner_ty))
1097 }
1098 // TODO
1099 Literal::Int | Literal::Float => Ty::Unknown,
1100 },
1070 }; 1101 };
1071 // use a new type variable if we got Ty::Unknown here 1102 // use a new type variable if we got Ty::Unknown here
1072 let ty = self.insert_type_vars_shallow(ty); 1103 let ty = self.insert_type_vars_shallow(ty);
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 920188fc9..97d3d222f 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -133,6 +133,26 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
133} 133}
134 134
135#[test] 135#[test]
136fn infer_literals() {
137 check_inference(
138 r#"
139fn test() {
140 5i32;
141 "hello";
142 b"bytes";
143 'c';
144 b'b';
145 3.14;
146 5000;
147 (0u32, -5isize);
148 [true, true, false]
149}
150"#,
151 "literals.txt",
152 );
153}
154
155#[test]
136fn infer_backwards() { 156fn infer_backwards() {
137 check_inference( 157 check_inference(
138 r#" 158 r#"
diff --git a/crates/ra_hir/src/ty/tests/data/basics.txt b/crates/ra_hir/src/ty/tests/data/basics.txt
index ac7faae0a..e02947ba8 100644
--- a/crates/ra_hir/src/ty/tests/data/basics.txt
+++ b/crates/ra_hir/src/ty/tests/data/basics.txt
@@ -9,5 +9,5 @@
9[69; 70) 'd': &str 9[69; 70) 'd': &str
10[76; 82) '1usize': [unknown] 10[76; 82) '1usize': [unknown]
11[88; 94) '1isize': [unknown] 11[88; 94) '1isize': [unknown]
12[100; 106) '"test"': [unknown] 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/literals.txt b/crates/ra_hir/src/ty/tests/data/literals.txt
new file mode 100644
index 000000000..8b22eee31
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/literals.txt
@@ -0,0 +1,10 @@
1[11; 135) '{ ...lse] }': ()
2[17; 21) '5i32': [unknown]
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': [unknown]
8[83; 87) '5000': [unknown]
9[93; 108) '(0u32, -5isize)': [unknown]
10[114; 133) '[true,...false]': ()