diff options
| author | Dylan DPC <dylan.dpc@gmail.com> | 2020-03-22 15:48:32 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-22 15:48:32 +0100 |
| commit | ea44d71f9bc76d2136e20553259d43f55f282db1 (patch) | |
| tree | 792b0ffe15867a29de688c9a94547b8bea5e8ff7 /src/librustc_parse/parser/expr.rs | |
| parent | 9890d9a9d0e76cecbb6cfad41c0901f248430877 (diff) | |
| parent | 4d30b92e3e57cf606a25c807a9e4ab2b7a4d1064 (diff) | |
| download | rust-ea44d71f9bc76d2136e20553259d43f55f282db1.tar.gz rust-ea44d71f9bc76d2136e20553259d43f55f282db1.zip | |
Rollup merge of #70209 - Centril:recover-quant-closure, r=petrochenkov
parser: recover on `for<'a> |...| body` closures When encountering `for` and `<` is 1 token ahead, interpret this as an explicitly quantified generic closure and recover, rather than attempting to parse a `for` loop. This provides both improved diagnostics as well as an insurance policy for the ability to use this as the syntax for generic closures in the future. As requested by r? @eddyb
Diffstat (limited to 'src/librustc_parse/parser/expr.rs')
| -rw-r--r-- | src/librustc_parse/parser/expr.rs | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index b993857681a..b205a4b3222 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -925,8 +925,17 @@ impl<'a> Parser<'a> { self.parse_closure_expr(attrs) } else if self.eat_keyword(kw::If) { self.parse_if_expr(attrs) - } else if self.eat_keyword(kw::For) { - self.parse_for_expr(None, self.prev_token.span, attrs) + } else if self.check_keyword(kw::For) { + if self.choose_generics_over_qpath(1) { + // NOTE(Centril, eddyb): DO NOT REMOVE! Beyond providing parser recovery, + // this is an insurance policy in case we allow qpaths in (tuple-)struct patterns. + // When `for <Foo as Bar>::Proj in $expr $block` is wanted, + // you can disambiguate in favor of a pattern with `(...)`. + self.recover_quantified_closure_expr(attrs) + } else { + assert!(self.eat_keyword(kw::For)); + self.parse_for_expr(None, self.prev_token.span, attrs) + } } else if self.eat_keyword(kw::While) { self.parse_while_expr(None, self.prev_token.span, attrs) } else if let Some(label) = self.eat_label() { @@ -1417,6 +1426,26 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs)) } + /// Recover on an explicitly quantified closure expression, e.g., `for<'a> |x: &'a u8| *x + 1`. + fn recover_quantified_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> { + let lo = self.token.span; + let _ = self.parse_late_bound_lifetime_defs()?; + let span_for = lo.to(self.prev_token.span); + let closure = self.parse_closure_expr(attrs)?; + + self.struct_span_err(span_for, "cannot introduce explicit parameters for a closure") + .span_label(closure.span, "the parameters are attached to this closure") + .span_suggestion( + span_for, + "remove the parameters", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + + Ok(self.mk_expr_err(lo.to(closure.span))) + } + /// Parses a closure expression (e.g., `move |args| expr`). fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> { let lo = self.token.span; |
