1 use super::{LoweringContext, ParamMode, ParenthesizedGenericArgs, ImplTraitContext};
2 use crate::hir::{self, HirVec};
3 use crate::hir::ptr::P;
5 use rustc_data_structures::thin_vec::ThinVec;
8 use syntax::ptr::P as AstP;
10 use syntax::source_map::{respan, DesugaringKind};
11 use syntax::symbol::{sym, Symbol};
13 impl LoweringContext<'_> {
14 fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> HirVec<hir::Expr> {
15 exprs.iter().map(|x| self.lower_expr(x)).collect()
18 pub(super) fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
19 let kind = match e.node {
20 ExprKind::Box(ref inner) => hir::ExprKind::Box(P(self.lower_expr(inner))),
21 ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
22 ExprKind::Repeat(ref expr, ref count) => {
23 let expr = P(self.lower_expr(expr));
24 let count = self.lower_anon_const(count);
25 hir::ExprKind::Repeat(expr, count)
27 ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
28 ExprKind::Call(ref f, ref args) => {
29 let f = P(self.lower_expr(f));
30 hir::ExprKind::Call(f, self.lower_exprs(args))
32 ExprKind::MethodCall(ref seg, ref args) => {
33 let hir_seg = P(self.lower_path_segment(
38 ParenthesizedGenericArgs::Err,
39 ImplTraitContext::disallowed(),
42 let args = self.lower_exprs(args);
43 hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
45 ExprKind::Binary(binop, ref lhs, ref rhs) => {
46 let binop = self.lower_binop(binop);
47 let lhs = P(self.lower_expr(lhs));
48 let rhs = P(self.lower_expr(rhs));
49 hir::ExprKind::Binary(binop, lhs, rhs)
51 ExprKind::Unary(op, ref ohs) => {
52 let op = self.lower_unop(op);
53 let ohs = P(self.lower_expr(ohs));
54 hir::ExprKind::Unary(op, ohs)
56 ExprKind::Lit(ref l) => hir::ExprKind::Lit(respan(l.span, l.node.clone())),
57 ExprKind::Cast(ref expr, ref ty) => {
58 let expr = P(self.lower_expr(expr));
59 hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::disallowed()))
61 ExprKind::Type(ref expr, ref ty) => {
62 let expr = P(self.lower_expr(expr));
63 hir::ExprKind::Type(expr, self.lower_ty(ty, ImplTraitContext::disallowed()))
65 ExprKind::AddrOf(m, ref ohs) => {
66 let m = self.lower_mutability(m);
67 let ohs = P(self.lower_expr(ohs));
68 hir::ExprKind::AddrOf(m, ohs)
70 ExprKind::Let(ref pats, ref scrutinee) => {
71 // If we got here, the `let` expression is not allowed.
73 .struct_span_err(e.span, "`let` expressions are not supported here")
74 .note("only supported directly in conditions of `if`- and `while`-expressions")
75 .note("as well as when nested within `&&` and parenthesis in those conditions")
78 // For better recovery, we emit:
80 // match scrutinee { pats => true, _ => false }
82 // While this doesn't fully match the user's intent, it has key advantages:
83 // 1. We can avoid using `abort_if_errors`.
84 // 2. We can typeck both `pats` and `scrutinee`.
85 // 3. `pats` is allowed to be refutable.
86 // 4. The return type of the block is `bool` which seems like what the user wanted.
87 let scrutinee = self.lower_expr(scrutinee);
89 let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
90 let expr = self.expr_bool(e.span, true);
91 self.arm(pats, P(expr))
94 let pats = hir_vec![self.pat_wild(e.span)];
95 let expr = self.expr_bool(e.span, false);
96 self.arm(pats, P(expr))
100 vec![then_arm, else_arm].into(),
101 hir::MatchSource::Normal,
104 // FIXME(#53667): handle lowering of && and parens.
105 ExprKind::If(ref cond, ref then, ref else_opt) => {
106 // `_ => else_block` where `else_block` is `{}` if there's `None`:
107 let else_pat = self.pat_wild(e.span);
108 let (else_expr, contains_else_clause) = match else_opt {
109 None => (self.expr_block_empty(e.span), false),
110 Some(els) => (self.lower_expr(els), true),
112 let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
114 // Handle then + scrutinee:
115 let then_blk = self.lower_block(then, false);
116 let then_expr = self.expr_block(then_blk, ThinVec::new());
117 let (then_pats, scrutinee, desugar) = match cond.node {
118 // `<pat> => <then>`:
119 ExprKind::Let(ref pats, ref scrutinee) => {
120 let scrutinee = self.lower_expr(scrutinee);
121 let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
122 let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
123 (pats, scrutinee, desugar)
128 let cond = self.lower_expr(cond);
129 let span_block = self.mark_span_with_reason(
130 DesugaringKind::CondTemporary, cond.span, None
132 // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
133 // to preserve drop semantics since `if cond { ... }` does not
134 // let temporaries live outside of `cond`.
135 let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
137 let desugar = hir::MatchSource::IfDesugar { contains_else_clause };
138 let pats = hir_vec![self.pat_bool(e.span, true)];
139 (pats, cond, desugar)
142 let then_arm = self.arm(then_pats, P(then_expr));
144 hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar)
146 // FIXME(#53667): handle lowering of && and parens.
147 ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
148 // Note that the block AND the condition are evaluated in the loop scope.
149 // This is done to allow `break` from inside the condition of the loop.
153 let else_pat = this.pat_wild(e.span);
154 let else_expr = this.expr_break(e.span, ThinVec::new());
155 this.arm(hir_vec![else_pat], else_expr)
158 // Handle then + scrutinee:
159 let then_blk = this.lower_block(body, false);
160 let then_expr = this.expr_block(then_blk, ThinVec::new());
161 let (then_pats, scrutinee, desugar, source) = match cond.node {
162 ExprKind::Let(ref pats, ref scrutinee) => {
165 // [opt_ident]: loop {
166 // match <sub_expr> {
171 let scrutinee = this.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
172 let pats = pats.iter().map(|pat| this.lower_pat(pat)).collect();
173 let desugar = hir::MatchSource::WhileLetDesugar;
174 (pats, scrutinee, desugar, hir::LoopSource::WhileLet)
177 // We desugar: `'label: while $cond $body` into:
181 // match DropTemps($cond) {
189 let cond = this.with_loop_condition_scope(|this| this.lower_expr(cond));
190 let span_block = this.mark_span_with_reason(
191 DesugaringKind::CondTemporary, cond.span, None
193 // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
194 // to preserve drop semantics since `while cond { ... }` does not
195 // let temporaries live outside of `cond`.
196 let cond = this.expr_drop_temps(span_block, P(cond), ThinVec::new());
198 let desugar = hir::MatchSource::WhileDesugar;
200 let pats = hir_vec![this.pat_bool(e.span, true)];
201 (pats, cond, desugar, hir::LoopSource::While)
204 let then_arm = this.arm(then_pats, P(then_expr));
206 // `match <scrutinee> { ... }`
207 let match_expr = this.expr_match(
210 hir_vec![then_arm, else_arm],
214 // `[opt_ident]: loop { ... }`
216 P(this.block_expr(P(match_expr))),
217 this.lower_label(opt_label),
221 ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
223 this.lower_block(body, false),
224 this.lower_label(opt_label),
225 hir::LoopSource::Loop,
228 ExprKind::TryBlock(ref body) => {
229 self.with_catch_scope(body.id, |this| {
230 let unstable_span = this.mark_span_with_reason(
231 DesugaringKind::TryBlock,
233 this.allow_try_trait.clone(),
235 let mut block = this.lower_block(body, true).into_inner();
236 let tail = block.expr.take().map_or_else(
238 let span = this.sess.source_map().end_point(unstable_span);
241 node: hir::ExprKind::Tup(hir_vec![]),
242 attrs: ThinVec::new(),
243 hir_id: this.next_id(),
246 |x: P<hir::Expr>| x.into_inner(),
248 block.expr = Some(this.wrap_in_try_constructor(
249 sym::from_ok, tail, unstable_span));
250 hir::ExprKind::Block(P(block), None)
253 ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match(
254 P(self.lower_expr(expr)),
255 arms.iter().map(|x| self.lower_arm(x)).collect(),
256 hir::MatchSource::Normal,
258 ExprKind::Async(capture_clause, closure_node_id, ref block) => {
259 self.make_async_expr(capture_clause, closure_node_id, None, block.span, |this| {
260 this.with_new_scopes(|this| {
261 let block = this.lower_block(block, false);
262 this.expr_block(block, ThinVec::new())
266 ExprKind::Await(ref expr) => self.lower_await(e.span, expr),
268 capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span
270 if let IsAsync::Async { closure_id, .. } = asyncness {
271 let outer_decl = FnDecl {
272 inputs: decl.inputs.clone(),
273 output: FunctionRetTy::Default(fn_decl_span),
276 // We need to lower the declaration outside the new scope, because we
277 // have to conserve the state of being inside a loop condition for the
278 // closure argument types.
279 let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
281 self.with_new_scopes(|this| {
282 // FIXME(cramertj): allow `async` non-`move` closures with arguments.
283 if capture_clause == CaptureBy::Ref &&
284 !decl.inputs.is_empty()
290 "`async` non-`move` closures with arguments \
291 are not currently supported",
293 .help("consider using `let` statements to manually capture \
294 variables by reference before entering an \
295 `async move` closure")
299 // Transform `async |x: u8| -> X { ... }` into
300 // `|x: u8| future_from_generator(|| -> X { ... })`.
301 let body_id = this.lower_fn_body(&outer_decl, |this| {
302 let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output {
305 let async_body = this.make_async_expr(
306 capture_clause, closure_id, async_ret_ty, body.span,
308 this.with_new_scopes(|this| this.lower_expr(body))
310 this.expr(fn_decl_span, async_body, ThinVec::new())
312 hir::ExprKind::Closure(
313 this.lower_capture_clause(capture_clause),
321 // Lower outside new scope to preserve `is_in_loop_condition`.
322 let fn_decl = self.lower_fn_decl(decl, None, false, None);
324 self.with_new_scopes(|this| {
325 this.current_item = Some(fn_decl_span);
326 let mut generator_kind = None;
327 let body_id = this.lower_fn_body(decl, |this| {
328 let e = this.lower_expr(body);
329 generator_kind = this.generator_kind;
332 let generator_option = this.generator_movability_for_fn(
338 hir::ExprKind::Closure(
339 this.lower_capture_clause(capture_clause),
348 ExprKind::Block(ref blk, opt_label) => {
349 hir::ExprKind::Block(self.lower_block(blk,
350 opt_label.is_some()),
351 self.lower_label(opt_label))
353 ExprKind::Assign(ref el, ref er) => {
354 hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er)))
356 ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
357 self.lower_binop(op),
358 P(self.lower_expr(el)),
359 P(self.lower_expr(er)),
361 ExprKind::Field(ref el, ident) => hir::ExprKind::Field(P(self.lower_expr(el)), ident),
362 ExprKind::Index(ref el, ref er) => {
363 hir::ExprKind::Index(P(self.lower_expr(el)), P(self.lower_expr(er)))
365 // Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
366 ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => {
367 let id = self.next_id();
368 let e1 = self.lower_expr(e1);
369 let e2 = self.lower_expr(e2);
370 self.expr_call_std_assoc_fn(
373 &[sym::ops, sym::RangeInclusive],
378 ExprKind::Range(ref e1, ref e2, lims) => {
379 use syntax::ast::RangeLimits::*;
381 let path = match (e1, e2, lims) {
382 (&None, &None, HalfOpen) => sym::RangeFull,
383 (&Some(..), &None, HalfOpen) => sym::RangeFrom,
384 (&None, &Some(..), HalfOpen) => sym::RangeTo,
385 (&Some(..), &Some(..), HalfOpen) => sym::Range,
386 (&None, &Some(..), Closed) => sym::RangeToInclusive,
387 (&Some(..), &Some(..), Closed) => unreachable!(),
388 (_, &None, Closed) => self.diagnostic()
389 .span_fatal(e.span, "inclusive range with no end")
393 let fields = e1.iter()
394 .map(|e| ("start", e))
395 .chain(e2.iter().map(|e| ("end", e)))
397 let expr = P(self.lower_expr(&e));
398 let ident = Ident::new(Symbol::intern(s), e.span);
399 self.field(ident, expr, e.span)
401 .collect::<P<[hir::Field]>>();
403 let is_unit = fields.is_empty();
404 let struct_path = [sym::ops, path];
405 let struct_path = self.std_path(e.span, &struct_path, None, is_unit);
406 let struct_path = hir::QPath::Resolved(None, P(struct_path));
409 hir_id: self.lower_node_id(e.id),
411 hir::ExprKind::Path(struct_path)
413 hir::ExprKind::Struct(P(struct_path), fields, None)
416 attrs: e.attrs.clone(),
419 ExprKind::Path(ref qself, ref path) => {
420 let qpath = self.lower_qpath(
425 ImplTraitContext::disallowed(),
427 hir::ExprKind::Path(qpath)
429 ExprKind::Break(opt_label, ref opt_expr) => {
430 let destination = if self.is_in_loop_condition && opt_label.is_none() {
433 target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
436 self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
438 hir::ExprKind::Break(
440 opt_expr.as_ref().map(|x| P(self.lower_expr(x))),
443 ExprKind::Continue(opt_label) => {
444 hir::ExprKind::Continue(if self.is_in_loop_condition && opt_label.is_none() {
447 target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
450 self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
453 ExprKind::Ret(ref e) => hir::ExprKind::Ret(e.as_ref().map(|x| P(self.lower_expr(x)))),
454 ExprKind::InlineAsm(ref asm) => {
455 let hir_asm = hir::InlineAsm {
456 inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
459 .map(|out| hir::InlineAsmOutput {
460 constraint: out.constraint.clone(),
462 is_indirect: out.is_indirect,
466 asm: asm.asm.clone(),
467 asm_str_style: asm.asm_str_style,
468 clobbers: asm.clobbers.clone().into(),
469 volatile: asm.volatile,
470 alignstack: asm.alignstack,
471 dialect: asm.dialect,
474 let outputs = asm.outputs
476 .map(|out| self.lower_expr(&out.expr))
478 let inputs = asm.inputs
480 .map(|&(_, ref input)| self.lower_expr(input))
482 hir::ExprKind::InlineAsm(P(hir_asm), outputs, inputs)
484 ExprKind::Struct(ref path, ref fields, ref maybe_expr) => hir::ExprKind::Struct(
490 ImplTraitContext::disallowed(),
492 fields.iter().map(|x| self.lower_field(x)).collect(),
493 maybe_expr.as_ref().map(|x| P(self.lower_expr(x))),
495 ExprKind::Paren(ref ex) => {
496 let mut ex = self.lower_expr(ex);
497 // Include parens in span, but only if it is a super-span.
498 if e.span.contains(ex.span) {
501 // Merge attributes into the inner expression.
502 let mut attrs = e.attrs.clone();
503 attrs.extend::<Vec<_>>(ex.attrs.into());
508 ExprKind::Yield(ref opt_expr) => {
509 match self.generator_kind {
510 Some(hir::GeneratorKind::Gen) => {},
511 Some(hir::GeneratorKind::Async) => {
516 "`async` generators are not yet supported",
518 self.sess.abort_if_errors();
521 self.generator_kind = Some(hir::GeneratorKind::Gen);
526 .map(|x| self.lower_expr(x))
527 .unwrap_or_else(|| self.expr_unit(e.span));
528 hir::ExprKind::Yield(P(expr), hir::YieldSource::Yield)
531 ExprKind::Err => hir::ExprKind::Err,
533 // Desugar `ExprForLoop`
534 // from: `[opt_ident]: for <pat> in <head> <body>`
535 ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
539 // let result = match ::std::iter::IntoIterator::into_iter(<head>) {
541 // [opt_ident]: loop {
543 // match ::std::iter::Iterator::next(&mut iter) {
544 // ::std::option::Option::Some(val) => __next = val,
545 // ::std::option::Option::None => break
547 // let <pat> = __next;
548 // StmtKind::Expr(<body>);
556 let mut head = self.lower_expr(head);
557 let head_sp = head.span;
558 let desugared_span = self.mark_span_with_reason(
559 DesugaringKind::ForLoop,
563 head.span = desugared_span;
565 let iter = Ident::with_empty_ctxt(sym::iter);
567 let next_ident = Ident::with_empty_ctxt(sym::__next);
568 let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
571 hir::BindingAnnotation::Mutable,
574 // `::std::option::Option::Some(val) => __next = val`
576 let val_ident = Ident::with_empty_ctxt(sym::val);
577 let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
578 let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid));
579 let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
580 let assign = P(self.expr(
582 hir::ExprKind::Assign(next_expr, val_expr),
585 let some_pat = self.pat_some(pat.span, val_pat);
586 self.arm(hir_vec![some_pat], assign)
589 // `::std::option::Option::None => break`
592 self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new()));
593 let pat = self.pat_none(e.span);
594 self.arm(hir_vec![pat], break_expr)
598 let (iter_pat, iter_pat_nid) = self.pat_ident_binding_mode(
601 hir::BindingAnnotation::Mutable
604 // `match ::std::iter::Iterator::next(&mut iter) { ... }`
606 let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid));
607 let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
608 let next_path = &[sym::iter, sym::Iterator, sym::next];
609 let next_expr = P(self.expr_call_std_path(
612 hir_vec![ref_mut_iter],
614 let arms = hir_vec![pat_arm, break_arm];
616 self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar)
618 let match_stmt = self.stmt_expr(head_sp, match_expr);
620 let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));
623 let next_let = self.stmt_let_pat(
628 hir::LocalSource::ForLoopDesugar,
631 // `let <pat> = __next`
632 let pat = self.lower_pat(pat);
633 let pat_let = self.stmt_let_pat(
638 hir::LocalSource::ForLoopDesugar,
641 let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
642 let body_expr = self.expr_block(body_block, ThinVec::new());
643 let body_stmt = self.stmt_expr(body.span, body_expr);
645 let loop_block = P(self.block_all(
647 hir_vec![next_let, match_stmt, pat_let, body_stmt],
651 // `[opt_ident]: loop { ... }`
652 let loop_expr = hir::ExprKind::Loop(
654 self.lower_label(opt_label),
655 hir::LoopSource::ForLoop,
657 let loop_expr = P(hir::Expr {
658 hir_id: self.lower_node_id(e.id),
661 attrs: ThinVec::new(),
664 // `mut iter => { ... }`
665 let iter_arm = self.arm(hir_vec![iter_pat], loop_expr);
667 // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
668 let into_iter_expr = {
670 &[sym::iter, sym::IntoIterator, sym::into_iter];
671 P(self.expr_call_std_path(
678 let match_expr = P(self.expr_match(
682 hir::MatchSource::ForLoopDesugar,
685 // This is effectively `{ let _result = ...; _result }`.
686 // The construct was introduced in #21984 and is necessary to make sure that
687 // temporaries in the `head` expression are dropped and do not leak to the
688 // surrounding scope of the `match` since the `match` is not a terminating scope.
690 // Also, add the attributes to the outer returned expr node.
691 return self.expr_drop_temps(head_sp, match_expr, e.attrs.clone())
694 // Desugar `ExprKind::Try`
696 ExprKind::Try(ref sub_expr) => {
699 // match Try::into_result(<expr>) {
700 // Ok(val) => #[allow(unreachable_code)] val,
701 // Err(err) => #[allow(unreachable_code)]
702 // // If there is an enclosing `catch {...}`
703 // break 'catch_target Try::from_error(From::from(err)),
705 // return Try::from_error(From::from(err)),
708 let unstable_span = self.mark_span_with_reason(
709 DesugaringKind::QuestionMark,
711 self.allow_try_trait.clone(),
713 let try_span = self.sess.source_map().end_point(e.span);
714 let try_span = self.mark_span_with_reason(
715 DesugaringKind::QuestionMark,
717 self.allow_try_trait.clone(),
720 // `Try::into_result(<expr>)`
723 let sub_expr = self.lower_expr(sub_expr);
725 let path = &[sym::ops, sym::Try, sym::into_result];
726 P(self.expr_call_std_path(
733 // `#[allow(unreachable_code)]`
735 // `allow(unreachable_code)`
737 let allow_ident = Ident::new(sym::allow, e.span);
738 let uc_ident = Ident::new(sym::unreachable_code, e.span);
739 let uc_nested = attr::mk_nested_word_item(uc_ident);
740 attr::mk_list_item(allow_ident, vec![uc_nested])
742 attr::mk_attr_outer(allow)
744 let attrs = vec![attr];
746 // `Ok(val) => #[allow(unreachable_code)] val,`
748 let val_ident = Ident::with_empty_ctxt(sym::val);
749 let (val_pat, val_pat_nid) = self.pat_ident(e.span, val_ident);
750 let val_expr = P(self.expr_ident_with_attrs(
754 ThinVec::from(attrs.clone()),
756 let ok_pat = self.pat_ok(e.span, val_pat);
758 self.arm(hir_vec![ok_pat], val_expr)
761 // `Err(err) => #[allow(unreachable_code)]
762 // return Try::from_error(From::from(err)),`
764 let err_ident = Ident::with_empty_ctxt(sym::err);
765 let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
767 let from_path = &[sym::convert, sym::From, sym::from];
768 let err_expr = self.expr_ident(try_span, err_ident, err_local_nid);
769 self.expr_call_std_path(try_span, from_path, hir_vec![err_expr])
772 self.wrap_in_try_constructor(sym::from_error, from_expr, unstable_span);
773 let thin_attrs = ThinVec::from(attrs);
774 let catch_scope = self.catch_scopes.last().map(|x| *x);
775 let ret_expr = if let Some(catch_node) = catch_scope {
776 let target_id = Ok(self.lower_node_id(catch_node));
779 hir::ExprKind::Break(
789 P(self.expr(try_span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs))
792 let err_pat = self.pat_err(try_span, err_local);
793 self.arm(hir_vec![err_pat], ret_expr)
796 hir::ExprKind::Match(
798 hir_vec![err_arm, ok_arm],
799 hir::MatchSource::TryDesugar,
803 ExprKind::Mac(_) => panic!("Shouldn't exist here"),
807 hir_id: self.lower_node_id(e.id),
810 attrs: e.attrs.clone(),