]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir_build/src/build/expr/into.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / compiler / rustc_mir_build / src / build / expr / into.rs
CommitLineData
e9174d1e
SL
1//! See docs in build/expr/mod.rs
2
9fa01778
XL
3use crate::build::expr::category::{Category, RvalueFunc};
4use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
3dfed10e 5use rustc_ast::InlineAsmOptions;
60c5eb7d 6use rustc_data_structures::fx::FxHashMap;
3dfed10e 7use rustc_data_structures::stack::ensure_sufficient_stack;
dfeec247 8use rustc_hir as hir;
6a06907d 9use rustc_index::vec::Idx;
ba9703b0 10use rustc_middle::mir::*;
17df50a5 11use rustc_middle::thir::*;
5e7ed085 12use rustc_middle::ty::CanonicalUserTypeAnnotation;
cdc7bbd5 13use std::iter;
cc61c64b 14
dc9dc135 15impl<'a, 'tcx> Builder<'a, 'tcx> {
e9174d1e
SL
16 /// Compile `expr`, storing the result into `destination`, which
17 /// is assumed to be uninitialized.
6a06907d 18 crate fn expr_into_dest(
b7449926 19 &mut self,
ba9703b0 20 destination: Place<'tcx>,
b7449926 21 mut block: BasicBlock,
17df50a5 22 expr: &Expr<'tcx>,
b7449926 23 ) -> BlockAnd<()> {
6a06907d 24 debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
e9174d1e
SL
25
26 // since we frequently have to reference `self` from within a
27 // closure, where `self` would be shadowed, it's easier to
28 // just use the name `this` uniformly
29 let this = self;
30 let expr_span = expr.span;
3157f602 31 let source_info = this.source_info(expr_span);
e9174d1e 32
5869c6ff
XL
33 let expr_is_block_or_scope =
34 matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. });
0bf4aa26
XL
35
36 if !expr_is_block_or_scope {
37 this.block_context.push(BlockFrame::SubExpr);
38 }
39
40 let block_and = match expr.kind {
dfeec247 41 ExprKind::Scope { region_scope, lint_level, value } => {
ea8adc8c 42 let region_scope = (region_scope, source_info);
3dfed10e
XL
43 ensure_sufficient_stack(|| {
44 this.in_scope(region_scope, lint_level, |this| {
17df50a5 45 this.expr_into_dest(destination, block, &this.thir[value])
3dfed10e
XL
46 })
47 })
e9174d1e 48 }
6a06907d 49 ExprKind::Block { body: ref ast_block } => {
cc61c64b 50 this.ast_block(destination, block, ast_block, source_info)
e9174d1e 51 }
17df50a5
XL
52 ExprKind::Match { scrutinee, ref arms } => {
53 this.match_expr(destination, expr_span, block, &this.thir[scrutinee], arms)
e9174d1e 54 }
94222f64
XL
55 ExprKind::If { cond, then, else_opt, if_then_scope } => {
56 let then_blk;
57 let then_expr = &this.thir[then];
58 let then_source_info = this.source_info(then_expr.span);
59 let condition_scope = this.local_scope();
60
61 let mut else_blk = unpack!(
62 then_blk = this.in_scope(
63 (if_then_scope, then_source_info),
64 LintLevel::Inherited,
65 |this| {
66 let (then_block, else_block) =
67 this.in_if_then_scope(condition_scope, |this| {
68 let then_blk = unpack!(this.then_else_break(
69 block,
70 &this.thir[cond],
71 Some(condition_scope),
72 condition_scope,
73 then_expr.span,
74 ));
75 this.expr_into_dest(destination, then_blk, then_expr)
76 });
77 then_block.and(else_block)
78 },
17df50a5 79 )
5869c6ff 80 );
5869c6ff 81
94222f64
XL
82 else_blk = if let Some(else_opt) = else_opt {
83 unpack!(this.expr_into_dest(destination, else_blk, &this.thir[else_opt]))
5869c6ff
XL
84 } else {
85 // Body of the `if` expression without an `else` clause must return `()`, thus
94222f64 86 // we implicitly generate an `else {}` if it is not specified.
5869c6ff 87 let correct_si = this.source_info(expr_span.shrink_to_hi());
94222f64
XL
88 this.cfg.push_assign_unit(else_blk, correct_si, destination, this.tcx);
89 else_blk
5869c6ff
XL
90 };
91
92 let join_block = this.cfg.start_new_block();
5099ac24
FG
93 this.cfg.goto(then_blk, source_info, join_block);
94 this.cfg.goto(else_blk, source_info, join_block);
5869c6ff
XL
95 join_block.unit()
96 }
94222f64
XL
97 ExprKind::Let { expr, ref pat } => {
98 let scope = this.local_scope();
99 let (true_block, false_block) = this.in_if_then_scope(scope, |this| {
100 this.lower_let_expr(block, &this.thir[expr], pat, scope, expr_span)
101 });
102
94222f64
XL
103 this.cfg.push_assign_constant(
104 true_block,
105 source_info,
106 destination,
107 Constant {
108 span: expr_span,
109 user_ty: None,
5e7ed085 110 literal: ConstantKind::from_bool(this.tcx, true),
94222f64
XL
111 },
112 );
113
114 this.cfg.push_assign_constant(
115 false_block,
116 source_info,
117 destination,
118 Constant {
119 span: expr_span,
120 user_ty: None,
5e7ed085 121 literal: ConstantKind::from_bool(this.tcx, false),
94222f64
XL
122 },
123 );
124
5099ac24 125 let join_block = this.cfg.start_new_block();
94222f64
XL
126 this.cfg.goto(true_block, source_info, join_block);
127 this.cfg.goto(false_block, source_info, join_block);
128 join_block.unit()
129 }
5bcae85e 130 ExprKind::NeverToAny { source } => {
17df50a5 131 let source = &this.thir[source];
5869c6ff
XL
132 let is_call =
133 matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. });
5bcae85e 134
60c5eb7d
XL
135 // (#66975) Source could be a const of type `!`, so has to
136 // exist in the generated MIR.
5869c6ff
XL
137 unpack!(
138 block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut,)
139 );
5bcae85e
SL
140
141 // This is an optimization. If the expression was a call then we already have an
142 // unreachable block. Don't bother to terminate it and create a new one.
143 if is_call {
144 block.unit()
145 } else {
dfeec247 146 this.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
5bcae85e
SL
147 let end_block = this.cfg.start_new_block();
148 end_block.unit()
149 }
150 }
e9174d1e
SL
151 ExprKind::LogicalOp { op, lhs, rhs } => {
152 // And:
153 //
cdc7bbd5
XL
154 // [block: If(lhs)] -true-> [else_block: dest = (rhs)]
155 // | (false)
156 // [shortcurcuit_block: dest = false]
e9174d1e
SL
157 //
158 // Or:
159 //
cdc7bbd5
XL
160 // [block: If(lhs)] -false-> [else_block: dest = (rhs)]
161 // | (true)
162 // [shortcurcuit_block: dest = true]
e9174d1e 163
cdc7bbd5 164 let (shortcircuit_block, mut else_block, join_block) = (
b7449926
XL
165 this.cfg.start_new_block(),
166 this.cfg.start_new_block(),
167 this.cfg.start_new_block(),
168 );
e9174d1e 169
17df50a5 170 let lhs = unpack!(block = this.as_local_operand(block, &this.thir[lhs]));
e9174d1e 171 let blocks = match op {
cdc7bbd5
XL
172 LogicalOp::And => (else_block, shortcircuit_block),
173 LogicalOp::Or => (shortcircuit_block, else_block),
e9174d1e 174 };
6a06907d 175 let term = TerminatorKind::if_(this.tcx, lhs, blocks.0, blocks.1);
8bb4bdeb 176 this.cfg.terminate(block, source_info, term);
e9174d1e 177
e9174d1e 178 this.cfg.push_assign_constant(
cdc7bbd5 179 shortcircuit_block,
b7449926
XL
180 source_info,
181 destination,
6a06907d
XL
182 Constant {
183 span: expr_span,
184 user_ty: None,
cdc7bbd5 185 literal: match op {
5e7ed085
FG
186 LogicalOp::And => ConstantKind::from_bool(this.tcx, false),
187 LogicalOp::Or => ConstantKind::from_bool(this.tcx, true),
cdc7bbd5 188 },
6a06907d 189 },
b7449926 190 );
cdc7bbd5 191 this.cfg.goto(shortcircuit_block, source_info, join_block);
416331ca 192
17df50a5 193 let rhs = unpack!(else_block = this.as_local_operand(else_block, &this.thir[rhs]));
cdc7bbd5
XL
194 this.cfg.push_assign(else_block, source_info, destination, Rvalue::Use(rhs));
195 this.cfg.goto(else_block, source_info, join_block);
e9174d1e
SL
196
197 join_block.unit()
198 }
416331ca 199 ExprKind::Loop { body } => {
2c00a5a8
XL
200 // [block]
201 // |
202 // [loop_block] -> [body_block] -/eval. body/-> [body_block_end]
203 // | ^ |
204 // false link | |
205 // | +-----------------------------------------+
206 // +-> [diverge_cleanup]
207 // The false link is required to make sure borrowck considers unwinds through the
208 // body, even when the exact code in the body cannot unwind
e9174d1e
SL
209
210 let loop_block = this.cfg.start_new_block();
e9174d1e 211
dfeec247
XL
212 // Start the loop.
213 this.cfg.goto(block, source_info, loop_block);
e9174d1e 214
29967ef6 215 this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| {
ba9703b0
XL
216 // conduct the test, if necessary
217 let body_block = this.cfg.start_new_block();
ba9703b0
XL
218 this.cfg.terminate(
219 loop_block,
220 source_info,
29967ef6 221 TerminatorKind::FalseUnwind { real_target: body_block, unwind: None },
ba9703b0 222 );
29967ef6 223 this.diverge_from(loop_block);
ba9703b0 224
94222f64 225 // The “return” value of the loop body must always be a unit. We therefore
ba9703b0
XL
226 // introduce a unit temporary as the destination for the loop body.
227 let tmp = this.get_unit_temp();
228 // Execute the body, branching back to the test.
17df50a5
XL
229 let body_block_end =
230 unpack!(this.expr_into_dest(tmp, body_block, &this.thir[body]));
ba9703b0 231 this.cfg.goto(body_block_end, source_info, loop_block);
29967ef6
XL
232
233 // Loops are only exited by `break` expressions.
234 None
235 })
e9174d1e 236 }
17df50a5
XL
237 ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => {
238 let fun = unpack!(block = this.as_local_operand(block, &this.thir[fun]));
5869c6ff
XL
239 let args: Vec<_> = args
240 .into_iter()
17df50a5
XL
241 .copied()
242 .map(|arg| unpack!(block = this.as_local_call_operand(block, &this.thir[arg])))
5869c6ff 243 .collect();
cc61c64b 244
5869c6ff 245 let success = this.cfg.start_new_block();
e1599b0c 246
5869c6ff 247 this.record_operands_moved(&args);
e1599b0c 248
6a06907d 249 debug!("expr_into_dest: fn_span={:?}", fn_span);
f035d41b 250
5869c6ff
XL
251 this.cfg.terminate(
252 block,
253 source_info,
254 TerminatorKind::Call {
255 func: fun,
256 args,
257 cleanup: None,
258 // FIXME(varkor): replace this with an uninhabitedness-based check.
259 // This requires getting access to the current module to call
260 // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
261 destination: if expr.ty.is_never() {
262 None
263 } else {
264 Some((destination, success))
b7449926 265 },
5869c6ff
XL
266 from_hir_call,
267 fn_span,
268 },
269 );
270 this.diverge_from(block);
271 success.unit()
e9174d1e 272 }
17df50a5 273 ExprKind::Use { source } => this.expr_into_dest(destination, block, &this.thir[source]),
60c5eb7d 274 ExprKind::Borrow { arg, borrow_kind } => {
17df50a5 275 let arg = &this.thir[arg];
60c5eb7d
XL
276 // We don't do this in `as_rvalue` because we use `as_place`
277 // for borrow expressions, so we cannot create an `RValue` that
278 // remains valid across user code. `as_rvalue` is usually called
279 // by this method anyway, so this shouldn't cause too many
280 // unnecessary temporaries.
281 let arg_place = match borrow_kind {
282 BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)),
283 _ => unpack!(block = this.as_place(block, arg)),
284 };
6a06907d 285 let borrow = Rvalue::Ref(this.tcx.lifetimes.re_erased, borrow_kind, arg_place);
60c5eb7d
XL
286 this.cfg.push_assign(block, source_info, destination, borrow);
287 block.unit()
288 }
dfeec247 289 ExprKind::AddressOf { mutability, arg } => {
17df50a5 290 let arg = &this.thir[arg];
dfeec247
XL
291 let place = match mutability {
292 hir::Mutability::Not => this.as_read_only_place(block, arg),
293 hir::Mutability::Mut => this.as_place(block, arg),
294 };
295 let address_of = Rvalue::AddressOf(mutability, unpack!(block = place));
296 this.cfg.push_assign(block, source_info, destination, address_of);
297 block.unit()
298 }
136023e0
XL
299 ExprKind::Adt(box Adt {
300 adt_def,
301 variant_index,
302 substs,
303 user_ty,
304 ref fields,
305 ref base,
306 }) => {
60c5eb7d
XL
307 // See the notes for `ExprKind::Array` in `as_rvalue` and for
308 // `ExprKind::Borrow` above.
309 let is_union = adt_def.is_union();
dfeec247 310 let active_field_index = if is_union { Some(fields[0].name.index()) } else { None };
60c5eb7d 311
dfeec247 312 let scope = this.local_scope();
60c5eb7d
XL
313
314 // first process the set of fields that were provided
315 // (evaluating them in order given by user)
316 let fields_map: FxHashMap<_, _> = fields
317 .into_iter()
17df50a5 318 .map(|f| {
c295e0f8 319 let local_info = Box::new(LocalInfo::AggregateTemp);
17df50a5
XL
320 (
321 f.name,
322 unpack!(
c295e0f8
XL
323 block = this.as_operand(
324 block,
325 Some(scope),
326 &this.thir[f.expr],
327 Some(local_info)
328 )
17df50a5
XL
329 ),
330 )
331 })
dfeec247 332 .collect();
60c5eb7d 333
6a06907d 334 let field_names: Vec<_> =
5e7ed085 335 (0..adt_def.variant(variant_index).fields.len()).map(Field::new).collect();
60c5eb7d 336
fc512014 337 let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
17df50a5
XL
338 let place_builder =
339 unpack!(block = this.as_place_builder(block, &this.thir[*base]));
ba9703b0
XL
340
341 // MIR does not natively support FRU, so for each
342 // base-supplied field, generate an operand that
343 // reads it from the base.
17df50a5 344 iter::zip(field_names, &**field_types)
ba9703b0
XL
345 .map(|(n, ty)| match fields_map.get(&n) {
346 Some(v) => v.clone(),
5869c6ff
XL
347 None => {
348 let place_builder = place_builder.clone();
349 this.consume_by_copy_or_move(
350 place_builder
5099ac24 351 .field(n, *ty)
6a06907d 352 .into_place(this.tcx, this.typeck_results),
5869c6ff
XL
353 )
354 }
ba9703b0
XL
355 })
356 .collect()
357 } else {
358 field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect()
359 };
60c5eb7d
XL
360
361 let inferred_ty = expr.ty;
362 let user_ty = user_ty.map(|ty| {
363 this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
364 span: source_info.span,
365 user_ty: ty,
366 inferred_ty,
367 })
368 });
94222f64 369 let adt = Box::new(AggregateKind::Adt(
5e7ed085 370 adt_def.did(),
60c5eb7d
XL
371 variant_index,
372 substs,
373 user_ty,
374 active_field_index,
94222f64 375 ));
60c5eb7d
XL
376 this.cfg.push_assign(
377 block,
378 source_info,
379 destination,
dfeec247 380 Rvalue::Aggregate(adt, fields),
60c5eb7d
XL
381 );
382 block.unit()
383 }
17df50a5
XL
384 ExprKind::InlineAsm { template, ref operands, options, line_spans } => {
385 use rustc_middle::{mir, thir};
f9f354fc
XL
386 let operands = operands
387 .into_iter()
6a06907d 388 .map(|op| match *op {
3dfed10e 389 thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In {
f9f354fc 390 reg,
17df50a5 391 value: unpack!(block = this.as_local_operand(block, &this.thir[expr])),
f9f354fc 392 },
3dfed10e 393 thir::InlineAsmOperand::Out { reg, late, expr } => {
f9f354fc
XL
394 mir::InlineAsmOperand::Out {
395 reg,
396 late,
17df50a5
XL
397 place: expr.map(|expr| {
398 unpack!(block = this.as_place(block, &this.thir[expr]))
399 }),
f9f354fc
XL
400 }
401 }
3dfed10e 402 thir::InlineAsmOperand::InOut { reg, late, expr } => {
17df50a5 403 let place = unpack!(block = this.as_place(block, &this.thir[expr]));
f9f354fc
XL
404 mir::InlineAsmOperand::InOut {
405 reg,
406 late,
407 // This works because asm operands must be Copy
408 in_value: Operand::Copy(place),
409 out_place: Some(place),
410 }
411 }
3dfed10e 412 thir::InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
f9f354fc
XL
413 mir::InlineAsmOperand::InOut {
414 reg,
415 late,
17df50a5
XL
416 in_value: unpack!(
417 block = this.as_local_operand(block, &this.thir[in_expr])
418 ),
419 out_place: out_expr.map(|out_expr| {
420 unpack!(block = this.as_place(block, &this.thir[out_expr]))
f9f354fc
XL
421 }),
422 }
423 }
cdc7bbd5
XL
424 thir::InlineAsmOperand::Const { value, span } => {
425 mir::InlineAsmOperand::Const {
94222f64
XL
426 value: Box::new(Constant {
427 span,
428 user_ty: None,
429 literal: value.into(),
430 }),
cdc7bbd5
XL
431 }
432 }
17df50a5 433 thir::InlineAsmOperand::SymFn { expr } => mir::InlineAsmOperand::SymFn {
94222f64 434 value: Box::new(this.as_constant(&this.thir[expr])),
17df50a5 435 },
3dfed10e 436 thir::InlineAsmOperand::SymStatic { def_id } => {
f035d41b 437 mir::InlineAsmOperand::SymStatic { def_id }
f9f354fc
XL
438 }
439 })
440 .collect();
441
c295e0f8
XL
442 if !options.contains(InlineAsmOptions::NORETURN) {
443 this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
444 }
f9f354fc 445
c295e0f8 446 let destination_block = this.cfg.start_new_block();
f9f354fc
XL
447 this.cfg.terminate(
448 block,
449 source_info,
450 TerminatorKind::InlineAsm {
451 template,
452 operands,
453 options,
454 line_spans,
455 destination: if options.contains(InlineAsmOptions::NORETURN) {
456 None
457 } else {
c295e0f8 458 Some(destination_block)
f9f354fc 459 },
a2a8927a 460 cleanup: None,
f9f354fc
XL
461 },
462 );
a2a8927a
XL
463 if options.contains(InlineAsmOptions::MAY_UNWIND) {
464 this.diverge_from(block);
465 }
c295e0f8 466 destination_block.unit()
f9f354fc 467 }
60c5eb7d 468
a7813a04 469 // These cases don't actually need a destination
5099ac24 470 ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
a1dfa0c6 471 unpack!(block = this.stmt_expr(block, expr, None));
6a06907d 472 this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
ff7c6d11 473 block.unit()
a7813a04
XL
474 }
475
3dfed10e
XL
476 ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Return { .. } => {
477 unpack!(block = this.stmt_expr(block, expr, None));
478 // No assign, as these have type `!`.
479 block.unit()
480 }
481
8faf50e0 482 // Avoid creating a temporary
dfeec247 483 ExprKind::VarRef { .. }
fc512014 484 | ExprKind::UpvarRef { .. }
dfeec247
XL
485 | ExprKind::PlaceTypeAscription { .. }
486 | ExprKind::ValueTypeAscription { .. } => {
8faf50e0
XL
487 debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
488
489 let place = unpack!(block = this.as_place(block, expr));
490 let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
dfeec247 491 this.cfg.push_assign(block, source_info, destination, rvalue);
8faf50e0
XL
492 block.unit()
493 }
b7449926 494 ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
6a06907d 495 debug_assert_eq!(Category::of(&expr.kind), Some(Category::Place));
8faf50e0
XL
496
497 // Create a "fake" temporary variable so that we check that the
498 // value is Sized. Usually, this is caught in type checking, but
499 // in the case of box expr there is no such check.
e1599b0c 500 if !destination.projection.is_empty() {
f9f354fc 501 this.local_decls.push(LocalDecl::new(expr.ty, expr.span));
8faf50e0
XL
502 }
503
8faf50e0
XL
504 let place = unpack!(block = this.as_place(block, expr));
505 let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
dfeec247 506 this.cfg.push_assign(block, source_info, destination, rvalue);
8faf50e0
XL
507 block.unit()
508 }
509
74b04a01
XL
510 ExprKind::Yield { value } => {
511 let scope = this.local_scope();
c295e0f8
XL
512 let value =
513 unpack!(block = this.as_operand(block, Some(scope), &this.thir[value], None));
74b04a01 514 let resume = this.cfg.start_new_block();
74b04a01
XL
515 this.cfg.terminate(
516 block,
517 source_info,
29967ef6 518 TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None },
74b04a01 519 );
29967ef6 520 this.generator_drop_cleanup(block);
74b04a01
XL
521 resume.unit()
522 }
523
e9174d1e 524 // these are the cases that are more naturally handled by some other mode
b7449926
XL
525 ExprKind::Unary { .. }
526 | ExprKind::Binary { .. }
527 | ExprKind::Box { .. }
528 | ExprKind::Cast { .. }
48663c56 529 | ExprKind::Pointer { .. }
b7449926 530 | ExprKind::Repeat { .. }
b7449926
XL
531 | ExprKind::Array { .. }
532 | ExprKind::Tuple { .. }
b7449926 533 | ExprKind::Closure { .. }
29967ef6 534 | ExprKind::ConstBlock { .. }
b7449926 535 | ExprKind::Literal { .. }
5e7ed085
FG
536 | ExprKind::NamedConst { .. }
537 | ExprKind::NonHirLiteral { .. }
538 | ExprKind::ConstParam { .. }
f9f354fc 539 | ExprKind::ThreadLocalRef(_)
74b04a01 540 | ExprKind::StaticRef { .. } => {
e9174d1e 541 debug_assert!(match Category::of(&expr.kind).unwrap() {
0bf4aa26 542 // should be handled above
e9174d1e 543 Category::Rvalue(RvalueFunc::Into) => false,
0bf4aa26
XL
544
545 // must be handled above or else we get an
546 // infinite loop in the builder; see
0731742a 547 // e.g., `ExprKind::VarRef` above
0bf4aa26
XL
548 Category::Place => false,
549
e9174d1e
SL
550 _ => true,
551 });
552
8bb4bdeb 553 let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
0731742a 554 this.cfg.push_assign(block, source_info, destination, rvalue);
e9174d1e
SL
555 block.unit()
556 }
0bf4aa26
XL
557 };
558
559 if !expr_is_block_or_scope {
560 let popped = this.block_context.pop();
561 assert!(popped.is_some());
e9174d1e 562 }
0bf4aa26
XL
563
564 block_and
e9174d1e 565 }
e9174d1e 566}