Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/body/lower.rs')
| -rw-r--r-- | crates/hir-def/src/body/lower.rs | 101 |
1 files changed, 78 insertions, 23 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index e6bea706d8..688c9e86bb 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -28,9 +28,9 @@ use crate::{ data::adt::StructKind, db::DefDatabase, hir::{ - dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, ClosureKind, Expr, ExprId, - Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat, RecordLitField, - Statement, + dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Expr, + ExprId, Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat, + RecordLitField, Statement, }, item_scope::BuiltinShadowMode, lang_item::LangItem, @@ -67,6 +67,7 @@ pub(super) fn lower( is_lowering_assignee_expr: false, is_lowering_generator: false, label_ribs: Vec::new(), + current_binding_owner: None, } .collect(params, body, is_async_fn) } @@ -92,6 +93,7 @@ struct ExprCollector<'a> { // resolution label_ribs: Vec<LabelRib>, + current_binding_owner: Option<ExprId>, } #[derive(Clone, Debug)] @@ -261,11 +263,16 @@ impl ExprCollector<'_> { } Some(ast::BlockModifier::Const(_)) => { self.with_label_rib(RibKind::Constant, |this| { - this.collect_block_(e, |id, statements, tail| Expr::Const { - id, - statements, - tail, - }) + this.collect_as_a_binding_owner_bad( + |this| { + this.collect_block_(e, |id, statements, tail| Expr::Const { + id, + statements, + tail, + }) + }, + syntax_ptr, + ) }) } None => self.collect_block(e), @@ -461,6 +468,8 @@ impl ExprCollector<'_> { } } ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| { + let (result_expr_id, prev_binding_owner) = + this.initialize_binding_owner(syntax_ptr); let mut args = Vec::new(); let mut arg_types = Vec::new(); if let Some(pl) = e.param_list() { @@ -494,17 +503,19 @@ impl ExprCollector<'_> { ClosureKind::Closure }; this.is_lowering_generator = prev_is_lowering_generator; - - this.alloc_expr( - Expr::Closure { - args: args.into(), - arg_types: arg_types.into(), - ret_type, - body, - closure_kind, - }, - syntax_ptr, - ) + let capture_by = + if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref }; + this.is_lowering_generator = prev_is_lowering_generator; + this.current_binding_owner = prev_binding_owner; + this.body.exprs[result_expr_id] = Expr::Closure { + args: args.into(), + arg_types: arg_types.into(), + ret_type, + body, + closure_kind, + capture_by, + }; + result_expr_id }), ast::Expr::BinExpr(e) => { let op = e.op_kind(); @@ -545,7 +556,15 @@ impl ExprCollector<'_> { ArrayExprKind::Repeat { initializer, repeat } => { let initializer = self.collect_expr_opt(initializer); let repeat = self.with_label_rib(RibKind::Constant, |this| { - this.collect_expr_opt(repeat) + if let Some(repeat) = repeat { + let syntax_ptr = AstPtr::new(&repeat); + this.collect_as_a_binding_owner_bad( + |this| this.collect_expr(repeat), + syntax_ptr, + ) + } else { + this.missing_expr() + } }); self.alloc_expr( Expr::Array(Array::Repeat { initializer, repeat }), @@ -592,6 +611,32 @@ impl ExprCollector<'_> { }) } + fn initialize_binding_owner( + &mut self, + syntax_ptr: AstPtr<ast::Expr>, + ) -> (ExprId, Option<ExprId>) { + let result_expr_id = self.alloc_expr(Expr::Missing, syntax_ptr); + let prev_binding_owner = self.current_binding_owner.take(); + self.current_binding_owner = Some(result_expr_id); + (result_expr_id, prev_binding_owner) + } + + /// FIXME: This function is bad. It will produce a dangling `Missing` expr which wastes memory. Currently + /// it is used only for const blocks and repeat expressions, which are also hacky and ideally should have + /// their own body. Don't add more usage for this function so that we can remove this function after + /// separating those bodies. + fn collect_as_a_binding_owner_bad( + &mut self, + job: impl FnOnce(&mut ExprCollector<'_>) -> ExprId, + syntax_ptr: AstPtr<ast::Expr>, + ) -> ExprId { + let (id, prev_owner) = self.initialize_binding_owner(syntax_ptr); + let tmp = job(self); + self.body.exprs[id] = mem::replace(&mut self.body.exprs[tmp], Expr::Missing); + self.current_binding_owner = prev_owner; + id + } + /// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`, /// `try { <stmts>; }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(()) }` /// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator. @@ -1112,8 +1157,13 @@ impl ExprCollector<'_> { } ast::Pat::ConstBlockPat(const_block_pat) => { if let Some(block) = const_block_pat.block_expr() { - let expr_id = - self.with_label_rib(RibKind::Constant, |this| this.collect_block(block)); + let expr_id = self.with_label_rib(RibKind::Constant, |this| { + let syntax_ptr = AstPtr::new(&block.clone().into()); + this.collect_as_a_binding_owner_bad( + |this| this.collect_block(block), + syntax_ptr, + ) + }); Pat::ConstBlock(expr_id) } else { Pat::Missing @@ -1272,7 +1322,12 @@ impl ExprCollector<'_> { } fn alloc_binding(&mut self, name: Name, mode: BindingAnnotation) -> BindingId { - self.body.bindings.alloc(Binding { name, mode, definitions: SmallVec::new() }) + self.body.bindings.alloc(Binding { + name, + mode, + definitions: SmallVec::new(), + owner: self.current_binding_owner, + }) } fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { |