summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_parse/src/parser/path.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_parse/src/parser/path.rs
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_parse/src/parser/path.rs')
-rw-r--r--compiler/rustc_parse/src/parser/path.rs113
1 files changed, 76 insertions, 37 deletions
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index c25c23d84..feb7e829c 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -1,5 +1,6 @@
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{Parser, Restrictions, TokenType};
+use crate::errors::PathSingleColon;
use crate::{errors, maybe_whole};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
@@ -8,7 +9,7 @@ use rustc_ast::{
AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
Path, PathSegment, QSelf,
};
-use rustc_errors::{pluralize, Applicability, PResult};
+use rustc_errors::{Applicability, IntoDiagnostic, PResult};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::symbol::{kw, sym, Ident};
use std::mem;
@@ -24,7 +25,19 @@ pub enum PathStyle {
/// In all such contexts the non-path interpretation is preferred by default for practical
/// reasons, but the path interpretation can be forced by the disambiguator `::`, e.g.
/// `x<y>` - comparisons, `x::<y>` - unambiguously a path.
+ ///
+ /// Also, a path may never be followed by a `:`. This means that we can eagerly recover if
+ /// we encounter it.
Expr,
+ /// The same as `Expr`, but may be followed by a `:`.
+ /// For example, this code:
+ /// ```rust
+ /// struct S;
+ ///
+ /// let S: S;
+ /// // ^ Followed by a `:`
+ /// ```
+ Pat,
/// In other contexts, notably in types, no ambiguity exists and paths can be written
/// without the disambiguator, e.g., `x<y>` - unambiguously a path.
/// Paths with disambiguators are still accepted, `x::<Y>` - unambiguously a path too.
@@ -38,6 +51,12 @@ pub enum PathStyle {
Mod,
}
+impl PathStyle {
+ fn has_generic_ambiguity(&self) -> bool {
+ matches!(self, Self::Expr | Self::Pat)
+ }
+}
+
impl<'a> Parser<'a> {
/// Parses a qualified path.
/// Assumes that the leading `<` has been parsed already.
@@ -150,16 +169,13 @@ impl<'a> Parser<'a> {
//
if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
{
- parser
- .struct_span_err(
- path.segments
- .iter()
- .filter_map(|segment| segment.args.as_ref())
- .map(|arg| arg.span())
- .collect::<Vec<_>>(),
- "unexpected generic arguments in path",
- )
- .emit();
+ let span = path
+ .segments
+ .iter()
+ .filter_map(|segment| segment.args.as_ref())
+ .map(|arg| arg.span())
+ .collect::<Vec<_>>();
+ parser.sess.emit_err(errors::GenericsInPath { span });
}
};
@@ -186,7 +202,6 @@ impl<'a> Parser<'a> {
segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
}
self.parse_path_segments(&mut segments, style, ty_generics)?;
-
Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None })
}
@@ -198,7 +213,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, ()> {
loop {
let segment = self.parse_path_segment(style, ty_generics)?;
- if style == PathStyle::Expr {
+ if style.has_generic_ambiguity() {
// In order to check for trailing angle brackets, we must have finished
// recursing (`parse_path_segment` can indirectly call this function),
// that is, the next token must be the highlighted part of the below example:
@@ -220,6 +235,29 @@ impl<'a> Parser<'a> {
segments.push(segment);
if self.is_import_coupler() || !self.eat(&token::ModSep) {
+ if style == PathStyle::Expr
+ && self.may_recover()
+ && self.token == token::Colon
+ && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
+ {
+ // Emit a special error message for `a::b:c` to help users
+ // otherwise, `a: c` might have meant to introduce a new binding
+ if self.token.span.lo() == self.prev_token.span.hi()
+ && self.look_ahead(1, |token| self.token.span.hi() == token.span.lo())
+ {
+ self.bump(); // bump past the colon
+ self.sess.emit_err(PathSingleColon {
+ span: self.prev_token.span,
+ type_ascription: self
+ .sess
+ .unstable_features
+ .is_nightly_build()
+ .then_some(()),
+ });
+ }
+ continue;
+ }
+
return Ok(());
}
}
@@ -273,8 +311,25 @@ impl<'a> Parser<'a> {
ty_generics,
)?;
self.expect_gt().map_err(|mut err| {
+ // Try to recover a `:` into a `::`
+ if self.token == token::Colon
+ && self.look_ahead(1, |token| {
+ token.is_ident() && !token.is_reserved_ident()
+ })
+ {
+ err.cancel();
+ err = PathSingleColon {
+ span: self.token.span,
+ type_ascription: self
+ .sess
+ .unstable_features
+ .is_nightly_build()
+ .then_some(()),
+ }
+ .into_diagnostic(self.diagnostic());
+ }
// Attempt to find places where a missing `>` might belong.
- if let Some(arg) = args
+ else if let Some(arg) = args
.iter()
.rev()
.find(|arg| !matches!(arg, AngleBracketedArg::Constraint(_)))
@@ -467,23 +522,10 @@ impl<'a> Parser<'a> {
// i.e. no multibyte characters, in this range.
let span =
lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
- self.struct_span_err(
+ self.sess.emit_err(errors::UnmatchedAngle {
span,
- &format!(
- "unmatched angle bracket{}",
- pluralize!(snapshot.unmatched_angle_bracket_count)
- ),
- )
- .span_suggestion(
- span,
- &format!(
- "remove extra angle bracket{}",
- pluralize!(snapshot.unmatched_angle_bracket_count)
- ),
- "",
- Applicability::MachineApplicable,
- )
- .emit();
+ plural: snapshot.unmatched_angle_bracket_count > 1,
+ });
// Try again without unmatched angle bracket characters.
self.parse_angle_args(ty_generics)
@@ -564,7 +606,7 @@ impl<'a> Parser<'a> {
let kind = if self.eat(&token::Colon) {
// Parse associated type constraint bound.
- let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
+ let bounds = self.parse_generic_bounds()?;
AssocConstraintKind::Bound { bounds }
} else if self.eat(&token::Eq) {
self.parse_assoc_equality_term(ident, self.prev_token.span)?
@@ -620,10 +662,7 @@ impl<'a> Parser<'a> {
c.into()
}
Some(GenericArg::Lifetime(lt)) => {
- self.struct_span_err(span, "associated lifetimes are not supported")
- .span_label(lt.ident.span, "the lifetime is given here")
- .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
- .emit();
+ self.sess.emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span });
self.mk_ty(span, ast::TyKind::Err).into()
}
None => {
@@ -640,14 +679,14 @@ impl<'a> Parser<'a> {
);
err.span_suggestion(
eq.to(before_next),
- &format!("remove the `=` if `{}` is a type", ident),
+ format!("remove the `=` if `{}` is a type", ident),
"",
Applicability::MaybeIncorrect,
)
} else {
err.span_label(
self.token.span,
- &format!("expected type, found {}", super::token_descr(&self.token)),
+ format!("expected type, found {}", super::token_descr(&self.token)),
)
};
return Err(err);