aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/db.rs6
-rw-r--r--crates/ra_hir/src/function.rs6
-rw-r--r--crates/ra_hir/src/lib.rs1
-rw-r--r--crates/ra_hir/src/mock.rs3
-rw-r--r--crates/ra_hir/src/query_definitions.rs8
-rw-r--r--crates/ra_hir/src/ty.rs478
-rw-r--r--crates/ra_hir/src/ty/primitive.rs98
-rw-r--r--crates/ra_hir/src/ty/tests.rs45
8 files changed, 643 insertions, 2 deletions
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
19salsa::query_group! { 20salsa::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
13use crate::{ DefId, HirDatabase }; 13use crate::{ DefId, HirDatabase, ty::InferenceResult };
14 14
15pub use self::scope::FnScopes; 15pub 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;
25mod krate; 25mod krate;
26mod module; 26mod module;
27mod function; 27mod function;
28mod ty;
28 29
29use std::ops::Index; 30use 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
9use crate::{db, DefId, DefLoc}; 9use crate::{db, DefId, DefLoc};
10 10
11const WORKSPACE: SourceRootId = SourceRootId(0); 11pub const WORKSPACE: SourceRootId = SourceRootId(0);
12 12
13#[derive(Debug)] 13#[derive(Debug)]
14pub(crate) struct MockDatabase { 14pub(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
39pub(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
38pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> { 46pub(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 @@
1mod primitive;
2#[cfg(test)]
3mod tests;
4
5use rustc_hash::{FxHashMap, FxHashSet};
6
7use std::sync::Arc;
8use std::collections::HashMap;
9
10use ra_db::LocalSyntaxPtr;
11use ra_syntax::{
12 TextRange, TextUnit,
13 algo::visit::{visitor, Visitor},
14 ast::{self, AstNode, DocCommentsOwner, NameOwner, LoopBodyOwner, ArgListOwner},
15 SyntaxNodeRef
16};
17
18use 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)]
27pub 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
142type TyRef = Arc<Ty>;
143
144impl 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)]
170pub struct InferenceResult {
171 type_for: FxHashMap<LocalSyntaxPtr, Ty>,
172}
173
174#[derive(Clone, PartialEq, Eq, Debug)]
175pub struct InferenceContext {
176 scopes: Arc<FnScopes>,
177 // TODO unification tables...
178 type_for: FxHashMap<LocalSyntaxPtr, Ty>,
179}
180
181impl 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
460pub 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 @@
1use std::fmt;
2
3#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
4pub enum IntTy {
5 Isize,
6 I8,
7 I16,
8 I32,
9 I64,
10 I128,
11}
12
13impl fmt::Debug for IntTy {
14 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15 fmt::Display::fmt(self, f)
16 }
17}
18
19impl fmt::Display for IntTy {
20 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21 write!(f, "{}", self.ty_to_string())
22 }
23}
24
25impl 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)]
39pub enum UintTy {
40 Usize,
41 U8,
42 U16,
43 U32,
44 U64,
45 U128,
46}
47
48impl 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
61impl fmt::Debug for UintTy {
62 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63 fmt::Display::fmt(self, f)
64 }
65}
66
67impl 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)]
74pub enum FloatTy {
75 F32,
76 F64,
77}
78
79impl fmt::Debug for FloatTy {
80 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81 fmt::Display::fmt(self, f)
82 }
83}
84
85impl fmt::Display for FloatTy {
86 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87 write!(f, "{}", self.ty_to_string())
88 }
89}
90
91impl 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 @@
1use std::sync::Arc;
2
3use salsa::Database;
4use ra_db::{FilesDatabase, CrateGraph, SyntaxDatabase};
5use ra_syntax::{SmolStr, algo::visit::{visitor, Visitor}, ast::{self, AstNode}};
6use relative_path::RelativePath;
7
8use crate::{source_binder, mock::WORKSPACE, module::ModuleSourceNode};
9
10use crate::{
11 self as hir,
12 db::HirDatabase,
13 mock::MockDatabase,
14};
15
16fn 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]
32fn 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}