diff options
Diffstat (limited to 'crates/ra_hir/src/ty.rs')
-rw-r--r-- | crates/ra_hir/src/ty.rs | 601 |
1 files changed, 601 insertions, 0 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs new file mode 100644 index 000000000..c759d4c8b --- /dev/null +++ b/crates/ra_hir/src/ty.rs | |||
@@ -0,0 +1,601 @@ | |||
1 | mod primitive; | ||
2 | #[cfg(test)] | ||
3 | mod tests; | ||
4 | |||
5 | use std::sync::Arc; | ||
6 | use std::fmt; | ||
7 | |||
8 | use log; | ||
9 | use rustc_hash::{FxHashMap}; | ||
10 | |||
11 | use ra_db::{LocalSyntaxPtr, Cancelable}; | ||
12 | use ra_syntax::{ | ||
13 | SmolStr, | ||
14 | ast::{self, AstNode, LoopBodyOwner, ArgListOwner}, | ||
15 | SyntaxNodeRef | ||
16 | }; | ||
17 | |||
18 | use crate::{Def, DefId, FnScopes, Module, Function, Path, db::HirDatabase}; | ||
19 | |||
20 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | ||
21 | pub enum Ty { | ||
22 | /// The primitive boolean type. Written as `bool`. | ||
23 | Bool, | ||
24 | |||
25 | /// The primitive character type; holds a Unicode scalar value | ||
26 | /// (a non-surrogate code point). Written as `char`. | ||
27 | Char, | ||
28 | |||
29 | /// A primitive signed integer type. For example, `i32`. | ||
30 | Int(primitive::IntTy), | ||
31 | |||
32 | /// A primitive unsigned integer type. For example, `u32`. | ||
33 | Uint(primitive::UintTy), | ||
34 | |||
35 | /// A primitive floating-point type. For example, `f64`. | ||
36 | Float(primitive::FloatTy), | ||
37 | |||
38 | // Structures, enumerations and unions. | ||
39 | // Adt(AdtDef, Substs), | ||
40 | /// The pointee of a string slice. Written as `str`. | ||
41 | Str, | ||
42 | |||
43 | // An array with the given length. Written as `[T; n]`. | ||
44 | // Array(Ty, ty::Const), | ||
45 | /// The pointee of an array slice. Written as `[T]`. | ||
46 | Slice(TyRef), | ||
47 | |||
48 | // A raw pointer. Written as `*mut T` or `*const T` | ||
49 | // RawPtr(TypeAndMut<'tcx>), | ||
50 | |||
51 | // A reference; a pointer with an associated lifetime. Written as | ||
52 | // `&'a mut T` or `&'a T`. | ||
53 | // Ref(Ty<'tcx>, hir::Mutability), | ||
54 | /// A pointer to a function. Written as `fn() -> i32`. | ||
55 | /// | ||
56 | /// For example the type of `bar` here: | ||
57 | /// | ||
58 | /// ```rust | ||
59 | /// fn foo() -> i32 { 1 } | ||
60 | /// let bar: fn() -> i32 = foo; | ||
61 | /// ``` | ||
62 | FnPtr(Arc<FnSig>), | ||
63 | |||
64 | // A trait, defined with `dyn trait`. | ||
65 | // Dynamic(), | ||
66 | /// The anonymous type of a closure. Used to represent the type of | ||
67 | /// `|a| a`. | ||
68 | // Closure(DefId, ClosureSubsts<'tcx>), | ||
69 | |||
70 | /// The anonymous type of a generator. Used to represent the type of | ||
71 | /// `|a| yield a`. | ||
72 | // Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability), | ||
73 | |||
74 | /// A type representin the types stored inside a generator. | ||
75 | /// This should only appear in GeneratorInteriors. | ||
76 | // GeneratorWitness(Binder<&'tcx List<Ty<'tcx>>>), | ||
77 | |||
78 | /// The never type `!` | ||
79 | Never, | ||
80 | |||
81 | /// A tuple type. For example, `(i32, bool)`. | ||
82 | Tuple(Vec<Ty>), | ||
83 | |||
84 | // The projection of an associated type. For example, | ||
85 | // `<T as Trait<..>>::N`. | ||
86 | // Projection(ProjectionTy), | ||
87 | |||
88 | // Opaque (`impl Trait`) type found in a return type. | ||
89 | // The `DefId` comes either from | ||
90 | // * the `impl Trait` ast::Ty node, | ||
91 | // * or the `existential type` declaration | ||
92 | // The substitutions are for the generics of the function in question. | ||
93 | // Opaque(DefId, Substs), | ||
94 | |||
95 | // A type parameter; for example, `T` in `fn f<T>(x: T) {} | ||
96 | // Param(ParamTy), | ||
97 | |||
98 | // A placeholder type - universally quantified higher-ranked type. | ||
99 | // Placeholder(ty::PlaceholderType), | ||
100 | |||
101 | // A type variable used during type checking. | ||
102 | // Infer(InferTy), | ||
103 | /// A placeholder for a type which could not be computed; this is | ||
104 | /// propagated to avoid useless error messages. | ||
105 | Unknown, | ||
106 | } | ||
107 | |||
108 | type TyRef = Arc<Ty>; | ||
109 | |||
110 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | ||
111 | pub struct FnSig { | ||
112 | input: Vec<Ty>, | ||
113 | output: Ty, | ||
114 | } | ||
115 | |||
116 | impl Ty { | ||
117 | pub fn new(_db: &impl HirDatabase, node: ast::TypeRef) -> Cancelable<Self> { | ||
118 | use ra_syntax::ast::TypeRef::*; | ||
119 | Ok(match node { | ||
120 | ParenType(_inner) => Ty::Unknown, // TODO | ||
121 | TupleType(_inner) => Ty::Unknown, // TODO | ||
122 | NeverType(..) => Ty::Never, | ||
123 | PathType(inner) => { | ||
124 | let path = if let Some(p) = inner.path() { | ||
125 | p | ||
126 | } else { | ||
127 | return Ok(Ty::Unknown); | ||
128 | }; | ||
129 | if path.qualifier().is_none() { | ||
130 | let name = path | ||
131 | .segment() | ||
132 | .and_then(|s| s.name_ref()) | ||
133 | .map(|n| n.text()) | ||
134 | .unwrap_or(SmolStr::new("")); | ||
135 | if let Some(int_ty) = primitive::IntTy::from_string(&name) { | ||
136 | Ty::Int(int_ty) | ||
137 | } else if let Some(uint_ty) = primitive::UintTy::from_string(&name) { | ||
138 | Ty::Uint(uint_ty) | ||
139 | } else if let Some(float_ty) = primitive::FloatTy::from_string(&name) { | ||
140 | Ty::Float(float_ty) | ||
141 | } else { | ||
142 | // TODO | ||
143 | Ty::Unknown | ||
144 | } | ||
145 | } else { | ||
146 | // TODO | ||
147 | Ty::Unknown | ||
148 | } | ||
149 | } | ||
150 | PointerType(_inner) => Ty::Unknown, // TODO | ||
151 | ArrayType(_inner) => Ty::Unknown, // TODO | ||
152 | SliceType(_inner) => Ty::Unknown, // TODO | ||
153 | ReferenceType(_inner) => Ty::Unknown, // TODO | ||
154 | PlaceholderType(_inner) => Ty::Unknown, // TODO | ||
155 | FnPointerType(_inner) => Ty::Unknown, // TODO | ||
156 | ForType(_inner) => Ty::Unknown, // TODO | ||
157 | ImplTraitType(_inner) => Ty::Unknown, // TODO | ||
158 | DynTraitType(_inner) => Ty::Unknown, // TODO | ||
159 | }) | ||
160 | } | ||
161 | |||
162 | pub fn unit() -> Self { | ||
163 | Ty::Tuple(Vec::new()) | ||
164 | } | ||
165 | } | ||
166 | |||
167 | impl fmt::Display for Ty { | ||
168 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
169 | match self { | ||
170 | Ty::Bool => write!(f, "bool"), | ||
171 | Ty::Char => write!(f, "char"), | ||
172 | Ty::Int(t) => write!(f, "{}", t.ty_to_string()), | ||
173 | Ty::Uint(t) => write!(f, "{}", t.ty_to_string()), | ||
174 | Ty::Float(t) => write!(f, "{}", t.ty_to_string()), | ||
175 | Ty::Str => write!(f, "str"), | ||
176 | Ty::Slice(t) => write!(f, "[{}]", t), | ||
177 | Ty::Never => write!(f, "!"), | ||
178 | Ty::Tuple(ts) => { | ||
179 | write!(f, "(")?; | ||
180 | for t in ts { | ||
181 | write!(f, "{},", t)?; | ||
182 | } | ||
183 | write!(f, ")") | ||
184 | } | ||
185 | Ty::FnPtr(sig) => { | ||
186 | write!(f, "fn(")?; | ||
187 | for t in &sig.input { | ||
188 | write!(f, "{},", t)?; | ||
189 | } | ||
190 | write!(f, ") -> {}", sig.output) | ||
191 | } | ||
192 | Ty::Unknown => write!(f, "[unknown]"), | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | |||
197 | pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { | ||
198 | let syntax = f.syntax(db); | ||
199 | let node = syntax.borrowed(); | ||
200 | // TODO we ignore type parameters for now | ||
201 | let input = node | ||
202 | .param_list() | ||
203 | .map(|pl| { | ||
204 | pl.params() | ||
205 | .map(|p| { | ||
206 | p.type_ref() | ||
207 | .map(|t| Ty::new(db, t)) | ||
208 | .unwrap_or(Ok(Ty::Unknown)) | ||
209 | }) | ||
210 | .collect() | ||
211 | }) | ||
212 | .unwrap_or_else(|| Ok(Vec::new()))?; | ||
213 | let output = node | ||
214 | .ret_type() | ||
215 | .and_then(|rt| rt.type_ref()) | ||
216 | .map(|t| Ty::new(db, t)) | ||
217 | .unwrap_or(Ok(Ty::Unknown))?; | ||
218 | let sig = FnSig { input, output }; | ||
219 | Ok(Ty::FnPtr(Arc::new(sig))) | ||
220 | } | ||
221 | |||
222 | // TODO this should probably be per namespace (i.e. types vs. values), since for | ||
223 | // a tuple struct `struct Foo(Bar)`, Foo has function type as a value, but | ||
224 | // defines the struct type Foo when used in the type namespace. rustc has a | ||
225 | // separate DefId for the constructor, but with the current DefId approach, that | ||
226 | // seems complicated. | ||
227 | pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> { | ||
228 | let def = def_id.resolve(db)?; | ||
229 | match def { | ||
230 | Def::Module(..) => { | ||
231 | log::debug!("trying to get type for module {:?}", def_id); | ||
232 | Ok(Ty::Unknown) | ||
233 | } | ||
234 | Def::Function(f) => type_for_fn(db, f), | ||
235 | Def::Item => { | ||
236 | log::debug!("trying to get type for item of unknown type {:?}", def_id); | ||
237 | Ok(Ty::Unknown) | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
243 | pub struct InferenceResult { | ||
244 | type_of: FxHashMap<LocalSyntaxPtr, Ty>, | ||
245 | } | ||
246 | |||
247 | impl InferenceResult { | ||
248 | pub fn type_of_node(&self, node: SyntaxNodeRef) -> Option<Ty> { | ||
249 | self.type_of.get(&LocalSyntaxPtr::new(node)).cloned() | ||
250 | } | ||
251 | } | ||
252 | |||
253 | #[derive(Clone, Debug)] | ||
254 | pub struct InferenceContext<'a, D: HirDatabase> { | ||
255 | db: &'a D, | ||
256 | scopes: Arc<FnScopes>, | ||
257 | module: Module, | ||
258 | // TODO unification tables... | ||
259 | type_of: FxHashMap<LocalSyntaxPtr, Ty>, | ||
260 | } | ||
261 | |||
262 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | ||
263 | fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self { | ||
264 | InferenceContext { | ||
265 | type_of: FxHashMap::default(), | ||
266 | db, | ||
267 | scopes, | ||
268 | module, | ||
269 | } | ||
270 | } | ||
271 | |||
272 | fn write_ty(&mut self, node: SyntaxNodeRef, ty: Ty) { | ||
273 | self.type_of.insert(LocalSyntaxPtr::new(node), ty); | ||
274 | } | ||
275 | |||
276 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> Option<Ty> { | ||
277 | if *ty1 == Ty::Unknown { | ||
278 | return Some(ty2.clone()); | ||
279 | } | ||
280 | if *ty2 == Ty::Unknown { | ||
281 | return Some(ty1.clone()); | ||
282 | } | ||
283 | if ty1 == ty2 { | ||
284 | return Some(ty1.clone()); | ||
285 | } | ||
286 | // TODO implement actual unification | ||
287 | return None; | ||
288 | } | ||
289 | |||
290 | fn unify_with_coercion(&mut self, ty1: &Ty, ty2: &Ty) -> Option<Ty> { | ||
291 | // TODO implement coercion | ||
292 | self.unify(ty1, ty2) | ||
293 | } | ||
294 | |||
295 | fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Cancelable<Option<Ty>> { | ||
296 | let ast_path = ctry!(expr.path()); | ||
297 | let path = ctry!(Path::from_ast(ast_path)); | ||
298 | if path.is_ident() { | ||
299 | // resolve locally | ||
300 | let name = ctry!(ast_path.segment().and_then(|s| s.name_ref())); | ||
301 | if let Some(scope_entry) = self.scopes.resolve_local_name(name) { | ||
302 | let ty = ctry!(self.type_of.get(&scope_entry.ptr())); | ||
303 | return Ok(Some(ty.clone())); | ||
304 | }; | ||
305 | }; | ||
306 | |||
307 | // resolve in module | ||
308 | let resolved = ctry!(self.module.resolve_path(self.db, path)?); | ||
309 | let ty = self.db.type_for_def(resolved)?; | ||
310 | // TODO we will need to add type variables for type parameters etc. here | ||
311 | Ok(Some(ty)) | ||
312 | } | ||
313 | |||
314 | fn infer_expr(&mut self, expr: ast::Expr) -> Cancelable<Ty> { | ||
315 | let ty = match expr { | ||
316 | ast::Expr::IfExpr(e) => { | ||
317 | if let Some(condition) = e.condition() { | ||
318 | if let Some(e) = condition.expr() { | ||
319 | // TODO if no pat, this should be bool | ||
320 | self.infer_expr(e)?; | ||
321 | } | ||
322 | // TODO write type for pat | ||
323 | }; | ||
324 | let if_ty = if let Some(block) = e.then_branch() { | ||
325 | self.infer_block(block)? | ||
326 | } else { | ||
327 | Ty::Unknown | ||
328 | }; | ||
329 | let else_ty = if let Some(block) = e.else_branch() { | ||
330 | self.infer_block(block)? | ||
331 | } else { | ||
332 | Ty::Unknown | ||
333 | }; | ||
334 | if let Some(ty) = self.unify(&if_ty, &else_ty) { | ||
335 | ty | ||
336 | } else { | ||
337 | // TODO report diagnostic | ||
338 | Ty::Unknown | ||
339 | } | ||
340 | } | ||
341 | ast::Expr::BlockExpr(e) => { | ||
342 | if let Some(block) = e.block() { | ||
343 | self.infer_block(block)? | ||
344 | } else { | ||
345 | Ty::Unknown | ||
346 | } | ||
347 | } | ||
348 | ast::Expr::LoopExpr(e) => { | ||
349 | if let Some(block) = e.loop_body() { | ||
350 | self.infer_block(block)?; | ||
351 | }; | ||
352 | // TODO never, or the type of the break param | ||
353 | Ty::Unknown | ||
354 | } | ||
355 | ast::Expr::WhileExpr(e) => { | ||
356 | if let Some(condition) = e.condition() { | ||
357 | if let Some(e) = condition.expr() { | ||
358 | // TODO if no pat, this should be bool | ||
359 | self.infer_expr(e)?; | ||
360 | } | ||
361 | // TODO write type for pat | ||
362 | }; | ||
363 | if let Some(block) = e.loop_body() { | ||
364 | // TODO | ||
365 | self.infer_block(block)?; | ||
366 | }; | ||
367 | // TODO always unit? | ||
368 | Ty::Unknown | ||
369 | } | ||
370 | ast::Expr::ForExpr(e) => { | ||
371 | if let Some(expr) = e.iterable() { | ||
372 | self.infer_expr(expr)?; | ||
373 | } | ||
374 | if let Some(_pat) = e.pat() { | ||
375 | // TODO write type for pat | ||
376 | } | ||
377 | if let Some(block) = e.loop_body() { | ||
378 | self.infer_block(block)?; | ||
379 | } | ||
380 | // TODO always unit? | ||
381 | Ty::Unknown | ||
382 | } | ||
383 | ast::Expr::LambdaExpr(e) => { | ||
384 | let _body_ty = if let Some(body) = e.body() { | ||
385 | self.infer_expr(body)? | ||
386 | } else { | ||
387 | Ty::Unknown | ||
388 | }; | ||
389 | Ty::Unknown | ||
390 | } | ||
391 | ast::Expr::CallExpr(e) => { | ||
392 | let callee_ty = if let Some(e) = e.expr() { | ||
393 | self.infer_expr(e)? | ||
394 | } else { | ||
395 | Ty::Unknown | ||
396 | }; | ||
397 | if let Some(arg_list) = e.arg_list() { | ||
398 | for arg in arg_list.args() { | ||
399 | // TODO unify / expect argument type | ||
400 | self.infer_expr(arg)?; | ||
401 | } | ||
402 | } | ||
403 | match callee_ty { | ||
404 | Ty::FnPtr(sig) => sig.output.clone(), | ||
405 | _ => { | ||
406 | // not callable | ||
407 | // TODO report an error? | ||
408 | Ty::Unknown | ||
409 | } | ||
410 | } | ||
411 | } | ||
412 | ast::Expr::MethodCallExpr(e) => { | ||
413 | let _receiver_ty = if let Some(e) = e.expr() { | ||
414 | self.infer_expr(e)? | ||
415 | } else { | ||
416 | Ty::Unknown | ||
417 | }; | ||
418 | if let Some(arg_list) = e.arg_list() { | ||
419 | for arg in arg_list.args() { | ||
420 | // TODO unify / expect argument type | ||
421 | self.infer_expr(arg)?; | ||
422 | } | ||
423 | } | ||
424 | Ty::Unknown | ||
425 | } | ||
426 | ast::Expr::MatchExpr(e) => { | ||
427 | let _ty = if let Some(match_expr) = e.expr() { | ||
428 | self.infer_expr(match_expr)? | ||
429 | } else { | ||
430 | Ty::Unknown | ||
431 | }; | ||
432 | if let Some(match_arm_list) = e.match_arm_list() { | ||
433 | for arm in match_arm_list.arms() { | ||
434 | // TODO type the bindings in pat | ||
435 | // TODO type the guard | ||
436 | let _ty = if let Some(e) = arm.expr() { | ||
437 | self.infer_expr(e)? | ||
438 | } else { | ||
439 | Ty::Unknown | ||
440 | }; | ||
441 | } | ||
442 | // TODO unify all the match arm types | ||
443 | Ty::Unknown | ||
444 | } else { | ||
445 | Ty::Unknown | ||
446 | } | ||
447 | } | ||
448 | ast::Expr::TupleExpr(_e) => Ty::Unknown, | ||
449 | ast::Expr::ArrayExpr(_e) => Ty::Unknown, | ||
450 | ast::Expr::PathExpr(e) => self.infer_path_expr(e)?.unwrap_or(Ty::Unknown), | ||
451 | ast::Expr::ContinueExpr(_e) => Ty::Never, | ||
452 | ast::Expr::BreakExpr(_e) => Ty::Never, | ||
453 | ast::Expr::ParenExpr(e) => { | ||
454 | if let Some(e) = e.expr() { | ||
455 | self.infer_expr(e)? | ||
456 | } else { | ||
457 | Ty::Unknown | ||
458 | } | ||
459 | } | ||
460 | ast::Expr::Label(_e) => Ty::Unknown, | ||
461 | ast::Expr::ReturnExpr(e) => { | ||
462 | if let Some(e) = e.expr() { | ||
463 | // TODO unify with return type | ||
464 | self.infer_expr(e)?; | ||
465 | }; | ||
466 | Ty::Never | ||
467 | } | ||
468 | ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => { | ||
469 | // Can this even occur outside of a match expression? | ||
470 | Ty::Unknown | ||
471 | } | ||
472 | ast::Expr::StructLit(_e) => Ty::Unknown, | ||
473 | ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => { | ||
474 | // Can this even occur outside of a struct literal? | ||
475 | Ty::Unknown | ||
476 | } | ||
477 | ast::Expr::IndexExpr(_e) => Ty::Unknown, | ||
478 | ast::Expr::FieldExpr(_e) => Ty::Unknown, | ||
479 | ast::Expr::TryExpr(e) => { | ||
480 | let _inner_ty = if let Some(e) = e.expr() { | ||
481 | self.infer_expr(e)? | ||
482 | } else { | ||
483 | Ty::Unknown | ||
484 | }; | ||
485 | Ty::Unknown | ||
486 | } | ||
487 | ast::Expr::CastExpr(e) => { | ||
488 | let _inner_ty = if let Some(e) = e.expr() { | ||
489 | self.infer_expr(e)? | ||
490 | } else { | ||
491 | Ty::Unknown | ||
492 | }; | ||
493 | let cast_ty = e | ||
494 | .type_ref() | ||
495 | .map(|t| Ty::new(self.db, t)) | ||
496 | .unwrap_or(Ok(Ty::Unknown))?; | ||
497 | // TODO do the coercion... | ||
498 | cast_ty | ||
499 | } | ||
500 | ast::Expr::RefExpr(e) => { | ||
501 | let _inner_ty = if let Some(e) = e.expr() { | ||
502 | self.infer_expr(e)? | ||
503 | } else { | ||
504 | Ty::Unknown | ||
505 | }; | ||
506 | Ty::Unknown | ||
507 | } | ||
508 | ast::Expr::PrefixExpr(e) => { | ||
509 | let _inner_ty = if let Some(e) = e.expr() { | ||
510 | self.infer_expr(e)? | ||
511 | } else { | ||
512 | Ty::Unknown | ||
513 | }; | ||
514 | Ty::Unknown | ||
515 | } | ||
516 | ast::Expr::RangeExpr(_e) => Ty::Unknown, | ||
517 | ast::Expr::BinExpr(_e) => Ty::Unknown, | ||
518 | ast::Expr::Literal(_e) => Ty::Unknown, | ||
519 | }; | ||
520 | self.write_ty(expr.syntax(), ty.clone()); | ||
521 | Ok(ty) | ||
522 | } | ||
523 | |||
524 | fn infer_block(&mut self, node: ast::Block) -> Cancelable<Ty> { | ||
525 | for stmt in node.statements() { | ||
526 | match stmt { | ||
527 | ast::Stmt::LetStmt(stmt) => { | ||
528 | let decl_ty = if let Some(type_ref) = stmt.type_ref() { | ||
529 | Ty::new(self.db, type_ref)? | ||
530 | } else { | ||
531 | Ty::Unknown | ||
532 | }; | ||
533 | let ty = if let Some(expr) = stmt.initializer() { | ||
534 | // TODO pass expectation | ||
535 | let expr_ty = self.infer_expr(expr)?; | ||
536 | self.unify_with_coercion(&expr_ty, &decl_ty) | ||
537 | .unwrap_or(decl_ty) | ||
538 | } else { | ||
539 | decl_ty | ||
540 | }; | ||
541 | |||
542 | if let Some(pat) = stmt.pat() { | ||
543 | self.write_ty(pat.syntax(), ty); | ||
544 | }; | ||
545 | } | ||
546 | ast::Stmt::ExprStmt(expr_stmt) => { | ||
547 | if let Some(expr) = expr_stmt.expr() { | ||
548 | self.infer_expr(expr)?; | ||
549 | } | ||
550 | } | ||
551 | } | ||
552 | } | ||
553 | let ty = if let Some(expr) = node.expr() { | ||
554 | self.infer_expr(expr)? | ||
555 | } else { | ||
556 | Ty::unit() | ||
557 | }; | ||
558 | self.write_ty(node.syntax(), ty.clone()); | ||
559 | Ok(ty) | ||
560 | } | ||
561 | } | ||
562 | |||
563 | pub fn infer(db: &impl HirDatabase, function: Function) -> Cancelable<InferenceResult> { | ||
564 | let scopes = function.scopes(db); | ||
565 | let module = function.module(db)?; | ||
566 | let mut ctx = InferenceContext::new(db, scopes, module); | ||
567 | |||
568 | let syntax = function.syntax(db); | ||
569 | let node = syntax.borrowed(); | ||
570 | |||
571 | if let Some(param_list) = node.param_list() { | ||
572 | for param in param_list.params() { | ||
573 | let pat = if let Some(pat) = param.pat() { | ||
574 | pat | ||
575 | } else { | ||
576 | continue; | ||
577 | }; | ||
578 | if let Some(type_ref) = param.type_ref() { | ||
579 | let ty = Ty::new(db, type_ref)?; | ||
580 | ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty); | ||
581 | } else { | ||
582 | // TODO self param | ||
583 | ctx.type_of | ||
584 | .insert(LocalSyntaxPtr::new(pat.syntax()), Ty::Unknown); | ||
585 | }; | ||
586 | } | ||
587 | } | ||
588 | |||
589 | // TODO get Ty for node.ret_type() and pass that to infer_block as expectation | ||
590 | // (see Expectation in rustc_typeck) | ||
591 | |||
592 | if let Some(block) = node.body() { | ||
593 | ctx.infer_block(block)?; | ||
594 | } | ||
595 | |||
596 | // TODO 'resolve' the types: replace inference variables by their inferred results | ||
597 | |||
598 | Ok(InferenceResult { | ||
599 | type_of: ctx.type_of, | ||
600 | }) | ||
601 | } | ||