aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorUnreal Hoang <[email protected]>2019-07-08 16:02:15 +0100
committerUnreal Hoang <[email protected]>2019-07-08 16:19:09 +0100
commit944f71afc692733cbc151bb3113d45a8159de132 (patch)
treed7f7e23f43a461d526d143cd4e4e0ba7021a7c4e /crates
parent64b718bff7df788bfe6e8e2dce24b20faf9be235 (diff)
projection over std::ops::Try::Ok to infer try/?
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/name.rs3
-rw-r--r--crates/ra_hir/src/ty/infer.rs39
-rw-r--r--crates/ra_hir/src/ty/tests.rs37
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
115pub(crate) const INTO_ITERATOR: Name = 115pub(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"));
117pub(crate) const ITEM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item")); 117pub(crate) const ITEM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item"));
118pub(crate) const OPS: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"ops"));
119pub(crate) const TRY: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try"));
120pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok"));
118 121
119fn resolve_name(text: &SmolStr) -> SmolStr { 122fn 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]
24fn infer_try() {
25 let (mut db, pos) = MockDatabase::with_position(
26 r#"
27//- /main.rs
28enum Result<O, E> {
29 Ok(O),
30 Err(E)
31}
32
33impl<O, E> ::std::ops::Try for Result<O, E> {
34 type Ok = O;
35 type Error = E;
36}
37fn test() {
38 let r: Result<i32, u64> = Result::Ok(1);
39 let v = r?;
40 v<|>;
41}
42
43//- /lib.rs
44mod 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]
24fn infer_for_loop() { 60fn 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]
60fn infer_basics() { 97fn infer_basics() {
61 assert_snapshot_matches!( 98 assert_snapshot_matches!(