From 0edb5b4a501a66baa7db8ececf46135e6246f4de Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 24 Dec 2019 19:45:28 +0800 Subject: [PATCH] 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 1aa9a9b7d7..0a282f31b5 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 8e12942011..bf401df359 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 e97b814739..08c220cfe8 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 76e2198b66..08d1bf0449 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 9f9d6e63cb..73e1c407c0 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 f99984fe0f..8bf6aa2f0d 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 08aafb610d..7d11f0176c 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" ], ),