Rollup merge of #141876 - compiler-errors:missing-let-ty, r=SparrowLii
Don't declare variables in `ExprKind::Let` in invalid positions Handle `let` expressions in invalid positions specially during resolve in order to avoid making destructuring-assignment expressions that reference (invalid) variables that have not yet been delcared yet. See further explanation in test and comment in the source. Fixes rust-lang/rust#141844
This commit is contained in:
commit
69ebe39cea
4 changed files with 46 additions and 3 deletions
|
|
@ -2370,6 +2370,10 @@ impl Expr<'_> {
|
|||
// Lang item paths cannot currently be local variables or statics.
|
||||
ExprKind::Path(QPath::LangItem(..)) => false,
|
||||
|
||||
// Suppress errors for bad expressions.
|
||||
ExprKind::Err(_guar)
|
||||
| ExprKind::Let(&LetExpr { recovered: ast::Recovered::Yes(_guar), .. }) => true,
|
||||
|
||||
// Partially qualified paths in expressions can only legally
|
||||
// refer to associated items which are always rvalues.
|
||||
ExprKind::Path(QPath::TypeRelative(..))
|
||||
|
|
@ -2401,8 +2405,7 @@ impl Expr<'_> {
|
|||
| ExprKind::Binary(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Cast(..)
|
||||
| ExprKind::DropTemps(..)
|
||||
| ExprKind::Err(_) => false,
|
||||
| ExprKind::DropTemps(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4898,11 +4898,28 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
self.resolve_expr(e, Some(expr));
|
||||
}
|
||||
|
||||
ExprKind::Let(ref pat, ref scrutinee, _, _) => {
|
||||
ExprKind::Let(ref pat, ref scrutinee, _, Recovered::No) => {
|
||||
self.visit_expr(scrutinee);
|
||||
self.resolve_pattern_top(pat, PatternSource::Let);
|
||||
}
|
||||
|
||||
ExprKind::Let(ref pat, ref scrutinee, _, Recovered::Yes(_)) => {
|
||||
self.visit_expr(scrutinee);
|
||||
// This is basically a tweaked, inlined `resolve_pattern_top`.
|
||||
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
|
||||
self.resolve_pattern(pat, PatternSource::Let, &mut bindings);
|
||||
// We still collect the bindings in this `let` expression which is in
|
||||
// an invalid position (and therefore shouldn't declare variables into
|
||||
// its parent scope). To avoid unnecessary errors though, we do just
|
||||
// reassign the resolutions to `Res::Err`.
|
||||
for (_, bindings) in &mut bindings {
|
||||
for (_, binding) in bindings {
|
||||
*binding = Res::Err;
|
||||
}
|
||||
}
|
||||
self.apply_pattern_bindings(bindings);
|
||||
}
|
||||
|
||||
ExprKind::If(ref cond, ref then, ref opt_else) => {
|
||||
self.with_rib(ValueNS, RibKind::Normal, |this| {
|
||||
let old = this.diag_metadata.in_if_condition.replace(cond);
|
||||
|
|
|
|||
13
tests/ui/destructuring-assignment/bad-let-in-destructure.rs
Normal file
13
tests/ui/destructuring-assignment/bad-let-in-destructure.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// Regression test for <https://github.com/rust-lang/rust/issues/141844>.
|
||||
|
||||
fn main() {
|
||||
// The following expression gets desugared into something like:
|
||||
// ```
|
||||
// let (lhs,) = x; (let x = 1) = lhs;
|
||||
// ```
|
||||
// This used to ICE since we haven't yet declared the type for `x` when
|
||||
// checking the first desugared statement, whose RHS resolved to `x` since
|
||||
// in the AST, the `let` expression was visited first.
|
||||
(let x = 1,) = x;
|
||||
//~^ ERROR expected expression, found `let` statement
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
error: expected expression, found `let` statement
|
||||
--> $DIR/bad-let-in-destructure.rs:11:4
|
||||
|
|
||||
LL | (let x = 1,) = x;
|
||||
| ^^^
|
||||
|
|
||||
= note: only supported directly in conditions of `if` and `while` expressions
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue