aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty.rs')
-rw-r--r--crates/ra_hir/src/ty.rs601
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 @@
1mod primitive;
2#[cfg(test)]
3mod tests;
4
5use std::sync::Arc;
6use std::fmt;
7
8use log;
9use rustc_hash::{FxHashMap};
10
11use ra_db::{LocalSyntaxPtr, Cancelable};
12use ra_syntax::{
13 SmolStr,
14 ast::{self, AstNode, LoopBodyOwner, ArgListOwner},
15 SyntaxNodeRef
16};
17
18use crate::{Def, DefId, FnScopes, Module, Function, Path, db::HirDatabase};
19
20#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
21pub 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
108type TyRef = Arc<Ty>;
109
110#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
111pub struct FnSig {
112 input: Vec<Ty>,
113 output: Ty,
114}
115
116impl 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
167impl 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
197pub 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.
227pub 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)]
243pub struct InferenceResult {
244 type_of: FxHashMap<LocalSyntaxPtr, Ty>,
245}
246
247impl 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)]
254pub 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
262impl<'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
563pub 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}