@@ -39,9 +39,27 @@ struct ThenElseArgs {
3939 /// `self.local_scope()` is used.
4040 temp_scope_override : Option < region:: Scope > ,
4141 variable_source_info : SourceInfo ,
42+ /// Determines how bindings should be handled when lowering `let` expressions.
43+ ///
4244 /// 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 ,
4563}
4664
4765impl < ' a , ' tcx > Builder < ' a , ' tcx > {
@@ -57,7 +75,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
5775 expr_id : ExprId ,
5876 temp_scope_override : Option < region:: Scope > ,
5977 variable_source_info : SourceInfo ,
60- declare_let_bindings : bool ,
78+ declare_let_bindings : DeclareLetBindings ,
6179 ) -> BlockAnd < ( ) > {
6280 self . then_else_break_inner (
6381 block,
@@ -91,13 +109,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
91109 this. then_else_break_inner (
92110 block,
93111 lhs,
94- ThenElseArgs { declare_let_bindings : true , ..args } ,
112+ ThenElseArgs {
113+ declare_let_bindings : DeclareLetBindings :: LetNotPermitted ,
114+ ..args
115+ } ,
95116 )
96117 } ) ;
97118 let rhs_success_block = unpack ! ( this. then_else_break_inner(
98119 failure_block,
99120 rhs,
100- ThenElseArgs { declare_let_bindings: true , ..args } ,
121+ ThenElseArgs {
122+ declare_let_bindings: DeclareLetBindings :: LetNotPermitted ,
123+ ..args
124+ } ,
101125 ) ) ;
102126
103127 // Make the LHS and RHS success arms converge to a common block.
@@ -127,7 +151,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
127151 this. then_else_break_inner (
128152 block,
129153 arg,
130- ThenElseArgs { declare_let_bindings : true , ..args } ,
154+ ThenElseArgs {
155+ declare_let_bindings : DeclareLetBindings :: LetNotPermitted ,
156+ ..args
157+ } ,
131158 )
132159 } ) ;
133160 this. break_for_else ( success_block, args. variable_source_info ) ;
@@ -1991,16 +2018,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
19912018// Pat binding - used for `let` and function parameters as well.
19922019
19932020impl < ' 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.
19962029 pub ( crate ) fn lower_let_expr (
19972030 & mut self ,
19982031 mut block : BasicBlock ,
19992032 expr_id : ExprId ,
20002033 pat : & Pat < ' tcx > ,
20012034 source_scope : Option < SourceScope > ,
20022035 scope_span : Span ,
2003- declare_bindings : bool ,
2036+ declare_let_bindings : DeclareLetBindings ,
20042037 storages_alive : bool ,
20052038 ) -> BlockAnd < ( ) > {
20062039 let expr_span = self . thir [ expr_id] . span ;
@@ -2017,10 +2050,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
20172050
20182051 self . break_for_else ( otherwise_block, self . source_info ( expr_span) ) ;
20192052
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+ }
20242069 }
20252070
20262071 let success = self . bind_pattern (
@@ -2203,7 +2248,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
22032248 guard,
22042249 None , // Use `self.local_scope()` as the temp scope
22052250 this. source_info ( arm. span ) ,
2206- false , // For guards, `let` bindings are declared separately
2251+ DeclareLetBindings :: No , // For guards, `let` bindings are declared separately
22072252 )
22082253 } ) ;
22092254
0 commit comments