From 944f71afc692733cbc151bb3113d45a8159de132 Mon Sep 17 00:00:00 2001 From: Unreal Hoang Date: Tue, 9 Jul 2019 00:02:15 +0900 Subject: projection over std::ops::Try::Ok to infer try/? --- crates/ra_hir/src/name.rs | 3 +++ crates/ra_hir/src/ty/infer.rs | 39 +++++++++++++++++++++++++++++++++++++-- crates/ra_hir/src/ty/tests.rs | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 2 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 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#"; diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 52a49070a..2f1c50355 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -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 { + 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. diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index fe5e89f2d..d5c03c4bc 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -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 { + Ok(O), + Err(E) +} + +impl ::std::ops::Try for Result { + type Ok = O; + type Error = E; +} +fn test() { + let r: Result = 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!( -- cgit v1.2.3 From 741fc8fbfc10445ef90c8234e042d688d8bc293b Mon Sep 17 00:00:00 2001 From: Unreal Hoang Date: Tue, 9 Jul 2019 00:45:12 +0900 Subject: use namespaced consts for KnownName --- crates/ra_hir/src/ty/infer.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 2f1c50355..827addddd 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -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::{ @@ -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); @@ -1362,35 +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 { - 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 }, + 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, OK)?) + Some(trait_.associated_type_by_name(self.db, name::OK)?) } _ => None, } -- cgit v1.2.3 From 9a0d4b16b7d14530b77c96e2e18b80b3f5b526c8 Mon Sep 17 00:00:00 2001 From: Unreal Hoang Date: Tue, 9 Jul 2019 01:01:07 +0900 Subject: beautify tests --- crates/ra_hir/src/ty/tests.rs | 56 +++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index d5c03c4bc..6aea1fb4a 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -25,33 +25,41 @@ fn infer_try() { let (mut db, pos) = MockDatabase::with_position( r#" //- /main.rs -enum Result { - Ok(O), - Err(E) -} -impl ::std::ops::Try for Result { - type Ok = O; - type Error = E; -} fn test() { let r: Result = Result::Ok(1); let v = r?; v<|>; } -//- /lib.rs +//- /std.rs + +#[prelude_import] use ops::*; mod ops { trait Try { type Ok; type Error; } } + +#[prelude_import] use result::*; +mod result { + enum Result { + Ok(O), + Err(E) + } + + impl crate::ops::Try for Result { + type Ok = O; + type Error = E; + } +} + "#, ); db.set_crate_graph_from_fixture(crate_graph! { "main": ("/main.rs", ["std"]), - "std": ("/lib.rs", []), + "std": ("/std.rs", []), }); assert_eq!("i32", type_at_pos(&db, pos)); } @@ -61,15 +69,9 @@ fn infer_for_loop() { let (mut db, pos) = MockDatabase::with_position( r#" //- /main.rs -struct Vec {} -impl Vec { - fn new() -> Self { Vec {} } - fn push(&mut self, t: T) { } -} -impl ::std::iter::IntoIterator for Vec { - type Item=T; -} +use std::collections::Vec; + fn test() { let v = Vec::new(); v.push("foo"); @@ -78,17 +80,31 @@ fn test() { } } -//- /lib.rs +//- /std.rs + +#[prelude_import] use iter::*; mod iter { trait IntoIterator { type Item; } } + +mod collections { + struct Vec {} + impl Vec { + fn new() -> Self { Vec {} } + fn push(&mut self, t: T) { } + } + + impl crate::iter::IntoIterator for Vec { + 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)); } -- cgit v1.2.3