Unnamed repository; edit this file 'description' to name the repository.
Provide source map for the lowered `let self = self` binding in async fns
| -rw-r--r-- | crates/hir-def/src/expr_store/body.rs | 18 | ||||
| -rw-r--r-- | crates/hir-def/src/expr_store/lower.rs | 24 | ||||
| -rw-r--r-- | crates/hir-def/src/expr_store/pretty.rs | 2 | ||||
| -rw-r--r-- | crates/hir-def/src/expr_store/scope.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/mir/lower.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/closure_captures.rs | 12 | ||||
| -rw-r--r-- | crates/hir/src/display.rs | 2 | ||||
| -rw-r--r-- | crates/hir/src/lib.rs | 12 | ||||
| -rw-r--r-- | crates/hir/src/semantics/source_to_def.rs | 2 | ||||
| -rw-r--r-- | crates/hir/src/source_analyzer.rs | 2 |
12 files changed, 50 insertions, 32 deletions
diff --git a/crates/hir-def/src/expr_store/body.rs b/crates/hir-def/src/expr_store/body.rs index 3c7452507e..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 { @@ -122,6 +128,16 @@ impl Body { 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( &self, db: &dyn DefDatabase, diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index e683f06840..6060a5a234 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -8,6 +8,7 @@ mod path; use std::{cell::OnceCell, mem}; +use arrayvec::ArrayVec; use base_db::FxIndexSet; use cfg::CfgOptions; use either::Either; @@ -81,7 +82,7 @@ pub(super) fn lower_body( // even though they should be the same. Also, when the body comes from multiple expansions, their // hygiene is different. - let mut self_param = None; + let mut self_params = ArrayVec::new(); let mut source_map_self_param = None; let mut params = vec![]; let mut collector = ExprCollector::new(db, module, current_file_id); @@ -114,7 +115,7 @@ pub(super) fn lower_body( BindingAnnotation::new(is_mutable, false), hygiene, ); - self_param = Some(binding_id); + self_params.push(binding_id); source_map_self_param = Some(collector.expander.in_file(AstPtr::new(&self_param_syn))); } @@ -124,7 +125,7 @@ pub(super) fn lower_body( collector.with_expr_root(|collector| collector.missing_expr()); let (store, source_map) = collector.store.finish(); return ( - Body { store, params: params.into_boxed_slice(), self_param }, + Body { store, params: params.into_boxed_slice(), self_params }, BodySourceMap { self_param: source_map_self_param, store: source_map }, ); } @@ -142,7 +143,7 @@ pub(super) fn lower_body( BindingAnnotation::new(is_mutable, false), hygiene, ); - self_param = Some(binding_id); + self_params.push(binding_id); source_map_self_param = Some(collector.expander.in_file(AstPtr::new(&self_param_syn))); } @@ -166,7 +167,7 @@ pub(super) fn lower_body( collector.with_expr_root(|collector| { collector.collect( - self_param, + &mut self_params, &mut params, body, if is_async_fn { @@ -186,7 +187,7 @@ pub(super) fn lower_body( let (store, source_map) = collector.store.finish(); ( - Body { store, params: params.into_boxed_slice(), self_param }, + Body { store, params: params.into_boxed_slice(), self_params }, BodySourceMap { self_param: source_map_self_param, store: source_map }, ) } @@ -946,7 +947,7 @@ impl<'db> ExprCollector<'db> { /// drop order are stable. fn lower_coroutine_body_with_moved_arguments( &mut self, - self_param: Option<BindingId>, + self_params: &mut ArrayVec<BindingId, 2>, params: &mut [PatId], body: ExprId, kind: CoroutineKind, @@ -980,7 +981,7 @@ impl<'db> ExprCollector<'db> { let mut statements = Vec::new(); - if let Some(self_param) = self_param { + if let Some(&self_param) = self_params.first() { let Binding { ref name, mode, hygiene, .. } = self.store.bindings[self_param]; let name = name.clone(); let child_binding_id = self.alloc_binding(name.clone(), mode, hygiene); @@ -997,6 +998,7 @@ impl<'db> ExprCollector<'db> { initializer: Some(expr), else_branch: None, }); + self_params.push(child_binding_id); } for param in params { @@ -1098,7 +1100,7 @@ impl<'db> ExprCollector<'db> { fn collect( &mut self, - self_param: Option<BindingId>, + self_params: &mut ArrayVec<BindingId, 2>, params: &mut [PatId], expr: Option<ast::Expr>, awaitable: Awaitable, @@ -1116,7 +1118,7 @@ impl<'db> ExprCollector<'db> { (false, false) => unreachable!(), }; this.lower_coroutine_body_with_moved_arguments( - self_param, + self_params, params, body, kind, @@ -1593,7 +1595,7 @@ impl<'db> ExprCollector<'db> { // It's important that this expr is allocated immediately before the closure. // We rely on it for `coroutine_for_closure()`. body = this.lower_coroutine_body_with_moved_arguments( - None, + &mut ArrayVec::new(), &mut args, body, kind, diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs index 5afd7f38a7..34cedbd728 100644 --- a/crates/hir-def/src/expr_store/pretty.rs +++ b/crates/hir-def/src/expr_store/pretty.rs @@ -92,7 +92,7 @@ pub fn print_body_hir( }; if let DefWithBodyId::FunctionId(_) = owner { p.buf.push('('); - if let Some(self_param) = body.self_param { + if let Some(self_param) = body.self_param() { p.print_binding(self_param); p.buf.push_str(", "); } diff --git a/crates/hir-def/src/expr_store/scope.rs b/crates/hir-def/src/expr_store/scope.rs index 5663b8155c..ddb8285137 100644 --- a/crates/hir-def/src/expr_store/scope.rs +++ b/crates/hir-def/src/expr_store/scope.rs @@ -147,7 +147,7 @@ impl ExprScopes { ), }; let mut root = scopes.root_scope(); - if let Some(self_param) = body.self_param { + if let Some(self_param) = body.self_param() { scopes.add_bindings(body, root, self_param, body.binding_hygiene(self_param)); } scopes.add_params_bindings(body, root, &body.params); diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index b399a7e0ed..3ae3525baa 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -140,7 +140,7 @@ pub fn infer_query_with_inspect<'db>( } match def { - DefWithBodyId::FunctionId(f) => ctx.collect_fn(f, body.self_param, &body.params), + DefWithBodyId::FunctionId(f) => ctx.collect_fn(f, body.self_param(), &body.params), DefWithBodyId::ConstId(c) => ctx.collect_const(c, ConstSignature::of(db, c)), DefWithBodyId::StaticId(s) => ctx.collect_static(s, StaticSignature::of(db, s)), DefWithBodyId::VariantId(v) => { diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 763d52398b..3852db909e 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -2320,7 +2320,7 @@ pub fn mir_body_query<'db>(db: &'db dyn HirDatabase, def: InferBodyId) -> Result let (store, root_expr, self_param, params) = match def { InferBodyId::DefWithBodyId(def) => { let body = Body::of(db, def); - (&**body, body.root_expr(), body.self_param, &*body.params) + (&**body, body.root_expr(), body.self_param(), &*body.params) } InferBodyId::AnonConstId(def) => { let loc = def.loc(db); diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 9e70f69bad..d259ce7963 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -514,7 +514,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { for (def, krate) in defs { let (body, source_map) = Body::with_source_map(&db, def); let infer = InferenceResult::of(&db, def); - let self_param = body.self_param.map(|id| (id, source_map.self_param_syntax())); + let self_param = body.self_param().map(|id| (id, source_map.self_param_syntax())); infer_def(infer, body, source_map, self_param, krate); } diff --git a/crates/hir-ty/src/tests/closure_captures.rs b/crates/hir-ty/src/tests/closure_captures.rs index b01f44acbc..0a38635930 100644 --- a/crates/hir-ty/src/tests/closure_captures.rs +++ b/crates/hir-ty/src/tests/closure_captures.rs @@ -102,19 +102,19 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec // FIXME: Deduplicate this with hir::Local::sources(). let captured_local = capture.captured_local(); - let local_text_range = match body.self_param.zip(source_map.self_param_syntax()) + let local_text_range = if body.self_params.contains(&captured_local) + && let Some(source) = source_map.self_param_syntax() { - Some((param, source)) if param == captured_local => { - format!("{:?}", text_range(db, source)) - } - _ => source_map + format!("{:?}", text_range(db, source)) + } else { + source_map .patterns_for_binding(captured_local) .iter() .map(|&definition| { text_range(db, source_map.pat_syntax(definition).unwrap()) }) .map(|it| format!("{it:?}")) - .join(", "), + .join(", ") }; let place = display_place(db, body, &capture.place, captured_local); let capture_ty = capture diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index c87a175cee..a71851ea8c 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -204,7 +204,7 @@ fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Re first = false; } - let pat_id = body.params[param.idx - body.self_param.is_some() as usize]; + let pat_id = body.params[param.idx - body.self_param().is_some() as usize]; let pat_str = body.pretty_print_pat(db, func_id.into(), pat_id, true, f.edition()); f.write_str(&pat_str)?; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 3f83d068bb..0423a8fc4f 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -3000,14 +3000,14 @@ impl<'db> Param<'db> { Callee::Def(CallableDefId::FunctionId(it)) => { let parent = DefWithBodyId::FunctionId(it); let body = Body::of(db, parent); - if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) { + if let Some(self_param) = body.self_param().filter(|_| self.idx == 0) { Some(Local { parent: parent.into(), parent_infer: parent.into(), binding_id: self_param, }) } else if let Pat::Bind { id, .. } = - &body[body.params[self.idx - body.self_param.is_some() as usize]] + &body[body.params[self.idx - body.self_param().is_some() as usize]] { Some(Local { parent: parent.into(), @@ -4466,8 +4466,8 @@ impl Local { } ExpressionStoreOwnerId::Body(def_with_body_id) => { b = Body::with_source_map(db, def_with_body_id); - if let Some((param, source)) = b.0.self_param.zip(b.1.self_param_syntax()) - && param == self.binding_id + if b.0.self_params.contains(&self.binding_id) + && let Some(source) = b.1.self_param_syntax() { let root = source.file_syntax(db); return vec![LocalSource { @@ -4507,8 +4507,8 @@ impl Local { } ExpressionStoreOwnerId::Body(def_with_body_id) => { b = Body::with_source_map(db, def_with_body_id); - if let Some((param, source)) = b.0.self_param.zip(b.1.self_param_syntax()) - && param == self.binding_id + if b.0.self_params.contains(&self.binding_id) + && let Some(source) = b.1.self_param_syntax() { let root = source.file_syntax(db); return LocalSource { diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 1d1acd7f8e..583b3e4bda 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -371,7 +371,7 @@ impl SourceToDefCtx<'_, '_> { .as_expression_store_owner()? .as_def_with_body()?; let body = Body::of(self.db, container); - Some((container, body.self_param?)) + Some((container, body.self_param()?)) } pub(super) fn label_to_def( &mut self, diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 4029b004a7..cb3516ffdc 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -472,7 +472,7 @@ impl<'db> SourceAnalyzer<'db> { ) -> Option<Type<'db>> { let binding = match self.body_or_sig.as_ref()? { BodyOrSig::Sig { .. } | BodyOrSig::VariantFields { .. } => return None, - BodyOrSig::Body { body, .. } => body.self_param?, + BodyOrSig::Body { body, .. } => body.self_param()?, }; let ty = self.infer()?.binding_ty(binding); Some(Type::new_with_resolver(db, &self.resolver, ty)) |