Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/expr_store/body.rs')
| -rw-r--r-- | crates/hir-def/src/expr_store/body.rs | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/crates/hir-def/src/expr_store/body.rs b/crates/hir-def/src/expr_store/body.rs index 6be3e49a70..2fb47e59c5 100644 --- a/crates/hir-def/src/expr_store/body.rs +++ b/crates/hir-def/src/expr_store/body.rs @@ -2,6 +2,7 @@ //! consts. use std::ops; +use arrayvec::ArrayVec; use hir_expand::{InFile, Lookup}; use span::Edition; use syntax::ast; @@ -28,7 +29,12 @@ pub struct Body { /// If this `Body` is for the body of a constant, this will just be /// empty. pub params: Box<[PatId]>, - pub self_param: Option<BindingId>, + /// The first element, if it exists, is the real `self` binding. + /// + /// The second element is used for `async fn` (or `gen fn` etc.). These functions + /// have to put a `let self = self` inside the returned coroutine, and the second element + /// points at it. + pub self_params: ArrayVec<BindingId, 2>, } impl ops::Deref for Body { @@ -74,6 +80,7 @@ impl Body { let mut params = None; let mut is_async_fn = false; + let mut is_gen_fn = false; let InFile { file_id, value: body } = { match def { DefWithBodyId::FunctionId(f) => { @@ -81,6 +88,7 @@ impl Body { let src = f.source(db); params = src.value.param_list(); is_async_fn = src.value.async_token().is_some(); + is_gen_fn = src.value.gen_token().is_some(); src.map(|it| it.body().map(ast::Expr::from)) } DefWithBodyId::ConstId(c) => { @@ -101,7 +109,8 @@ impl Body { } }; let module = def.module(db); - let (body, source_map) = lower_body(db, def, file_id, module, params, body, is_async_fn); + let (body, source_map) = + lower_body(db, def, file_id, module, params, body, is_async_fn, is_gen_fn); (Arc::new(body), source_map) } @@ -114,7 +123,19 @@ impl Body { impl Body { pub fn root_expr(&self) -> ExprId { - self.store.expr_roots().next().unwrap() + // A `Body` can also contain root expressions that aren't the body (in the param patterns), + // but the body always come last. + self.store.expr_roots().next_back().unwrap() + } + + pub fn self_param(&self) -> Option<BindingId> { + self.self_params.first().copied() + } + + /// `async fn` (or `gen fn` etc.), have to put a `let self = self` inside the returned coroutine. + /// This function returns it. + pub fn coroutine_self_binding(&self) -> Option<BindingId> { + self.self_params.get(1).copied() } pub fn pretty_print( |