Implement infer await from async func

This commit is contained in:
Edwin Cheng 2019-12-24 19:45:28 +08:00
parent 60aa4d12f9
commit 0edb5b4a50
7 changed files with 112 additions and 5 deletions

View File

@ -6,12 +6,15 @@
name::{name, AsName, Name}, name::{name, AsName, Name},
AstId, InFile, 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::{ use crate::{
db::DefDatabase, db::DefDatabase,
path::{path, GenericArgs, Path},
src::HasSource, src::HasSource,
type_ref::{Mutability, TypeRef}, type_ref::{Mutability, TypeBound, TypeRef},
AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule,
ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
}; };
@ -62,11 +65,31 @@ pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<Func
TypeRef::unit() 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 }; let sig = FunctionData { name, params, ret_type, has_self_param };
Arc::new(sig) 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)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeAliasData { pub struct TypeAliasData {
pub name: Name, pub name: Name,

View File

@ -130,6 +130,11 @@ pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] } 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<Option<Arc<GenericArgs>>>) -> Path {
Path { type_anchor: None, mod_path: path, generic_args }
}
pub fn kind(&self) -> &PathKind { pub fn kind(&self) -> &PathKind {
&self.mod_path.kind &self.mod_path.kind
} }

View File

@ -37,8 +37,8 @@
use super::{ use super::{
primitive::{FloatTy, IntTy}, primitive::{FloatTy, IntTy},
traits::{Guidance, Obligation, ProjectionPredicate, Solution}, traits::{Guidance, Obligation, ProjectionPredicate, Solution},
ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, ApplicationTy, GenericPredicate, InEnvironment, ProjectionTy, Substs, TraitEnvironment,
TypeWalk, Uncertain, TraitRef, Ty, TypeCtor, TypeWalk, Uncertain,
}; };
use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic};
@ -379,6 +379,19 @@ fn resolve_associated_type_with_params(
) -> Ty { ) -> Ty {
match assoc_ty { match assoc_ty {
Some(res_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 ty = self.table.new_type_var();
let builder = Substs::build_for_def(self.db, res_assoc_ty) let builder = Substs::build_for_def(self.db, res_assoc_ty)
.push(inner_ty) .push(inner_ty)

View File

@ -37,6 +37,63 @@ trait Future {
assert_eq!("u64", type_at_pos(&db, pos)); 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<Output = u64>", type_at_pos(&db, pos));
}
#[test] #[test]
fn infer_try() { fn infer_try() {
let (db, pos) = TestDB::with_position( let (db, pos) = TestDB::with_position(

View File

@ -1129,6 +1129,7 @@ impl ast::NameOwner for FnDef {}
impl ast::TypeParamsOwner for FnDef {} impl ast::TypeParamsOwner for FnDef {}
impl ast::AttrsOwner for FnDef {} impl ast::AttrsOwner for FnDef {}
impl ast::DocCommentsOwner for FnDef {} impl ast::DocCommentsOwner for FnDef {}
impl ast::AsyncOwner for FnDef {}
impl FnDef { impl FnDef {
pub fn param_list(&self) -> Option<ParamList> { pub fn param_list(&self) -> Option<ParamList> {
AstChildren::new(&self.syntax).next() AstChildren::new(&self.syntax).next()

View File

@ -8,6 +8,7 @@
ast::{self, child_opt, children, AstChildren, AstNode, AstToken}, ast::{self, child_opt, children, AstChildren, AstNode, AstToken},
match_ast, match_ast,
syntax_node::{SyntaxElementChildren, SyntaxNodeChildren}, syntax_node::{SyntaxElementChildren, SyntaxNodeChildren},
SyntaxKind,
}; };
pub trait TypeAscriptionOwner: AstNode { pub trait TypeAscriptionOwner: AstNode {
@ -105,6 +106,12 @@ fn has_atom_attr(&self, atom: &str) -> bool {
} }
} }
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 { pub trait DocCommentsOwner: AstNode {
fn doc_comments(&self) -> CommentIter { fn doc_comments(&self) -> CommentIter {
CommentIter { iter: self.syntax().children_with_tokens() } CommentIter { iter: self.syntax().children_with_tokens() }

View File

@ -275,7 +275,8 @@ Grammar(
"NameOwner", "NameOwner",
"TypeParamsOwner", "TypeParamsOwner",
"AttrsOwner", "AttrsOwner",
"DocCommentsOwner" "DocCommentsOwner",
"AsyncOwner"
], ],
options: [ "ParamList", ["body", "BlockExpr"], "RetType" ], options: [ "ParamList", ["body", "BlockExpr"], "RetType" ],
), ),