@@ -39,9 +39,27 @@ struct ThenElseArgs {
39
39
/// `self.local_scope()` is used.
40
40
temp_scope_override : Option < region:: Scope > ,
41
41
variable_source_info : SourceInfo ,
42
+ /// Determines how bindings should be handled when lowering `let` expressions.
43
+ ///
42
44
/// Forwarded to [`Builder::lower_let_expr`] when lowering [`ExprKind::Let`].
43
- /// When false (for match guards), `let` bindings won't be declared.
44
- declare_let_bindings : bool ,
45
+ declare_let_bindings : DeclareLetBindings ,
46
+ }
47
+
48
+ /// Should lowering a `let` expression also declare its bindings?
49
+ ///
50
+ /// Used by [`Builder::lower_let_expr`] when lowering [`ExprKind::Let`].
51
+ #[ derive( Clone , Copy ) ]
52
+ pub ( crate ) enum DeclareLetBindings {
53
+ /// Yes, declare `let` bindings as normal for `if` conditions.
54
+ Yes ,
55
+ /// No, don't declare `let` bindings, because the caller declares them
56
+ /// separately due to special requirements.
57
+ ///
58
+ /// Used for match guards and let-else.
59
+ No ,
60
+ /// Let expressions are not permitted in this context, so it is a bug to
61
+ /// try to lower one (e.g inside lazy-boolean-or or boolean-not).
62
+ LetNotPermitted ,
45
63
}
46
64
47
65
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
@@ -57,7 +75,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
57
75
expr_id : ExprId ,
58
76
temp_scope_override : Option < region:: Scope > ,
59
77
variable_source_info : SourceInfo ,
60
- declare_let_bindings : bool ,
78
+ declare_let_bindings : DeclareLetBindings ,
61
79
) -> BlockAnd < ( ) > {
62
80
self . then_else_break_inner (
63
81
block,
@@ -91,13 +109,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
91
109
this. then_else_break_inner (
92
110
block,
93
111
lhs,
94
- ThenElseArgs { declare_let_bindings : true , ..args } ,
112
+ ThenElseArgs {
113
+ declare_let_bindings : DeclareLetBindings :: LetNotPermitted ,
114
+ ..args
115
+ } ,
95
116
)
96
117
} ) ;
97
118
let rhs_success_block = unpack ! ( this. then_else_break_inner(
98
119
failure_block,
99
120
rhs,
100
- ThenElseArgs { declare_let_bindings: true , ..args } ,
121
+ ThenElseArgs {
122
+ declare_let_bindings: DeclareLetBindings :: LetNotPermitted ,
123
+ ..args
124
+ } ,
101
125
) ) ;
102
126
103
127
// Make the LHS and RHS success arms converge to a common block.
@@ -127,7 +151,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
127
151
this. then_else_break_inner (
128
152
block,
129
153
arg,
130
- ThenElseArgs { declare_let_bindings : true , ..args } ,
154
+ ThenElseArgs {
155
+ declare_let_bindings : DeclareLetBindings :: LetNotPermitted ,
156
+ ..args
157
+ } ,
131
158
)
132
159
} ) ;
133
160
this. break_for_else ( success_block, args. variable_source_info ) ;
@@ -1991,16 +2018,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1991
2018
// Pat binding - used for `let` and function parameters as well.
1992
2019
1993
2020
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
1994
- /// If the bindings have already been declared, set `declare_bindings` to
1995
- /// `false` to avoid duplicated bindings declaration; used for if-let guards.
2021
+ /// Lowers a `let` expression that appears in a suitable context
2022
+ /// (e.g. an `if` condition or match guard).
2023
+ ///
2024
+ /// Also used for lowering let-else statements, since they have similar
2025
+ /// needs despite not actually using `let` expressions.
2026
+ ///
2027
+ /// Use [`LetBindingsMode`] to control whether the `let` bindings are
2028
+ /// declared or not.
1996
2029
pub ( crate ) fn lower_let_expr (
1997
2030
& mut self ,
1998
2031
mut block : BasicBlock ,
1999
2032
expr_id : ExprId ,
2000
2033
pat : & Pat < ' tcx > ,
2001
2034
source_scope : Option < SourceScope > ,
2002
2035
scope_span : Span ,
2003
- declare_bindings : bool ,
2036
+ declare_let_bindings : DeclareLetBindings ,
2004
2037
storages_alive : bool ,
2005
2038
) -> BlockAnd < ( ) > {
2006
2039
let expr_span = self . thir [ expr_id] . span ;
@@ -2017,10 +2050,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2017
2050
2018
2051
self . break_for_else ( otherwise_block, self . source_info ( expr_span) ) ;
2019
2052
2020
- if declare_bindings {
2021
- let expr_place = scrutinee. try_to_place ( self ) ;
2022
- let opt_expr_place = expr_place. as_ref ( ) . map ( |place| ( Some ( place) , expr_span) ) ;
2023
- self . declare_bindings ( source_scope, pat. span . to ( scope_span) , pat, None , opt_expr_place) ;
2053
+ match declare_let_bindings {
2054
+ DeclareLetBindings :: Yes => {
2055
+ let expr_place = scrutinee. try_to_place ( self ) ;
2056
+ let opt_expr_place = expr_place. as_ref ( ) . map ( |place| ( Some ( place) , expr_span) ) ;
2057
+ self . declare_bindings (
2058
+ source_scope,
2059
+ pat. span . to ( scope_span) ,
2060
+ pat,
2061
+ None ,
2062
+ opt_expr_place,
2063
+ ) ;
2064
+ }
2065
+ DeclareLetBindings :: No => { } // Caller is responsible for bindings.
2066
+ DeclareLetBindings :: LetNotPermitted => {
2067
+ self . tcx . dcx ( ) . span_bug ( expr_span, "let expression not expected in this context" )
2068
+ }
2024
2069
}
2025
2070
2026
2071
let success = self . bind_pattern (
@@ -2203,7 +2248,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2203
2248
guard,
2204
2249
None , // Use `self.local_scope()` as the temp scope
2205
2250
this. source_info ( arm. span ) ,
2206
- false , // For guards, `let` bindings are declared separately
2251
+ DeclareLetBindings :: No , // For guards, `let` bindings are declared separately
2207
2252
)
2208
2253
} ) ;
2209
2254
0 commit comments