@@ -30,76 +30,92 @@ mod util;
30
30
use std:: borrow:: Borrow ;
31
31
use std:: mem;
32
32
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
+
33
49
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
34
50
/// Lowers a condition in a way that ensures that variables bound in any let
35
51
/// expressions are definitely initialized in the if body.
36
52
///
37
- /// If `declare_bindings ` is false then variables created in `let`
53
+ /// If `declare_let_bindings ` is false then variables created in `let`
38
54
/// expressions will not be declared. This is for if let guards on arms with
39
55
/// an or pattern, where the guard is lowered multiple times.
40
56
pub ( crate ) fn then_else_break (
41
57
& mut self ,
42
- mut block : BasicBlock ,
58
+ block : BasicBlock ,
43
59
expr_id : ExprId ,
44
60
temp_scope_override : Option < region:: Scope > ,
45
61
break_scope : region:: Scope ,
46
62
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 ,
48
82
) -> BlockAnd < ( ) > {
49
83
let this = self ;
50
84
let expr = & this. thir [ expr_id] ;
51
85
let expr_span = expr. span ;
52
86
53
87
match expr. kind {
54
88
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) ) ;
73
91
rhs_then_block. unit ( )
74
92
}
75
93
ExprKind :: LogicalOp { op : LogicalOp :: Or , lhs, rhs } => {
76
94
let local_scope = this. local_scope ( ) ;
77
95
let ( lhs_success_block, failure_block) =
78
96
this. in_if_then_scope ( local_scope, expr_span, |this| {
79
- this. then_else_break (
97
+ this. then_else_break_inner (
80
98
block,
81
99
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
+ } ,
86
105
)
87
106
} ) ;
88
- let rhs_success_block = unpack ! ( this. then_else_break (
107
+ let rhs_success_block = unpack ! ( this. then_else_break_inner (
89
108
failure_block,
90
109
rhs,
91
- temp_scope_override,
92
- break_scope,
93
- variable_source_info,
94
- true ,
110
+ ThenElseArgs { declare_let_bindings: true , ..args } ,
95
111
) ) ;
96
112
97
113
// Make the LHS and RHS success arms converge to a common block.
98
114
// (We can't just make LHS goto RHS, because `rhs_success_block`
99
115
// might contain statements that we don't want on the LHS path.)
100
116
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) ;
103
119
success_block. unit ( )
104
120
}
105
121
ExprKind :: Unary { op : UnOp :: Not , arg } => {
@@ -111,50 +127,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
111
127
if this. tcx . sess . instrument_coverage ( ) {
112
128
this. cfg . push_coverage_span_marker ( block, this. source_info ( expr_span) ) ;
113
129
}
114
- this. then_else_break (
130
+ this. then_else_break_inner (
115
131
block,
116
132
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
+ } ,
121
138
)
122
139
} ) ;
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 ) ;
124
141
failure_block. unit ( )
125
142
}
126
143
ExprKind :: Scope { region_scope, lint_level, value } => {
127
144
let region_scope = ( region_scope, this. source_info ( expr_span) ) ;
128
145
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)
137
147
} )
138
148
}
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) ,
147
150
ExprKind :: Let { expr, ref pat } => this. lower_let_expr (
148
151
block,
149
152
expr,
150
153
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 ,
155
158
) ,
156
159
_ => {
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 ( ) ) ;
158
162
let mutability = Mutability :: Mut ;
159
163
let place =
160
164
unpack ! ( block = this. as_temp( block, Some ( temp_scope) , expr_id, mutability) ) ;
@@ -166,7 +170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
166
170
167
171
let source_info = this. source_info ( expr_span) ;
168
172
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) ;
170
174
171
175
then_block. unit ( )
172
176
}
@@ -2105,10 +2109,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2105
2109
this. then_else_break (
2106
2110
block,
2107
2111
guard,
2108
- None ,
2112
+ None , // Use `self.local_scope()` as the temp scope
2109
2113
match_scope,
2110
2114
this. source_info ( arm. span ) ,
2111
- false ,
2115
+ false , // For guards, `let` bindings are declared separately
2112
2116
)
2113
2117
} ) ;
2114
2118
0 commit comments