projection over std::ops::Try::Ok to infer try/?
This commit is contained in:
parent
64b718bff7
commit
944f71afc6
@ -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#";
|
||||
|
@ -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());
|
||||
@ -1360,6 +1375,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_ops_try_ok(&self) -> Option<TypeAlias> {
|
||||
use crate::name::{OK, OPS, TRY};
|
||||
|
||||
let ops_try_path = Path {
|
||||
kind: PathKind::Abs,
|
||||
segments: vec![
|
||||
PathSegment { name: STD, args_and_bindings: None },
|
||||
PathSegment { name: OPS, args_and_bindings: None },
|
||||
PathSegment { 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, OK)?)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The ID of a type variable.
|
||||
|
@ -20,6 +20,42 @@ use crate::{
|
||||
// against snapshots of the expected results using insta. Use cargo-insta to
|
||||
// update the snapshots.
|
||||
|
||||
#[test]
|
||||
fn infer_try() {
|
||||
let (mut db, pos) = MockDatabase::with_position(
|
||||
r#"
|
||||
//- /main.rs
|
||||
enum Result<O, E> {
|
||||
Ok(O),
|
||||
Err(E)
|
||||
}
|
||||
|
||||
impl<O, E> ::std::ops::Try for Result<O, E> {
|
||||
type Ok = O;
|
||||
type Error = E;
|
||||
}
|
||||
fn test() {
|
||||
let r: Result<i32, u64> = Result::Ok(1);
|
||||
let v = r?;
|
||||
v<|>;
|
||||
}
|
||||
|
||||
//- /lib.rs
|
||||
mod ops {
|
||||
trait Try {
|
||||
type Ok;
|
||||
type Error;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
db.set_crate_graph_from_fixture(crate_graph! {
|
||||
"main": ("/main.rs", ["std"]),
|
||||
"std": ("/lib.rs", []),
|
||||
});
|
||||
assert_eq!("i32", type_at_pos(&db, pos));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_for_loop() {
|
||||
let (mut db, pos) = MockDatabase::with_position(
|
||||
@ -56,6 +92,7 @@ mod iter {
|
||||
});
|
||||
assert_eq!("&str", type_at_pos(&db, pos));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_basics() {
|
||||
assert_snapshot_matches!(
|
||||
|
Loading…
x
Reference in New Issue
Block a user