@@ -30,76 +30,90 @@ 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`]. If false, variables created in `let`
45
+ /// expressions will not be declared. This is for if let guards on arms with
46
+ /// an or pattern, where the guard is lowered multiple times.
47
+ declare_let_bindings : bool ,
48
+ }
49
+
33
50
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
34
51
/// Lowers a condition in a way that ensures that variables bound in any let
35
52
/// expressions are definitely initialized in the if body.
36
- ///
37
- /// If `declare_bindings` is false then variables created in `let`
38
- /// expressions will not be declared. This is for if let guards on arms with
39
- /// an or pattern, where the guard is lowered multiple times.
40
53
pub ( crate ) fn then_else_break (
41
54
& mut self ,
42
- mut block : BasicBlock ,
55
+ block : BasicBlock ,
43
56
expr_id : ExprId ,
44
- temp_scope_override : Option < region:: Scope > ,
57
+ temp_scope : region:: Scope ,
45
58
break_scope : region:: Scope ,
46
59
variable_source_info : SourceInfo ,
47
- declare_bindings : bool ,
60
+ ) -> BlockAnd < ( ) > {
61
+ // Forward to the inner implementation, with args set up for ordinary
62
+ // `if`-like lowering (i.e. not match guards).
63
+ self . then_else_break_inner (
64
+ block,
65
+ expr_id,
66
+ ThenElseArgs {
67
+ temp_scope_override : Some ( temp_scope) ,
68
+ break_scope,
69
+ variable_source_info,
70
+ declare_let_bindings : true ,
71
+ } ,
72
+ )
73
+ }
74
+
75
+ fn then_else_break_inner (
76
+ & mut self ,
77
+ block : BasicBlock , // Block that the condition and branch will be lowered into
78
+ expr_id : ExprId , // Condition expression to lower
79
+ args : ThenElseArgs ,
48
80
) -> BlockAnd < ( ) > {
49
81
let this = self ;
50
82
let expr = & this. thir [ expr_id] ;
51
83
let expr_span = expr. span ;
52
84
53
85
match expr. kind {
54
86
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
-
87
+ let lhs_then_block = unpack ! ( this. then_else_break_inner( block, lhs, args) ) ;
88
+ let rhs_then_block = unpack ! ( this. then_else_break_inner( lhs_then_block, rhs, args) ) ;
73
89
rhs_then_block. unit ( )
74
90
}
75
91
ExprKind :: LogicalOp { op : LogicalOp :: Or , lhs, rhs } => {
76
92
let local_scope = this. local_scope ( ) ;
77
93
let ( lhs_success_block, failure_block) =
78
94
this. in_if_then_scope ( local_scope, expr_span, |this| {
79
- this. then_else_break (
95
+ this. then_else_break_inner (
80
96
block,
81
97
lhs,
82
- temp_scope_override,
83
- local_scope,
84
- variable_source_info,
85
- true ,
98
+ ThenElseArgs {
99
+ break_scope : local_scope,
100
+ declare_let_bindings : true ,
101
+ ..args
102
+ } ,
86
103
)
87
104
} ) ;
88
- let rhs_success_block = unpack ! ( this. then_else_break (
105
+ let rhs_success_block = unpack ! ( this. then_else_break_inner (
89
106
failure_block,
90
107
rhs,
91
- temp_scope_override,
92
- break_scope,
93
- variable_source_info,
94
- true ,
108
+ ThenElseArgs { declare_let_bindings: true , ..args } ,
95
109
) ) ;
96
110
97
111
// Make the LHS and RHS success arms converge to a common block.
98
112
// (We can't just make LHS goto RHS, because `rhs_success_block`
99
113
// might contain statements that we don't want on the LHS path.)
100
114
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) ;
115
+ this. cfg . goto ( lhs_success_block, args . variable_source_info , success_block) ;
116
+ this. cfg . goto ( rhs_success_block, args . variable_source_info , success_block) ;
103
117
success_block. unit ( )
104
118
}
105
119
ExprKind :: Unary { op : UnOp :: Not , arg } => {
@@ -111,50 +125,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
111
125
if this. tcx . sess . instrument_coverage ( ) {
112
126
this. cfg . push_coverage_span_marker ( block, this. source_info ( expr_span) ) ;
113
127
}
114
- this. then_else_break (
128
+ this. then_else_break_inner (
115
129
block,
116
130
arg,
117
- temp_scope_override,
118
- local_scope,
119
- variable_source_info,
120
- true ,
131
+ ThenElseArgs {
132
+ break_scope : local_scope,
133
+ declare_let_bindings : true ,
134
+ ..args
135
+ } ,
121
136
)
122
137
} ) ;
123
- this. break_for_else ( success_block, break_scope, variable_source_info) ;
138
+ this. break_for_else ( success_block, args . break_scope , args . variable_source_info ) ;
124
139
failure_block. unit ( )
125
140
}
126
141
ExprKind :: Scope { region_scope, lint_level, value } => {
127
142
let region_scope = ( region_scope, this. source_info ( expr_span) ) ;
128
143
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
- )
144
+ this. then_else_break_inner ( block, value, args)
137
145
} )
138
146
}
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
- ) ,
147
+ ExprKind :: Use { source } => this. then_else_break_inner ( block, source, args) ,
147
148
ExprKind :: Let { expr, ref pat } => this. lower_let_expr (
148
149
block,
149
150
expr,
150
151
pat,
151
- break_scope,
152
- Some ( variable_source_info. scope ) ,
153
- variable_source_info. span ,
154
- declare_bindings ,
152
+ args . break_scope ,
153
+ Some ( args . variable_source_info . scope ) ,
154
+ args . variable_source_info . span ,
155
+ args . declare_let_bindings ,
155
156
) ,
156
157
_ => {
157
- let temp_scope = temp_scope_override. unwrap_or_else ( || this. local_scope ( ) ) ;
158
+ let mut block = block;
159
+ let temp_scope = args. temp_scope_override . unwrap_or_else ( || this. local_scope ( ) ) ;
158
160
let mutability = Mutability :: Mut ;
159
161
let place =
160
162
unpack ! ( block = this. as_temp( block, Some ( temp_scope) , expr_id, mutability) ) ;
@@ -166,7 +168,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
166
168
167
169
let source_info = this. source_info ( expr_span) ;
168
170
this. cfg . terminate ( block, source_info, term) ;
169
- this. break_for_else ( else_block, break_scope, source_info) ;
171
+ this. break_for_else ( else_block, args . break_scope , source_info) ;
170
172
171
173
then_block. unit ( )
172
174
}
@@ -2102,13 +2104,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2102
2104
let ( post_guard_block, otherwise_post_guard_block) =
2103
2105
self . in_if_then_scope ( match_scope, guard_span, |this| {
2104
2106
guard_span = this. thir [ guard] . span ;
2105
- this. then_else_break (
2107
+ // Directly invoke the "inner" impl, so that we don't need a
2108
+ // wrapper function for just this one guard-specific call site.
2109
+ this. then_else_break_inner (
2106
2110
block,
2107
2111
guard,
2108
- None ,
2109
- match_scope,
2110
- this. source_info ( arm. span ) ,
2111
- false ,
2112
+ ThenElseArgs {
2113
+ temp_scope_override : None , // Use `self.local_scope()`
2114
+ break_scope : match_scope,
2115
+ variable_source_info : this. source_info ( arm. span ) ,
2116
+ // For guards, `let` bindings are declared separately.
2117
+ declare_let_bindings : false ,
2118
+ } ,
2112
2119
)
2113
2120
} ) ;
2114
2121
0 commit comments