Skip to content

Commit

Permalink
Merge #1512
Browse files Browse the repository at this point in the history
1512: Infer ? operator r=unrealhoang a=unrealhoang

Logical continuation of #1501

cc #1426

Co-authored-by: Unreal Hoang <unrealhoang@gmail.com>
  • Loading branch information
bors[bot] and unrealhoang committed Jul 9, 2019
2 parents ecdc6cd + 9a0d4b1 commit 35f28c5
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 17 deletions.
3 changes: 3 additions & 0 deletions crates/ra_hir/src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ pub(crate) const ITER: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"iter
pub(crate) const INTO_ITERATOR: Name =
Name::new(SmolStr::new_inline_from_ascii(12, b"IntoIterator"));
pub(crate) const ITEM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item"));
pub(crate) const OPS: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"ops"));
pub(crate) const TRY: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try"));
pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok"));

fn resolve_name(text: &SmolStr) -> SmolStr {
let raw_start = "r#";
Expand Down
49 changes: 41 additions & 8 deletions crates/ra_hir/src/ty/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use crate::{
PatId, Statement, UnaryOp,
},
generics::{GenericParams, HasGenericParams},
name::{INTO_ITERATOR, ITEM, ITER, SELF_TYPE, STD},
name,
nameres::{Namespace, PerNs},
path::{GenericArg, GenericArgs, PathKind, PathSegment},
resolve::{
Expand Down Expand Up @@ -843,7 +843,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
// Parent arguments are unknown, except for the receiver type
if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) {
for param in &parent_generics.params {
if param.name == SELF_TYPE {
if param.name == name::SELF_TYPE {
substs.push(receiver_ty.clone());
} else {
substs.push(Ty::Unknown);
Expand Down Expand Up @@ -1140,8 +1140,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
self.insert_type_vars(ty)
}
Expr::Try { expr } => {
let _inner_ty = self.infer_expr(*expr, &Expectation::none());
Ty::Unknown
let inner_ty = self.infer_expr(*expr, &Expectation::none());
let ty = match self.resolve_ops_try_ok() {
Some(ops_try_ok_alias) => {
let ty = self.new_type_var();
let projection = ProjectionPredicate {
ty: ty.clone(),
projection_ty: ProjectionTy {
associated_ty: ops_try_ok_alias,
parameters: vec![inner_ty].into(),
},
};
self.obligations.push(Obligation::Projection(projection));
self.resolve_ty_as_possible(&mut vec![], ty)
}
None => Ty::Unknown,
};
ty
}
Expr::Cast { expr, type_ref } => {
let _inner_ty = self.infer_expr(*expr, &Expectation::none());
Expand Down Expand Up @@ -1347,15 +1362,33 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let into_iter_path = Path {
kind: PathKind::Abs,
segments: vec![
PathSegment { name: STD, args_and_bindings: None },
PathSegment { name: ITER, args_and_bindings: None },
PathSegment { name: INTO_ITERATOR, args_and_bindings: None },
PathSegment { name: name::STD, args_and_bindings: None },
PathSegment { name: name::ITER, args_and_bindings: None },
PathSegment { name: name::INTO_ITERATOR, args_and_bindings: None },
],
};

match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() {
PerNs { types: Some(Def(Trait(trait_))), .. } => {
Some(trait_.associated_type_by_name(self.db, ITEM)?)
Some(trait_.associated_type_by_name(self.db, name::ITEM)?)
}
_ => None,
}
}

fn resolve_ops_try_ok(&self) -> Option<TypeAlias> {
let ops_try_path = Path {
kind: PathKind::Abs,
segments: vec![
PathSegment { name: name::STD, args_and_bindings: None },
PathSegment { name: name::OPS, args_and_bindings: None },
PathSegment { name: name::TRY, args_and_bindings: None },
],
};

match self.resolver.resolve_path_segments(self.db, &ops_try_path).into_fully_resolved() {
PerNs { types: Some(Def(Trait(trait_))), .. } => {
Some(trait_.associated_type_by_name(self.db, name::OK)?)
}
_ => None,
}
Expand Down
71 changes: 62 additions & 9 deletions crates/ra_hir/src/ty/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,57 @@ use crate::{
// update the snapshots.

#[test]
fn infer_for_loop() {
fn infer_try() {
let (mut db, pos) = MockDatabase::with_position(
r#"
//- /main.rs
struct Vec<T> {}
impl<T> Vec<T> {
fn new() -> Self { Vec {} }
fn push(&mut self, t: T) { }
fn test() {
let r: Result<i32, u64> = Result::Ok(1);
let v = r?;
v<|>;
}
impl<T> ::std::iter::IntoIterator for Vec<T> {
type Item=T;
//- /std.rs
#[prelude_import] use ops::*;
mod ops {
trait Try {
type Ok;
type Error;
}
}
#[prelude_import] use result::*;
mod result {
enum Result<O, E> {
Ok(O),
Err(E)
}
impl<O, E> crate::ops::Try for Result<O, E> {
type Ok = O;
type Error = E;
}
}
"#,
);
db.set_crate_graph_from_fixture(crate_graph! {
"main": ("/main.rs", ["std"]),
"std": ("/std.rs", []),
});
assert_eq!("i32", type_at_pos(&db, pos));
}

#[test]
fn infer_for_loop() {
let (mut db, pos) = MockDatabase::with_position(
r#"
//- /main.rs
use std::collections::Vec;
fn test() {
let v = Vec::new();
v.push("foo");
Expand All @@ -42,20 +80,35 @@ fn test() {
}
}
//- /lib.rs
//- /std.rs
#[prelude_import] use iter::*;
mod iter {
trait IntoIterator {
type Item;
}
}
mod collections {
struct Vec<T> {}
impl<T> Vec<T> {
fn new() -> Self { Vec {} }
fn push(&mut self, t: T) { }
}
impl<T> crate::iter::IntoIterator for Vec<T> {
type Item=T;
}
}
"#,
);
db.set_crate_graph_from_fixture(crate_graph! {
"main": ("/main.rs", ["std"]),
"std": ("/lib.rs", []),
"std": ("/std.rs", []),
});
assert_eq!("&str", type_at_pos(&db, pos));
}

#[test]
fn infer_basics() {
assert_snapshot_matches!(
Expand Down

0 comments on commit 35f28c5

Please sign in to comment.