diff options
Diffstat (limited to 'crates/ra_hir')
-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/method_resolution.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 71 |
4 files changed, 112 insertions, 21 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 1f74108a4..26ddf0317 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -41,7 +41,7 @@ use crate::{ | |||
41 | PatId, Statement, UnaryOp, | 41 | PatId, Statement, UnaryOp, |
42 | }, | 42 | }, |
43 | generics::{GenericParams, HasGenericParams}, | 43 | generics::{GenericParams, HasGenericParams}, |
44 | name::{INTO_ITERATOR, ITEM, ITER, SELF_TYPE, STD}, | 44 | name, |
45 | nameres::{Namespace, PerNs}, | 45 | nameres::{Namespace, PerNs}, |
46 | path::{GenericArg, GenericArgs, PathKind, PathSegment}, | 46 | path::{GenericArg, GenericArgs, PathKind, PathSegment}, |
47 | resolve::{ | 47 | resolve::{ |
@@ -820,7 +820,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
820 | // Parent arguments are unknown, except for the receiver type | 820 | // Parent arguments are unknown, except for the receiver type |
821 | if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) { | 821 | if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) { |
822 | for param in &parent_generics.params { | 822 | for param in &parent_generics.params { |
823 | if param.name == SELF_TYPE { | 823 | if param.name == name::SELF_TYPE { |
824 | substs.push(receiver_ty.clone()); | 824 | substs.push(receiver_ty.clone()); |
825 | } else { | 825 | } else { |
826 | substs.push(Ty::Unknown); | 826 | substs.push(Ty::Unknown); |
@@ -1117,8 +1117,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1117 | self.insert_type_vars(ty) | 1117 | self.insert_type_vars(ty) |
1118 | } | 1118 | } |
1119 | Expr::Try { expr } => { | 1119 | Expr::Try { expr } => { |
1120 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); | 1120 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); |
1121 | Ty::Unknown | 1121 | let ty = match self.resolve_ops_try_ok() { |
1122 | Some(ops_try_ok_alias) => { | ||
1123 | let ty = self.new_type_var(); | ||
1124 | let projection = ProjectionPredicate { | ||
1125 | ty: ty.clone(), | ||
1126 | projection_ty: ProjectionTy { | ||
1127 | associated_ty: ops_try_ok_alias, | ||
1128 | parameters: vec![inner_ty].into(), | ||
1129 | }, | ||
1130 | }; | ||
1131 | self.obligations.push(Obligation::Projection(projection)); | ||
1132 | self.resolve_ty_as_possible(&mut vec![], ty) | ||
1133 | } | ||
1134 | None => Ty::Unknown, | ||
1135 | }; | ||
1136 | ty | ||
1122 | } | 1137 | } |
1123 | Expr::Cast { expr, type_ref } => { | 1138 | Expr::Cast { expr, type_ref } => { |
1124 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); | 1139 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); |
@@ -1324,15 +1339,33 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1324 | let into_iter_path = Path { | 1339 | let into_iter_path = Path { |
1325 | kind: PathKind::Abs, | 1340 | kind: PathKind::Abs, |
1326 | segments: vec![ | 1341 | segments: vec![ |
1327 | PathSegment { name: STD, args_and_bindings: None }, | 1342 | PathSegment { name: name::STD, args_and_bindings: None }, |
1328 | PathSegment { name: ITER, args_and_bindings: None }, | 1343 | PathSegment { name: name::ITER, args_and_bindings: None }, |
1329 | PathSegment { name: INTO_ITERATOR, args_and_bindings: None }, | 1344 | PathSegment { name: name::INTO_ITERATOR, args_and_bindings: None }, |
1330 | ], | 1345 | ], |
1331 | }; | 1346 | }; |
1332 | 1347 | ||
1333 | match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() { | 1348 | match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() { |
1334 | PerNs { types: Some(Def(Trait(trait_))), .. } => { | 1349 | PerNs { types: Some(Def(Trait(trait_))), .. } => { |
1335 | Some(trait_.associated_type_by_name(self.db, ITEM)?) | 1350 | Some(trait_.associated_type_by_name(self.db, name::ITEM)?) |
1351 | } | ||
1352 | _ => None, | ||
1353 | } | ||
1354 | } | ||
1355 | |||
1356 | fn resolve_ops_try_ok(&self) -> Option<TypeAlias> { | ||
1357 | let ops_try_path = Path { | ||
1358 | kind: PathKind::Abs, | ||
1359 | segments: vec![ | ||
1360 | PathSegment { name: name::STD, args_and_bindings: None }, | ||
1361 | PathSegment { name: name::OPS, args_and_bindings: None }, | ||
1362 | PathSegment { name: name::TRY, args_and_bindings: None }, | ||
1363 | ], | ||
1364 | }; | ||
1365 | |||
1366 | match self.resolver.resolve_path_segments(self.db, &ops_try_path).into_fully_resolved() { | ||
1367 | PerNs { types: Some(Def(Trait(trait_))), .. } => { | ||
1368 | Some(trait_.associated_type_by_name(self.db, name::OK)?) | ||
1336 | } | 1369 | } |
1337 | _ => None, | 1370 | _ => None, |
1338 | } | 1371 | } |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index e214bf1af..353820436 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -14,7 +14,7 @@ use crate::{ | |||
14 | nameres::CrateModuleId, | 14 | nameres::CrateModuleId, |
15 | resolve::Resolver, | 15 | resolve::Resolver, |
16 | traits::TraitItem, | 16 | traits::TraitItem, |
17 | ty::primitive::{UncertainFloatTy, UncertainIntTy}, | 17 | ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, |
18 | ty::{Ty, TypeCtor}, | 18 | ty::{Ty, TypeCtor}, |
19 | Crate, Function, HirDatabase, Module, Name, Trait, | 19 | Crate, Function, HirDatabase, Module, Name, Trait, |
20 | }; | 20 | }; |
@@ -132,9 +132,11 @@ fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayV | |||
132 | TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()), | 132 | TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()), |
133 | TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"), | 133 | TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"), |
134 | TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"), | 134 | TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"), |
135 | TypeCtor::Float(UncertainFloatTy::Known(f)) => { | 135 | TypeCtor::Float(UncertainFloatTy::Known(f)) => match f.bitness { |
136 | lang_item_crate!(db, cur_crate, f.ty_to_string()) | 136 | // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) |
137 | } | 137 | FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"), |
138 | FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"), | ||
139 | }, | ||
138 | TypeCtor::Int(UncertainIntTy::Known(i)) => { | 140 | TypeCtor::Int(UncertainIntTy::Known(i)) => { |
139 | lang_item_crate!(db, cur_crate, i.ty_to_string()) | 141 | lang_item_crate!(db, cur_crate, i.ty_to_string()) |
140 | } | 142 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 7340bb9bd..2410602a6 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!( |