diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/docs.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/marks.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 37 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_in_elseif.snap | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 49 |
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 | ||
29 | pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option<Documentation> { | 29 | pub(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 @@ | |||
1 | test_utils::marks!( | 1 | test_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; | |||
29 | use join_to_string::join; | 29 | use join_to_string::join; |
30 | use rustc_hash::FxHashMap; | 30 | use rustc_hash::FxHashMap; |
31 | 31 | ||
32 | use test_utils::tested_by; | ||
33 | |||
32 | use crate::{ | 34 | use 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 | --- | ||
2 | created: "2019-01-26T21:36:52.714121185+00:00" | ||
3 | creator: [email protected] | ||
4 | expression: "&result" | ||
5 | source: 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 | --- | ||
2 | created: "2019-01-26T22:42:22.329980185+00:00" | ||
3 | creator: [email protected] | ||
4 | expression: "&result" | ||
5 | source: 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 | --- | ||
2 | created: "2019-01-26T22:42:22.331805845+00:00" | ||
3 | creator: [email protected] | ||
4 | expression: "&result" | ||
5 | source: 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 | ||
4 | use ra_db::{SourceDatabase, salsa::Database}; | 4 | use ra_db::{SourceDatabase, salsa::Database}; |
5 | use ra_syntax::ast::{self, AstNode}; | 5 | use ra_syntax::ast::{self, AstNode}; |
6 | use test_utils::covers; | ||
6 | 7 | ||
7 | use crate::{ | 8 | use crate::{ |
8 | source_binder, | 9 | source_binder, |
@@ -285,6 +286,23 @@ fn test() { | |||
285 | } | 286 | } |
286 | 287 | ||
287 | #[test] | 288 | #[test] |
289 | fn infer_in_elseif() { | ||
290 | check_inference( | ||
291 | "infer_in_elseif", | ||
292 | r#" | ||
293 | struct Foo { field: i32 } | ||
294 | fn main(foo: Foo) { | ||
295 | if true { | ||
296 | |||
297 | } else if false { | ||
298 | foo.field | ||
299 | } | ||
300 | } | ||
301 | "#, | ||
302 | ) | ||
303 | } | ||
304 | |||
305 | #[test] | ||
288 | fn infer_inherent_method() { | 306 | fn 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] | ||
567 | fn 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#" | ||
573 | fn test() { | ||
574 | let y = unknown; | ||
575 | [y, &y]; | ||
576 | } | ||
577 | "#, | ||
578 | ); | ||
579 | } | ||
580 | |||
581 | #[test] | ||
582 | fn 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#" | ||
588 | fn test() { | ||
589 | let x = unknown; | ||
590 | let y = unknown; | ||
591 | [(x, y), (&y, &x)]; | ||
592 | } | ||
593 | "#, | ||
594 | ); | ||
595 | } | ||
596 | |||
548 | fn infer(content: &str) -> String { | 597 | fn 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); |