Implement infer await from async func
This commit is contained in:
parent
60aa4d12f9
commit
0edb5b4a50
@ -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,
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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(
|
||||||
|
@ -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()
|
||||||
|
@ -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() }
|
||||||
|
@ -275,7 +275,8 @@ Grammar(
|
|||||||
"NameOwner",
|
"NameOwner",
|
||||||
"TypeParamsOwner",
|
"TypeParamsOwner",
|
||||||
"AttrsOwner",
|
"AttrsOwner",
|
||||||
"DocCommentsOwner"
|
"DocCommentsOwner",
|
||||||
|
"AsyncOwner"
|
||||||
],
|
],
|
||||||
options: [ "ParamList", ["body", "BlockExpr"], "RetType" ],
|
options: [ "ParamList", ["body", "BlockExpr"], "RetType" ],
|
||||||
),
|
),
|
||||||
|
Loading…
Reference in New Issue
Block a user