Skip to content

Commit 35f28c5

Browse files
Merge #1512
1512: Infer ? operator r=unrealhoang a=unrealhoang Logical continuation of #1501 cc #1426 Co-authored-by: Unreal Hoang <[email protected]>
2 parents ecdc6cd + 9a0d4b1 commit 35f28c5

File tree

3 files changed

+106
-17
lines changed

3 files changed

+106
-17
lines changed

crates/ra_hir/src/name.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ pub(crate) const ITER: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"iter
115115
pub(crate) const INTO_ITERATOR: Name =
116116
Name::new(SmolStr::new_inline_from_ascii(12, b"IntoIterator"));
117117
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"));
118121

119122
fn resolve_name(text: &SmolStr) -> SmolStr {
120123
let raw_start = "r#";

crates/ra_hir/src/ty/infer.rs

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use crate::{
4040
PatId, Statement, UnaryOp,
4141
},
4242
generics::{GenericParams, HasGenericParams},
43-
name::{INTO_ITERATOR, ITEM, ITER, SELF_TYPE, STD},
43+
name,
4444
nameres::{Namespace, PerNs},
4545
path::{GenericArg, GenericArgs, PathKind, PathSegment},
4646
resolve::{
@@ -843,7 +843,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
843843
// Parent arguments are unknown, except for the receiver type
844844
if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) {
845845
for param in &parent_generics.params {
846-
if param.name == SELF_TYPE {
846+
if param.name == name::SELF_TYPE {
847847
substs.push(receiver_ty.clone());
848848
} else {
849849
substs.push(Ty::Unknown);
@@ -1140,8 +1140,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
11401140
self.insert_type_vars(ty)
11411141
}
11421142
Expr::Try { expr } => {
1143-
let _inner_ty = self.infer_expr(*expr, &Expectation::none());
1144-
Ty::Unknown
1143+
let inner_ty = self.infer_expr(*expr, &Expectation::none());
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
11451160
}
11461161
Expr::Cast { expr, type_ref } => {
11471162
let _inner_ty = self.infer_expr(*expr, &Expectation::none());
@@ -1347,15 +1362,33 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
13471362
let into_iter_path = Path {
13481363
kind: PathKind::Abs,
13491364
segments: vec![
1350-
PathSegment { name: STD, args_and_bindings: None },
1351-
PathSegment { name: ITER, args_and_bindings: None },
1352-
PathSegment { name: INTO_ITERATOR, args_and_bindings: None },
1365+
PathSegment { name: name::STD, args_and_bindings: None },
1366+
PathSegment { name: name::ITER, args_and_bindings: None },
1367+
PathSegment { name: name::INTO_ITERATOR, args_and_bindings: None },
13531368
],
13541369
};
13551370

13561371
match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() {
13571372
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)?)
13591392
}
13601393
_ => None,
13611394
}

crates/ra_hir/src/ty/tests.rs

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,57 @@ use crate::{
2121
// update the snapshots.
2222

2323
#[test]
24-
fn infer_for_loop() {
24+
fn infer_try() {
2525
let (mut db, pos) = MockDatabase::with_position(
2626
r#"
2727
//- /main.rs
28-
struct Vec<T> {}
29-
impl<T> Vec<T> {
30-
fn new() -> Self { Vec {} }
31-
fn push(&mut self, t: T) { }
28+
29+
fn test() {
30+
let r: Result<i32, u64> = Result::Ok(1);
31+
let v = r?;
32+
v<|>;
3233
}
3334
34-
impl<T> ::std::iter::IntoIterator for Vec<T> {
35-
type Item=T;
35+
//- /std.rs
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));
3665
}
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+
3775
fn test() {
3876
let v = Vec::new();
3977
v.push("foo");
@@ -42,20 +80,35 @@ fn test() {
4280
}
4381
}
4482
45-
//- /lib.rs
83+
//- /std.rs
84+
85+
#[prelude_import] use iter::*;
4686
mod iter {
4787
trait IntoIterator {
4888
type Item;
4989
}
5090
}
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+
}
51103
"#,
52104
);
53105
db.set_crate_graph_from_fixture(crate_graph! {
54106
"main": ("/main.rs", ["std"]),
55-
"std": ("/lib.rs", []),
107+
"std": ("/std.rs", []),
56108
});
57109
assert_eq!("&str", type_at_pos(&db, pos));
58110
}
111+
59112
#[test]
60113
fn infer_basics() {
61114
assert_snapshot_matches!(

0 commit comments

Comments
 (0)