diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/name.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 39 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 37 |
3 files changed, 77 insertions, 2 deletions
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index 5f64b7759..40c9d6002 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs | |||
@@ -115,6 +115,9 @@ pub(crate) const ITER: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"iter | |||
115 | pub(crate) const INTO_ITERATOR: Name = | 115 | pub(crate) const INTO_ITERATOR: Name = |
116 | Name::new(SmolStr::new_inline_from_ascii(12, b"IntoIterator")); | 116 | Name::new(SmolStr::new_inline_from_ascii(12, b"IntoIterator")); |
117 | pub(crate) const ITEM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item")); | 117 | pub(crate) const ITEM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item")); |
118 | pub(crate) const OPS: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"ops")); | ||
119 | pub(crate) const TRY: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try")); | ||
120 | pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); | ||
118 | 121 | ||
119 | fn resolve_name(text: &SmolStr) -> SmolStr { | 122 | fn resolve_name(text: &SmolStr) -> SmolStr { |
120 | let raw_start = "r#"; | 123 | let raw_start = "r#"; |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 52a49070a..2f1c50355 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -1140,8 +1140,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1140 | self.insert_type_vars(ty) | 1140 | self.insert_type_vars(ty) |
1141 | } | 1141 | } |
1142 | Expr::Try { expr } => { | 1142 | Expr::Try { expr } => { |
1143 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); | 1143 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); |
1144 | Ty::Unknown | 1144 | let ty = match self.resolve_ops_try_ok() { |
1145 | Some(ops_try_ok_alias) => { | ||
1146 | let ty = self.new_type_var(); | ||
1147 | let projection = ProjectionPredicate { | ||
1148 | ty: ty.clone(), | ||
1149 | projection_ty: ProjectionTy { | ||
1150 | associated_ty: ops_try_ok_alias, | ||
1151 | parameters: vec![inner_ty].into(), | ||
1152 | }, | ||
1153 | }; | ||
1154 | self.obligations.push(Obligation::Projection(projection)); | ||
1155 | self.resolve_ty_as_possible(&mut vec![], ty) | ||
1156 | } | ||
1157 | None => Ty::Unknown, | ||
1158 | }; | ||
1159 | ty | ||
1145 | } | 1160 | } |
1146 | Expr::Cast { expr, type_ref } => { | 1161 | Expr::Cast { expr, type_ref } => { |
1147 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); | 1162 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); |
@@ -1360,6 +1375,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1360 | _ => None, | 1375 | _ => None, |
1361 | } | 1376 | } |
1362 | } | 1377 | } |
1378 | |||
1379 | fn resolve_ops_try_ok(&self) -> Option<TypeAlias> { | ||
1380 | use crate::name::{OK, OPS, TRY}; | ||
1381 | |||
1382 | let ops_try_path = Path { | ||
1383 | kind: PathKind::Abs, | ||
1384 | segments: vec![ | ||
1385 | PathSegment { name: STD, args_and_bindings: None }, | ||
1386 | PathSegment { name: OPS, args_and_bindings: None }, | ||
1387 | PathSegment { name: TRY, args_and_bindings: None }, | ||
1388 | ], | ||
1389 | }; | ||
1390 | |||
1391 | match self.resolver.resolve_path_segments(self.db, &ops_try_path).into_fully_resolved() { | ||
1392 | PerNs { types: Some(Def(Trait(trait_))), .. } => { | ||
1393 | Some(trait_.associated_type_by_name(self.db, OK)?) | ||
1394 | } | ||
1395 | _ => None, | ||
1396 | } | ||
1397 | } | ||
1363 | } | 1398 | } |
1364 | 1399 | ||
1365 | /// The ID of a type variable. | 1400 | /// The ID of a type variable. |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index fe5e89f2d..d5c03c4bc 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -21,6 +21,42 @@ use crate::{ | |||
21 | // update the snapshots. | 21 | // update the snapshots. |
22 | 22 | ||
23 | #[test] | 23 | #[test] |
24 | fn infer_try() { | ||
25 | let (mut db, pos) = MockDatabase::with_position( | ||
26 | r#" | ||
27 | //- /main.rs | ||
28 | enum Result<O, E> { | ||
29 | Ok(O), | ||
30 | Err(E) | ||
31 | } | ||
32 | |||
33 | impl<O, E> ::std::ops::Try for Result<O, E> { | ||
34 | type Ok = O; | ||
35 | type Error = E; | ||
36 | } | ||
37 | fn test() { | ||
38 | let r: Result<i32, u64> = Result::Ok(1); | ||
39 | let v = r?; | ||
40 | v<|>; | ||
41 | } | ||
42 | |||
43 | //- /lib.rs | ||
44 | mod ops { | ||
45 | trait Try { | ||
46 | type Ok; | ||
47 | type Error; | ||
48 | } | ||
49 | } | ||
50 | "#, | ||
51 | ); | ||
52 | db.set_crate_graph_from_fixture(crate_graph! { | ||
53 | "main": ("/main.rs", ["std"]), | ||
54 | "std": ("/lib.rs", []), | ||
55 | }); | ||
56 | assert_eq!("i32", type_at_pos(&db, pos)); | ||
57 | } | ||
58 | |||
59 | #[test] | ||
24 | fn infer_for_loop() { | 60 | fn infer_for_loop() { |
25 | let (mut db, pos) = MockDatabase::with_position( | 61 | let (mut db, pos) = MockDatabase::with_position( |
26 | r#" | 62 | r#" |
@@ -56,6 +92,7 @@ mod iter { | |||
56 | }); | 92 | }); |
57 | assert_eq!("&str", type_at_pos(&db, pos)); | 93 | assert_eq!("&str", type_at_pos(&db, pos)); |
58 | } | 94 | } |
95 | |||
59 | #[test] | 96 | #[test] |
60 | fn infer_basics() { | 97 | fn infer_basics() { |
61 | assert_snapshot_matches!( | 98 | assert_snapshot_matches!( |