aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/name.rs3
-rw-r--r--crates/ra_hir/src/ty/infer.rs49
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs10
-rw-r--r--crates/ra_hir/src/ty/tests.rs71
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
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 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]
24fn infer_for_loop() { 24fn 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
28struct Vec<T> {} 28
29impl<T> Vec<T> { 29fn 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
34impl<T> ::std::iter::IntoIterator for Vec<T> { 35//- /std.rs
35 type Item=T; 36
37#[prelude_import] use ops::*;
38mod ops {
39 trait Try {
40 type Ok;
41 type Error;
42 }
43}
44
45#[prelude_import] use result::*;
46mod 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]
68fn infer_for_loop() {
69 let (mut db, pos) = MockDatabase::with_position(
70 r#"
71//- /main.rs
72
73use std::collections::Vec;
74
37fn test() { 75fn 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::*;
46mod iter { 86mod iter {
47 trait IntoIterator { 87 trait IntoIterator {
48 type Item; 88 type Item;
49 } 89 }
50} 90}
91
92mod 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]
60fn infer_basics() { 113fn infer_basics() {
61 assert_snapshot_matches!( 114 assert_snapshot_matches!(