Parser: recover from ::: to ::

This commit is contained in:
Pavel Grigorenko 2024-09-21 20:07:52 +03:00
parent 74fd001cda
commit e90e2593ea
8 changed files with 239 additions and 15 deletions

View file

@ -16,7 +16,7 @@ use tracing::debug;
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{Parser, Restrictions, TokenType};
use crate::errors::PathSingleColon;
use crate::errors::{PathSingleColon, PathTripleColon};
use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};
use crate::{errors, maybe_whole};
@ -210,7 +210,7 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
let mut segments = ThinVec::new();
let mod_sep_ctxt = self.token.span.ctxt();
if self.eat(&token::PathSep) {
if self.eat_path_sep() {
segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
}
self.parse_path_segments(&mut segments, style, ty_generics)?;
@ -246,7 +246,7 @@ impl<'a> Parser<'a> {
}
segments.push(segment);
if self.is_import_coupler() || !self.eat(&token::PathSep) {
if self.is_import_coupler() || !self.eat_path_sep() {
if style == PathStyle::Expr
&& self.may_recover()
&& self.token == token::Colon
@ -272,6 +272,18 @@ impl<'a> Parser<'a> {
}
}
/// Eat `::` or, potentially, `:::`.
#[must_use]
pub(super) fn eat_path_sep(&mut self) -> bool {
let result = self.eat(&token::PathSep);
if result && self.may_recover() {
if self.eat_noexpect(&token::Colon) {
self.dcx().emit_err(PathTripleColon { span: self.prev_token.span });
}
}
result
}
pub(super) fn parse_path_segment(
&mut self,
style: PathStyle,
@ -297,9 +309,7 @@ impl<'a> Parser<'a> {
Ok(
if style == PathStyle::Type && check_args_start(self)
|| style != PathStyle::Mod
&& self.check(&token::PathSep)
&& self.look_ahead(1, |t| is_args_start(t))
|| style != PathStyle::Mod && self.check_path_sep_and_look_ahead(is_args_start)
{
// We use `style == PathStyle::Expr` to check if this is in a recursion or not. If
// it isn't, then we reset the unmatched angle bracket count as we're about to start
@ -310,7 +320,8 @@ impl<'a> Parser<'a> {
// Generic arguments are found - `<`, `(`, `::<` or `::(`.
// First, eat `::` if it exists.
let _ = self.eat(&token::PathSep);
let _ = self.eat_path_sep();
let lo = self.token.span;
let args = if self.eat_lt() {
// `<'a, T, A = U>`