diff options
-rw-r--r-- | crates/ra_analysis/src/db.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/function.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/query_definitions.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 478 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/primitive.rs | 98 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 45 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 44 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 14 |
11 files changed, 689 insertions, 15 deletions
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index 94729d296..f26c49887 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs | |||
@@ -93,6 +93,7 @@ salsa::database_storage! { | |||
93 | fn item_map() for hir::db::ItemMapQuery; | 93 | fn item_map() for hir::db::ItemMapQuery; |
94 | fn fn_syntax() for hir::db::FnSyntaxQuery; | 94 | fn fn_syntax() for hir::db::FnSyntaxQuery; |
95 | fn submodules() for hir::db::SubmodulesQuery; | 95 | fn submodules() for hir::db::SubmodulesQuery; |
96 | fn infer() for hir::db::InferQuery; | ||
96 | } | 97 | } |
97 | } | 98 | } |
98 | } | 99 | } |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 62cf9ab17..f0bff3c02 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -14,6 +14,7 @@ use crate::{ | |||
14 | function::FnId, | 14 | function::FnId, |
15 | module::{ModuleId, ModuleTree, ModuleSource, | 15 | module::{ModuleId, ModuleTree, ModuleSource, |
16 | nameres::{ItemMap, InputModuleItems}}, | 16 | nameres::{ItemMap, InputModuleItems}}, |
17 | ty::InferenceResult, | ||
17 | }; | 18 | }; |
18 | 19 | ||
19 | salsa::query_group! { | 20 | salsa::query_group! { |
@@ -30,6 +31,11 @@ pub trait HirDatabase: SyntaxDatabase | |||
30 | use fn query_definitions::fn_syntax; | 31 | use fn query_definitions::fn_syntax; |
31 | } | 32 | } |
32 | 33 | ||
34 | fn infer(fn_id: FnId) -> Arc<InferenceResult> { | ||
35 | type InferQuery; | ||
36 | use fn query_definitions::infer; | ||
37 | } | ||
38 | |||
33 | fn file_items(file_id: FileId) -> Arc<SourceFileItems> { | 39 | fn file_items(file_id: FileId) -> Arc<SourceFileItems> { |
34 | type SourceFileItemsQuery; | 40 | type SourceFileItemsQuery; |
35 | use fn query_definitions::file_items; | 41 | use fn query_definitions::file_items; |
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs index 2925beb16..360e9e9a0 100644 --- a/crates/ra_hir/src/function.rs +++ b/crates/ra_hir/src/function.rs | |||
@@ -10,7 +10,7 @@ use ra_syntax::{ | |||
10 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, | 10 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{ DefId, HirDatabase }; | 13 | use crate::{ DefId, HirDatabase, ty::InferenceResult }; |
14 | 14 | ||
15 | pub use self::scope::FnScopes; | 15 | pub use self::scope::FnScopes; |
16 | 16 | ||
@@ -35,6 +35,10 @@ impl Function { | |||
35 | let syntax = db.fn_syntax(self.fn_id); | 35 | let syntax = db.fn_syntax(self.fn_id); |
36 | FnSignatureInfo::new(syntax.borrowed()) | 36 | FnSignatureInfo::new(syntax.borrowed()) |
37 | } | 37 | } |
38 | |||
39 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | ||
40 | db.infer(self.fn_id) | ||
41 | } | ||
38 | } | 42 | } |
39 | 43 | ||
40 | #[derive(Debug, Clone)] | 44 | #[derive(Debug, Clone)] |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index f56214b47..e84f44675 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -25,6 +25,7 @@ pub mod source_binder; | |||
25 | mod krate; | 25 | mod krate; |
26 | mod module; | 26 | mod module; |
27 | mod function; | 27 | mod function; |
28 | mod ty; | ||
28 | 29 | ||
29 | use std::ops::Index; | 30 | use std::ops::Index; |
30 | 31 | ||
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 9423e6571..a9fa540d5 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -8,7 +8,7 @@ use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; | |||
8 | 8 | ||
9 | use crate::{db, DefId, DefLoc}; | 9 | use crate::{db, DefId, DefLoc}; |
10 | 10 | ||
11 | const WORKSPACE: SourceRootId = SourceRootId(0); | 11 | pub const WORKSPACE: SourceRootId = SourceRootId(0); |
12 | 12 | ||
13 | #[derive(Debug)] | 13 | #[derive(Debug)] |
14 | pub(crate) struct MockDatabase { | 14 | pub(crate) struct MockDatabase { |
@@ -182,6 +182,7 @@ salsa::database_storage! { | |||
182 | fn item_map() for db::ItemMapQuery; | 182 | fn item_map() for db::ItemMapQuery; |
183 | fn fn_syntax() for db::FnSyntaxQuery; | 183 | fn fn_syntax() for db::FnSyntaxQuery; |
184 | fn submodules() for db::SubmodulesQuery; | 184 | fn submodules() for db::SubmodulesQuery; |
185 | fn infer() for db::InferQuery; | ||
185 | } | 186 | } |
186 | } | 187 | } |
187 | } | 188 | } |
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs index efaeb1525..ccbfdf028 100644 --- a/crates/ra_hir/src/query_definitions.rs +++ b/crates/ra_hir/src/query_definitions.rs | |||
@@ -19,6 +19,7 @@ use crate::{ | |||
19 | imp::Submodule, | 19 | imp::Submodule, |
20 | nameres::{InputModuleItems, ItemMap, Resolver}, | 20 | nameres::{InputModuleItems, ItemMap, Resolver}, |
21 | }, | 21 | }, |
22 | ty::{self, InferenceResult} | ||
22 | }; | 23 | }; |
23 | 24 | ||
24 | /// Resolve `FnId` to the corresponding `SyntaxNode` | 25 | /// Resolve `FnId` to the corresponding `SyntaxNode` |
@@ -35,6 +36,13 @@ pub(super) fn fn_scopes(db: &impl HirDatabase, fn_id: FnId) -> Arc<FnScopes> { | |||
35 | Arc::new(res) | 36 | Arc::new(res) |
36 | } | 37 | } |
37 | 38 | ||
39 | pub(super) fn infer(db: &impl HirDatabase, fn_id: FnId) -> Arc<InferenceResult> { | ||
40 | let syntax = db.fn_syntax(fn_id); | ||
41 | let scopes = db.fn_scopes(fn_id); | ||
42 | let res = ty::infer(db, syntax.borrowed(), scopes); | ||
43 | Arc::new(res) | ||
44 | } | ||
45 | |||
38 | pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> { | 46 | pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> { |
39 | let mut res = SourceFileItems::new(file_id); | 47 | let mut res = SourceFileItems::new(file_id); |
40 | let source_file = db.source_file(file_id); | 48 | let source_file = db.source_file(file_id); |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs new file mode 100644 index 000000000..36dc5d137 --- /dev/null +++ b/crates/ra_hir/src/ty.rs | |||
@@ -0,0 +1,478 @@ | |||
1 | mod primitive; | ||
2 | #[cfg(test)] | ||
3 | mod tests; | ||
4 | |||
5 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
6 | |||
7 | use std::sync::Arc; | ||
8 | use std::collections::HashMap; | ||
9 | |||
10 | use ra_db::LocalSyntaxPtr; | ||
11 | use ra_syntax::{ | ||
12 | TextRange, TextUnit, | ||
13 | algo::visit::{visitor, Visitor}, | ||
14 | ast::{self, AstNode, DocCommentsOwner, NameOwner, LoopBodyOwner, ArgListOwner}, | ||
15 | SyntaxNodeRef | ||
16 | }; | ||
17 | |||
18 | use crate::{ | ||
19 | FnScopes, | ||
20 | db::HirDatabase, | ||
21 | arena::{Arena, Id}, | ||
22 | }; | ||
23 | |||
24 | // pub(crate) type TypeId = Id<Ty>; | ||
25 | |||
26 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | ||
27 | pub enum Ty { | ||
28 | /// The primitive boolean type. Written as `bool`. | ||
29 | Bool, | ||
30 | |||
31 | /// The primitive character type; holds a Unicode scalar value | ||
32 | /// (a non-surrogate code point). Written as `char`. | ||
33 | Char, | ||
34 | |||
35 | /// A primitive signed integer type. For example, `i32`. | ||
36 | Int(primitive::IntTy), | ||
37 | |||
38 | /// A primitive unsigned integer type. For example, `u32`. | ||
39 | Uint(primitive::UintTy), | ||
40 | |||
41 | /// A primitive floating-point type. For example, `f64`. | ||
42 | Float(primitive::FloatTy), | ||
43 | |||
44 | /// Structures, enumerations and unions. | ||
45 | /// | ||
46 | /// Substs here, possibly against intuition, *may* contain `Param`s. | ||
47 | /// That is, even after substitution it is possible that there are type | ||
48 | /// variables. This happens when the `Adt` corresponds to an ADT | ||
49 | /// definition and not a concrete use of it. | ||
50 | // Adt(&'tcx AdtDef, &'tcx Substs<'tcx>), | ||
51 | |||
52 | // Foreign(DefId), | ||
53 | |||
54 | /// The pointee of a string slice. Written as `str`. | ||
55 | Str, | ||
56 | |||
57 | /// An array with the given length. Written as `[T; n]`. | ||
58 | // Array(Ty<'tcx>, &'tcx ty::Const<'tcx>), | ||
59 | |||
60 | /// The pointee of an array slice. Written as `[T]`. | ||
61 | Slice(TyRef), | ||
62 | |||
63 | /// A raw pointer. Written as `*mut T` or `*const T` | ||
64 | // RawPtr(TypeAndMut<'tcx>), | ||
65 | |||
66 | /// A reference; a pointer with an associated lifetime. Written as | ||
67 | /// `&'a mut T` or `&'a T`. | ||
68 | // Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability), | ||
69 | |||
70 | /// The anonymous type of a function declaration/definition. Each | ||
71 | /// function has a unique type, which is output (for a function | ||
72 | /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`. | ||
73 | /// | ||
74 | /// For example the type of `bar` here: | ||
75 | /// | ||
76 | /// ```rust | ||
77 | /// fn foo() -> i32 { 1 } | ||
78 | /// let bar = foo; // bar: fn() -> i32 {foo} | ||
79 | /// ``` | ||
80 | // FnDef(DefId, &'tcx Substs<'tcx>), | ||
81 | |||
82 | /// A pointer to a function. Written as `fn() -> i32`. | ||
83 | /// | ||
84 | /// For example the type of `bar` here: | ||
85 | /// | ||
86 | /// ```rust | ||
87 | /// fn foo() -> i32 { 1 } | ||
88 | /// let bar: fn() -> i32 = foo; | ||
89 | /// ``` | ||
90 | // FnPtr(PolyFnSig<'tcx>), | ||
91 | |||
92 | /// A trait, defined with `trait`. | ||
93 | // Dynamic(Binder<&'tcx List<ExistentialPredicate<'tcx>>>, ty::Region<'tcx>), | ||
94 | |||
95 | /// The anonymous type of a closure. Used to represent the type of | ||
96 | /// `|a| a`. | ||
97 | // Closure(DefId, ClosureSubsts<'tcx>), | ||
98 | |||
99 | /// The anonymous type of a generator. Used to represent the type of | ||
100 | /// `|a| yield a`. | ||
101 | // Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability), | ||
102 | |||
103 | /// A type representin the types stored inside a generator. | ||
104 | /// This should only appear in GeneratorInteriors. | ||
105 | // GeneratorWitness(Binder<&'tcx List<Ty<'tcx>>>), | ||
106 | |||
107 | /// The never type `!` | ||
108 | Never, | ||
109 | |||
110 | /// A tuple type. For example, `(i32, bool)`. | ||
111 | Tuple(Vec<Ty>), | ||
112 | |||
113 | /// The projection of an associated type. For example, | ||
114 | /// `<T as Trait<..>>::N`. | ||
115 | // Projection(ProjectionTy<'tcx>), | ||
116 | |||
117 | /// Opaque (`impl Trait`) type found in a return type. | ||
118 | /// The `DefId` comes either from | ||
119 | /// * the `impl Trait` ast::Ty node, | ||
120 | /// * or the `existential type` declaration | ||
121 | /// The substitutions are for the generics of the function in question. | ||
122 | /// After typeck, the concrete type can be found in the `types` map. | ||
123 | // Opaque(DefId, &'tcx Substs<'tcx>), | ||
124 | |||
125 | /// A type parameter; for example, `T` in `fn f<T>(x: T) {} | ||
126 | // Param(ParamTy), | ||
127 | |||
128 | /// Bound type variable, used only when preparing a trait query. | ||
129 | // Bound(ty::DebruijnIndex, BoundTy), | ||
130 | |||
131 | /// A placeholder type - universally quantified higher-ranked type. | ||
132 | // Placeholder(ty::PlaceholderType), | ||
133 | |||
134 | /// A type variable used during type checking. | ||
135 | // Infer(InferTy), | ||
136 | |||
137 | /// A placeholder for a type which could not be computed; this is | ||
138 | /// propagated to avoid useless error messages. | ||
139 | Unknown, | ||
140 | } | ||
141 | |||
142 | type TyRef = Arc<Ty>; | ||
143 | |||
144 | impl Ty { | ||
145 | pub fn new(node: ast::TypeRef) -> Self { | ||
146 | use ra_syntax::ast::TypeRef::*; | ||
147 | match node { | ||
148 | ParenType(_inner) => Ty::Unknown, // TODO | ||
149 | TupleType(_inner) => Ty::Unknown, // TODO | ||
150 | NeverType(..) => Ty::Never, | ||
151 | PathType(_inner) => Ty::Unknown, // TODO | ||
152 | PointerType(_inner) => Ty::Unknown, // TODO | ||
153 | ArrayType(_inner) => Ty::Unknown, // TODO | ||
154 | SliceType(_inner) => Ty::Unknown, // TODO | ||
155 | ReferenceType(_inner) => Ty::Unknown, // TODO | ||
156 | PlaceholderType(_inner) => Ty::Unknown, // TODO | ||
157 | FnPointerType(_inner) => Ty::Unknown, // TODO | ||
158 | ForType(_inner) => Ty::Unknown, // TODO | ||
159 | ImplTraitType(_inner) => Ty::Unknown, // TODO | ||
160 | DynTraitType(_inner) => Ty::Unknown, // TODO | ||
161 | } | ||
162 | } | ||
163 | |||
164 | pub fn unit() -> Self { | ||
165 | Ty::Tuple(Vec::new()) | ||
166 | } | ||
167 | } | ||
168 | |||
169 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
170 | pub struct InferenceResult { | ||
171 | type_for: FxHashMap<LocalSyntaxPtr, Ty>, | ||
172 | } | ||
173 | |||
174 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
175 | pub struct InferenceContext { | ||
176 | scopes: Arc<FnScopes>, | ||
177 | // TODO unification tables... | ||
178 | type_for: FxHashMap<LocalSyntaxPtr, Ty>, | ||
179 | } | ||
180 | |||
181 | impl InferenceContext { | ||
182 | fn new(scopes: Arc<FnScopes>) -> Self { | ||
183 | InferenceContext { | ||
184 | type_for: FxHashMap::default(), | ||
185 | scopes | ||
186 | } | ||
187 | } | ||
188 | |||
189 | fn write_ty(&mut self, node: SyntaxNodeRef, ty: Ty) { | ||
190 | self.type_for.insert(LocalSyntaxPtr::new(node), ty); | ||
191 | } | ||
192 | |||
193 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | ||
194 | unimplemented!() | ||
195 | } | ||
196 | |||
197 | fn infer_expr(&mut self, expr: ast::Expr) -> Ty { | ||
198 | let ty = match expr { | ||
199 | ast::Expr::IfExpr(e) => { | ||
200 | if let Some(condition) = e.condition() { | ||
201 | if let Some(e) = condition.expr() { | ||
202 | // TODO if no pat, this should be bool | ||
203 | self.infer_expr(e); | ||
204 | } | ||
205 | // TODO write type for pat | ||
206 | }; | ||
207 | let if_ty = if let Some(block) = e.then_branch() { | ||
208 | self.infer_block(block) | ||
209 | } else { | ||
210 | Ty::Unknown | ||
211 | }; | ||
212 | let else_ty = if let Some(block) = e.else_branch() { | ||
213 | self.infer_block(block) | ||
214 | } else { | ||
215 | Ty::Unknown | ||
216 | }; | ||
217 | if self.unify(&if_ty, &else_ty) { | ||
218 | // TODO actually, need to take the 'more specific' type (not unknown, never, ...) | ||
219 | if_ty | ||
220 | } else { | ||
221 | // TODO report diagnostic | ||
222 | Ty::Unknown | ||
223 | } | ||
224 | } | ||
225 | ast::Expr::BlockExpr(e) => { | ||
226 | if let Some(block) = e.block() { | ||
227 | self.infer_block(block) | ||
228 | } else { | ||
229 | Ty::Unknown | ||
230 | } | ||
231 | } | ||
232 | ast::Expr::LoopExpr(e) => { | ||
233 | if let Some(block) = e.loop_body() { | ||
234 | self.infer_block(block); | ||
235 | }; | ||
236 | // TODO never, or the type of the break param | ||
237 | Ty::Unknown | ||
238 | } | ||
239 | ast::Expr::WhileExpr(e) => { | ||
240 | if let Some(condition) = e.condition() { | ||
241 | if let Some(e) = condition.expr() { | ||
242 | // TODO if no pat, this should be bool | ||
243 | self.infer_expr(e); | ||
244 | } | ||
245 | // TODO write type for pat | ||
246 | }; | ||
247 | if let Some(block) = e.loop_body() { | ||
248 | // TODO | ||
249 | self.infer_block(block); | ||
250 | }; | ||
251 | // TODO always unit? | ||
252 | Ty::Unknown | ||
253 | } | ||
254 | ast::Expr::ForExpr(e) => { | ||
255 | if let Some(expr) = e.iterable() { | ||
256 | self.infer_expr(expr); | ||
257 | } | ||
258 | if let Some(pat) = e.pat() { | ||
259 | // TODO write type for pat | ||
260 | } | ||
261 | if let Some(block) = e.loop_body() { | ||
262 | self.infer_block(block); | ||
263 | } | ||
264 | // TODO always unit? | ||
265 | Ty::Unknown | ||
266 | } | ||
267 | ast::Expr::LambdaExpr(e) => { | ||
268 | let body_ty = if let Some(body) = e.body() { | ||
269 | self.infer_expr(body) | ||
270 | } else { | ||
271 | Ty::Unknown | ||
272 | }; | ||
273 | Ty::Unknown | ||
274 | } | ||
275 | ast::Expr::CallExpr(e) => { | ||
276 | if let Some(arg_list) = e.arg_list() { | ||
277 | for arg in arg_list.args() { | ||
278 | // TODO unify / expect argument type | ||
279 | self.infer_expr(arg); | ||
280 | } | ||
281 | } | ||
282 | Ty::Unknown | ||
283 | } | ||
284 | ast::Expr::MethodCallExpr(e) => { | ||
285 | if let Some(arg_list) = e.arg_list() { | ||
286 | for arg in arg_list.args() { | ||
287 | // TODO unify / expect argument type | ||
288 | self.infer_expr(arg); | ||
289 | } | ||
290 | } | ||
291 | Ty::Unknown | ||
292 | } | ||
293 | ast::Expr::MatchExpr(e) => { | ||
294 | let ty = if let Some(match_expr) = e.expr() { | ||
295 | self.infer_expr(match_expr) | ||
296 | } else { | ||
297 | Ty::Unknown | ||
298 | }; | ||
299 | if let Some(match_arm_list) = e.match_arm_list() { | ||
300 | for arm in match_arm_list.arms() { | ||
301 | // TODO type the bindings in pat | ||
302 | // TODO type the guard | ||
303 | let ty = if let Some(e) = arm.expr() { | ||
304 | self.infer_expr(e) | ||
305 | } else { | ||
306 | Ty::Unknown | ||
307 | }; | ||
308 | } | ||
309 | // TODO unify all the match arm types | ||
310 | Ty::Unknown | ||
311 | } else { | ||
312 | Ty::Unknown | ||
313 | } | ||
314 | } | ||
315 | ast::Expr::TupleExpr(e) => { | ||
316 | Ty::Unknown | ||
317 | } | ||
318 | ast::Expr::ArrayExpr(e) => { | ||
319 | Ty::Unknown | ||
320 | } | ||
321 | ast::Expr::PathExpr(e) => { | ||
322 | if let Some(p) = e.path() { | ||
323 | if p.qualifier().is_none() { | ||
324 | if let Some(name) = p.segment().and_then(|s| s.name_ref()) { | ||
325 | let s = self.scopes.resolve_local_name(name); | ||
326 | if let Some(scope_entry) = s { | ||
327 | if let Some(ty) = self.type_for.get(&scope_entry.ptr()) { | ||
328 | ty.clone() | ||
329 | } else { | ||
330 | // TODO introduce type variable? | ||
331 | Ty::Unknown | ||
332 | } | ||
333 | } else { | ||
334 | Ty::Unknown | ||
335 | } | ||
336 | } else { | ||
337 | Ty::Unknown | ||
338 | } | ||
339 | } else { | ||
340 | // TODO resolve path | ||
341 | Ty::Unknown | ||
342 | } | ||
343 | } else { | ||
344 | Ty::Unknown | ||
345 | } | ||
346 | } | ||
347 | ast::Expr::ContinueExpr(e) => { | ||
348 | Ty::Never | ||
349 | } | ||
350 | ast::Expr::BreakExpr(e) => { | ||
351 | Ty::Never | ||
352 | } | ||
353 | ast::Expr::ParenExpr(e) => { | ||
354 | if let Some(e) = e.expr() { | ||
355 | self.infer_expr(e) | ||
356 | } else { | ||
357 | Ty::Unknown | ||
358 | } | ||
359 | } | ||
360 | ast::Expr::Label(e) => { | ||
361 | Ty::Unknown | ||
362 | } | ||
363 | ast::Expr::ReturnExpr(e) => { | ||
364 | if let Some(e) = e.expr() { | ||
365 | // TODO unify with return type | ||
366 | self.infer_expr(e); | ||
367 | }; | ||
368 | Ty::Never | ||
369 | } | ||
370 | ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => { | ||
371 | // Can this even occur outside of a match expression? | ||
372 | Ty::Unknown | ||
373 | } | ||
374 | ast::Expr::StructLit(e) => { | ||
375 | Ty::Unknown | ||
376 | } | ||
377 | ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => { | ||
378 | // Can this even occur outside of a struct literal? | ||
379 | Ty::Unknown | ||
380 | } | ||
381 | ast::Expr::IndexExpr(e) => { | ||
382 | Ty::Unknown | ||
383 | } | ||
384 | ast::Expr::FieldExpr(e) => { | ||
385 | Ty::Unknown | ||
386 | } | ||
387 | ast::Expr::TryExpr(e) => { | ||
388 | let inner_ty = if let Some(e) = e.expr() { | ||
389 | self.infer_expr(e) | ||
390 | } else { | ||
391 | Ty::Unknown | ||
392 | }; | ||
393 | Ty::Unknown | ||
394 | } | ||
395 | ast::Expr::CastExpr(e) => { | ||
396 | let inner_ty = if let Some(e) = e.expr() { | ||
397 | self.infer_expr(e) | ||
398 | } else { | ||
399 | Ty::Unknown | ||
400 | }; | ||
401 | let cast_ty = e.type_ref().map(Ty::new).unwrap_or(Ty::Unknown); | ||
402 | // TODO do the coercion... | ||
403 | cast_ty | ||
404 | } | ||
405 | ast::Expr::RefExpr(e) => { | ||
406 | let inner_ty = if let Some(e) = e.expr() { | ||
407 | self.infer_expr(e) | ||
408 | } else { | ||
409 | Ty::Unknown | ||
410 | }; | ||
411 | Ty::Unknown | ||
412 | } | ||
413 | ast::Expr::PrefixExpr(e) => { | ||
414 | let inner_ty = if let Some(e) = e.expr() { | ||
415 | self.infer_expr(e) | ||
416 | } else { | ||
417 | Ty::Unknown | ||
418 | }; | ||
419 | Ty::Unknown | ||
420 | } | ||
421 | ast::Expr::RangeExpr(e) => { | ||
422 | Ty::Unknown | ||
423 | } | ||
424 | ast::Expr::BinExpr(e) => { | ||
425 | Ty::Unknown | ||
426 | } | ||
427 | ast::Expr::Literal(e) => { | ||
428 | Ty::Unknown | ||
429 | } | ||
430 | }; | ||
431 | self.write_ty(expr.syntax(), ty.clone()); | ||
432 | ty | ||
433 | } | ||
434 | |||
435 | fn infer_block(&mut self, node: ast::Block) -> Ty { | ||
436 | for stmt in node.statements() { | ||
437 | match stmt { | ||
438 | ast::Stmt::LetStmt(stmt) => { | ||
439 | if let Some(expr) = stmt.initializer() { | ||
440 | self.infer_expr(expr); | ||
441 | } | ||
442 | } | ||
443 | ast::Stmt::ExprStmt(expr_stmt) => { | ||
444 | if let Some(expr) = expr_stmt.expr() { | ||
445 | self.infer_expr(expr); | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | let ty = if let Some(expr) = node.expr() { | ||
451 | self.infer_expr(expr) | ||
452 | } else { | ||
453 | Ty::unit() | ||
454 | }; | ||
455 | self.write_ty(node.syntax(), ty.clone()); | ||
456 | ty | ||
457 | } | ||
458 | } | ||
459 | |||
460 | pub fn infer(db: &impl HirDatabase, node: ast::FnDef, scopes: Arc<FnScopes>) -> InferenceResult { | ||
461 | let mut ctx = InferenceContext::new(scopes); | ||
462 | |||
463 | for param in node.param_list().unwrap().params() { | ||
464 | let pat = param.pat().unwrap(); | ||
465 | let type_ref = param.type_ref().unwrap(); | ||
466 | let ty = Ty::new(type_ref); | ||
467 | ctx.type_for.insert(LocalSyntaxPtr::new(pat.syntax()), ty); | ||
468 | } | ||
469 | |||
470 | // TODO get Ty for node.ret_type() and pass that to infer_block as expectation | ||
471 | // (see Expectation in rustc_typeck) | ||
472 | |||
473 | ctx.infer_block(node.body().unwrap()); | ||
474 | |||
475 | // TODO 'resolve' the types: replace inference variables by their inferred results | ||
476 | |||
477 | InferenceResult { type_for: ctx.type_for } | ||
478 | } | ||
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs new file mode 100644 index 000000000..4a5ce5a97 --- /dev/null +++ b/crates/ra_hir/src/ty/primitive.rs | |||
@@ -0,0 +1,98 @@ | |||
1 | use std::fmt; | ||
2 | |||
3 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] | ||
4 | pub enum IntTy { | ||
5 | Isize, | ||
6 | I8, | ||
7 | I16, | ||
8 | I32, | ||
9 | I64, | ||
10 | I128, | ||
11 | } | ||
12 | |||
13 | impl fmt::Debug for IntTy { | ||
14 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
15 | fmt::Display::fmt(self, f) | ||
16 | } | ||
17 | } | ||
18 | |||
19 | impl fmt::Display for IntTy { | ||
20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
21 | write!(f, "{}", self.ty_to_string()) | ||
22 | } | ||
23 | } | ||
24 | |||
25 | impl IntTy { | ||
26 | pub fn ty_to_string(&self) -> &'static str { | ||
27 | match *self { | ||
28 | IntTy::Isize => "isize", | ||
29 | IntTy::I8 => "i8", | ||
30 | IntTy::I16 => "i16", | ||
31 | IntTy::I32 => "i32", | ||
32 | IntTy::I64 => "i64", | ||
33 | IntTy::I128 => "i128", | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | |||
38 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] | ||
39 | pub enum UintTy { | ||
40 | Usize, | ||
41 | U8, | ||
42 | U16, | ||
43 | U32, | ||
44 | U64, | ||
45 | U128, | ||
46 | } | ||
47 | |||
48 | impl UintTy { | ||
49 | pub fn ty_to_string(&self) -> &'static str { | ||
50 | match *self { | ||
51 | UintTy::Usize => "usize", | ||
52 | UintTy::U8 => "u8", | ||
53 | UintTy::U16 => "u16", | ||
54 | UintTy::U32 => "u32", | ||
55 | UintTy::U64 => "u64", | ||
56 | UintTy::U128 => "u128", | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | impl fmt::Debug for UintTy { | ||
62 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
63 | fmt::Display::fmt(self, f) | ||
64 | } | ||
65 | } | ||
66 | |||
67 | impl fmt::Display for UintTy { | ||
68 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
69 | write!(f, "{}", self.ty_to_string()) | ||
70 | } | ||
71 | } | ||
72 | |||
73 | #[derive(Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)] | ||
74 | pub enum FloatTy { | ||
75 | F32, | ||
76 | F64, | ||
77 | } | ||
78 | |||
79 | impl fmt::Debug for FloatTy { | ||
80 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
81 | fmt::Display::fmt(self, f) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | impl fmt::Display for FloatTy { | ||
86 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
87 | write!(f, "{}", self.ty_to_string()) | ||
88 | } | ||
89 | } | ||
90 | |||
91 | impl FloatTy { | ||
92 | pub fn ty_to_string(self) -> &'static str { | ||
93 | match self { | ||
94 | FloatTy::F32 => "f32", | ||
95 | FloatTy::F64 => "f64", | ||
96 | } | ||
97 | } | ||
98 | } | ||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs new file mode 100644 index 000000000..f2466dd51 --- /dev/null +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -0,0 +1,45 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use salsa::Database; | ||
4 | use ra_db::{FilesDatabase, CrateGraph, SyntaxDatabase}; | ||
5 | use ra_syntax::{SmolStr, algo::visit::{visitor, Visitor}, ast::{self, AstNode}}; | ||
6 | use relative_path::RelativePath; | ||
7 | |||
8 | use crate::{source_binder, mock::WORKSPACE, module::ModuleSourceNode}; | ||
9 | |||
10 | use crate::{ | ||
11 | self as hir, | ||
12 | db::HirDatabase, | ||
13 | mock::MockDatabase, | ||
14 | }; | ||
15 | |||
16 | fn infer_all_fns(fixture: &str) -> () { | ||
17 | let (db, source_root) = MockDatabase::with_files(fixture); | ||
18 | for &file_id in source_root.files.values() { | ||
19 | let source_file = db.source_file(file_id); | ||
20 | for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) { | ||
21 | let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap().unwrap(); | ||
22 | let inference_result = func.infer(&db); | ||
23 | for (syntax_ptr, ty) in &inference_result.type_for { | ||
24 | let node = syntax_ptr.resolve(&source_file); | ||
25 | eprintln!("{} '{}': {:?}", syntax_ptr.range(), node.text(), ty); | ||
26 | } | ||
27 | } | ||
28 | } | ||
29 | } | ||
30 | |||
31 | #[test] | ||
32 | fn infer_smoke_test() { | ||
33 | let text = " | ||
34 | //- /lib.rs | ||
35 | fn foo(x: u32, y: !) -> i128 { | ||
36 | x; | ||
37 | y; | ||
38 | return 1; | ||
39 | \"hello\"; | ||
40 | 0 | ||
41 | } | ||
42 | "; | ||
43 | |||
44 | infer_all_fns(text); | ||
45 | } | ||
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index bf056131e..91f27fb26 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -523,7 +523,15 @@ impl<R: TreeRoot<RaTypes>> CastExprNode<R> { | |||
523 | } | 523 | } |
524 | 524 | ||
525 | 525 | ||
526 | impl<'a> CastExpr<'a> {} | 526 | impl<'a> CastExpr<'a> { |
527 | pub fn expr(self) -> Option<Expr<'a>> { | ||
528 | super::child_opt(self) | ||
529 | } | ||
530 | |||
531 | pub fn type_ref(self) -> Option<TypeRef<'a>> { | ||
532 | super::child_opt(self) | ||
533 | } | ||
534 | } | ||
527 | 535 | ||
528 | // Char | 536 | // Char |
529 | #[derive(Debug, Clone, Copy,)] | 537 | #[derive(Debug, Clone, Copy,)] |
@@ -2312,6 +2320,10 @@ impl<'a> Param<'a> { | |||
2312 | pub fn pat(self) -> Option<Pat<'a>> { | 2320 | pub fn pat(self) -> Option<Pat<'a>> { |
2313 | super::child_opt(self) | 2321 | super::child_opt(self) |
2314 | } | 2322 | } |
2323 | |||
2324 | pub fn type_ref(self) -> Option<TypeRef<'a>> { | ||
2325 | super::child_opt(self) | ||
2326 | } | ||
2315 | } | 2327 | } |
2316 | 2328 | ||
2317 | // ParamList | 2329 | // ParamList |
@@ -2394,7 +2406,11 @@ impl<R: TreeRoot<RaTypes>> ParenExprNode<R> { | |||
2394 | } | 2406 | } |
2395 | 2407 | ||
2396 | 2408 | ||
2397 | impl<'a> ParenExpr<'a> {} | 2409 | impl<'a> ParenExpr<'a> { |
2410 | pub fn expr(self) -> Option<Expr<'a>> { | ||
2411 | super::child_opt(self) | ||
2412 | } | ||
2413 | } | ||
2398 | 2414 | ||
2399 | // ParenType | 2415 | // ParenType |
2400 | #[derive(Debug, Clone, Copy,)] | 2416 | #[derive(Debug, Clone, Copy,)] |
@@ -2829,7 +2845,11 @@ impl<R: TreeRoot<RaTypes>> PrefixExprNode<R> { | |||
2829 | } | 2845 | } |
2830 | 2846 | ||
2831 | 2847 | ||
2832 | impl<'a> PrefixExpr<'a> {} | 2848 | impl<'a> PrefixExpr<'a> { |
2849 | pub fn expr(self) -> Option<Expr<'a>> { | ||
2850 | super::child_opt(self) | ||
2851 | } | ||
2852 | } | ||
2833 | 2853 | ||
2834 | // RangeExpr | 2854 | // RangeExpr |
2835 | #[derive(Debug, Clone, Copy,)] | 2855 | #[derive(Debug, Clone, Copy,)] |
@@ -2940,7 +2960,11 @@ impl<R: TreeRoot<RaTypes>> RefExprNode<R> { | |||
2940 | } | 2960 | } |
2941 | 2961 | ||
2942 | 2962 | ||
2943 | impl<'a> RefExpr<'a> {} | 2963 | impl<'a> RefExpr<'a> { |
2964 | pub fn expr(self) -> Option<Expr<'a>> { | ||
2965 | super::child_opt(self) | ||
2966 | } | ||
2967 | } | ||
2944 | 2968 | ||
2945 | // RefPat | 2969 | // RefPat |
2946 | #[derive(Debug, Clone, Copy,)] | 2970 | #[derive(Debug, Clone, Copy,)] |
@@ -3088,7 +3112,11 @@ impl<R: TreeRoot<RaTypes>> ReturnExprNode<R> { | |||
3088 | } | 3112 | } |
3089 | 3113 | ||
3090 | 3114 | ||
3091 | impl<'a> ReturnExpr<'a> {} | 3115 | impl<'a> ReturnExpr<'a> { |
3116 | pub fn expr(self) -> Option<Expr<'a>> { | ||
3117 | super::child_opt(self) | ||
3118 | } | ||
3119 | } | ||
3092 | 3120 | ||
3093 | // SelfParam | 3121 | // SelfParam |
3094 | #[derive(Debug, Clone, Copy,)] | 3122 | #[derive(Debug, Clone, Copy,)] |
@@ -3578,7 +3606,11 @@ impl<R: TreeRoot<RaTypes>> TryExprNode<R> { | |||
3578 | } | 3606 | } |
3579 | 3607 | ||
3580 | 3608 | ||
3581 | impl<'a> TryExpr<'a> {} | 3609 | impl<'a> TryExpr<'a> { |
3610 | pub fn expr(self) -> Option<Expr<'a>> { | ||
3611 | super::child_opt(self) | ||
3612 | } | ||
3613 | } | ||
3582 | 3614 | ||
3583 | // TupleExpr | 3615 | // TupleExpr |
3584 | #[derive(Debug, Clone, Copy,)] | 3616 | #[derive(Debug, Clone, Copy,)] |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index eed67637e..c43db51b6 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -346,7 +346,7 @@ Grammar( | |||
346 | 346 | ||
347 | "TupleExpr": (), | 347 | "TupleExpr": (), |
348 | "ArrayExpr": (), | 348 | "ArrayExpr": (), |
349 | "ParenExpr": (), | 349 | "ParenExpr": (options: ["Expr"]), |
350 | "PathExpr": (options: ["Path"]), | 350 | "PathExpr": (options: ["Path"]), |
351 | "LambdaExpr": ( | 351 | "LambdaExpr": ( |
352 | options: [ | 352 | options: [ |
@@ -377,7 +377,7 @@ Grammar( | |||
377 | "BlockExpr": ( | 377 | "BlockExpr": ( |
378 | options: [ "Block" ] | 378 | options: [ "Block" ] |
379 | ), | 379 | ), |
380 | "ReturnExpr": (), | 380 | "ReturnExpr": (options: ["Expr"]), |
381 | "MatchExpr": ( | 381 | "MatchExpr": ( |
382 | options: [ "Expr", "MatchArmList" ], | 382 | options: [ "Expr", "MatchArmList" ], |
383 | ), | 383 | ), |
@@ -405,10 +405,10 @@ Grammar( | |||
405 | ), | 405 | ), |
406 | "IndexExpr": (), | 406 | "IndexExpr": (), |
407 | "FieldExpr": (), | 407 | "FieldExpr": (), |
408 | "TryExpr": (), | 408 | "TryExpr": (options: ["Expr"]), |
409 | "CastExpr": (), | 409 | "CastExpr": (options: ["Expr", "TypeRef"]), |
410 | "RefExpr": (), | 410 | "RefExpr": (options: ["Expr"]), |
411 | "PrefixExpr": (), | 411 | "PrefixExpr": (options: ["Expr"]), |
412 | "RangeExpr": (), | 412 | "RangeExpr": (), |
413 | "BinExpr": (), | 413 | "BinExpr": (), |
414 | "String": (), | 414 | "String": (), |
@@ -521,7 +521,7 @@ Grammar( | |||
521 | ), | 521 | ), |
522 | "SelfParam": (), | 522 | "SelfParam": (), |
523 | "Param": ( | 523 | "Param": ( |
524 | options: [ "Pat" ], | 524 | options: [ "Pat", "TypeRef" ], |
525 | ), | 525 | ), |
526 | "UseItem": ( | 526 | "UseItem": ( |
527 | options: [ "UseTree" ] | 527 | options: [ "UseTree" ] |