From 0edb5b4a501a66baa7db8ececf46135e6246f4de Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 24 Dec 2019 19:45:28 +0800 Subject: Implement infer await from async func --- crates/ra_hir_def/src/data.rs | 27 +++++++++++++++-- crates/ra_hir_def/src/path.rs | 5 +++ crates/ra_hir_ty/src/infer.rs | 17 +++++++++-- crates/ra_hir_ty/src/tests/traits.rs | 57 +++++++++++++++++++++++++++++++++++ crates/ra_syntax/src/ast/generated.rs | 1 + crates/ra_syntax/src/ast/traits.rs | 7 +++++ crates/ra_syntax/src/grammar.ron | 3 +- 7 files changed, 112 insertions(+), 5 deletions(-) diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 1aa9a9b7d..0a282f31b 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -6,12 +6,15 @@ use hir_expand::{ name::{name, AsName, Name}, AstId, InFile, }; -use ra_syntax::ast::{self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner}; +use ra_syntax::ast::{ + self, AstNode, AsyncOwner, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, +}; use crate::{ db::DefDatabase, + path::{path, GenericArgs, Path}, src::HasSource, - type_ref::{Mutability, TypeRef}, + type_ref::{Mutability, TypeBound, TypeRef}, AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, }; @@ -62,11 +65,31 @@ impl FunctionData { TypeRef::unit() }; + let ret_type = if src.value.is_async() { + let future_impl = desugar_future_path(ret_type); + let ty_bound = TypeBound::Path(future_impl); + TypeRef::ImplTrait(vec![ty_bound]) + } else { + ret_type + }; + let sig = FunctionData { name, params, ret_type, has_self_param }; Arc::new(sig) } } +fn desugar_future_path(orig: TypeRef) -> Path { + let path = path![std::future::Future]; + + let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); + + let mut last = GenericArgs::empty(); + last.bindings.push((name![Output], orig)); + generic_args.push(Some(Arc::new(last))); + + Path::from_known_path(path, generic_args) +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct TypeAliasData { pub name: Name, diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 8e1294201..bf401df35 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -130,6 +130,11 @@ impl Path { Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] } } + /// Converts a known mod path to `Path`. + pub(crate) fn from_known_path(path: ModPath, generic_args: Vec>>) -> Path { + Path { type_anchor: None, mod_path: path, generic_args } + } + pub fn kind(&self) -> &PathKind { &self.mod_path.kind } diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index e97b81473..08c220cfe 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -37,8 +37,8 @@ use test_utils::tested_by; use super::{ primitive::{FloatTy, IntTy}, traits::{Guidance, Obligation, ProjectionPredicate, Solution}, - ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, - TypeWalk, Uncertain, + ApplicationTy, GenericPredicate, InEnvironment, ProjectionTy, Substs, TraitEnvironment, + TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, }; use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; @@ -379,6 +379,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ) -> Ty { match assoc_ty { Some(res_assoc_ty) => { + // Fast path: Check if inner_ty is is `impl Trait` and contained input TypeAlias id + if let Ty::Opaque(ref predicates) = inner_ty { + for p in predicates.iter() { + if let GenericPredicate::Projection(projection) = p { + if projection.projection_ty.associated_ty == res_assoc_ty + && projection.ty != Ty::Unknown + { + return projection.ty.clone(); + } + } + } + } + let ty = self.table.new_type_var(); let builder = Substs::build_for_def(self.db, res_assoc_ty) .push(inner_ty) diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 76e2198b6..08d1bf044 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -37,6 +37,63 @@ mod future { assert_eq!("u64", type_at_pos(&db, pos)); } +#[test] +fn infer_async() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std + +async fn foo() -> u64 { + 128 +} + +fn test() { + let r = foo(); + let v = r.await; + v<|>; +} + +//- /std.rs crate:std +#[prelude_import] use future::*; +mod future { + trait Future { + type Output; + } +} + +"#, + ); + assert_eq!("u64", type_at_pos(&db, pos)); +} + +#[test] +fn infer_desugar_async() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std + +async fn foo() -> u64 { + 128 +} + +fn test() { + let r = foo(); + r<|>; +} + +//- /std.rs crate:std +#[prelude_import] use future::*; +mod future { + trait Future { + type Output; + } +} + +"#, + ); + assert_eq!("impl Future", type_at_pos(&db, pos)); +} + #[test] fn infer_try() { let (db, pos) = TestDB::with_position( diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 9f9d6e63c..73e1c407c 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -1129,6 +1129,7 @@ impl ast::NameOwner for FnDef {} impl ast::TypeParamsOwner for FnDef {} impl ast::AttrsOwner for FnDef {} impl ast::DocCommentsOwner for FnDef {} +impl ast::AsyncOwner for FnDef {} impl FnDef { pub fn param_list(&self) -> Option { AstChildren::new(&self.syntax).next() diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs index f99984fe0..8bf6aa2f0 100644 --- a/crates/ra_syntax/src/ast/traits.rs +++ b/crates/ra_syntax/src/ast/traits.rs @@ -8,6 +8,7 @@ use crate::{ ast::{self, child_opt, children, AstChildren, AstNode, AstToken}, match_ast, syntax_node::{SyntaxElementChildren, SyntaxNodeChildren}, + SyntaxKind, }; pub trait TypeAscriptionOwner: AstNode { @@ -105,6 +106,12 @@ pub trait AttrsOwner: AstNode { } } +pub trait AsyncOwner: AstNode { + fn is_async(&self) -> bool { + self.syntax().children_with_tokens().any(|t| t.kind() == SyntaxKind::ASYNC_KW) + } +} + pub trait DocCommentsOwner: AstNode { fn doc_comments(&self) -> CommentIter { CommentIter { iter: self.syntax().children_with_tokens() } diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 08aafb610..7d11f0176 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -275,7 +275,8 @@ Grammar( "NameOwner", "TypeParamsOwner", "AttrsOwner", - "DocCommentsOwner" + "DocCommentsOwner", + "AsyncOwner" ], options: [ "ParamList", ["body", "BlockExpr"], "RetType" ], ), -- cgit v1.2.3 From d0537cda9eb55e7a596a0cf05e0c1423e8c430a8 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 24 Dec 2019 19:52:48 +0800 Subject: Formatting --- crates/ra_hir_def/src/data.rs | 2 -- crates/ra_hir_def/src/path.rs | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 0a282f31b..a1b31c411 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -80,9 +80,7 @@ impl FunctionData { fn desugar_future_path(orig: TypeRef) -> Path { let path = path![std::future::Future]; - let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); - let mut last = GenericArgs::empty(); last.bindings.push((name![Output], orig)); generic_args.push(Some(Arc::new(last))); diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index bf401df35..107d2d799 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -131,7 +131,10 @@ impl Path { } /// Converts a known mod path to `Path`. - pub(crate) fn from_known_path(path: ModPath, generic_args: Vec>>) -> Path { + pub(crate) fn from_known_path( + path: ModPath, + generic_args: Vec>>, + ) -> Path { Path { type_anchor: None, mod_path: path, generic_args } } -- cgit v1.2.3 From 3a2cf708ed1c80d403af957791dfe35ad5dee0a3 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 24 Dec 2019 23:39:17 +0800 Subject: Add FIXME --- crates/ra_hir_ty/src/infer.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 08c220cfe..e40df65e3 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -379,7 +379,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ) -> Ty { match assoc_ty { Some(res_assoc_ty) => { - // Fast path: Check if inner_ty is is `impl Trait` and contained input TypeAlias id + // FIXME: + // Check if inner_ty is is `impl Trait` and contained input TypeAlias id + // this is a workaround while Chalk assoc type projection doesn't always work yet, + // but once that is fixed I don't think we should keep this + // (we'll probably change how associated types are resolved anyway) if let Ty::Opaque(ref predicates) = inner_ty { for p in predicates.iter() { if let GenericPredicate::Projection(projection) = p { -- cgit v1.2.3 From 42813126d92cc1fb145e75752b5a95d884ea9a12 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 24 Dec 2019 23:39:44 +0800 Subject: Check if parameters is empty --- crates/ra_hir_ty/src/infer.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index e40df65e3..32c0d07a5 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -387,10 +387,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { if let Ty::Opaque(ref predicates) = inner_ty { for p in predicates.iter() { if let GenericPredicate::Projection(projection) = p { - if projection.projection_ty.associated_ty == res_assoc_ty - && projection.ty != Ty::Unknown - { - return projection.ty.clone(); + if projection.projection_ty.associated_ty == res_assoc_ty { + if let ty_app!(_, params) = &projection.ty { + if params.len() == 0 { + return projection.ty.clone(); + } + } } } } -- cgit v1.2.3 From 208ad97fdc9427f1243ac170c1c25f9f7d6ae964 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Wed, 25 Dec 2019 00:25:18 +0800 Subject: Remove AsyncOwner --- crates/ra_hir_def/src/data.rs | 4 +--- crates/ra_syntax/src/ast/extensions.rs | 4 ++++ crates/ra_syntax/src/ast/generated.rs | 1 - crates/ra_syntax/src/ast/traits.rs | 7 ------- crates/ra_syntax/src/grammar.ron | 3 +-- 5 files changed, 6 insertions(+), 13 deletions(-) diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index a1b31c411..c900a6a18 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -6,9 +6,7 @@ use hir_expand::{ name::{name, AsName, Name}, AstId, InFile, }; -use ra_syntax::ast::{ - self, AstNode, AsyncOwner, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, -}; +use ra_syntax::ast::{self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner}; use crate::{ db::DefDatabase, diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index a8f625176..baaef3023 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs @@ -221,6 +221,10 @@ impl ast::FnDef { .and_then(|it| it.into_token()) .filter(|it| it.kind() == T![;]) } + + pub fn is_async(&self) -> bool { + self.syntax().children_with_tokens().any(|it| it.kind() == T![async]) + } } impl ast::LetStmt { diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 73e1c407c..9f9d6e63c 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -1129,7 +1129,6 @@ impl ast::NameOwner for FnDef {} impl ast::TypeParamsOwner for FnDef {} impl ast::AttrsOwner for FnDef {} impl ast::DocCommentsOwner for FnDef {} -impl ast::AsyncOwner for FnDef {} impl FnDef { pub fn param_list(&self) -> Option { AstChildren::new(&self.syntax).next() diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs index 8bf6aa2f0..f99984fe0 100644 --- a/crates/ra_syntax/src/ast/traits.rs +++ b/crates/ra_syntax/src/ast/traits.rs @@ -8,7 +8,6 @@ use crate::{ ast::{self, child_opt, children, AstChildren, AstNode, AstToken}, match_ast, syntax_node::{SyntaxElementChildren, SyntaxNodeChildren}, - SyntaxKind, }; pub trait TypeAscriptionOwner: AstNode { @@ -106,12 +105,6 @@ pub trait AttrsOwner: AstNode { } } -pub trait AsyncOwner: AstNode { - fn is_async(&self) -> bool { - self.syntax().children_with_tokens().any(|t| t.kind() == SyntaxKind::ASYNC_KW) - } -} - pub trait DocCommentsOwner: AstNode { fn doc_comments(&self) -> CommentIter { CommentIter { iter: self.syntax().children_with_tokens() } diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 7d11f0176..08aafb610 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -275,8 +275,7 @@ Grammar( "NameOwner", "TypeParamsOwner", "AttrsOwner", - "DocCommentsOwner", - "AsyncOwner" + "DocCommentsOwner" ], options: [ "ParamList", ["body", "BlockExpr"], "RetType" ], ), -- cgit v1.2.3