Skip to content

Commit d55e5e5

Browse files
committed
Replace a magic boolean with enum DeclareLetBindings
The new enum `DeclareLetBindings` has three variants: - `Yes`: Declare `let` bindings as normal, for `if` conditions. - `No`: Don't declare bindings, for match guards and let-else. - `LetNotPermitted`: Assert that `let` expressions should not occur.
1 parent 227ebd9 commit d55e5e5

File tree

3 files changed

+64
-17
lines changed

3 files changed

+64
-17
lines changed

compiler/rustc_mir_build/src/build/block.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::build::matches::DeclareLetBindings;
12
use crate::build::ForGuard::OutsideGuard;
23
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
34
use rustc_middle::middle::region::Scope;
@@ -213,7 +214,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
213214
pattern,
214215
None,
215216
initializer_span,
216-
false,
217+
DeclareLetBindings::No,
217218
true,
218219
)
219220
});

compiler/rustc_mir_build/src/build/expr/into.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! See docs in build/expr/mod.rs
22
33
use crate::build::expr::category::{Category, RvalueFunc};
4+
use crate::build::matches::DeclareLetBindings;
45
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary};
56
use rustc_ast::InlineAsmOptions;
67
use rustc_data_structures::fx::FxHashMap;
@@ -86,7 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
8687
cond,
8788
Some(condition_scope), // Temp scope
8889
source_info,
89-
true, // Declare `let` bindings normally
90+
DeclareLetBindings::Yes, // Declare `let` bindings normally
9091
));
9192

9293
// Lower the `then` arm into its block.
@@ -163,7 +164,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
163164
source_info,
164165
// This flag controls how inner `let` expressions are lowered,
165166
// but either way there shouldn't be any of those in here.
166-
true,
167+
DeclareLetBindings::LetNotPermitted,
167168
)
168169
});
169170
let (short_circuit, continuation, constant) = match op {

compiler/rustc_mir_build/src/build/matches/mod.rs

+59-14
Original file line numberDiff line numberDiff line change
@@ -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

4765
impl<'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

19932020
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.
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

Comments
 (0)