@@ -426,7 +426,7 @@ pub struct ExprCollector<'db> {
426426 /// and we need to find the current definition. So we track the number of definitions we saw.
427427 current_block_legacy_macro_defs_count : FxHashMap < Name , usize > ,
428428
429- current_try_block_label : Option < LabelId > ,
429+ current_try_block : Option < TryBlock > ,
430430
431431 label_ribs : Vec < LabelRib > ,
432432 unowned_bindings : Vec < BindingId > ,
@@ -472,6 +472,13 @@ enum Awaitable {
472472 No ( & ' static str ) ,
473473}
474474
475+ enum TryBlock {
476+ // `try { ... }`
477+ Homogeneous { label : LabelId } ,
478+ // `try bikeshed Ty { ... }`
479+ Heterogeneous { label : LabelId } ,
480+ }
481+
475482#[ derive( Debug , Default ) ]
476483struct BindingList {
477484 map : FxHashMap < ( Name , HygieneId ) , BindingId > ,
@@ -532,7 +539,7 @@ impl<'db> ExprCollector<'db> {
532539 lang_items : OnceCell :: new ( ) ,
533540 store : ExpressionStoreBuilder :: default ( ) ,
534541 expander,
535- current_try_block_label : None ,
542+ current_try_block : None ,
536543 is_lowering_coroutine : false ,
537544 label_ribs : Vec :: new ( ) ,
538545 unowned_bindings : Vec :: new ( ) ,
@@ -1069,7 +1076,9 @@ impl<'db> ExprCollector<'db> {
10691076 self . alloc_expr ( Expr :: Let { pat, expr } , syntax_ptr)
10701077 }
10711078 ast:: Expr :: BlockExpr ( e) => match e. modifier ( ) {
1072- Some ( ast:: BlockModifier :: Try ( _) ) => self . desugar_try_block ( e) ,
1079+ Some ( ast:: BlockModifier :: Try { try_token : _, bikeshed_token : _, result_type } ) => {
1080+ self . desugar_try_block ( e, result_type)
1081+ }
10731082 Some ( ast:: BlockModifier :: Unsafe ( _) ) => {
10741083 self . collect_block_ ( e, |id, statements, tail| Expr :: Unsafe {
10751084 id,
@@ -1344,7 +1353,7 @@ impl<'db> ExprCollector<'db> {
13441353 . map ( |it| this. lower_type_ref_disallow_impl_trait ( it) ) ;
13451354
13461355 let prev_is_lowering_coroutine = mem:: take ( & mut this. is_lowering_coroutine ) ;
1347- let prev_try_block_label = this. current_try_block_label . take ( ) ;
1356+ let prev_try_block = this. current_try_block . take ( ) ;
13481357
13491358 let awaitable = if e. async_token ( ) . is_some ( ) {
13501359 Awaitable :: Yes
@@ -1369,7 +1378,7 @@ impl<'db> ExprCollector<'db> {
13691378 let capture_by =
13701379 if e. move_token ( ) . is_some ( ) { CaptureBy :: Value } else { CaptureBy :: Ref } ;
13711380 this. is_lowering_coroutine = prev_is_lowering_coroutine;
1372- this. current_try_block_label = prev_try_block_label ;
1381+ this. current_try_block = prev_try_block ;
13731382 this. alloc_expr (
13741383 Expr :: Closure {
13751384 args : args. into ( ) ,
@@ -1686,11 +1695,15 @@ impl<'db> ExprCollector<'db> {
16861695 /// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`,
16871696 /// `try { <stmts>; }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(()) }`
16881697 /// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator.
1689- fn desugar_try_block ( & mut self , e : BlockExpr ) -> ExprId {
1698+ fn desugar_try_block ( & mut self , e : BlockExpr , result_type : Option < ast :: Type > ) -> ExprId {
16901699 let try_from_output = self . lang_path ( self . lang_items ( ) . TryTraitFromOutput ) ;
16911700 let label = self . generate_new_name ( ) ;
16921701 let label = self . alloc_label_desugared ( Label { name : label } , AstPtr :: new ( & e) . wrap_right ( ) ) ;
1693- let old_label = self . current_try_block_label . replace ( label) ;
1702+ let try_block_info = match result_type {
1703+ Some ( _) => TryBlock :: Heterogeneous { label } ,
1704+ None => TryBlock :: Homogeneous { label } ,
1705+ } ;
1706+ let old_try_block = self . current_try_block . replace ( try_block_info) ;
16941707
16951708 let ptr = AstPtr :: new ( & e) . upcast ( ) ;
16961709 let ( btail, expr_id) = self . with_labeled_rib ( label, HygieneId :: ROOT , |this| {
@@ -1720,8 +1733,38 @@ impl<'db> ExprCollector<'db> {
17201733 unreachable ! ( "block was lowered to non-block" ) ;
17211734 } ;
17221735 * tail = Some ( next_tail) ;
1723- self . current_try_block_label = old_label;
1724- expr_id
1736+ self . current_try_block = old_try_block;
1737+ match result_type {
1738+ Some ( ty) => {
1739+ // `{ let <name>: <ty> = <expr>; <name> }`
1740+ let name = self . generate_new_name ( ) ;
1741+ let type_ref = self . lower_type_ref_disallow_impl_trait ( ty) ;
1742+ let binding = self . alloc_binding (
1743+ name. clone ( ) ,
1744+ BindingAnnotation :: Unannotated ,
1745+ HygieneId :: ROOT ,
1746+ ) ;
1747+ let pat = self . alloc_pat_desugared ( Pat :: Bind { id : binding, subpat : None } ) ;
1748+ self . add_definition_to_binding ( binding, pat) ;
1749+ let tail_expr =
1750+ self . alloc_expr_desugared_with_ptr ( Expr :: Path ( Path :: from ( name) ) , ptr) ;
1751+ self . alloc_expr_desugared_with_ptr (
1752+ Expr :: Block {
1753+ id : None ,
1754+ statements : Box :: new ( [ Statement :: Let {
1755+ pat,
1756+ type_ref : Some ( type_ref) ,
1757+ initializer : Some ( expr_id) ,
1758+ else_branch : None ,
1759+ } ] ) ,
1760+ tail : Some ( tail_expr) ,
1761+ label : None ,
1762+ } ,
1763+ ptr,
1764+ )
1765+ }
1766+ None => expr_id,
1767+ }
17251768 }
17261769
17271770 /// Desugar `ast::WhileExpr` from: `[opt_ident]: while <cond> <body>` into:
@@ -1863,6 +1906,8 @@ impl<'db> ExprCollector<'db> {
18631906 /// ControlFlow::Continue(val) => val,
18641907 /// ControlFlow::Break(residual) =>
18651908 /// // If there is an enclosing `try {...}`:
1909+ /// break 'catch_target Residual::into_try_type(residual),
1910+ /// // If there is an enclosing `try bikeshed Ty {...}`:
18661911 /// break 'catch_target Try::from_residual(residual),
18671912 /// // Otherwise:
18681913 /// return Try::from_residual(residual),
@@ -1873,7 +1918,6 @@ impl<'db> ExprCollector<'db> {
18731918 let try_branch = self . lang_path ( lang_items. TryTraitBranch ) ;
18741919 let cf_continue = self . lang_path ( lang_items. ControlFlowContinue ) ;
18751920 let cf_break = self . lang_path ( lang_items. ControlFlowBreak ) ;
1876- let try_from_residual = self . lang_path ( lang_items. TryTraitFromResidual ) ;
18771921 let operand = self . collect_expr_opt ( e. expr ( ) ) ;
18781922 let try_branch = self . alloc_expr ( try_branch. map_or ( Expr :: Missing , Expr :: Path ) , syntax_ptr) ;
18791923 let expr = self
@@ -1910,13 +1954,23 @@ impl<'db> ExprCollector<'db> {
19101954 guard : None ,
19111955 expr : {
19121956 let it = self . alloc_expr ( Expr :: Path ( Path :: from ( break_name) ) , syntax_ptr) ;
1913- let callee = self
1914- . alloc_expr ( try_from_residual. map_or ( Expr :: Missing , Expr :: Path ) , syntax_ptr) ;
1957+ let convert_fn = match self . current_try_block {
1958+ Some ( TryBlock :: Homogeneous { .. } ) => {
1959+ self . lang_path ( lang_items. ResidualIntoTryType )
1960+ }
1961+ Some ( TryBlock :: Heterogeneous { .. } ) | None => {
1962+ self . lang_path ( lang_items. TryTraitFromResidual )
1963+ }
1964+ } ;
1965+ let callee =
1966+ self . alloc_expr ( convert_fn. map_or ( Expr :: Missing , Expr :: Path ) , syntax_ptr) ;
19151967 let result =
19161968 self . alloc_expr ( Expr :: Call { callee, args : Box :: new ( [ it] ) } , syntax_ptr) ;
19171969 self . alloc_expr (
1918- match self . current_try_block_label {
1919- Some ( label) => Expr :: Break { expr : Some ( result) , label : Some ( label) } ,
1970+ match self . current_try_block {
1971+ Some (
1972+ TryBlock :: Heterogeneous { label } | TryBlock :: Homogeneous { label } ,
1973+ ) => Expr :: Break { expr : Some ( result) , label : Some ( label) } ,
19201974 None => Expr :: Return { expr : Some ( result) } ,
19211975 } ,
19221976 syntax_ptr,
0 commit comments