summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_parse/src/parser/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src/parser/mod.rs')
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs138
1 files changed, 83 insertions, 55 deletions
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 1a7ae4069..b91432f10 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -11,7 +11,6 @@ mod stmt;
mod ty;
use crate::lexer::UnmatchedDelim;
-use ast::Gen;
pub use attr_wrapper::AttrWrapper;
pub use diagnostics::AttemptLocalParseRecovery;
pub(crate) use expr::ForbiddenLetReason;
@@ -21,13 +20,14 @@ pub use path::PathStyle;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
-use rustc_ast::tokenstream::{AttributesData, DelimSpan, Spacing};
+use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
use rustc_ast::util::case::Case;
use rustc_ast::AttrId;
+use rustc_ast::CoroutineKind;
use rustc_ast::DUMMY_NODE_ID;
use rustc_ast::{self as ast, AnonConst, Const, DelimArgs, Extern};
-use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, Mutability, StrLit};
+use rustc_ast::{AttrArgs, AttrArgsEq, Expr, ExprKind, Mutability, StrLit};
use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
@@ -93,7 +93,7 @@ pub enum TrailingToken {
macro_rules! maybe_whole {
($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
if let token::Interpolated(nt) = &$p.token.kind {
- if let token::$constructor(x) = &**nt {
+ if let token::$constructor(x) = &nt.0 {
let $x = x.clone();
$p.bump();
return Ok($e);
@@ -107,15 +107,15 @@ macro_rules! maybe_whole {
macro_rules! maybe_recover_from_interpolated_ty_qpath {
($self: expr, $allow_qpath_recovery: expr) => {
if $allow_qpath_recovery
- && $self.may_recover()
- && $self.look_ahead(1, |t| t == &token::ModSep)
- && let token::Interpolated(nt) = &$self.token.kind
- && let token::NtTy(ty) = &**nt
- {
- let ty = ty.clone();
- $self.bump();
- return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_token.span, ty);
- }
+ && $self.may_recover()
+ && $self.look_ahead(1, |t| t == &token::ModSep)
+ && let token::Interpolated(nt) = &$self.token.kind
+ && let token::NtTy(ty) = &nt.0
+ {
+ let ty = ty.clone();
+ $self.bump();
+ return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_token.span, ty);
+ }
};
}
@@ -130,7 +130,7 @@ pub struct Parser<'a> {
pub sess: &'a ParseSess,
/// The current token.
pub token: Token,
- /// The spacing for the current token
+ /// The spacing for the current token.
pub token_spacing: Spacing,
/// The previous token.
pub prev_token: Token,
@@ -240,7 +240,7 @@ struct TokenCursor {
// Token streams surrounding the current one. The delimiters for stack[n]'s
// tokens are in `stack[n-1]`. `stack[0]` (when present) has no delimiters
// because it's the outermost token stream which never has delimiters.
- stack: Vec<(TokenTreeCursor, Delimiter, DelimSpan)>,
+ stack: Vec<(TokenTreeCursor, DelimSpan, DelimSpacing, Delimiter)>,
}
impl TokenCursor {
@@ -264,24 +264,31 @@ impl TokenCursor {
));
return (token.clone(), spacing);
}
- &TokenTree::Delimited(sp, delim, ref tts) => {
+ &TokenTree::Delimited(sp, spacing, delim, ref tts) => {
let trees = tts.clone().into_trees();
- self.stack.push((mem::replace(&mut self.tree_cursor, trees), delim, sp));
+ self.stack.push((
+ mem::replace(&mut self.tree_cursor, trees),
+ sp,
+ spacing,
+ delim,
+ ));
if delim != Delimiter::Invisible {
- return (Token::new(token::OpenDelim(delim), sp.open), Spacing::Alone);
+ return (Token::new(token::OpenDelim(delim), sp.open), spacing.open);
}
// No open delimiter to return; continue on to the next iteration.
}
};
- } else if let Some((tree_cursor, delim, span)) = self.stack.pop() {
+ } else if let Some((tree_cursor, span, spacing, delim)) = self.stack.pop() {
// We have exhausted this token stream. Move back to its parent token stream.
self.tree_cursor = tree_cursor;
if delim != Delimiter::Invisible {
- return (Token::new(token::CloseDelim(delim), span.close), Spacing::Alone);
+ return (Token::new(token::CloseDelim(delim), span.close), spacing.close);
}
// No close delimiter to return; continue on to the next iteration.
} else {
- // We have exhausted the outermost token stream.
+ // We have exhausted the outermost token stream. The use of
+ // `Spacing::Alone` is arbitrary and immaterial, because the
+ // `Eof` token's spacing is never used.
return (Token::new(token::Eof, DUMMY_SP), Spacing::Alone);
}
}
@@ -367,12 +374,14 @@ impl TokenDescription {
pub(super) fn token_descr(token: &Token) -> String {
let name = pprust::token_to_string(token).to_string();
- let kind = TokenDescription::from_token(token).map(|kind| match kind {
- TokenDescription::ReservedIdentifier => "reserved identifier",
- TokenDescription::Keyword => "keyword",
- TokenDescription::ReservedKeyword => "reserved keyword",
- TokenDescription::DocComment => "doc comment",
- });
+ let kind = match (TokenDescription::from_token(token), &token.kind) {
+ (Some(TokenDescription::ReservedIdentifier), _) => Some("reserved identifier"),
+ (Some(TokenDescription::Keyword), _) => Some("keyword"),
+ (Some(TokenDescription::ReservedKeyword), _) => Some("reserved keyword"),
+ (Some(TokenDescription::DocComment), _) => Some("doc comment"),
+ (None, TokenKind::Interpolated(node)) => Some(node.0.descr()),
+ (None, _) => None,
+ };
if let Some(kind) = kind { format!("{kind} `{name}`") } else { format!("`{name}`") }
}
@@ -662,7 +671,7 @@ impl<'a> Parser<'a> {
fn check_inline_const(&self, dist: usize) -> bool {
self.is_keyword_ahead(dist, &[kw::Const])
&& self.look_ahead(dist + 1, |t| match &t.kind {
- token::Interpolated(nt) => matches!(**nt, token::NtBlock(..)),
+ token::Interpolated(nt) => matches!(&nt.0, token::NtBlock(..)),
token::OpenDelim(Delimiter::Brace) => true,
_ => false,
})
@@ -697,8 +706,8 @@ impl<'a> Parser<'a> {
// is not needed (we'll capture the entire 'glued' token),
// and `bump` will set this field to `None`
self.break_last_token = true;
- // Use the spacing of the glued token as the spacing
- // of the unglued second token.
+ // Use the spacing of the glued token as the spacing of the
+ // unglued second token.
self.bump_with((Token::new(second, second_span), self.token_spacing));
true
}
@@ -830,8 +839,8 @@ impl<'a> Parser<'a> {
// https://github.com/rust-lang/rust/issues/72373
if self.prev_token.is_ident() && self.token.kind == token::DotDot {
let msg = format!(
- "if you meant to bind the contents of \
- the rest of the array pattern into `{}`, use `@`",
+ "if you meant to bind the contents of the rest of the array \
+ pattern into `{}`, use `@`",
pprust::token_to_string(&self.prev_token)
);
expect_err
@@ -873,6 +882,9 @@ impl<'a> Parser<'a> {
if self.token == token::Colon {
// we will try to recover in `maybe_recover_struct_lit_bad_delims`
return Err(expect_err);
+ } else if let [token::CloseDelim(Delimiter::Parenthesis)] = kets
+ {
+ return Err(expect_err);
} else {
expect_err.emit();
break;
@@ -1063,7 +1075,7 @@ impl<'a> Parser<'a> {
return looker(&self.token);
}
- if let Some(&(_, delim, span)) = self.token_cursor.stack.last()
+ if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last()
&& delim != Delimiter::Invisible
{
// We are not in the outermost token stream, and the token stream
@@ -1072,7 +1084,7 @@ impl<'a> Parser<'a> {
let tree_cursor = &self.token_cursor.tree_cursor;
let all_normal = (0..dist).all(|i| {
let token = tree_cursor.look_ahead(i);
- !matches!(token, Some(TokenTree::Delimited(_, Delimiter::Invisible, _)))
+ !matches!(token, Some(TokenTree::Delimited(.., Delimiter::Invisible, _)))
});
if all_normal {
// There were no skipped delimiters. Do lookahead by plain indexing.
@@ -1081,7 +1093,7 @@ impl<'a> Parser<'a> {
// Indexing stayed within the current token stream.
match tree {
TokenTree::Token(token, _) => looker(token),
- TokenTree::Delimited(dspan, delim, _) => {
+ TokenTree::Delimited(dspan, _, delim, _) => {
looker(&Token::new(token::OpenDelim(*delim), dspan.open))
}
}
@@ -1115,27 +1127,42 @@ impl<'a> Parser<'a> {
}
/// Returns whether any of the given keywords are `dist` tokens ahead of the current one.
- fn is_keyword_ahead(&self, dist: usize, kws: &[Symbol]) -> bool {
+ pub(crate) fn is_keyword_ahead(&self, dist: usize, kws: &[Symbol]) -> bool {
self.look_ahead(dist, |t| kws.iter().any(|&kw| t.is_keyword(kw)))
}
/// Parses asyncness: `async` or nothing.
- fn parse_asyncness(&mut self, case: Case) -> Async {
+ fn parse_coroutine_kind(&mut self, case: Case) -> Option<CoroutineKind> {
+ let span = self.token.uninterpolated_span();
if self.eat_keyword_case(kw::Async, case) {
- let span = self.prev_token.uninterpolated_span();
- Async::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
- } else {
- Async::No
- }
- }
-
- /// Parses genness: `gen` or nothing.
- fn parse_genness(&mut self, case: Case) -> Gen {
- if self.token.span.at_least_rust_2024() && self.eat_keyword_case(kw::Gen, case) {
- let span = self.prev_token.uninterpolated_span();
- Gen::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
+ // FIXME(gen_blocks): Do we want to unconditionally parse `gen` and then
+ // error if edition <= 2024, like we do with async and edition <= 2018?
+ if self.token.uninterpolated_span().at_least_rust_2024()
+ && self.eat_keyword_case(kw::Gen, case)
+ {
+ let gen_span = self.prev_token.uninterpolated_span();
+ Some(CoroutineKind::AsyncGen {
+ span: span.to(gen_span),
+ closure_id: DUMMY_NODE_ID,
+ return_impl_trait_id: DUMMY_NODE_ID,
+ })
+ } else {
+ Some(CoroutineKind::Async {
+ span,
+ closure_id: DUMMY_NODE_ID,
+ return_impl_trait_id: DUMMY_NODE_ID,
+ })
+ }
+ } else if self.token.uninterpolated_span().at_least_rust_2024()
+ && self.eat_keyword_case(kw::Gen, case)
+ {
+ Some(CoroutineKind::Gen {
+ span,
+ closure_id: DUMMY_NODE_ID,
+ return_impl_trait_id: DUMMY_NODE_ID,
+ })
} else {
- Gen::No
+ None
}
}
@@ -1244,7 +1271,7 @@ impl<'a> Parser<'a> {
|| self.check(&token::OpenDelim(Delimiter::Brace));
delimited.then(|| {
- let TokenTree::Delimited(dspan, delim, tokens) = self.parse_token_tree() else {
+ let TokenTree::Delimited(dspan, _, delim, tokens) = self.parse_token_tree() else {
unreachable!()
};
DelimArgs { dspan, delim, tokens }
@@ -1268,7 +1295,7 @@ impl<'a> Parser<'a> {
token::OpenDelim(..) => {
// Grab the tokens within the delimiters.
let stream = self.token_cursor.tree_cursor.stream.clone();
- let (_, delim, span) = *self.token_cursor.stack.last().unwrap();
+ let (_, span, spacing, delim) = *self.token_cursor.stack.last().unwrap();
// Advance the token cursor through the entire delimited
// sequence. After getting the `OpenDelim` we are *within* the
@@ -1288,12 +1315,13 @@ impl<'a> Parser<'a> {
// Consume close delimiter
self.bump();
- TokenTree::Delimited(span, delim, stream)
+ TokenTree::Delimited(span, spacing, delim, stream)
}
token::CloseDelim(_) | token::Eof => unreachable!(),
_ => {
+ let prev_spacing = self.token_spacing;
self.bump();
- TokenTree::Token(self.prev_token.clone(), Spacing::Alone)
+ TokenTree::Token(self.prev_token.clone(), prev_spacing)
}
}
}
@@ -1479,7 +1507,7 @@ pub(crate) fn make_unclosed_delims_error(
opening_candidate: unmatched.candidate_span,
unclosed: unmatched.unclosed_span,
}
- .into_diagnostic(&sess.span_diagnostic);
+ .into_diagnostic(&sess.dcx);
Some(err)
}