aboutsummaryrefslogtreecommitdiff
path: root/crates
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
parent8caff4e03475c20392f13e8c6ad469bd01a4b4ce (diff)
Implement type inference for literals (WIP)
Diffstat (limited to 'crates')
-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
-rw-r--r--crates/ra_syntax/src/lib.rs5
-rw-r--r--crates/ra_syntax/src/yellow.rs12
-rw-r--r--crates/ra_syntax/src/yellow/syntax_text.rs11
8 files changed, 166 insertions, 5 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]': ()
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index 2a095817a..6181df9d7 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..03df00fc6 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 {