Skip to content

Commit d1ca653

Browse files
committed
Auto merge of #44484 - tirr-c:issue-44332, r=petrochenkov
Parse nested closure with two consecutive parameter lists properly This is a followup of #44332. --- Currently, in nightly, this does not compile: ```rust fn main() { let f = |_||x, y| x+y; println!("{}", f(())(1, 2)); // should print 3 } ``` `|_||x, y| x+y` should be parsed as `|_| (|x, y| x+y)`, but the parser didn't accept `||` between `_` and `x`. This patch fixes the problem. r? @petrochenkov
2 parents 9421141 + 31cf11a commit d1ca653

File tree

2 files changed

+52
-6
lines changed

2 files changed

+52
-6
lines changed

src/libsyntax/parse/parser.rs

+38-6
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,12 @@ fn dummy_arg(span: Span) -> Arg {
481481
Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID }
482482
}
483483

484+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
485+
enum TokenExpectType {
486+
Expect,
487+
NoExpect,
488+
}
489+
484490
impl<'a> Parser<'a> {
485491
pub fn new(sess: &'a ParseSess,
486492
tokens: TokenStream,
@@ -797,6 +803,23 @@ impl<'a> Parser<'a> {
797803
}
798804
}
799805

806+
/// Expect and consume an `|`. If `||` is seen, replace it with a single
807+
/// `|` and continue. If an `|` is not seen, signal an error.
808+
fn expect_or(&mut self) -> PResult<'a, ()> {
809+
self.expected_tokens.push(TokenType::Token(token::BinOp(token::Or)));
810+
match self.token {
811+
token::BinOp(token::Or) => {
812+
self.bump();
813+
Ok(())
814+
}
815+
token::OrOr => {
816+
let span = self.span.with_lo(self.span.lo() + BytePos(1));
817+
Ok(self.bump_with(token::BinOp(token::Or), span))
818+
}
819+
_ => self.unexpected()
820+
}
821+
}
822+
800823
pub fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) {
801824
match suffix {
802825
None => {/* everything ok */}
@@ -946,6 +969,7 @@ impl<'a> Parser<'a> {
946969

947970
self.parse_seq_to_before_tokens(kets,
948971
SeqSep::none(),
972+
TokenExpectType::Expect,
949973
|p| Ok(p.parse_token_tree()),
950974
|mut e| handler.cancel(&mut e));
951975
}
@@ -975,13 +999,14 @@ impl<'a> Parser<'a> {
975999
-> Vec<T>
9761000
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
9771001
{
978-
self.parse_seq_to_before_tokens(&[ket], sep, f, |mut e| e.emit())
1002+
self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f, |mut e| e.emit())
9791003
}
9801004

9811005
// `fe` is an error handler.
9821006
fn parse_seq_to_before_tokens<T, F, Fe>(&mut self,
9831007
kets: &[&token::Token],
9841008
sep: SeqSep,
1009+
expect: TokenExpectType,
9851010
mut f: F,
9861011
mut fe: Fe)
9871012
-> Vec<T>
@@ -1005,7 +1030,12 @@ impl<'a> Parser<'a> {
10051030
}
10061031
}
10071032
}
1008-
if sep.trailing_sep_allowed && kets.iter().any(|k| self.check(k)) {
1033+
if sep.trailing_sep_allowed && kets.iter().any(|k| {
1034+
match expect {
1035+
TokenExpectType::Expect => self.check(k),
1036+
TokenExpectType::NoExpect => self.token == **k,
1037+
}
1038+
}) {
10091039
break;
10101040
}
10111041

@@ -4694,12 +4724,14 @@ impl<'a> Parser<'a> {
46944724
Vec::new()
46954725
} else {
46964726
self.expect(&token::BinOp(token::Or))?;
4697-
let args = self.parse_seq_to_before_end(
4698-
&token::BinOp(token::Or),
4727+
let args = self.parse_seq_to_before_tokens(
4728+
&[&token::BinOp(token::Or), &token::OrOr],
46994729
SeqSep::trailing_allowed(token::Comma),
4700-
|p| p.parse_fn_block_arg()
4730+
TokenExpectType::NoExpect,
4731+
|p| p.parse_fn_block_arg(),
4732+
|mut e| e.emit()
47014733
);
4702-
self.expect(&token::BinOp(token::Or))?;
4734+
self.expect_or()?;
47034735
args
47044736
}
47054737
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let f = |_||x, y| x+y;
13+
assert_eq!(f(())(1, 2), 3);
14+
}

0 commit comments

Comments
 (0)