@@ -30,76 +30,92 @@ mod util;
3030use std:: borrow:: Borrow ;
3131use std:: mem;
3232
33+ /// Arguments to [`Builder::then_else_break_inner`] that are usually forwarded
34+ /// to recursive invocations.
35+ #[ derive( Clone , Copy ) ]
36+ struct ThenElseArgs {
37+ /// Used as the temp scope for lowering `expr`. If absent (for match guards),
38+ /// `self.local_scope()` is used.
39+ temp_scope_override : Option < region:: Scope > ,
40+ /// Scope to pass to [`Builder::break_for_else`]. Must match the scope used
41+ /// by the enclosing call to [`Builder::in_if_then_scope`].
42+ break_scope : region:: Scope ,
43+ variable_source_info : SourceInfo ,
44+ /// Forwarded to [`Builder::lower_let_expr`] when lowering [`ExprKind::Let`].
45+ /// When false (for match guards), `let` bindings won't be declared.
46+ declare_let_bindings : bool ,
47+ }
48+
3349impl < ' a , ' tcx > Builder < ' a , ' tcx > {
3450 /// Lowers a condition in a way that ensures that variables bound in any let
3551 /// expressions are definitely initialized in the if body.
3652 ///
37- /// If `declare_bindings ` is false then variables created in `let`
53+ /// If `declare_let_bindings ` is false then variables created in `let`
3854 /// expressions will not be declared. This is for if let guards on arms with
3955 /// an or pattern, where the guard is lowered multiple times.
4056 pub ( crate ) fn then_else_break (
4157 & mut self ,
42- mut block : BasicBlock ,
58+ block : BasicBlock ,
4359 expr_id : ExprId ,
4460 temp_scope_override : Option < region:: Scope > ,
4561 break_scope : region:: Scope ,
4662 variable_source_info : SourceInfo ,
47- declare_bindings : bool ,
63+ declare_let_bindings : bool ,
64+ ) -> BlockAnd < ( ) > {
65+ self . then_else_break_inner (
66+ block,
67+ expr_id,
68+ ThenElseArgs {
69+ temp_scope_override,
70+ break_scope,
71+ variable_source_info,
72+ declare_let_bindings,
73+ } ,
74+ )
75+ }
76+
77+ fn then_else_break_inner (
78+ & mut self ,
79+ block : BasicBlock , // Block that the condition and branch will be lowered into
80+ expr_id : ExprId , // Condition expression to lower
81+ args : ThenElseArgs ,
4882 ) -> BlockAnd < ( ) > {
4983 let this = self ;
5084 let expr = & this. thir [ expr_id] ;
5185 let expr_span = expr. span ;
5286
5387 match expr. kind {
5488 ExprKind :: LogicalOp { op : LogicalOp :: And , lhs, rhs } => {
55- let lhs_then_block = unpack ! ( this. then_else_break(
56- block,
57- lhs,
58- temp_scope_override,
59- break_scope,
60- variable_source_info,
61- declare_bindings,
62- ) ) ;
63-
64- let rhs_then_block = unpack ! ( this. then_else_break(
65- lhs_then_block,
66- rhs,
67- temp_scope_override,
68- break_scope,
69- variable_source_info,
70- declare_bindings,
71- ) ) ;
72-
89+ let lhs_then_block = unpack ! ( this. then_else_break_inner( block, lhs, args) ) ;
90+ let rhs_then_block = unpack ! ( this. then_else_break_inner( lhs_then_block, rhs, args) ) ;
7391 rhs_then_block. unit ( )
7492 }
7593 ExprKind :: LogicalOp { op : LogicalOp :: Or , lhs, rhs } => {
7694 let local_scope = this. local_scope ( ) ;
7795 let ( lhs_success_block, failure_block) =
7896 this. in_if_then_scope ( local_scope, expr_span, |this| {
79- this. then_else_break (
97+ this. then_else_break_inner (
8098 block,
8199 lhs,
82- temp_scope_override,
83- local_scope,
84- variable_source_info,
85- true ,
100+ ThenElseArgs {
101+ break_scope : local_scope,
102+ declare_let_bindings : true ,
103+ ..args
104+ } ,
86105 )
87106 } ) ;
88- let rhs_success_block = unpack ! ( this. then_else_break (
107+ let rhs_success_block = unpack ! ( this. then_else_break_inner (
89108 failure_block,
90109 rhs,
91- temp_scope_override,
92- break_scope,
93- variable_source_info,
94- true ,
110+ ThenElseArgs { declare_let_bindings: true , ..args } ,
95111 ) ) ;
96112
97113 // Make the LHS and RHS success arms converge to a common block.
98114 // (We can't just make LHS goto RHS, because `rhs_success_block`
99115 // might contain statements that we don't want on the LHS path.)
100116 let success_block = this. cfg . start_new_block ( ) ;
101- this. cfg . goto ( lhs_success_block, variable_source_info, success_block) ;
102- this. cfg . goto ( rhs_success_block, variable_source_info, success_block) ;
117+ this. cfg . goto ( lhs_success_block, args . variable_source_info , success_block) ;
118+ this. cfg . goto ( rhs_success_block, args . variable_source_info , success_block) ;
103119 success_block. unit ( )
104120 }
105121 ExprKind :: Unary { op : UnOp :: Not , arg } => {
@@ -111,50 +127,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
111127 if this. tcx . sess . instrument_coverage ( ) {
112128 this. cfg . push_coverage_span_marker ( block, this. source_info ( expr_span) ) ;
113129 }
114- this. then_else_break (
130+ this. then_else_break_inner (
115131 block,
116132 arg,
117- temp_scope_override,
118- local_scope,
119- variable_source_info,
120- true ,
133+ ThenElseArgs {
134+ break_scope : local_scope,
135+ declare_let_bindings : true ,
136+ ..args
137+ } ,
121138 )
122139 } ) ;
123- this. break_for_else ( success_block, break_scope, variable_source_info) ;
140+ this. break_for_else ( success_block, args . break_scope , args . variable_source_info ) ;
124141 failure_block. unit ( )
125142 }
126143 ExprKind :: Scope { region_scope, lint_level, value } => {
127144 let region_scope = ( region_scope, this. source_info ( expr_span) ) ;
128145 this. in_scope ( region_scope, lint_level, |this| {
129- this. then_else_break (
130- block,
131- value,
132- temp_scope_override,
133- break_scope,
134- variable_source_info,
135- declare_bindings,
136- )
146+ this. then_else_break_inner ( block, value, args)
137147 } )
138148 }
139- ExprKind :: Use { source } => this. then_else_break (
140- block,
141- source,
142- temp_scope_override,
143- break_scope,
144- variable_source_info,
145- declare_bindings,
146- ) ,
149+ ExprKind :: Use { source } => this. then_else_break_inner ( block, source, args) ,
147150 ExprKind :: Let { expr, ref pat } => this. lower_let_expr (
148151 block,
149152 expr,
150153 pat,
151- break_scope,
152- Some ( variable_source_info. scope ) ,
153- variable_source_info. span ,
154- declare_bindings ,
154+ args . break_scope ,
155+ Some ( args . variable_source_info . scope ) ,
156+ args . variable_source_info . span ,
157+ args . declare_let_bindings ,
155158 ) ,
156159 _ => {
157- let temp_scope = temp_scope_override. unwrap_or_else ( || this. local_scope ( ) ) ;
160+ let mut block = block;
161+ let temp_scope = args. temp_scope_override . unwrap_or_else ( || this. local_scope ( ) ) ;
158162 let mutability = Mutability :: Mut ;
159163 let place =
160164 unpack ! ( block = this. as_temp( block, Some ( temp_scope) , expr_id, mutability) ) ;
@@ -166,7 +170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
166170
167171 let source_info = this. source_info ( expr_span) ;
168172 this. cfg . terminate ( block, source_info, term) ;
169- this. break_for_else ( else_block, break_scope, source_info) ;
173+ this. break_for_else ( else_block, args . break_scope , source_info) ;
170174
171175 then_block. unit ( )
172176 }
@@ -2105,10 +2109,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21052109 this. then_else_break (
21062110 block,
21072111 guard,
2108- None ,
2112+ None , // Use `self.local_scope()` as the temp scope
21092113 match_scope,
21102114 this. source_info ( arm. span ) ,
2111- false ,
2115+ false , // For guards, `let` bindings are declared separately
21122116 )
21132117 } ) ;
21142118
0 commit comments