summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_parse/src/parser/ty.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /compiler/rustc_parse/src/parser/ty.rs
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_parse/src/parser/ty.rs')
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs69
1 files changed, 61 insertions, 8 deletions
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 2a8512acf..b7206b576 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -1,9 +1,11 @@
use super::{Parser, PathStyle, TokenType};
+use crate::errors::{FnPtrWithGenerics, FnPtrWithGenericsSugg};
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
+use rustc_ast::util::case::Case;
use rustc_ast::{
self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
@@ -267,16 +269,21 @@ impl<'a> Parser<'a> {
} else if self.eat_keyword(kw::Underscore) {
// A type to be inferred `_`
TyKind::Infer
- } else if self.check_fn_front_matter(false) {
+ } else if self.check_fn_front_matter(false, Case::Sensitive) {
// Function pointer type
- self.parse_ty_bare_fn(lo, Vec::new(), recover_return_sign)?
+ self.parse_ty_bare_fn(lo, Vec::new(), None, recover_return_sign)?
} else if self.check_keyword(kw::For) {
// Function pointer type or bound list (trait object type) starting with a poly-trait.
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
- if self.check_fn_front_matter(false) {
- self.parse_ty_bare_fn(lo, lifetime_defs, recover_return_sign)?
+ if self.check_fn_front_matter(false, Case::Sensitive) {
+ self.parse_ty_bare_fn(
+ lo,
+ lifetime_defs,
+ Some(self.prev_token.span.shrink_to_lo()),
+ recover_return_sign,
+ )?
} else {
let path = self.parse_path(PathStyle::Type)?;
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
@@ -401,7 +408,7 @@ impl<'a> Parser<'a> {
.span_suggestions(
span.shrink_to_hi(),
"add `mut` or `const` here",
- ["mut ".to_string(), "const ".to_string()].into_iter(),
+ ["mut ".to_string(), "const ".to_string()],
Applicability::HasPlaceholders,
)
.emit();
@@ -518,7 +525,8 @@ impl<'a> Parser<'a> {
fn parse_ty_bare_fn(
&mut self,
lo: Span,
- params: Vec<GenericParam>,
+ mut params: Vec<GenericParam>,
+ param_insertion_point: Option<Span>,
recover_return_sign: RecoverReturnSign,
) -> PResult<'a, TyKind> {
let inherited_vis = rustc_ast::Visibility {
@@ -528,7 +536,10 @@ impl<'a> Parser<'a> {
};
let span_start = self.token.span;
let ast::FnHeader { ext, unsafety, constness, asyncness } =
- self.parse_fn_front_matter(&inherited_vis)?;
+ self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?;
+ if self.may_recover() && self.token.kind == TokenKind::Lt {
+ self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;
+ }
let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
let whole_span = lo.to(self.prev_token.span);
if let ast::Const::Yes(span) = constness {
@@ -544,6 +555,48 @@ impl<'a> Parser<'a> {
Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl, decl_span })))
}
+ /// Recover from function pointer types with a generic parameter list (e.g. `fn<'a>(&'a str)`).
+ fn recover_fn_ptr_with_generics(
+ &mut self,
+ lo: Span,
+ params: &mut Vec<GenericParam>,
+ param_insertion_point: Option<Span>,
+ ) -> PResult<'a, ()> {
+ let generics = self.parse_generics()?;
+ let arity = generics.params.len();
+
+ let mut lifetimes: Vec<_> = generics
+ .params
+ .into_iter()
+ .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime))
+ .collect();
+
+ let sugg = if !lifetimes.is_empty() {
+ let snippet =
+ lifetimes.iter().map(|param| param.ident.as_str()).intersperse(", ").collect();
+
+ let (left, snippet) = if let Some(span) = param_insertion_point {
+ (span, if params.is_empty() { snippet } else { format!(", {snippet}") })
+ } else {
+ (lo.shrink_to_lo(), format!("for<{snippet}> "))
+ };
+
+ Some(FnPtrWithGenericsSugg {
+ left,
+ snippet,
+ right: generics.span,
+ arity,
+ for_param_list_exists: param_insertion_point.is_some(),
+ })
+ } else {
+ None
+ };
+
+ self.sess.emit_err(FnPtrWithGenerics { span: generics.span, sugg });
+ params.append(&mut lifetimes);
+ Ok(())
+ }
+
/// Emit an error for the given bad function pointer qualifier.
fn error_fn_ptr_bad_qualifier(&self, span: Span, qual_span: Span, qual: &str) {
self.struct_span_err(span, &format!("an `fn` pointer type cannot be `{}`", qual))
@@ -612,7 +665,7 @@ impl<'a> Parser<'a> {
// Macro invocation in type position
Ok(TyKind::MacCall(P(MacCall {
path,
- args: self.parse_mac_args()?,
+ args: self.parse_delim_args()?,
prior_type_ascription: self.last_type_ascription,
})))
} else if allow_plus == AllowPlus::Yes && self.check_plus() {