diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_analysis/src/completion/complete_dot.rs | 14 | ||||
-rw-r--r-- | crates/ra_analysis/src/hover.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 31 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 544 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 24 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0001_basics.txt | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0004_struct.txt | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0005_refs.txt | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0006_backwards.txt | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt | 14 |
10 files changed, 308 insertions, 342 deletions
diff --git a/crates/ra_analysis/src/completion/complete_dot.rs b/crates/ra_analysis/src/completion/complete_dot.rs index 031d8b98f..ef3f4271b 100644 --- a/crates/ra_analysis/src/completion/complete_dot.rs +++ b/crates/ra_analysis/src/completion/complete_dot.rs | |||
@@ -1,3 +1,4 @@ | |||
1 | use ra_db::LocalSyntaxPtr; | ||
1 | use ra_syntax::ast::AstNode; | 2 | use ra_syntax::ast::AstNode; |
2 | use hir::{Ty, Def}; | 3 | use hir::{Ty, Def}; |
3 | 4 | ||
@@ -11,11 +12,14 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) -> Ca | |||
11 | _ => return Ok(()), | 12 | _ => return Ok(()), |
12 | }; | 13 | }; |
13 | let infer_result = function.infer(ctx.db)?; | 14 | let infer_result = function.infer(ctx.db)?; |
14 | let receiver_ty = if let Some(ty) = infer_result.type_of_node(receiver.syntax()) { | 15 | let syntax_mapping = function.body_syntax_mapping(ctx.db)?; |
15 | ty | 16 | let expr = |
16 | } else { | 17 | if let Some(expr) = syntax_mapping.syntax_expr(LocalSyntaxPtr::new(receiver.syntax())) { |
17 | return Ok(()); | 18 | expr |
18 | }; | 19 | } else { |
20 | return Ok(()); | ||
21 | }; | ||
22 | let receiver_ty = infer_result[expr].clone(); | ||
19 | if !ctx.is_method_call { | 23 | if !ctx.is_method_call { |
20 | complete_fields(acc, ctx, receiver_ty)?; | 24 | complete_fields(acc, ctx, receiver_ty)?; |
21 | } | 25 | } |
diff --git a/crates/ra_analysis/src/hover.rs b/crates/ra_analysis/src/hover.rs index ba1fb9beb..067e5c12d 100644 --- a/crates/ra_analysis/src/hover.rs +++ b/crates/ra_analysis/src/hover.rs | |||
@@ -64,7 +64,14 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable<Option | |||
64 | parent_fn | 64 | parent_fn |
65 | )?); | 65 | )?); |
66 | let infer = function.infer(db)?; | 66 | let infer = function.infer(db)?; |
67 | Ok(infer.type_of_node(node).map(|t| t.to_string())) | 67 | let syntax_mapping = function.body_syntax_mapping(db)?; |
68 | if let Some(expr) = syntax_mapping.node_expr(node) { | ||
69 | Ok(Some(infer[expr].to_string())) | ||
70 | } else if let Some(pat) = syntax_mapping.node_pat(node) { | ||
71 | Ok(Some(infer[pat].to_string())) | ||
72 | } else { | ||
73 | Ok(None) | ||
74 | } | ||
68 | } | 75 | } |
69 | 76 | ||
70 | // FIXME: this should not really use navigation target. Rather, approximatelly | 77 | // FIXME: this should not really use navigation target. Rather, approximatelly |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 6866fc2ac..c87d76735 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -5,7 +5,7 @@ use rustc_hash::FxHashMap; | |||
5 | 5 | ||
6 | use ra_arena::{Arena, RawId, impl_arena_id}; | 6 | use ra_arena::{Arena, RawId, impl_arena_id}; |
7 | use ra_db::{LocalSyntaxPtr, Cancelable}; | 7 | use ra_db::{LocalSyntaxPtr, Cancelable}; |
8 | use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner}; | 8 | use ra_syntax::{SyntaxNodeRef, ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner}}; |
9 | 9 | ||
10 | use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; | 10 | use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; |
11 | 11 | ||
@@ -77,12 +77,22 @@ impl BodySyntaxMapping { | |||
77 | pub fn syntax_expr(&self, ptr: LocalSyntaxPtr) -> Option<ExprId> { | 77 | pub fn syntax_expr(&self, ptr: LocalSyntaxPtr) -> Option<ExprId> { |
78 | self.expr_syntax_mapping.get(&ptr).cloned() | 78 | self.expr_syntax_mapping.get(&ptr).cloned() |
79 | } | 79 | } |
80 | pub fn node_expr(&self, node: SyntaxNodeRef) -> Option<ExprId> { | ||
81 | self.expr_syntax_mapping | ||
82 | .get(&LocalSyntaxPtr::new(node)) | ||
83 | .cloned() | ||
84 | } | ||
80 | pub fn pat_syntax(&self, pat: PatId) -> Option<LocalSyntaxPtr> { | 85 | pub fn pat_syntax(&self, pat: PatId) -> Option<LocalSyntaxPtr> { |
81 | self.pat_syntax_mapping_back.get(&pat).cloned() | 86 | self.pat_syntax_mapping_back.get(&pat).cloned() |
82 | } | 87 | } |
83 | pub fn syntax_pat(&self, ptr: LocalSyntaxPtr) -> Option<PatId> { | 88 | pub fn syntax_pat(&self, ptr: LocalSyntaxPtr) -> Option<PatId> { |
84 | self.pat_syntax_mapping.get(&ptr).cloned() | 89 | self.pat_syntax_mapping.get(&ptr).cloned() |
85 | } | 90 | } |
91 | pub fn node_pat(&self, node: SyntaxNodeRef) -> Option<PatId> { | ||
92 | self.pat_syntax_mapping | ||
93 | .get(&LocalSyntaxPtr::new(node)) | ||
94 | .cloned() | ||
95 | } | ||
86 | 96 | ||
87 | pub fn body(&self) -> &Arc<Body> { | 97 | pub fn body(&self) -> &Arc<Body> { |
88 | &self.body | 98 | &self.body |
@@ -159,6 +169,11 @@ pub enum Expr { | |||
159 | expr: ExprId, | 169 | expr: ExprId, |
160 | op: Option<UnaryOp>, | 170 | op: Option<UnaryOp>, |
161 | }, | 171 | }, |
172 | BinaryOp { | ||
173 | lhs: ExprId, | ||
174 | rhs: ExprId, | ||
175 | op: Option<BinaryOp>, | ||
176 | }, | ||
162 | Lambda { | 177 | Lambda { |
163 | args: Vec<PatId>, | 178 | args: Vec<PatId>, |
164 | arg_types: Vec<Option<TypeRef>>, | 179 | arg_types: Vec<Option<TypeRef>>, |
@@ -166,7 +181,8 @@ pub enum Expr { | |||
166 | }, | 181 | }, |
167 | } | 182 | } |
168 | 183 | ||
169 | pub type UnaryOp = ast::PrefixOp; | 184 | pub use ra_syntax::ast::PrefixOp as UnaryOp; |
185 | pub use ra_syntax::ast::BinOp as BinaryOp; | ||
170 | 186 | ||
171 | #[derive(Debug, Clone, Eq, PartialEq)] | 187 | #[derive(Debug, Clone, Eq, PartialEq)] |
172 | pub struct MatchArm { | 188 | pub struct MatchArm { |
@@ -266,6 +282,10 @@ impl Expr { | |||
266 | Expr::Lambda { body, .. } => { | 282 | Expr::Lambda { body, .. } => { |
267 | f(*body); | 283 | f(*body); |
268 | } | 284 | } |
285 | Expr::BinaryOp { lhs, rhs, .. } => { | ||
286 | f(*lhs); | ||
287 | f(*rhs); | ||
288 | } | ||
269 | Expr::Field { expr, .. } | 289 | Expr::Field { expr, .. } |
270 | | Expr::Try { expr } | 290 | | Expr::Try { expr } |
271 | | Expr::Cast { expr, .. } | 291 | | Expr::Cast { expr, .. } |
@@ -586,6 +606,12 @@ impl ExprCollector { | |||
586 | syntax_ptr, | 606 | syntax_ptr, |
587 | ) | 607 | ) |
588 | } | 608 | } |
609 | ast::Expr::BinExpr(e) => { | ||
610 | let lhs = self.collect_expr_opt(e.lhs()); | ||
611 | let rhs = self.collect_expr_opt(e.rhs()); | ||
612 | let op = e.op(); | ||
613 | self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr) | ||
614 | } | ||
589 | 615 | ||
590 | // TODO implement HIR for these: | 616 | // TODO implement HIR for these: |
591 | ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | 617 | ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), |
@@ -593,7 +619,6 @@ impl ExprCollector { | |||
593 | ast::Expr::TupleExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | 619 | ast::Expr::TupleExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), |
594 | ast::Expr::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | 620 | ast::Expr::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), |
595 | ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | 621 | ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), |
596 | ast::Expr::BinExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
597 | ast::Expr::Literal(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | 622 | ast::Expr::Literal(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), |
598 | } | 623 | } |
599 | } | 624 | } |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index b685259d7..6bdfdd7b4 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -17,6 +17,7 @@ mod primitive; | |||
17 | #[cfg(test)] | 17 | #[cfg(test)] |
18 | mod tests; | 18 | mod tests; |
19 | 19 | ||
20 | use std::ops::Index; | ||
20 | use std::sync::Arc; | 21 | use std::sync::Arc; |
21 | use std::{fmt, mem}; | 22 | use std::{fmt, mem}; |
22 | 23 | ||
@@ -24,18 +25,15 @@ use log; | |||
24 | use rustc_hash::FxHashMap; | 25 | use rustc_hash::FxHashMap; |
25 | use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError}; | 26 | use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError}; |
26 | 27 | ||
27 | use ra_db::{LocalSyntaxPtr, Cancelable}; | 28 | use ra_db::Cancelable; |
28 | use ra_syntax::{ | ||
29 | ast::{self, AstNode, LoopBodyOwner, ArgListOwner, PrefixOp, BinOp}, | ||
30 | SyntaxNodeRef | ||
31 | }; | ||
32 | 29 | ||
33 | use crate::{ | 30 | use crate::{ |
34 | Def, DefId, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock, | 31 | Def, DefId, Module, Function, Struct, Enum, Path, Name, ImplBlock, |
32 | FnSignature, FnScopes, | ||
35 | db::HirDatabase, | 33 | db::HirDatabase, |
36 | type_ref::{TypeRef, Mutability}, | 34 | type_ref::{TypeRef, Mutability}, |
37 | name::KnownName, | 35 | name::KnownName, |
38 | ScopesWithSyntaxMapping, | 36 | expr::{Body, Expr, ExprId, PatId, UnaryOp, BinaryOp, Statement}, |
39 | }; | 37 | }; |
40 | 38 | ||
41 | /// The ID of a type variable. | 39 | /// The ID of a type variable. |
@@ -82,9 +80,10 @@ impl UnifyValue for TypeVarValue { | |||
82 | match (value1, value2) { | 80 | match (value1, value2) { |
83 | // We should never equate two type variables, both of which have | 81 | // We should never equate two type variables, both of which have |
84 | // known types. Instead, we recursively equate those types. | 82 | // known types. Instead, we recursively equate those types. |
85 | (TypeVarValue::Known(..), TypeVarValue::Known(..)) => { | 83 | (TypeVarValue::Known(t1), TypeVarValue::Known(t2)) => panic!( |
86 | panic!("equating two type variables, both of which have known types") | 84 | "equating two type variables, both of which have known types: {:?} and {:?}", |
87 | } | 85 | t1, t2 |
86 | ), | ||
88 | 87 | ||
89 | // If one side is known, prefer that one. | 88 | // If one side is known, prefer that one. |
90 | (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()), | 89 | (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()), |
@@ -321,26 +320,6 @@ impl Ty { | |||
321 | Ok(ty) | 320 | Ok(ty) |
322 | } | 321 | } |
323 | 322 | ||
324 | // TODO: These should not be necessary long-term, since everything will work on HIR | ||
325 | pub(crate) fn from_ast_opt( | ||
326 | db: &impl HirDatabase, | ||
327 | module: &Module, | ||
328 | impl_block: Option<&ImplBlock>, | ||
329 | node: Option<ast::TypeRef>, | ||
330 | ) -> Cancelable<Self> { | ||
331 | node.map(|n| Ty::from_ast(db, module, impl_block, n)) | ||
332 | .unwrap_or(Ok(Ty::Unknown)) | ||
333 | } | ||
334 | |||
335 | pub(crate) fn from_ast( | ||
336 | db: &impl HirDatabase, | ||
337 | module: &Module, | ||
338 | impl_block: Option<&ImplBlock>, | ||
339 | node: ast::TypeRef, | ||
340 | ) -> Cancelable<Self> { | ||
341 | Ty::from_hir(db, module, impl_block, &TypeRef::from_ast(node)) | ||
342 | } | ||
343 | |||
344 | pub fn unit() -> Self { | 323 | pub fn unit() -> Self { |
345 | Ty::Tuple(Arc::new([])) | 324 | Ty::Tuple(Arc::new([])) |
346 | } | 325 | } |
@@ -417,26 +396,18 @@ impl fmt::Display for Ty { | |||
417 | // Functions returning declared types for items | 396 | // Functions returning declared types for items |
418 | 397 | ||
419 | /// Compute the declared type of a function. This should not need to look at the | 398 | /// Compute the declared type of a function. This should not need to look at the |
420 | /// function body (but currently uses the function AST, so does anyway - TODO). | 399 | /// function body. |
421 | fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { | 400 | fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { |
422 | let syntax = f.syntax(db); | 401 | let signature = f.signature(db); |
423 | let module = f.module(db)?; | 402 | let module = f.module(db)?; |
424 | let impl_block = f.impl_block(db)?; | 403 | let impl_block = f.impl_block(db)?; |
425 | let node = syntax.borrowed(); | ||
426 | // TODO we ignore type parameters for now | 404 | // TODO we ignore type parameters for now |
427 | let input = node | 405 | let input = signature |
428 | .param_list() | 406 | .args() |
429 | .map(|pl| { | 407 | .iter() |
430 | pl.params() | 408 | .map(|tr| Ty::from_hir(db, &module, impl_block.as_ref(), tr)) |
431 | .map(|p| Ty::from_ast_opt(db, &module, impl_block.as_ref(), p.type_ref())) | 409 | .collect::<Cancelable<Vec<_>>>()?; |
432 | .collect() | 410 | let output = Ty::from_hir(db, &module, impl_block.as_ref(), signature.ret_type())?; |
433 | }) | ||
434 | .unwrap_or_else(|| Ok(Vec::new()))?; | ||
435 | let output = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) { | ||
436 | Ty::from_ast(db, &module, impl_block.as_ref(), type_ref)? | ||
437 | } else { | ||
438 | Ty::unit() | ||
439 | }; | ||
440 | let sig = FnSig { input, output }; | 411 | let sig = FnSig { input, output }; |
441 | Ok(Ty::FnPtr(Arc::new(sig))) | 412 | Ok(Ty::FnPtr(Arc::new(sig))) |
442 | } | 413 | } |
@@ -499,16 +470,23 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name) | |||
499 | /// The result of type inference: A mapping from expressions and patterns to types. | 470 | /// The result of type inference: A mapping from expressions and patterns to types. |
500 | #[derive(Clone, PartialEq, Eq, Debug)] | 471 | #[derive(Clone, PartialEq, Eq, Debug)] |
501 | pub struct InferenceResult { | 472 | pub struct InferenceResult { |
502 | type_of: FxHashMap<LocalSyntaxPtr, Ty>, | 473 | type_of_expr: FxHashMap<ExprId, Ty>, |
474 | type_of_pat: FxHashMap<PatId, Ty>, | ||
503 | } | 475 | } |
504 | 476 | ||
505 | impl InferenceResult { | 477 | impl Index<ExprId> for InferenceResult { |
506 | /// Returns the type of the given syntax node, if it was inferred. Will | 478 | type Output = Ty; |
507 | /// return `None` for syntax nodes not in the inferred function or not | 479 | |
508 | /// pointing to an expression/pattern, `Some(Ty::Unknown)` for | 480 | fn index(&self, expr: ExprId) -> &Ty { |
509 | /// expressions/patterns that could not be inferred. | 481 | self.type_of_expr.get(&expr).unwrap_or(&Ty::Unknown) |
510 | pub fn type_of_node(&self, node: SyntaxNodeRef) -> Option<Ty> { | 482 | } |
511 | self.type_of.get(&LocalSyntaxPtr::new(node)).cloned() | 483 | } |
484 | |||
485 | impl Index<PatId> for InferenceResult { | ||
486 | type Output = Ty; | ||
487 | |||
488 | fn index(&self, pat: PatId) -> &Ty { | ||
489 | self.type_of_pat.get(&pat).unwrap_or(&Ty::Unknown) | ||
512 | } | 490 | } |
513 | } | 491 | } |
514 | 492 | ||
@@ -516,44 +494,46 @@ impl InferenceResult { | |||
516 | #[derive(Clone, Debug)] | 494 | #[derive(Clone, Debug)] |
517 | struct InferenceContext<'a, D: HirDatabase> { | 495 | struct InferenceContext<'a, D: HirDatabase> { |
518 | db: &'a D, | 496 | db: &'a D, |
519 | scopes: ScopesWithSyntaxMapping, | 497 | body: Arc<Body>, |
520 | /// The self param for the current method, if it exists. | 498 | scopes: Arc<FnScopes>, |
521 | self_param: Option<LocalSyntaxPtr>, | ||
522 | module: Module, | 499 | module: Module, |
523 | impl_block: Option<ImplBlock>, | 500 | impl_block: Option<ImplBlock>, |
524 | var_unification_table: InPlaceUnificationTable<TypeVarId>, | 501 | var_unification_table: InPlaceUnificationTable<TypeVarId>, |
525 | type_of: FxHashMap<LocalSyntaxPtr, Ty>, | 502 | type_of_expr: FxHashMap<ExprId, Ty>, |
503 | type_of_pat: FxHashMap<PatId, Ty>, | ||
526 | /// The return type of the function being inferred. | 504 | /// The return type of the function being inferred. |
527 | return_ty: Ty, | 505 | return_ty: Ty, |
528 | } | 506 | } |
529 | 507 | ||
530 | // helper function that determines whether a binary operator | 508 | // helper function that determines whether a binary operator |
531 | // always returns a boolean | 509 | // always returns a boolean |
532 | fn is_boolean_operator(op: BinOp) -> bool { | 510 | fn is_boolean_operator(op: BinaryOp) -> bool { |
533 | match op { | 511 | match op { |
534 | BinOp::BooleanOr | 512 | BinaryOp::BooleanOr |
535 | | BinOp::BooleanAnd | 513 | | BinaryOp::BooleanAnd |
536 | | BinOp::EqualityTest | 514 | | BinaryOp::EqualityTest |
537 | | BinOp::LesserEqualTest | 515 | | BinaryOp::LesserEqualTest |
538 | | BinOp::GreaterEqualTest | 516 | | BinaryOp::GreaterEqualTest |
539 | | BinOp::LesserTest | 517 | | BinaryOp::LesserTest |
540 | | BinOp::GreaterTest => true, | 518 | | BinaryOp::GreaterTest => true, |
541 | } | 519 | } |
542 | } | 520 | } |
543 | 521 | ||
544 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 522 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
545 | fn new( | 523 | fn new( |
546 | db: &'a D, | 524 | db: &'a D, |
547 | scopes: ScopesWithSyntaxMapping, | 525 | body: Arc<Body>, |
526 | scopes: Arc<FnScopes>, | ||
548 | module: Module, | 527 | module: Module, |
549 | impl_block: Option<ImplBlock>, | 528 | impl_block: Option<ImplBlock>, |
550 | ) -> Self { | 529 | ) -> Self { |
551 | InferenceContext { | 530 | InferenceContext { |
552 | type_of: FxHashMap::default(), | 531 | type_of_expr: FxHashMap::default(), |
532 | type_of_pat: FxHashMap::default(), | ||
553 | var_unification_table: InPlaceUnificationTable::new(), | 533 | var_unification_table: InPlaceUnificationTable::new(), |
554 | self_param: None, // set during parameter typing | ||
555 | return_ty: Ty::Unknown, // set in collect_fn_signature | 534 | return_ty: Ty::Unknown, // set in collect_fn_signature |
556 | db, | 535 | db, |
536 | body, | ||
557 | scopes, | 537 | scopes, |
558 | module, | 538 | module, |
559 | impl_block, | 539 | impl_block, |
@@ -561,24 +541,32 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
561 | } | 541 | } |
562 | 542 | ||
563 | fn resolve_all(mut self) -> InferenceResult { | 543 | fn resolve_all(mut self) -> InferenceResult { |
564 | let mut types = mem::replace(&mut self.type_of, FxHashMap::default()); | 544 | let mut expr_types = mem::replace(&mut self.type_of_expr, FxHashMap::default()); |
565 | for ty in types.values_mut() { | 545 | for ty in expr_types.values_mut() { |
546 | let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); | ||
547 | *ty = resolved; | ||
548 | } | ||
549 | let mut pat_types = mem::replace(&mut self.type_of_pat, FxHashMap::default()); | ||
550 | for ty in pat_types.values_mut() { | ||
566 | let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); | 551 | let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); |
567 | *ty = resolved; | 552 | *ty = resolved; |
568 | } | 553 | } |
569 | InferenceResult { type_of: types } | 554 | InferenceResult { |
555 | type_of_expr: expr_types, | ||
556 | type_of_pat: pat_types, | ||
557 | } | ||
570 | } | 558 | } |
571 | 559 | ||
572 | fn write_ty(&mut self, node: SyntaxNodeRef, ty: Ty) { | 560 | fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) { |
573 | self.type_of.insert(LocalSyntaxPtr::new(node), ty); | 561 | self.type_of_expr.insert(expr, ty); |
574 | } | 562 | } |
575 | 563 | ||
576 | fn make_ty(&self, type_ref: &TypeRef) -> Cancelable<Ty> { | 564 | fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { |
577 | Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref) | 565 | self.type_of_pat.insert(pat, ty); |
578 | } | 566 | } |
579 | 567 | ||
580 | fn make_ty_opt(&self, type_ref: Option<&TypeRef>) -> Cancelable<Ty> { | 568 | fn make_ty(&self, type_ref: &TypeRef) -> Cancelable<Ty> { |
581 | Ty::from_hir_opt(self.db, &self.module, self.impl_block.as_ref(), type_ref) | 569 | Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref) |
582 | } | 570 | } |
583 | 571 | ||
584 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | 572 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { |
@@ -673,23 +661,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
673 | }) | 661 | }) |
674 | } | 662 | } |
675 | 663 | ||
676 | fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Cancelable<Option<Ty>> { | 664 | fn infer_path_expr(&mut self, expr: ExprId, path: &Path) -> Cancelable<Option<Ty>> { |
677 | let ast_path = ctry!(expr.path()); | 665 | if path.is_ident() || path.is_self() { |
678 | let path = ctry!(Path::from_ast(ast_path)); | ||
679 | if path.is_ident() { | ||
680 | // resolve locally | 666 | // resolve locally |
681 | let name = ctry!(ast_path.segment().and_then(|s| s.name_ref())); | 667 | let name = path.as_ident().cloned().unwrap_or_else(Name::self_param); |
682 | if let Some(scope_entry) = self.scopes.resolve_local_name(name) { | 668 | if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) { |
683 | let ty = ctry!(self.type_of.get(&scope_entry.ptr())); | 669 | let ty = ctry!(self.type_of_pat.get(&scope_entry.pat())); |
684 | let ty = self.resolve_ty_as_possible(ty.clone()); | 670 | let ty = self.resolve_ty_as_possible(ty.clone()); |
685 | return Ok(Some(ty)); | 671 | return Ok(Some(ty)); |
686 | }; | 672 | }; |
687 | } else if path.is_self() { | ||
688 | // resolve `self` param | ||
689 | let self_param = ctry!(self.self_param); | ||
690 | let ty = ctry!(self.type_of.get(&self_param)); | ||
691 | let ty = self.resolve_ty_as_possible(ty.clone()); | ||
692 | return Ok(Some(ty)); | ||
693 | }; | 673 | }; |
694 | 674 | ||
695 | // resolve in module | 675 | // resolve in module |
@@ -699,8 +679,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
699 | Ok(Some(ty)) | 679 | Ok(Some(ty)) |
700 | } | 680 | } |
701 | 681 | ||
702 | fn resolve_variant(&self, path: Option<ast::Path>) -> Cancelable<(Ty, Option<DefId>)> { | 682 | fn resolve_variant(&self, path: Option<&Path>) -> Cancelable<(Ty, Option<DefId>)> { |
703 | let path = if let Some(path) = path.and_then(Path::from_ast) { | 683 | let path = if let Some(path) = path { |
704 | path | 684 | path |
705 | } else { | 685 | } else { |
706 | return Ok((Ty::Unknown, None)); | 686 | return Ok((Ty::Unknown, None)); |
@@ -719,74 +699,51 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
719 | }) | 699 | }) |
720 | } | 700 | } |
721 | 701 | ||
722 | fn infer_expr_opt( | 702 | fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Cancelable<Ty> { |
723 | &mut self, | 703 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
724 | expr: Option<ast::Expr>, | 704 | let ty = match &body[expr] { |
725 | expected: &Expectation, | 705 | Expr::Missing => Ty::Unknown, |
726 | ) -> Cancelable<Ty> { | 706 | Expr::If { |
727 | if let Some(e) = expr { | 707 | condition, |
728 | self.infer_expr(e, expected) | 708 | then_branch, |
729 | } else { | 709 | else_branch, |
730 | Ok(Ty::Unknown) | 710 | } => { |
731 | } | 711 | // if let is desugared to match, so this is always simple if |
732 | } | 712 | self.infer_expr(*condition, &Expectation::has_type(Ty::Bool))?; |
733 | 713 | let then_ty = self.infer_expr(*then_branch, expected)?; | |
734 | fn infer_expr(&mut self, expr: ast::Expr, expected: &Expectation) -> Cancelable<Ty> { | 714 | if let Some(else_branch) = else_branch { |
735 | let ty = match expr { | 715 | self.infer_expr(*else_branch, expected)?; |
736 | ast::Expr::IfExpr(e) => { | ||
737 | if let Some(condition) = e.condition() { | ||
738 | let expected = if condition.pat().is_none() { | ||
739 | Expectation::has_type(Ty::Bool) | ||
740 | } else { | ||
741 | Expectation::none() | ||
742 | }; | ||
743 | self.infer_expr_opt(condition.expr(), &expected)?; | ||
744 | // TODO write type for pat | ||
745 | }; | ||
746 | let if_ty = self.infer_block_opt(e.then_branch(), expected)?; | ||
747 | if let Some(else_branch) = e.else_branch() { | ||
748 | self.infer_block(else_branch, expected)?; | ||
749 | } else { | 716 | } else { |
750 | // no else branch -> unit | 717 | // no else branch -> unit |
751 | self.unify(&expected.ty, &Ty::unit()); // actually coerce | 718 | self.unify(&expected.ty, &Ty::unit()); // actually coerce |
752 | } | 719 | } |
753 | if_ty | 720 | then_ty |
754 | } | 721 | } |
755 | ast::Expr::BlockExpr(e) => self.infer_block_opt(e.block(), expected)?, | 722 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected)?, |
756 | ast::Expr::LoopExpr(e) => { | 723 | Expr::Loop { body } => { |
757 | self.infer_block_opt(e.loop_body(), &Expectation::has_type(Ty::unit()))?; | 724 | self.infer_expr(*body, &Expectation::has_type(Ty::unit()))?; |
758 | // TODO never, or the type of the break param | 725 | // TODO handle break with value |
759 | Ty::Unknown | 726 | Ty::Never |
760 | } | 727 | } |
761 | ast::Expr::WhileExpr(e) => { | 728 | Expr::While { condition, body } => { |
762 | if let Some(condition) = e.condition() { | 729 | // while let is desugared to a match loop, so this is always simple while |
763 | let expected = if condition.pat().is_none() { | 730 | self.infer_expr(*condition, &Expectation::has_type(Ty::Bool))?; |
764 | Expectation::has_type(Ty::Bool) | 731 | self.infer_expr(*body, &Expectation::has_type(Ty::unit()))?; |
765 | } else { | ||
766 | Expectation::none() | ||
767 | }; | ||
768 | self.infer_expr_opt(condition.expr(), &expected)?; | ||
769 | // TODO write type for pat | ||
770 | }; | ||
771 | self.infer_block_opt(e.loop_body(), &Expectation::has_type(Ty::unit()))?; | ||
772 | // TODO always unit? | ||
773 | Ty::unit() | 732 | Ty::unit() |
774 | } | 733 | } |
775 | ast::Expr::ForExpr(e) => { | 734 | Expr::For { iterable, body, .. } => { |
776 | let _iterable_ty = self.infer_expr_opt(e.iterable(), &Expectation::none()); | 735 | let _iterable_ty = self.infer_expr(*iterable, &Expectation::none()); |
777 | if let Some(_pat) = e.pat() { | 736 | // TODO write type for pat |
778 | // TODO write type for pat | 737 | self.infer_expr(*body, &Expectation::has_type(Ty::unit()))?; |
779 | } | ||
780 | self.infer_block_opt(e.loop_body(), &Expectation::has_type(Ty::unit()))?; | ||
781 | // TODO always unit? | ||
782 | Ty::unit() | 738 | Ty::unit() |
783 | } | 739 | } |
784 | ast::Expr::LambdaExpr(e) => { | 740 | Expr::Lambda { body, .. } => { |
785 | let _body_ty = self.infer_expr_opt(e.body(), &Expectation::none())?; | 741 | // TODO write types for args, infer lambda type etc. |
742 | let _body_ty = self.infer_expr(*body, &Expectation::none())?; | ||
786 | Ty::Unknown | 743 | Ty::Unknown |
787 | } | 744 | } |
788 | ast::Expr::CallExpr(e) => { | 745 | Expr::Call { callee, args } => { |
789 | let callee_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; | 746 | let callee_ty = self.infer_expr(*callee, &Expectation::none())?; |
790 | let (arg_tys, ret_ty) = match &callee_ty { | 747 | let (arg_tys, ret_ty) = match &callee_ty { |
791 | Ty::FnPtr(sig) => (&sig.input[..], sig.output.clone()), | 748 | Ty::FnPtr(sig) => (&sig.input[..], sig.output.clone()), |
792 | _ => { | 749 | _ => { |
@@ -795,112 +752,102 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
795 | (&[][..], Ty::Unknown) | 752 | (&[][..], Ty::Unknown) |
796 | } | 753 | } |
797 | }; | 754 | }; |
798 | if let Some(arg_list) = e.arg_list() { | 755 | for (i, arg) in args.iter().enumerate() { |
799 | for (i, arg) in arg_list.args().enumerate() { | 756 | self.infer_expr( |
800 | self.infer_expr( | 757 | *arg, |
801 | arg, | 758 | &Expectation::has_type(arg_tys.get(i).cloned().unwrap_or(Ty::Unknown)), |
802 | &Expectation::has_type(arg_tys.get(i).cloned().unwrap_or(Ty::Unknown)), | 759 | )?; |
803 | )?; | ||
804 | } | ||
805 | } | 760 | } |
806 | ret_ty | 761 | ret_ty |
807 | } | 762 | } |
808 | ast::Expr::MethodCallExpr(e) => { | 763 | Expr::MethodCall { receiver, args, .. } => { |
809 | let _receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; | 764 | let _receiver_ty = self.infer_expr(*receiver, &Expectation::none())?; |
810 | if let Some(arg_list) = e.arg_list() { | 765 | // TODO resolve method... |
811 | for arg in arg_list.args() { | 766 | for (_i, arg) in args.iter().enumerate() { |
812 | // TODO unify / expect argument type | 767 | // TODO unify / expect argument type |
813 | self.infer_expr(arg, &Expectation::none())?; | 768 | self.infer_expr(*arg, &Expectation::none())?; |
814 | } | ||
815 | } | 769 | } |
816 | Ty::Unknown | 770 | Ty::Unknown |
817 | } | 771 | } |
818 | ast::Expr::MatchExpr(e) => { | 772 | Expr::Match { expr, arms } => { |
819 | let _ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; | 773 | let _ty = self.infer_expr(*expr, &Expectation::none())?; |
820 | if let Some(match_arm_list) = e.match_arm_list() { | 774 | for arm in arms { |
821 | for arm in match_arm_list.arms() { | 775 | // TODO type the bindings in pats |
822 | // TODO type the bindings in pat | 776 | // TODO type the guard |
823 | // TODO type the guard | 777 | let _ty = self.infer_expr(arm.expr, &Expectation::none())?; |
824 | let _ty = self.infer_expr_opt(arm.expr(), &Expectation::none())?; | ||
825 | } | ||
826 | // TODO unify all the match arm types | ||
827 | Ty::Unknown | ||
828 | } else { | ||
829 | Ty::Unknown | ||
830 | } | 778 | } |
779 | // TODO unify all the match arm types | ||
780 | Ty::Unknown | ||
831 | } | 781 | } |
832 | ast::Expr::TupleExpr(_e) => Ty::Unknown, | 782 | Expr::Path(p) => self.infer_path_expr(expr, p)?.unwrap_or(Ty::Unknown), |
833 | ast::Expr::ArrayExpr(_e) => Ty::Unknown, | 783 | Expr::Continue => Ty::Never, |
834 | ast::Expr::PathExpr(e) => self.infer_path_expr(e)?.unwrap_or(Ty::Unknown), | 784 | Expr::Break { expr } => { |
835 | ast::Expr::ContinueExpr(_e) => Ty::Never, | 785 | if let Some(expr) = expr { |
836 | ast::Expr::BreakExpr(_e) => Ty::Never, | 786 | // TODO handle break with value |
837 | ast::Expr::ParenExpr(e) => self.infer_expr_opt(e.expr(), expected)?, | 787 | self.infer_expr(*expr, &Expectation::none())?; |
838 | ast::Expr::Label(_e) => Ty::Unknown, | 788 | } |
839 | ast::Expr::ReturnExpr(e) => { | ||
840 | // TODO expect return type of function | ||
841 | self.infer_expr_opt(e.expr(), &Expectation::none())?; | ||
842 | Ty::Never | 789 | Ty::Never |
843 | } | 790 | } |
844 | ast::Expr::StructLit(e) => { | 791 | Expr::Return { expr } => { |
845 | let (ty, def_id) = self.resolve_variant(e.path())?; | 792 | if let Some(expr) = expr { |
846 | if let Some(nfl) = e.named_field_list() { | 793 | self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone()))?; |
847 | for field in nfl.fields() { | ||
848 | let field_ty = if let (Some(def_id), Some(nr)) = (def_id, field.name_ref()) | ||
849 | { | ||
850 | self.db.type_for_field(def_id, nr.as_name())? | ||
851 | } else { | ||
852 | Ty::Unknown | ||
853 | }; | ||
854 | self.infer_expr_opt(field.expr(), &Expectation::has_type(field_ty))?; | ||
855 | } | ||
856 | } | 794 | } |
857 | ty | 795 | Ty::Never |
858 | } | 796 | } |
859 | ast::Expr::IndexExpr(_e) => Ty::Unknown, | 797 | Expr::StructLit { |
860 | ast::Expr::FieldExpr(e) => { | 798 | path, |
861 | let receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; | 799 | fields, |
862 | if let Some(nr) = e.name_ref() { | 800 | spread, |
863 | let ty = match receiver_ty { | 801 | } => { |
864 | Ty::Tuple(fields) => { | 802 | let (ty, def_id) = self.resolve_variant(path.as_ref())?; |
865 | let i = nr.text().parse::<usize>().ok(); | 803 | for field in fields { |
866 | i.and_then(|i| fields.get(i).cloned()) | 804 | let field_ty = if let Some(def_id) = def_id { |
867 | .unwrap_or(Ty::Unknown) | 805 | self.db.type_for_field(def_id, field.name.clone())? |
868 | } | 806 | } else { |
869 | Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, nr.as_name())?, | 807 | Ty::Unknown |
870 | _ => Ty::Unknown, | ||
871 | }; | 808 | }; |
872 | self.insert_type_vars(ty) | 809 | self.infer_expr(field.expr, &Expectation::has_type(field_ty))?; |
873 | } else { | 810 | } |
874 | Ty::Unknown | 811 | if let Some(expr) = spread { |
812 | self.infer_expr(*expr, &Expectation::has_type(ty.clone()))?; | ||
875 | } | 813 | } |
814 | ty | ||
815 | } | ||
816 | Expr::Field { expr, name } => { | ||
817 | let receiver_ty = self.infer_expr(*expr, &Expectation::none())?; | ||
818 | let ty = match receiver_ty { | ||
819 | Ty::Tuple(fields) => { | ||
820 | let i = name.to_string().parse::<usize>().ok(); | ||
821 | i.and_then(|i| fields.get(i).cloned()) | ||
822 | .unwrap_or(Ty::Unknown) | ||
823 | } | ||
824 | Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, name.clone())?, | ||
825 | _ => Ty::Unknown, | ||
826 | }; | ||
827 | self.insert_type_vars(ty) | ||
876 | } | 828 | } |
877 | ast::Expr::TryExpr(e) => { | 829 | Expr::Try { expr } => { |
878 | let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; | 830 | let _inner_ty = self.infer_expr(*expr, &Expectation::none())?; |
879 | Ty::Unknown | 831 | Ty::Unknown |
880 | } | 832 | } |
881 | ast::Expr::CastExpr(e) => { | 833 | Expr::Cast { expr, type_ref } => { |
882 | let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; | 834 | let _inner_ty = self.infer_expr(*expr, &Expectation::none())?; |
883 | let cast_ty = Ty::from_ast_opt( | 835 | let cast_ty = |
884 | self.db, | 836 | Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref)?; |
885 | &self.module, | ||
886 | self.impl_block.as_ref(), | ||
887 | e.type_ref(), | ||
888 | )?; | ||
889 | let cast_ty = self.insert_type_vars(cast_ty); | 837 | let cast_ty = self.insert_type_vars(cast_ty); |
890 | // TODO do the coercion... | 838 | // TODO check the cast... |
891 | cast_ty | 839 | cast_ty |
892 | } | 840 | } |
893 | ast::Expr::RefExpr(e) => { | 841 | Expr::Ref { expr, mutability } => { |
894 | // TODO pass the expectation down | 842 | // TODO pass the expectation down |
895 | let inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; | 843 | let inner_ty = self.infer_expr(*expr, &Expectation::none())?; |
896 | let m = Mutability::from_mutable(e.is_mut()); | ||
897 | // TODO reference coercions etc. | 844 | // TODO reference coercions etc. |
898 | Ty::Ref(Arc::new(inner_ty), m) | 845 | Ty::Ref(Arc::new(inner_ty), *mutability) |
899 | } | 846 | } |
900 | ast::Expr::PrefixExpr(e) => { | 847 | Expr::UnaryOp { expr, op } => { |
901 | let inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; | 848 | let inner_ty = self.infer_expr(*expr, &Expectation::none())?; |
902 | match e.op() { | 849 | match op { |
903 | Some(PrefixOp::Deref) => { | 850 | Some(UnaryOp::Deref) => { |
904 | match inner_ty { | 851 | match inner_ty { |
905 | // builtin deref: | 852 | // builtin deref: |
906 | Ty::Ref(ref_inner, _) => (*ref_inner).clone(), | 853 | Ty::Ref(ref_inner, _) => (*ref_inner).clone(), |
@@ -912,18 +859,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
912 | _ => Ty::Unknown, | 859 | _ => Ty::Unknown, |
913 | } | 860 | } |
914 | } | 861 | } |
915 | ast::Expr::RangeExpr(_e) => Ty::Unknown, | 862 | Expr::BinaryOp { lhs, rhs, op } => match op { |
916 | ast::Expr::BinExpr(e) => match e.op() { | ||
917 | Some(op) => { | 863 | Some(op) => { |
918 | let subtype_expectation = match op { | 864 | let subtype_expectation = match op { |
919 | BinOp::BooleanAnd | BinOp::BooleanOr => Expectation::has_type(Ty::Bool), | 865 | BinaryOp::BooleanAnd | BinaryOp::BooleanOr => { |
866 | Expectation::has_type(Ty::Bool) | ||
867 | } | ||
920 | _ => Expectation::none(), | 868 | _ => Expectation::none(), |
921 | }; | 869 | }; |
922 | let (lhs, rhs) = e.sub_exprs(); | 870 | let _lhs_ty = self.infer_expr(*lhs, &subtype_expectation)?; |
923 | let _lhs_ty = self.infer_expr_opt(lhs, &subtype_expectation)?; | 871 | let _rhs_ty = self.infer_expr(*rhs, &subtype_expectation)?; |
924 | let _rhs_ty = self.infer_expr_opt(rhs, &subtype_expectation)?; | ||
925 | 872 | ||
926 | if is_boolean_operator(op) { | 873 | if is_boolean_operator(*op) { |
927 | Ty::Bool | 874 | Ty::Bool |
928 | } else { | 875 | } else { |
929 | Ty::Unknown | 876 | Ty::Unknown |
@@ -931,128 +878,93 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
931 | } | 878 | } |
932 | _ => Ty::Unknown, | 879 | _ => Ty::Unknown, |
933 | }, | 880 | }, |
934 | ast::Expr::Literal(_e) => Ty::Unknown, | ||
935 | }; | 881 | }; |
936 | // use a new type variable if we got Ty::Unknown here | 882 | // use a new type variable if we got Ty::Unknown here |
937 | let ty = self.insert_type_vars_shallow(ty); | 883 | let ty = self.insert_type_vars_shallow(ty); |
938 | self.unify(&ty, &expected.ty); | 884 | self.unify(&ty, &expected.ty); |
939 | self.write_ty(expr.syntax(), ty.clone()); | 885 | let ty = self.resolve_ty_as_possible(ty); |
886 | self.write_expr_ty(expr, ty.clone()); | ||
940 | Ok(ty) | 887 | Ok(ty) |
941 | } | 888 | } |
942 | 889 | ||
943 | fn infer_block_opt( | 890 | fn infer_block( |
944 | &mut self, | 891 | &mut self, |
945 | node: Option<ast::Block>, | 892 | statements: &[Statement], |
893 | tail: Option<ExprId>, | ||
946 | expected: &Expectation, | 894 | expected: &Expectation, |
947 | ) -> Cancelable<Ty> { | 895 | ) -> Cancelable<Ty> { |
948 | if let Some(b) = node { | 896 | for stmt in statements { |
949 | self.infer_block(b, expected) | ||
950 | } else { | ||
951 | Ok(Ty::Unknown) | ||
952 | } | ||
953 | } | ||
954 | |||
955 | fn infer_block(&mut self, node: ast::Block, expected: &Expectation) -> Cancelable<Ty> { | ||
956 | for stmt in node.statements() { | ||
957 | match stmt { | 897 | match stmt { |
958 | ast::Stmt::LetStmt(stmt) => { | 898 | Statement::Let { |
959 | let decl_ty = Ty::from_ast_opt( | 899 | pat, |
900 | type_ref, | ||
901 | initializer, | ||
902 | } => { | ||
903 | let decl_ty = Ty::from_hir_opt( | ||
960 | self.db, | 904 | self.db, |
961 | &self.module, | 905 | &self.module, |
962 | self.impl_block.as_ref(), | 906 | self.impl_block.as_ref(), |
963 | stmt.type_ref(), | 907 | type_ref.as_ref(), |
964 | )?; | 908 | )?; |
965 | let decl_ty = self.insert_type_vars(decl_ty); | 909 | let decl_ty = self.insert_type_vars(decl_ty); |
966 | let ty = if let Some(expr) = stmt.initializer() { | 910 | let ty = if let Some(expr) = initializer { |
967 | let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?; | 911 | let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty))?; |
968 | expr_ty | 912 | expr_ty |
969 | } else { | 913 | } else { |
970 | decl_ty | 914 | decl_ty |
971 | }; | 915 | }; |
972 | 916 | ||
973 | if let Some(pat) = stmt.pat() { | 917 | self.write_pat_ty(*pat, ty); |
974 | self.write_ty(pat.syntax(), ty); | ||
975 | }; | ||
976 | } | 918 | } |
977 | ast::Stmt::ExprStmt(expr_stmt) => { | 919 | Statement::Expr(expr) => { |
978 | self.infer_expr_opt(expr_stmt.expr(), &Expectation::none())?; | 920 | self.infer_expr(*expr, &Expectation::none())?; |
979 | } | 921 | } |
980 | } | 922 | } |
981 | } | 923 | } |
982 | let ty = if let Some(expr) = node.expr() { | 924 | let ty = if let Some(expr) = tail { |
983 | self.infer_expr(expr, expected)? | 925 | self.infer_expr(expr, expected)? |
984 | } else { | 926 | } else { |
985 | Ty::unit() | 927 | Ty::unit() |
986 | }; | 928 | }; |
987 | self.write_ty(node.syntax(), ty.clone()); | ||
988 | Ok(ty) | 929 | Ok(ty) |
989 | } | 930 | } |
990 | 931 | ||
991 | fn collect_fn_signature(&mut self, node: ast::FnDef) -> Cancelable<()> { | 932 | fn collect_fn_signature(&mut self, signature: &FnSignature) -> Cancelable<()> { |
992 | if let Some(param_list) = node.param_list() { | 933 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
993 | if let Some(self_param) = param_list.self_param() { | 934 | for (type_ref, pat) in signature.args().iter().zip(body.args()) { |
994 | let self_type = if let Some(type_ref) = self_param.type_ref() { | 935 | let ty = self.make_ty(type_ref)?; |
995 | let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; | 936 | let ty = self.insert_type_vars(ty); |
996 | self.insert_type_vars(ty) | 937 | self.write_pat_ty(*pat, ty); |
997 | } else { | ||
998 | // TODO this should be handled by desugaring during HIR conversion | ||
999 | let ty = self.make_ty_opt(self.impl_block.as_ref().map(|i| i.target_type()))?; | ||
1000 | let ty = match self_param.flavor() { | ||
1001 | ast::SelfParamFlavor::Owned => ty, | ||
1002 | ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared), | ||
1003 | ast::SelfParamFlavor::MutRef => Ty::Ref(Arc::new(ty), Mutability::Mut), | ||
1004 | }; | ||
1005 | self.insert_type_vars(ty) | ||
1006 | }; | ||
1007 | if let Some(self_kw) = self_param.self_kw() { | ||
1008 | let self_param = LocalSyntaxPtr::new(self_kw.syntax()); | ||
1009 | self.self_param = Some(self_param); | ||
1010 | self.type_of.insert(self_param, self_type); | ||
1011 | } | ||
1012 | } | ||
1013 | for param in param_list.params() { | ||
1014 | let pat = if let Some(pat) = param.pat() { | ||
1015 | pat | ||
1016 | } else { | ||
1017 | continue; | ||
1018 | }; | ||
1019 | let ty = if let Some(type_ref) = param.type_ref() { | ||
1020 | let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; | ||
1021 | self.insert_type_vars(ty) | ||
1022 | } else { | ||
1023 | // missing type annotation | ||
1024 | self.new_type_var() | ||
1025 | }; | ||
1026 | self.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty); | ||
1027 | } | ||
1028 | } | 938 | } |
1029 | 939 | self.return_ty = { | |
1030 | self.return_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) { | 940 | let ty = self.make_ty(signature.ret_type())?; |
1031 | let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; | 941 | let ty = self.insert_type_vars(ty); |
1032 | self.insert_type_vars(ty) | 942 | ty |
1033 | } else { | ||
1034 | Ty::unit() | ||
1035 | }; | 943 | }; |
944 | Ok(()) | ||
945 | } | ||
1036 | 946 | ||
947 | fn infer_body(&mut self) -> Cancelable<()> { | ||
948 | self.infer_expr( | ||
949 | self.body.body_expr(), | ||
950 | &Expectation::has_type(self.return_ty.clone()), | ||
951 | )?; | ||
1037 | Ok(()) | 952 | Ok(()) |
1038 | } | 953 | } |
1039 | } | 954 | } |
1040 | 955 | ||
1041 | pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { | 956 | pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { |
1042 | let function = Function::new(def_id); // TODO: consts also need inference | 957 | let function = Function::new(def_id); // TODO: consts also need inference |
1043 | let scopes = function.scopes(db)?; | 958 | let body = function.body(db)?; |
959 | let scopes = db.fn_scopes(def_id)?; | ||
1044 | let module = function.module(db)?; | 960 | let module = function.module(db)?; |
1045 | let impl_block = function.impl_block(db)?; | 961 | let impl_block = function.impl_block(db)?; |
1046 | let mut ctx = InferenceContext::new(db, scopes, module, impl_block); | 962 | let mut ctx = InferenceContext::new(db, body, scopes, module, impl_block); |
1047 | |||
1048 | let syntax = function.syntax(db); | ||
1049 | let node = syntax.borrowed(); | ||
1050 | 963 | ||
1051 | ctx.collect_fn_signature(node)?; | 964 | let signature = function.signature(db); |
965 | ctx.collect_fn_signature(&signature)?; | ||
1052 | 966 | ||
1053 | if let Some(block) = node.body() { | 967 | ctx.infer_body()?; |
1054 | ctx.infer_block(block, &Expectation::has_type(ctx.return_ty.clone()))?; | ||
1055 | } | ||
1056 | 968 | ||
1057 | Ok(Arc::new(ctx.resolve_all())) | 969 | Ok(Arc::new(ctx.resolve_all())) |
1058 | } | 970 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 25a354947..e46f309ae 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -4,8 +4,9 @@ use std::path::{PathBuf, Path}; | |||
4 | use std::fs; | 4 | use std::fs; |
5 | 5 | ||
6 | use salsa::Database; | 6 | use salsa::Database; |
7 | use rustc_hash::FxHashMap; | ||
7 | 8 | ||
8 | use ra_db::{SyntaxDatabase}; | 9 | use ra_db::SyntaxDatabase; |
9 | use ra_syntax::ast::{self, AstNode}; | 10 | use ra_syntax::ast::{self, AstNode}; |
10 | use test_utils::{project_dir, assert_eq_text, read_text}; | 11 | use test_utils::{project_dir, assert_eq_text, read_text}; |
11 | 12 | ||
@@ -193,7 +194,25 @@ fn infer(content: &str) -> String { | |||
193 | .unwrap() | 194 | .unwrap() |
194 | .unwrap(); | 195 | .unwrap(); |
195 | let inference_result = func.infer(&db).unwrap(); | 196 | let inference_result = func.infer(&db).unwrap(); |
196 | for (syntax_ptr, ty) in &inference_result.type_of { | 197 | let body_syntax_mapping = func.body_syntax_mapping(&db).unwrap(); |
198 | let mut types = FxHashMap::default(); | ||
199 | for (pat, ty) in &inference_result.type_of_pat { | ||
200 | let syntax_ptr = if let Some(sp) = body_syntax_mapping.pat_syntax(*pat) { | ||
201 | sp | ||
202 | } else { | ||
203 | continue; | ||
204 | }; | ||
205 | types.insert(syntax_ptr, ty); | ||
206 | } | ||
207 | for (expr, ty) in &inference_result.type_of_expr { | ||
208 | let syntax_ptr = if let Some(sp) = body_syntax_mapping.expr_syntax(*expr) { | ||
209 | sp | ||
210 | } else { | ||
211 | continue; | ||
212 | }; | ||
213 | types.insert(syntax_ptr, ty); | ||
214 | } | ||
215 | for (syntax_ptr, ty) in &types { | ||
197 | let node = syntax_ptr.resolve(&source_file); | 216 | let node = syntax_ptr.resolve(&source_file); |
198 | write!( | 217 | write!( |
199 | acc, | 218 | acc, |
@@ -246,7 +265,6 @@ fn test_data_dir() -> PathBuf { | |||
246 | } | 265 | } |
247 | 266 | ||
248 | #[test] | 267 | #[test] |
249 | #[should_panic] // TODO this should work once hir::Expr is used | ||
250 | fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | 268 | fn typing_whitespace_inside_a_function_should_not_invalidate_types() { |
251 | let (mut db, pos) = MockDatabase::with_position( | 269 | let (mut db, pos) = MockDatabase::with_position( |
252 | " | 270 | " |
diff --git a/crates/ra_hir/src/ty/tests/data/0001_basics.txt b/crates/ra_hir/src/ty/tests/data/0001_basics.txt index 212e92e00..4df6b42c9 100644 --- a/crates/ra_hir/src/ty/tests/data/0001_basics.txt +++ b/crates/ra_hir/src/ty/tests/data/0001_basics.txt | |||
@@ -8,6 +8,6 @@ | |||
8 | [27; 28) 'c': ! | 8 | [27; 28) 'c': ! |
9 | [62; 63) 'c': ! | 9 | [62; 63) 'c': ! |
10 | [17; 18) 'b': isize | 10 | [17; 18) 'b': isize |
11 | [100; 106) '"test"': [unknown] | ||
12 | [42; 121) '{ ...f32; }': () | 11 | [42; 121) '{ ...f32; }': () |
12 | [100; 106) '"test"': [unknown] | ||
13 | [69; 70) 'd': &[unknown] | 13 | [69; 70) 'd': &[unknown] |
diff --git a/crates/ra_hir/src/ty/tests/data/0004_struct.txt b/crates/ra_hir/src/ty/tests/data/0004_struct.txt index b4af18b87..6f919b332 100644 --- a/crates/ra_hir/src/ty/tests/data/0004_struct.txt +++ b/crates/ra_hir/src/ty/tests/data/0004_struct.txt | |||
@@ -1,8 +1,8 @@ | |||
1 | [86; 90) 'C(1)': [unknown] | 1 | [86; 90) 'C(1)': [unknown] |
2 | [121; 122) 'B': B | 2 | [121; 122) 'B': B |
3 | [86; 87) 'C': [unknown] | 3 | [86; 87) 'C': [unknown] |
4 | [129; 130) '1': [unknown] | ||
5 | [107; 108) 'a': A | 4 | [107; 108) 'a': A |
5 | [129; 130) '1': [unknown] | ||
6 | [127; 128) 'C': [unknown] | 6 | [127; 128) 'C': [unknown] |
7 | [139; 142) 'a.b': B | 7 | [139; 142) 'a.b': B |
8 | [114; 133) 'A { b:...C(1) }': A | 8 | [114; 133) 'A { b:...C(1) }': A |
diff --git a/crates/ra_hir/src/ty/tests/data/0005_refs.txt b/crates/ra_hir/src/ty/tests/data/0005_refs.txt index 296e955c1..cc32162a1 100644 --- a/crates/ra_hir/src/ty/tests/data/0005_refs.txt +++ b/crates/ra_hir/src/ty/tests/data/0005_refs.txt | |||
@@ -6,9 +6,9 @@ | |||
6 | [46; 47) 'd': *mut u32 | 6 | [46; 47) 'd': *mut u32 |
7 | [59; 150) '{ ... *d; }': () | 7 | [59; 150) '{ ... *d; }': () |
8 | [116; 117) 'b': &mut u32 | 8 | [116; 117) 'b': &mut u32 |
9 | [72; 74) '*a': u32 | ||
9 | [131; 132) 'c': *const u32 | 10 | [131; 132) 'c': *const u32 |
10 | [130; 132) '*c': u32 | 11 | [130; 132) '*c': u32 |
11 | [72; 74) '*a': u32 | ||
12 | [107; 109) '*b': u32 | 12 | [107; 109) '*b': u32 |
13 | [108; 109) 'b': &mut u32 | 13 | [108; 109) 'b': &mut u32 |
14 | [9; 10) 'a': &u32 | 14 | [9; 10) 'a': &u32 |
@@ -17,7 +17,7 @@ | |||
17 | [100; 101) 'b': &mut u32 | 17 | [100; 101) 'b': &mut u32 |
18 | [81; 82) 'a': &u32 | 18 | [81; 82) 'a': &u32 |
19 | [80; 82) '&a': &&u32 | 19 | [80; 82) '&a': &&u32 |
20 | [73; 74) 'a': &u32 | ||
21 | [123; 124) 'c': *const u32 | 20 | [123; 124) 'c': *const u32 |
21 | [73; 74) 'a': &u32 | ||
22 | [31; 32) 'c': *const u32 | 22 | [31; 32) 'c': *const u32 |
23 | [138; 139) 'd': *mut u32 | 23 | [138; 139) 'd': *mut u32 |
diff --git a/crates/ra_hir/src/ty/tests/data/0006_backwards.txt b/crates/ra_hir/src/ty/tests/data/0006_backwards.txt index 120069401..0efae598e 100644 --- a/crates/ra_hir/src/ty/tests/data/0006_backwards.txt +++ b/crates/ra_hir/src/ty/tests/data/0006_backwards.txt | |||
@@ -1,12 +1,12 @@ | |||
1 | [22; 24) '{}': () | 1 | [22; 24) '{}': () |
2 | [14; 15) 'x': u32 | 2 | [14; 15) 'x': u32 |
3 | [142; 158) 'unknow...nction': [unknown] | 3 | [142; 158) 'unknow...nction': [unknown] |
4 | [126; 127) 'a': u32 | ||
5 | [198; 216) 'unknow...tion()': f64 | ||
6 | [228; 229) 'c': f64 | 4 | [228; 229) 'c': f64 |
5 | [198; 216) 'unknow...tion()': f64 | ||
6 | [126; 127) 'a': u32 | ||
7 | [198; 214) 'unknow...nction': [unknown] | 7 | [198; 214) 'unknow...nction': [unknown] |
8 | [166; 184) 'S { i3...d: b }': S | ||
9 | [222; 229) '&mut &c': &mut &f64 | 8 | [222; 229) '&mut &c': &mut &f64 |
9 | [166; 184) 'S { i3...d: b }': S | ||
10 | [194; 195) 'c': f64 | 10 | [194; 195) 'c': f64 |
11 | [92; 110) 'unknow...tion()': u32 | 11 | [92; 110) 'unknow...tion()': u32 |
12 | [142; 160) 'unknow...tion()': i32 | 12 | [142; 160) 'unknow...tion()': i32 |
diff --git a/crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt b/crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt index ca01ad159..0ae172914 100644 --- a/crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt +++ b/crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt | |||
@@ -1,31 +1,31 @@ | |||
1 | [28; 32) '0i32': i32 | 1 | [28; 32) '0i32': i32 |
2 | [22; 34) '{ 0i32 }': i32 | 2 | [22; 34) '{ 0i32 }': i32 |
3 | [6; 7) 'x': [unknown] | 3 | [6; 7) 'x': [unknown] |
4 | [127; 134) 'CONST_1': [unknown] | ||
5 | [201; 205) '3i32': bool | 4 | [201; 205) '3i32': bool |
5 | [127; 134) 'CONST_1': [unknown] | ||
6 | [76; 77) 'y': bool | 6 | [76; 77) 'y': bool |
7 | [65; 66) 'b': bool | ||
8 | [60; 66) 'a && b': bool | 7 | [60; 66) 'a && b': bool |
8 | [65; 66) 'b': bool | ||
9 | [229; 231) '10': [unknown] | ||
9 | [127; 145) 'CONST_...ONST_2': bool | 10 | [127; 145) 'CONST_...ONST_2': bool |
10 | [182; 183) 'd': [unknown] | 11 | [182; 183) 'd': [unknown] |
11 | [229; 231) '10': [unknown] | ||
12 | [209; 222) '"hello world"': bool | 12 | [209; 222) '"hello world"': bool |
13 | [229; 235) '10 < 3': bool | 13 | [229; 235) '10 < 3': bool |
14 | [186; 187) 'b': [unknown] | 14 | [186; 187) 'b': [unknown] |
15 | [159; 172) 'f(z || y) + 5': [unknown] | ||
16 | [56; 57) 'x': bool | 15 | [56; 57) 'x': bool |
16 | [159; 172) 'f(z || y) + 5': [unknown] | ||
17 | [112; 113) 'y': bool | 17 | [112; 113) 'y': bool |
18 | [201; 222) '3i32 &...world"': bool | ||
19 | [234; 235) '3': [unknown] | 18 | [234; 235) '3': [unknown] |
19 | [201; 222) '3i32 &...world"': bool | ||
20 | [138; 145) 'CONST_2': [unknown] | 20 | [138; 145) 'CONST_2': [unknown] |
21 | [80; 93) 'true || false': bool | 21 | [80; 93) 'true || false': bool |
22 | [46; 237) '{ ... < 3 }': bool | 22 | [46; 237) '{ ... < 3 }': bool |
23 | [197; 198) 'e': bool | 23 | [197; 198) 'e': bool |
24 | [107; 113) 'x == y': bool | 24 | [107; 113) 'x == y': bool |
25 | [88; 93) 'false': bool | 25 | [88; 93) 'false': bool |
26 | [80; 84) 'true': bool | ||
27 | [123; 124) 'h': bool | ||
28 | [155; 156) 'c': [unknown] | 26 | [155; 156) 'c': [unknown] |
27 | [123; 124) 'h': bool | ||
28 | [80; 84) 'true': bool | ||
29 | [103; 104) 'z': bool | 29 | [103; 104) 'z': bool |
30 | [60; 61) 'a': bool | 30 | [60; 61) 'a': bool |
31 | [107; 108) 'x': bool | 31 | [107; 108) 'x': bool |