aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-01-06 15:47:59 +0000
committerFlorian Diebold <[email protected]>2019-01-06 23:05:19 +0000
commit6210e82041849bad6129331b9e45ac0bae6fe569 (patch)
tree43656452729519e45f4aa036372526b2934a230c /crates
parent3c945ceb5e0dc287139de0589cc9a4b285911f17 (diff)
Use HIR Expr for type inference
Now we can reuse the type inference inside a function when typing whitespace etc. :)
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_analysis/src/completion/complete_dot.rs14
-rw-r--r--crates/ra_analysis/src/hover.rs9
-rw-r--r--crates/ra_hir/src/expr.rs31
-rw-r--r--crates/ra_hir/src/ty.rs544
-rw-r--r--crates/ra_hir/src/ty/tests.rs24
-rw-r--r--crates/ra_hir/src/ty/tests/data/0001_basics.txt2
-rw-r--r--crates/ra_hir/src/ty/tests/data/0004_struct.txt2
-rw-r--r--crates/ra_hir/src/ty/tests/data/0005_refs.txt4
-rw-r--r--crates/ra_hir/src/ty/tests/data/0006_backwards.txt6
-rw-r--r--crates/ra_hir/src/ty/tests/data/0008_boolean_op.txt14
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 @@
1use ra_db::LocalSyntaxPtr;
1use ra_syntax::ast::AstNode; 2use ra_syntax::ast::AstNode;
2use hir::{Ty, Def}; 3use 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
6use ra_arena::{Arena, RawId, impl_arena_id}; 6use ra_arena::{Arena, RawId, impl_arena_id};
7use ra_db::{LocalSyntaxPtr, Cancelable}; 7use ra_db::{LocalSyntaxPtr, Cancelable};
8use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner}; 8use ra_syntax::{SyntaxNodeRef, ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner}};
9 9
10use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; 10use 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
169pub type UnaryOp = ast::PrefixOp; 184pub use ra_syntax::ast::PrefixOp as UnaryOp;
185pub use ra_syntax::ast::BinOp as BinaryOp;
170 186
171#[derive(Debug, Clone, Eq, PartialEq)] 187#[derive(Debug, Clone, Eq, PartialEq)]
172pub struct MatchArm { 188pub 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)]
18mod tests; 18mod tests;
19 19
20use std::ops::Index;
20use std::sync::Arc; 21use std::sync::Arc;
21use std::{fmt, mem}; 22use std::{fmt, mem};
22 23
@@ -24,18 +25,15 @@ use log;
24use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
25use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError}; 26use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError};
26 27
27use ra_db::{LocalSyntaxPtr, Cancelable}; 28use ra_db::Cancelable;
28use ra_syntax::{
29 ast::{self, AstNode, LoopBodyOwner, ArgListOwner, PrefixOp, BinOp},
30 SyntaxNodeRef
31};
32 29
33use crate::{ 30use 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.
421fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { 400fn 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)]
501pub struct InferenceResult { 472pub 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
505impl InferenceResult { 477impl 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
485impl 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)]
517struct InferenceContext<'a, D: HirDatabase> { 495struct 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
532fn is_boolean_operator(op: BinOp) -> bool { 510fn 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
544impl<'a, D: HirDatabase> InferenceContext<'a, D> { 522impl<'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
1041pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { 956pub 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};
4use std::fs; 4use std::fs;
5 5
6use salsa::Database; 6use salsa::Database;
7use rustc_hash::FxHashMap;
7 8
8use ra_db::{SyntaxDatabase}; 9use ra_db::SyntaxDatabase;
9use ra_syntax::ast::{self, AstNode}; 10use ra_syntax::ast::{self, AstNode};
10use test_utils::{project_dir, assert_eq_text, read_text}; 11use 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
250fn typing_whitespace_inside_a_function_should_not_invalidate_types() { 268fn 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