diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-07-09 01:41:03 +0100 |
---|---|---|
committer | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-07-09 01:41:03 +0100 |
commit | 35f28c538a9b9f461bb4db1a78d02e9f02a3d296 (patch) | |
tree | a610ad33b7bc3a1e14770cb34036fa1430ebc900 /crates/ra_hir/src | |
parent | ecdc6cdce997c6ae251dbda2066de929f9d49c49 (diff) | |
parent | 9a0d4b16b7d14530b77c96e2e18b80b3f5b526c8 (diff) |
Merge #1512
1512: Infer ? operator r=unrealhoang a=unrealhoang
Logical continuation of https://github.com/rust-analyzer/rust-analyzer/pull/1501
cc https://github.com/rust-analyzer/rust-analyzer/issues/1426
Co-authored-by: Unreal Hoang <[email protected]>
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 | 49 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 71 |
3 files changed, 106 insertions, 17 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..827addddd 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -40,7 +40,7 @@ use crate::{ | |||
40 | PatId, Statement, UnaryOp, | 40 | PatId, Statement, UnaryOp, |
41 | }, | 41 | }, |
42 | generics::{GenericParams, HasGenericParams}, | 42 | generics::{GenericParams, HasGenericParams}, |
43 | name::{INTO_ITERATOR, ITEM, ITER, SELF_TYPE, STD}, | 43 | name, |
44 | nameres::{Namespace, PerNs}, | 44 | nameres::{Namespace, PerNs}, |
45 | path::{GenericArg, GenericArgs, PathKind, PathSegment}, | 45 | path::{GenericArg, GenericArgs, PathKind, PathSegment}, |
46 | resolve::{ | 46 | resolve::{ |
@@ -843,7 +843,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
843 | // Parent arguments are unknown, except for the receiver type | 843 | // Parent arguments are unknown, except for the receiver type |
844 | if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) { | 844 | if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) { |
845 | for param in &parent_generics.params { | 845 | for param in &parent_generics.params { |
846 | if param.name == SELF_TYPE { | 846 | if param.name == name::SELF_TYPE { |
847 | substs.push(receiver_ty.clone()); | 847 | substs.push(receiver_ty.clone()); |
848 | } else { | 848 | } else { |
849 | substs.push(Ty::Unknown); | 849 | substs.push(Ty::Unknown); |
@@ -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()); |
@@ -1347,15 +1362,33 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1347 | let into_iter_path = Path { | 1362 | let into_iter_path = Path { |
1348 | kind: PathKind::Abs, | 1363 | kind: PathKind::Abs, |
1349 | segments: vec![ | 1364 | segments: vec![ |
1350 | PathSegment { name: STD, args_and_bindings: None }, | 1365 | PathSegment { name: name::STD, args_and_bindings: None }, |
1351 | PathSegment { name: ITER, args_and_bindings: None }, | 1366 | PathSegment { name: name::ITER, args_and_bindings: None }, |
1352 | PathSegment { name: INTO_ITERATOR, args_and_bindings: None }, | 1367 | PathSegment { name: name::INTO_ITERATOR, args_and_bindings: None }, |
1353 | ], | 1368 | ], |
1354 | }; | 1369 | }; |
1355 | 1370 | ||
1356 | match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() { | 1371 | match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() { |
1357 | PerNs { types: Some(Def(Trait(trait_))), .. } => { | 1372 | PerNs { types: Some(Def(Trait(trait_))), .. } => { |
1358 | Some(trait_.associated_type_by_name(self.db, ITEM)?) | 1373 | Some(trait_.associated_type_by_name(self.db, name::ITEM)?) |
1374 | } | ||
1375 | _ => None, | ||
1376 | } | ||
1377 | } | ||
1378 | |||
1379 | fn resolve_ops_try_ok(&self) -> Option<TypeAlias> { | ||
1380 | let ops_try_path = Path { | ||
1381 | kind: PathKind::Abs, | ||
1382 | segments: vec![ | ||
1383 | PathSegment { name: name::STD, args_and_bindings: None }, | ||
1384 | PathSegment { name: name::OPS, args_and_bindings: None }, | ||
1385 | PathSegment { name: name::TRY, args_and_bindings: None }, | ||
1386 | ], | ||
1387 | }; | ||
1388 | |||
1389 | match self.resolver.resolve_path_segments(self.db, &ops_try_path).into_fully_resolved() { | ||
1390 | PerNs { types: Some(Def(Trait(trait_))), .. } => { | ||
1391 | Some(trait_.associated_type_by_name(self.db, name::OK)?) | ||
1359 | } | 1392 | } |
1360 | _ => None, | 1393 | _ => None, |
1361 | } | 1394 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index fe5e89f2d..6aea1fb4a 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -21,19 +21,57 @@ use crate::{ | |||
21 | // update the snapshots. | 21 | // update the snapshots. |
22 | 22 | ||
23 | #[test] | 23 | #[test] |
24 | fn infer_for_loop() { | 24 | fn infer_try() { |
25 | let (mut db, pos) = MockDatabase::with_position( | 25 | let (mut db, pos) = MockDatabase::with_position( |
26 | r#" | 26 | r#" |
27 | //- /main.rs | 27 | //- /main.rs |
28 | struct Vec<T> {} | 28 | |
29 | impl<T> Vec<T> { | 29 | fn test() { |
30 | fn new() -> Self { Vec {} } | 30 | let r: Result<i32, u64> = Result::Ok(1); |
31 | fn push(&mut self, t: T) { } | 31 | let v = r?; |
32 | v<|>; | ||
32 | } | 33 | } |
33 | 34 | ||
34 | impl<T> ::std::iter::IntoIterator for Vec<T> { | 35 | //- /std.rs |
35 | type Item=T; | 36 | |
37 | #[prelude_import] use ops::*; | ||
38 | mod ops { | ||
39 | trait Try { | ||
40 | type Ok; | ||
41 | type Error; | ||
42 | } | ||
43 | } | ||
44 | |||
45 | #[prelude_import] use result::*; | ||
46 | mod result { | ||
47 | enum Result<O, E> { | ||
48 | Ok(O), | ||
49 | Err(E) | ||
50 | } | ||
51 | |||
52 | impl<O, E> crate::ops::Try for Result<O, E> { | ||
53 | type Ok = O; | ||
54 | type Error = E; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | "#, | ||
59 | ); | ||
60 | db.set_crate_graph_from_fixture(crate_graph! { | ||
61 | "main": ("/main.rs", ["std"]), | ||
62 | "std": ("/std.rs", []), | ||
63 | }); | ||
64 | assert_eq!("i32", type_at_pos(&db, pos)); | ||
36 | } | 65 | } |
66 | |||
67 | #[test] | ||
68 | fn infer_for_loop() { | ||
69 | let (mut db, pos) = MockDatabase::with_position( | ||
70 | r#" | ||
71 | //- /main.rs | ||
72 | |||
73 | use std::collections::Vec; | ||
74 | |||
37 | fn test() { | 75 | fn test() { |
38 | let v = Vec::new(); | 76 | let v = Vec::new(); |
39 | v.push("foo"); | 77 | v.push("foo"); |
@@ -42,20 +80,35 @@ fn test() { | |||
42 | } | 80 | } |
43 | } | 81 | } |
44 | 82 | ||
45 | //- /lib.rs | 83 | //- /std.rs |
84 | |||
85 | #[prelude_import] use iter::*; | ||
46 | mod iter { | 86 | mod iter { |
47 | trait IntoIterator { | 87 | trait IntoIterator { |
48 | type Item; | 88 | type Item; |
49 | } | 89 | } |
50 | } | 90 | } |
91 | |||
92 | mod collections { | ||
93 | struct Vec<T> {} | ||
94 | impl<T> Vec<T> { | ||
95 | fn new() -> Self { Vec {} } | ||
96 | fn push(&mut self, t: T) { } | ||
97 | } | ||
98 | |||
99 | impl<T> crate::iter::IntoIterator for Vec<T> { | ||
100 | type Item=T; | ||
101 | } | ||
102 | } | ||
51 | "#, | 103 | "#, |
52 | ); | 104 | ); |
53 | db.set_crate_graph_from_fixture(crate_graph! { | 105 | db.set_crate_graph_from_fixture(crate_graph! { |
54 | "main": ("/main.rs", ["std"]), | 106 | "main": ("/main.rs", ["std"]), |
55 | "std": ("/lib.rs", []), | 107 | "std": ("/std.rs", []), |
56 | }); | 108 | }); |
57 | assert_eq!("&str", type_at_pos(&db, pos)); | 109 | assert_eq!("&str", type_at_pos(&db, pos)); |
58 | } | 110 | } |
111 | |||
59 | #[test] | 112 | #[test] |
60 | fn infer_basics() { | 113 | fn infer_basics() { |
61 | assert_snapshot_matches!( | 114 | assert_snapshot_matches!( |