diff options
| author | bors <bors@rust-lang.org> | 2022-08-02 06:09:22 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-08-02 06:09:22 +0000 |
| commit | ca37a45232b41789b31caec9a71714855f66c477 (patch) | |
| tree | 27b0f48de73c23bf4e8751255bbc490663a450a9 /compiler/rustc_parse/src/parser/expr.rs | |
| parent | 9538d2d0f1c708affa36ef8917729efec2e5e0ed (diff) | |
| parent | 6ab19fd4f505443919545b70890c86c0bfb3d2aa (diff) | |
| download | rust-ca37a45232b41789b31caec9a71714855f66c477.tar.gz rust-ca37a45232b41789b31caec9a71714855f66c477.zip | |
Auto merge of #100048 - matthiaskrgr:rollup-agimvm6, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #99156 (`codegen_fulfill_obligation` expect erased regions) - #99293 (only run --all-targets in stage0 for Std) - #99779 (Fix item info pos and height) - #99994 (Remove `guess_head_span`) - #100011 (Use Parser's `restrictions` instead of `let_expr_allowed`) - #100017 (kmc-solid: Update `Socket::connect_timeout` to be in line with #78802) - #100037 (Update rustc man page to match `rustc --help`) - #100042 (Update books) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_parse/src/parser/expr.rs')
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 56 |
1 files changed, 17 insertions, 39 deletions
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index c0f661f7dbb..e473f4d30cf 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1391,8 +1391,6 @@ impl<'a> Parser<'a> { } else if self.is_do_yeet() { self.parse_yeet_expr(attrs) } else if self.check_keyword(kw::Let) { - self.manage_let_chains_context(); - self.bump(); self.parse_let_expr(attrs) } else if self.eat_keyword(kw::Underscore) { Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs)) @@ -2342,32 +2340,24 @@ impl<'a> Parser<'a> { /// Parses the condition of a `if` or `while` expression. fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> { - self.with_let_management(true, |local_self| { - local_self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None) - }) + self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None) } - // Checks if `let` is in an invalid position like `let x = let y = 1;` or - // if the current `let` is in a let_chains context but nested in another - // expression like `if let Some(_) = _opt && [1, 2, 3][let _ = ()] = 1`. - // - // This method expects that the current token is `let`. - fn manage_let_chains_context(&mut self) { - debug_assert!(matches!(self.token.kind, TokenKind::Ident(kw::Let, _))); - let is_in_a_let_chains_context_but_nested_in_other_expr = self.let_expr_allowed - && !matches!( - self.prev_token.kind, - TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _) - ); - if !self.let_expr_allowed || is_in_a_let_chains_context_but_nested_in_other_expr { + /// Parses a `let $pat = $expr` pseudo-expression. + fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> { + // This is a *approximate* heuristic that detects if `let` chains are + // being parsed in the right position. It's approximate because it + // doesn't deny all invalid `let` expressions, just completely wrong usages. + let not_in_chain = !matches!( + self.prev_token.kind, + TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _) + ); + if !self.restrictions.contains(Restrictions::ALLOW_LET) || not_in_chain { self.struct_span_err(self.token.span, "expected expression, found `let` statement") .emit(); } - } - /// Parses a `let $pat = $expr` pseudo-expression. - /// The `let` token has already been eaten. - fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> { + self.bump(); // Eat `let` token let lo = self.prev_token.span; let pat = self.parse_pat_allow_top_alt( None, @@ -2687,7 +2677,9 @@ impl<'a> Parser<'a> { // `&&` tokens. fn check_let_expr(expr: &Expr) -> bool { match expr.kind { - ExprKind::Binary(_, ref lhs, ref rhs) => check_let_expr(lhs) || check_let_expr(rhs), + ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, ref lhs, ref rhs) => { + check_let_expr(lhs) || check_let_expr(rhs) + } ExprKind::Let(..) => true, _ => false, } @@ -2703,9 +2695,8 @@ impl<'a> Parser<'a> { )?; let guard = if this.eat_keyword(kw::If) { let if_span = this.prev_token.span; - let cond = this.with_let_management(true, |local_this| local_this.parse_expr())?; - let has_let_expr = check_let_expr(&cond); - if has_let_expr { + let cond = this.parse_expr_res(Restrictions::ALLOW_LET, None)?; + if check_let_expr(&cond) { let span = if_span.to(cond.span); this.sess.gated_spans.gate(sym::if_let_guard, span); } @@ -3279,17 +3270,4 @@ impl<'a> Parser<'a> { Ok((res, trailing)) }) } - - // Calls `f` with the internal `let_expr_allowed` set to `let_expr_allowed` and then - // sets the internal `let_expr_allowed` back to its original value. - fn with_let_management<T>( - &mut self, - let_expr_allowed: bool, - f: impl FnOnce(&mut Self) -> T, - ) -> T { - let last_let_expr_allowed = mem::replace(&mut self.let_expr_allowed, let_expr_allowed); - let rslt = f(self); - self.let_expr_allowed = last_let_expr_allowed; - rslt - } } |
