Skip to content

Commit d2d0f62

Browse files
Don't declare variables in ExprKind::Let in invalid positions
1 parent ec28ae9 commit d2d0f62

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed

compiler/rustc_resolve/src/late.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4891,11 +4891,28 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
48914891
self.resolve_expr(e, Some(expr));
48924892
}
48934893

4894-
ExprKind::Let(ref pat, ref scrutinee, _, _) => {
4894+
ExprKind::Let(ref pat, ref scrutinee, _, Recovered::No) => {
48954895
self.visit_expr(scrutinee);
48964896
self.resolve_pattern_top(pat, PatternSource::Let);
48974897
}
48984898

4899+
ExprKind::Let(ref pat, ref scrutinee, _, Recovered::Yes(_)) => {
4900+
self.visit_expr(scrutinee);
4901+
// This is basically a tweaked, inlined `resolve_pattern_top`.
4902+
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
4903+
self.resolve_pattern(pat, PatternSource::Let, &mut bindings);
4904+
// We still collect the bindings in this `let` expression which is in
4905+
// an invalid position (and therefore shouldn't declare variables into
4906+
// its parent scope). To avoid unnecessary errors though, we do just
4907+
// reassign the resolutions to `Res::Err`.
4908+
for (_, bindings) in &mut bindings {
4909+
for (_, binding) in bindings {
4910+
*binding = Res::Err;
4911+
}
4912+
}
4913+
self.apply_pattern_bindings(bindings);
4914+
}
4915+
48994916
ExprKind::If(ref cond, ref then, ref opt_else) => {
49004917
self.with_rib(ValueNS, RibKind::Normal, |this| {
49014918
let old = this.diag_metadata.in_if_condition.replace(cond);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Regression test for <https://github.com/rust-lang/rust/issues/141844>.
2+
3+
fn main() {
4+
// The following expression gets desugared into something like:
5+
// ```
6+
// let (lhs,) = x; (let x = 1) = lhs;
7+
// ```
8+
// This used to ICE since we haven't yet declared the type for `x` when
9+
// checking the first desugared statement, whose RHS resolved to `x` since
10+
// in the AST, the `let` expression was visited first.
11+
(let x = 1,) = x;
12+
//~^ ERROR expected expression, found `let` statement
13+
//~| ERROR invalid left-hand side of assignment
14+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: expected expression, found `let` statement
2+
--> $DIR/bad-let-in-destructure.rs:10:4
3+
|
4+
LL | (let x = 1,) = x;
5+
| ^^^
6+
|
7+
= note: only supported directly in conditions of `if` and `while` expressions
8+
9+
error[E0070]: invalid left-hand side of assignment
10+
--> $DIR/bad-let-in-destructure.rs:10:16
11+
|
12+
LL | (let x = 1,) = x;
13+
| --------- ^
14+
| |
15+
| cannot assign to this expression
16+
17+
error: aborting due to 2 previous errors
18+
19+
For more information about this error, try `rustc --explain E0070`.

0 commit comments

Comments
 (0)