From 5ac9f5cdc7a88dcb9545d2e150780c8edee83b06 Mon Sep 17 00:00:00 2001 From: Unreal Hoang Date: Sat, 20 Jul 2019 19:35:49 +0900 Subject: add await expr to ast --- crates/ra_hir/src/expr.rs | 8 ++++++++ crates/ra_hir/src/ty/infer.rs | 3 +++ crates/ra_syntax/src/ast/generated.rs | 33 ++++++++++++++++++++++++++++++++- crates/ra_syntax/src/grammar.ron | 2 ++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 66cb9633b..7e3e0a07d 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -220,6 +220,9 @@ pub enum Expr { expr: ExprId, name: Name, }, + Await { + expr: ExprId, + }, Try { expr: ExprId, }, @@ -359,6 +362,7 @@ impl Expr { f(*rhs); } Expr::Field { expr, .. } + | Expr::Await { expr } | Expr::Try { expr } | Expr::Cast { expr, .. } | Expr::Ref { expr, .. } @@ -729,6 +733,10 @@ where }; self.alloc_expr(Expr::Field { expr, name }, syntax_ptr) } + ast::ExprKind::AwaitExpr(e) => { + let expr = self.collect_expr_opt(e.expr()); + self.alloc_expr(Expr::Await { expr }, syntax_ptr) + } ast::ExprKind::TryExpr(e) => { let expr = self.collect_expr_opt(e.expr()); self.alloc_expr(Expr::Try { expr }, syntax_ptr) diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 0e030576d..6eae595a9 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -1114,6 +1114,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { .unwrap_or(Ty::Unknown); self.insert_type_vars(ty) } + Expr::Await { .. } => { + Ty::Unknown + } Expr::Try { expr } => { let inner_ty = self.infer_expr(*expr, &Expectation::none()); let ty = match self.resolve_ops_try_ok() { diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 99fcdbd9a..da8cf4ae8 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -175,6 +175,32 @@ impl Attr { } } +// AwaitExpr +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AwaitExpr { + pub(crate) syntax: SyntaxNode, +} + +impl AstNode for AwaitExpr { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + AWAIT_EXPR => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { Some(AwaitExpr { syntax }) } else { None } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} + + +impl AwaitExpr { + pub fn expr(&self) -> Option { + super::child_opt(self) + } +} + // BinExpr #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct BinExpr { @@ -566,7 +592,7 @@ pub struct Expr { impl AstNode for Expr { fn can_cast(kind: SyntaxKind) -> bool { match kind { - | TUPLE_EXPR | ARRAY_EXPR | PAREN_EXPR | PATH_EXPR | LAMBDA_EXPR | IF_EXPR | LOOP_EXPR | FOR_EXPR | WHILE_EXPR | CONTINUE_EXPR | BREAK_EXPR | LABEL | BLOCK_EXPR | RETURN_EXPR | MATCH_EXPR | STRUCT_LIT | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR | FIELD_EXPR | TRY_EXPR | TRY_BLOCK_EXPR | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL => true, + | TUPLE_EXPR | ARRAY_EXPR | PAREN_EXPR | PATH_EXPR | LAMBDA_EXPR | IF_EXPR | LOOP_EXPR | FOR_EXPR | WHILE_EXPR | CONTINUE_EXPR | BREAK_EXPR | LABEL | BLOCK_EXPR | RETURN_EXPR | MATCH_EXPR | STRUCT_LIT | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR | FIELD_EXPR | AWAIT_EXPR | TRY_EXPR | TRY_BLOCK_EXPR | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL => true, _ => false, } } @@ -599,6 +625,7 @@ pub enum ExprKind { IndexExpr(IndexExpr), MethodCallExpr(MethodCallExpr), FieldExpr(FieldExpr), + AwaitExpr(AwaitExpr), TryExpr(TryExpr), TryBlockExpr(TryBlockExpr), CastExpr(CastExpr), @@ -669,6 +696,9 @@ impl From for Expr { impl From for Expr { fn from(n: FieldExpr) -> Expr { Expr { syntax: n.syntax } } } +impl From for Expr { + fn from(n: AwaitExpr) -> Expr { Expr { syntax: n.syntax } } +} impl From for Expr { fn from(n: TryExpr) -> Expr { Expr { syntax: n.syntax } } } @@ -719,6 +749,7 @@ impl Expr { INDEX_EXPR => ExprKind::IndexExpr(IndexExpr::cast(self.syntax.clone()).unwrap()), METHOD_CALL_EXPR => ExprKind::MethodCallExpr(MethodCallExpr::cast(self.syntax.clone()).unwrap()), FIELD_EXPR => ExprKind::FieldExpr(FieldExpr::cast(self.syntax.clone()).unwrap()), + AWAIT_EXPR => ExprKind::AwaitExpr(AwaitExpr::cast(self.syntax.clone()).unwrap()), TRY_EXPR => ExprKind::TryExpr(TryExpr::cast(self.syntax.clone()).unwrap()), TRY_BLOCK_EXPR => ExprKind::TryBlockExpr(TryBlockExpr::cast(self.syntax.clone()).unwrap()), CAST_EXPR => ExprKind::CastExpr(CastExpr::cast(self.syntax.clone()).unwrap()), diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 55494239e..817dedfbf 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -477,6 +477,7 @@ Grammar( ), "IndexExpr": (), "FieldExpr": (options: ["Expr", "NameRef"]), + "AwaitExpr": (options: ["Expr"]), "TryExpr": (options: ["Expr"]), "CastExpr": (options: ["Expr", "TypeRef"]), "RefExpr": (options: ["Expr"]), @@ -508,6 +509,7 @@ Grammar( "IndexExpr", "MethodCallExpr", "FieldExpr", + "AwaitExpr", "TryExpr", "TryBlockExpr", "CastExpr", -- cgit v1.2.3 From bacf926a77a3e4040ccaf64cce1b1517e41a8d47 Mon Sep 17 00:00:00 2001 From: Unreal Hoang Date: Sat, 20 Jul 2019 20:11:18 +0900 Subject: infer type for await by projecting inner_ty to Future::Output alias --- crates/ra_hir/src/name.rs | 3 +++ crates/ra_hir/src/ty/infer.rs | 42 ++++++++++++++++++++++++++++++++++++++++-- crates/ra_hir/src/ty/tests.rs | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index c589f8aba..6d14eea8e 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs @@ -118,6 +118,9 @@ 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")); +pub(crate) const FUTURE_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); +pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); +pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); 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 6eae595a9..a82dff711 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -1114,8 +1114,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { .unwrap_or(Ty::Unknown); self.insert_type_vars(ty) } - Expr::Await { .. } => { - Ty::Unknown + Expr::Await { expr } => { + let inner_ty = self.infer_expr(*expr, &Expectation::none()); + let ty = match self.resolve_future_future_output() { + Some(future_future_output_alias) => { + let ty = self.new_type_var(); + let projection = ProjectionPredicate { + ty: ty.clone(), + projection_ty: ProjectionTy { + associated_ty: future_future_output_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::Try { expr } => { let inner_ty = self.infer_expr(*expr, &Expectation::none()); @@ -1371,6 +1387,28 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { _ => None, } } + + fn resolve_future_future_output(&self) -> Option { + let future_future_path = Path { + kind: PathKind::Abs, + segments: vec![ + PathSegment { name: name::STD, args_and_bindings: None }, + PathSegment { name: name::FUTURE_MOD, args_and_bindings: None }, + PathSegment { name: name::FUTURE_TYPE, args_and_bindings: None }, + ], + }; + + match self + .resolver + .resolve_path_segments(self.db, &future_future_path) + .into_fully_resolved() + { + PerNs { types: Some(Def(Trait(trait_))), .. } => { + Some(trait_.associated_type_by_name(self.db, name::OUTPUT)?) + } + _ => 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 265740e54..d4bfcb888 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -20,6 +20,41 @@ use crate::{ // against snapshots of the expected results using insta. Use cargo-insta to // update the snapshots. +#[test] +fn infer_await() { + let (mut db, pos) = MockDatabase::with_position( + r#" +//- /main.rs + +struct IntFuture; + +impl Future for IntFuture { + type Output = u64; +} + +fn test() { + let r = IntFuture; + let v = r.await; + v<|>; +} + +//- /std.rs +#[prelude_import] use future::*; +mod future { + trait Future { + type Output; + } +} + +"#, + ); + db.set_crate_graph_from_fixture(crate_graph! { + "main": ("/main.rs", ["std"]), + "std": ("/std.rs", []), + }); + assert_eq!("u64", type_at_pos(&db, pos)); +} + #[test] fn infer_try() { let (mut db, pos) = MockDatabase::with_position( -- cgit v1.2.3