aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/docs.rs7
-rw-r--r--crates/ra_hir/src/expr.rs16
-rw-r--r--crates/ra_hir/src/marks.rs2
-rw-r--r--crates/ra_hir/src/ty.rs37
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_in_elseif.snap17
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap14
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap21
-rw-r--r--crates/ra_hir/src/ty/tests.rs49
8 files changed, 146 insertions, 17 deletions
diff --git a/crates/ra_hir/src/docs.rs b/crates/ra_hir/src/docs.rs
index b1b47af9e..5db72c08a 100644
--- a/crates/ra_hir/src/docs.rs
+++ b/crates/ra_hir/src/docs.rs
@@ -27,10 +27,5 @@ pub trait Docs {
27} 27}
28 28
29pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option<Documentation> { 29pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option<Documentation> {
30 let comments = node.doc_comment_text(); 30 node.doc_comment_text().map(|it| Documentation::new(&it))
31 if comments.is_empty() {
32 None
33 } else {
34 Some(Documentation::new(&comments))
35 }
36} 31}
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 29469af2c..60d997bbe 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -498,7 +498,13 @@ impl ExprCollector {
498 let then_branch = self.collect_block_opt(e.then_branch()); 498 let then_branch = self.collect_block_opt(e.then_branch());
499 let else_branch = e 499 let else_branch = e
500 .else_branch() 500 .else_branch()
501 .map(|e| self.collect_block(e)) 501 .map(|b| match b {
502 ast::ElseBranchFlavor::Block(it) => self.collect_block(it),
503 ast::ElseBranchFlavor::IfExpr(elif) => {
504 let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap();
505 self.collect_expr(expr)
506 }
507 })
502 .unwrap_or_else(|| self.empty_block()); 508 .unwrap_or_else(|| self.empty_block());
503 let placeholder_pat = self.pats.alloc(Pat::Missing); 509 let placeholder_pat = self.pats.alloc(Pat::Missing);
504 let arms = vec![ 510 let arms = vec![
@@ -521,7 +527,13 @@ impl ExprCollector {
521 } else { 527 } else {
522 let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr())); 528 let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr()));
523 let then_branch = self.collect_block_opt(e.then_branch()); 529 let then_branch = self.collect_block_opt(e.then_branch());
524 let else_branch = e.else_branch().map(|e| self.collect_block(e)); 530 let else_branch = e.else_branch().map(|b| match b {
531 ast::ElseBranchFlavor::Block(it) => self.collect_block(it),
532 ast::ElseBranchFlavor::IfExpr(elif) => {
533 let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap();
534 self.collect_expr(expr)
535 }
536 });
525 self.alloc_expr( 537 self.alloc_expr(
526 Expr::If { 538 Expr::If {
527 condition, 539 condition,
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index 338ed0516..d704c3adb 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -1,4 +1,6 @@
1test_utils::marks!( 1test_utils::marks!(
2 name_res_works_for_broken_modules 2 name_res_works_for_broken_modules
3 item_map_enum_importing 3 item_map_enum_importing
4 type_var_cycles_resolve_completely
5 type_var_cycles_resolve_as_possible
4); 6);
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 179ebddee..31ea45706 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -29,6 +29,8 @@ use ra_arena::map::ArenaMap;
29use join_to_string::join; 29use join_to_string::join;
30use rustc_hash::FxHashMap; 30use rustc_hash::FxHashMap;
31 31
32use test_utils::tested_by;
33
32use crate::{ 34use crate::{
33 Module, Function, Struct, StructField, Enum, EnumVariant, Path, Name, ImplBlock, 35 Module, Function, Struct, StructField, Enum, EnumVariant, Path, Name, ImplBlock,
34 FnSignature, FnScopes, ModuleDef, AdtDef, 36 FnSignature, FnScopes, ModuleDef, AdtDef,
@@ -862,14 +864,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
862 } 864 }
863 865
864 fn resolve_all(mut self) -> InferenceResult { 866 fn resolve_all(mut self) -> InferenceResult {
867 let mut tv_stack = Vec::new();
865 let mut expr_types = mem::replace(&mut self.type_of_expr, ArenaMap::default()); 868 let mut expr_types = mem::replace(&mut self.type_of_expr, ArenaMap::default());
866 for ty in expr_types.values_mut() { 869 for ty in expr_types.values_mut() {
867 let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); 870 let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown));
868 *ty = resolved; 871 *ty = resolved;
869 } 872 }
870 let mut pat_types = mem::replace(&mut self.type_of_pat, ArenaMap::default()); 873 let mut pat_types = mem::replace(&mut self.type_of_pat, ArenaMap::default());
871 for ty in pat_types.values_mut() { 874 for ty in pat_types.values_mut() {
872 let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); 875 let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown));
873 *ty = resolved; 876 *ty = resolved;
874 } 877 }
875 InferenceResult { 878 InferenceResult {
@@ -1014,13 +1017,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1014 /// by their known types. All types returned by the infer_* functions should 1017 /// by their known types. All types returned by the infer_* functions should
1015 /// be resolved as far as possible, i.e. contain no type variables with 1018 /// be resolved as far as possible, i.e. contain no type variables with
1016 /// known type. 1019 /// known type.
1017 fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { 1020 fn resolve_ty_as_possible(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
1018 ty.fold(&mut |ty| match ty { 1021 ty.fold(&mut |ty| match ty {
1019 Ty::Infer(tv) => { 1022 Ty::Infer(tv) => {
1020 let inner = tv.to_inner(); 1023 let inner = tv.to_inner();
1024 if tv_stack.contains(&inner) {
1025 tested_by!(type_var_cycles_resolve_as_possible);
1026 // recursive type
1027 return tv.fallback_value();
1028 }
1021 if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() { 1029 if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() {
1022 // known_ty may contain other variables that are known by now 1030 // known_ty may contain other variables that are known by now
1023 self.resolve_ty_as_possible(known_ty.clone()) 1031 tv_stack.push(inner);
1032 let result = self.resolve_ty_as_possible(tv_stack, known_ty.clone());
1033 tv_stack.pop();
1034 result
1024 } else { 1035 } else {
1025 ty 1036 ty
1026 } 1037 }
@@ -1049,13 +1060,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1049 1060
1050 /// Resolves the type completely; type variables without known type are 1061 /// Resolves the type completely; type variables without known type are
1051 /// replaced by Ty::Unknown. 1062 /// replaced by Ty::Unknown.
1052 fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { 1063 fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
1053 ty.fold(&mut |ty| match ty { 1064 ty.fold(&mut |ty| match ty {
1054 Ty::Infer(tv) => { 1065 Ty::Infer(tv) => {
1055 let inner = tv.to_inner(); 1066 let inner = tv.to_inner();
1067 if tv_stack.contains(&inner) {
1068 tested_by!(type_var_cycles_resolve_completely);
1069 // recursive type
1070 return tv.fallback_value();
1071 }
1056 if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() { 1072 if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() {
1057 // known_ty may contain other variables that are known by now 1073 // known_ty may contain other variables that are known by now
1058 self.resolve_ty_completely(known_ty.clone()) 1074 tv_stack.push(inner);
1075 let result = self.resolve_ty_completely(tv_stack, known_ty.clone());
1076 tv_stack.pop();
1077 result
1059 } else { 1078 } else {
1060 tv.fallback_value() 1079 tv.fallback_value()
1061 } 1080 }
@@ -1070,7 +1089,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1070 let name = path.as_ident().cloned().unwrap_or_else(Name::self_param); 1089 let name = path.as_ident().cloned().unwrap_or_else(Name::self_param);
1071 if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) { 1090 if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) {
1072 let ty = self.type_of_pat.get(scope_entry.pat())?; 1091 let ty = self.type_of_pat.get(scope_entry.pat())?;
1073 let ty = self.resolve_ty_as_possible(ty.clone()); 1092 let ty = self.resolve_ty_as_possible(&mut vec![], ty.clone());
1074 return Some(ty); 1093 return Some(ty);
1075 }; 1094 };
1076 }; 1095 };
@@ -1239,7 +1258,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1239 // use a new type variable if we got Ty::Unknown here 1258 // use a new type variable if we got Ty::Unknown here
1240 let ty = self.insert_type_vars_shallow(ty); 1259 let ty = self.insert_type_vars_shallow(ty);
1241 self.unify(&ty, expected); 1260 self.unify(&ty, expected);
1242 let ty = self.resolve_ty_as_possible(ty); 1261 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
1243 self.write_pat_ty(pat, ty.clone()); 1262 self.write_pat_ty(pat, ty.clone());
1244 ty 1263 ty
1245 } 1264 }
@@ -1538,7 +1557,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1538 // use a new type variable if we got Ty::Unknown here 1557 // use a new type variable if we got Ty::Unknown here
1539 let ty = self.insert_type_vars_shallow(ty); 1558 let ty = self.insert_type_vars_shallow(ty);
1540 self.unify(&ty, &expected.ty); 1559 self.unify(&ty, &expected.ty);
1541 let ty = self.resolve_ty_as_possible(ty); 1560 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
1542 self.write_expr_ty(tgt_expr, ty.clone()); 1561 self.write_expr_ty(tgt_expr, ty.clone());
1543 ty 1562 ty
1544 } 1563 }
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_in_elseif.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_in_elseif.snap
new file mode 100644
index 000000000..6a435e5cf
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_in_elseif.snap
@@ -0,0 +1,17 @@
1---
2created: "2019-01-26T21:36:52.714121185+00:00"
3creator: [email protected]
4expression: "&result"
5source: crates/ra_hir/src/ty/tests.rs
6---
7[35; 38) 'foo': Foo
8[45; 109) '{ ... } }': ()
9[51; 107) 'if tru... }': ()
10[54; 58) 'true': bool
11[59; 67) '{ }': ()
12[73; 107) 'if fal... }': i32
13[76; 81) 'false': bool
14[82; 107) '{ ... }': i32
15[92; 95) 'foo': Foo
16[92; 101) 'foo.field': i32
17
diff --git a/crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap b/crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap
new file mode 100644
index 000000000..c3227ff7e
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap
@@ -0,0 +1,14 @@
1---
2created: "2019-01-26T22:42:22.329980185+00:00"
3creator: [email protected]
4expression: "&result"
5source: crates/ra_hir/src/ty/tests.rs
6---
7[11; 48) '{ ...&y]; }': ()
8[21; 22) 'y': &[unknown]
9[25; 32) 'unknown': &[unknown]
10[38; 45) '[y, &y]': [&&[unknown]]
11[39; 40) 'y': &[unknown]
12[42; 44) '&y': &&[unknown]
13[43; 44) 'y': &[unknown]
14
diff --git a/crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap b/crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap
new file mode 100644
index 000000000..de124da5b
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap
@@ -0,0 +1,21 @@
1---
2created: "2019-01-26T22:42:22.331805845+00:00"
3creator: [email protected]
4expression: "&result"
5source: crates/ra_hir/src/ty/tests.rs
6---
7[11; 80) '{ ...x)]; }': ()
8[21; 22) 'x': &&[unknown]
9[25; 32) 'unknown': &&[unknown]
10[42; 43) 'y': &&[unknown]
11[46; 53) 'unknown': &&[unknown]
12[59; 77) '[(x, y..., &x)]': [(&&[unknown], &&[unknown])]
13[60; 66) '(x, y)': (&&[unknown], &&[unknown])
14[61; 62) 'x': &&[unknown]
15[64; 65) 'y': &&[unknown]
16[68; 76) '(&y, &x)': (&&&[unknown], &&&[unknown])
17[69; 71) '&y': &&&[unknown]
18[70; 71) 'y': &&[unknown]
19[73; 75) '&x': &&&[unknown]
20[74; 75) 'x': &&[unknown]
21
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index e0b0689f8..f74d6f5ea 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -3,6 +3,7 @@ use std::fmt::Write;
3 3
4use ra_db::{SourceDatabase, salsa::Database}; 4use ra_db::{SourceDatabase, salsa::Database};
5use ra_syntax::ast::{self, AstNode}; 5use ra_syntax::ast::{self, AstNode};
6use test_utils::covers;
6 7
7use crate::{ 8use crate::{
8 source_binder, 9 source_binder,
@@ -285,6 +286,23 @@ fn test() {
285} 286}
286 287
287#[test] 288#[test]
289fn infer_in_elseif() {
290 check_inference(
291 "infer_in_elseif",
292 r#"
293struct Foo { field: i32 }
294fn main(foo: Foo) {
295 if true {
296
297 } else if false {
298 foo.field
299 }
300}
301"#,
302 )
303}
304
305#[test]
288fn infer_inherent_method() { 306fn infer_inherent_method() {
289 check_inference( 307 check_inference(
290 "infer_inherent_method", 308 "infer_inherent_method",
@@ -545,6 +563,37 @@ fn quux() {
545 ); 563 );
546} 564}
547 565
566#[test]
567fn recursive_vars() {
568 covers!(type_var_cycles_resolve_completely);
569 covers!(type_var_cycles_resolve_as_possible);
570 check_inference(
571 "recursive_vars",
572 r#"
573fn test() {
574 let y = unknown;
575 [y, &y];
576}
577"#,
578 );
579}
580
581#[test]
582fn recursive_vars_2() {
583 covers!(type_var_cycles_resolve_completely);
584 covers!(type_var_cycles_resolve_as_possible);
585 check_inference(
586 "recursive_vars_2",
587 r#"
588fn test() {
589 let x = unknown;
590 let y = unknown;
591 [(x, y), (&y, &x)];
592}
593"#,
594 );
595}
596
548fn infer(content: &str) -> String { 597fn infer(content: &str) -> String {
549 let (db, _, file_id) = MockDatabase::with_single_file(content); 598 let (db, _, file_id) = MockDatabase::with_single_file(content);
550 let source_file = db.parse(file_id); 599 let source_file = db.parse(file_id);