Skip to content

Commit c6eda7d

Browse files
committed
Auto merge of #85346 - estebank:issue-84946, r=nagisa,varkor
Account for incorrect `impl Foo<const N: ty> {}` syntax Fix #84946
2 parents d2c24aa + 505b09e commit c6eda7d

File tree

10 files changed

+239
-64
lines changed

10 files changed

+239
-64
lines changed

compiler/rustc_ast/src/ast.rs

+15
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,21 @@ pub struct GenericParam {
405405
pub kind: GenericParamKind,
406406
}
407407

408+
impl GenericParam {
409+
pub fn span(&self) -> Span {
410+
match &self.kind {
411+
GenericParamKind::Lifetime | GenericParamKind::Type { default: None } => {
412+
self.ident.span
413+
}
414+
GenericParamKind::Type { default: Some(ty) } => self.ident.span.to(ty.span),
415+
GenericParamKind::Const { kw_span, default: Some(default), .. } => {
416+
kw_span.to(default.value.span)
417+
}
418+
GenericParamKind::Const { kw_span, default: None, ty } => kw_span.to(ty.span),
419+
}
420+
}
421+
}
422+
408423
/// Represents lifetime, type and const parameters attached to a declaration of
409424
/// a function, enum, trait, etc.
410425
#[derive(Clone, Encodable, Decodable, Debug)]

compiler/rustc_parse/src/parser/diagnostics.rs

+73-6
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ use rustc_ast as ast;
66
use rustc_ast::ptr::P;
77
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
88
use rustc_ast::util::parser::AssocOp;
9-
use rustc_ast::{AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec};
10-
use rustc_ast::{BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item};
11-
use rustc_ast::{ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty, TyKind};
9+
use rustc_ast::{
10+
AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
11+
BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Mutability, Param, Pat,
12+
PatKind, Path, PathSegment, QSelf, Ty, TyKind,
13+
};
1214
use rustc_ast_pretty::pprust;
1315
use rustc_data_structures::fx::FxHashSet;
1416
use rustc_errors::{pluralize, struct_span_err};
@@ -662,7 +664,7 @@ impl<'a> Parser<'a> {
662664
let snapshot = self.clone();
663665
self.bump();
664666
let lo = self.token.span;
665-
match self.parse_angle_args() {
667+
match self.parse_angle_args(None) {
666668
Ok(args) => {
667669
let span = lo.to(self.prev_token.span);
668670
// Detect trailing `>` like in `x.collect::Vec<_>>()`.
@@ -719,7 +721,7 @@ impl<'a> Parser<'a> {
719721
let x = self.parse_seq_to_before_end(
720722
&token::Gt,
721723
SeqSep::trailing_allowed(token::Comma),
722-
|p| p.parse_generic_arg(),
724+
|p| p.parse_generic_arg(None),
723725
);
724726
match x {
725727
Ok((_, _, false)) => {
@@ -1103,7 +1105,7 @@ impl<'a> Parser<'a> {
11031105
self.expect(&token::ModSep)?;
11041106

11051107
let mut path = ast::Path { segments: Vec::new(), span: DUMMY_SP, tokens: None };
1106-
self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
1108+
self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None)?;
11071109
path.span = ty_span.to(self.prev_token.span);
11081110

11091111
let ty_str = self.span_to_snippet(ty_span).unwrap_or_else(|_| pprust::ty_to_string(&ty));
@@ -1909,6 +1911,71 @@ impl<'a> Parser<'a> {
19091911
Ok(expr)
19101912
}
19111913

1914+
fn recover_const_param_decl(
1915+
&mut self,
1916+
ty_generics: Option<&Generics>,
1917+
) -> PResult<'a, Option<GenericArg>> {
1918+
let snapshot = self.clone();
1919+
let param = match self.parse_const_param(vec![]) {
1920+
Ok(param) => param,
1921+
Err(mut err) => {
1922+
err.cancel();
1923+
*self = snapshot;
1924+
return Err(err);
1925+
}
1926+
};
1927+
let mut err =
1928+
self.struct_span_err(param.span(), "unexpected `const` parameter declaration");
1929+
err.span_label(param.span(), "expected a `const` expression, not a parameter declaration");
1930+
if let (Some(generics), Ok(snippet)) =
1931+
(ty_generics, self.sess.source_map().span_to_snippet(param.span()))
1932+
{
1933+
let (span, sugg) = match &generics.params[..] {
1934+
[] => (generics.span, format!("<{}>", snippet)),
1935+
[.., generic] => (generic.span().shrink_to_hi(), format!(", {}", snippet)),
1936+
};
1937+
err.multipart_suggestion(
1938+
"`const` parameters must be declared for the `impl`",
1939+
vec![(span, sugg), (param.span(), param.ident.to_string())],
1940+
Applicability::MachineApplicable,
1941+
);
1942+
}
1943+
let value = self.mk_expr_err(param.span());
1944+
err.emit();
1945+
return Ok(Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })));
1946+
}
1947+
1948+
pub fn recover_const_param_declaration(
1949+
&mut self,
1950+
ty_generics: Option<&Generics>,
1951+
) -> PResult<'a, Option<GenericArg>> {
1952+
// We have to check for a few different cases.
1953+
if let Ok(arg) = self.recover_const_param_decl(ty_generics) {
1954+
return Ok(arg);
1955+
}
1956+
1957+
// We haven't consumed `const` yet.
1958+
let start = self.token.span;
1959+
self.bump(); // `const`
1960+
1961+
// Detect and recover from the old, pre-RFC2000 syntax for const generics.
1962+
let mut err = self
1963+
.struct_span_err(start, "expected lifetime, type, or constant, found keyword `const`");
1964+
if self.check_const_arg() {
1965+
err.span_suggestion_verbose(
1966+
start.until(self.token.span),
1967+
"the `const` keyword is only needed in the definition of the type",
1968+
String::new(),
1969+
Applicability::MaybeIncorrect,
1970+
);
1971+
err.emit();
1972+
Ok(Some(GenericArg::Const(self.parse_const_arg()?)))
1973+
} else {
1974+
let after_kw_const = self.token.span;
1975+
self.recover_const_arg(after_kw_const, err).map(Some)
1976+
}
1977+
}
1978+
19121979
/// Try to recover from possible generic const argument without `{` and `}`.
19131980
///
19141981
/// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest

compiler/rustc_parse/src/parser/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1150,7 +1150,7 @@ impl<'a> Parser<'a> {
11501150
}
11511151

11521152
let fn_span_lo = self.token.span;
1153-
let mut segment = self.parse_path_segment(PathStyle::Expr)?;
1153+
let mut segment = self.parse_path_segment(PathStyle::Expr, None)?;
11541154
self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]);
11551155
self.check_turbofish_missing_angle_brackets(&mut segment);
11561156

compiler/rustc_parse/src/parser/generics.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ impl<'a> Parser<'a> {
4848
})
4949
}
5050

51-
fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, GenericParam> {
51+
crate fn parse_const_param(
52+
&mut self,
53+
preceding_attrs: Vec<Attribute>,
54+
) -> PResult<'a, GenericParam> {
5255
let const_span = self.token.span;
5356

5457
self.expect_keyword(kw::Const)?;

compiler/rustc_parse/src/parser/item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ impl<'a> Parser<'a> {
514514
tokens: None,
515515
})
516516
} else {
517-
self.parse_ty()?
517+
self.parse_ty_with_generics_recovery(&generics)?
518518
};
519519

520520
// If `for` is missing we try to recover.

compiler/rustc_parse/src/parser/path.rs

+49-39
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ use super::{Parser, TokenType};
33
use crate::maybe_whole;
44
use rustc_ast::ptr::P;
55
use rustc_ast::token::{self, Token};
6-
use rustc_ast::{self as ast, AngleBracketedArg, AngleBracketedArgs, ParenthesizedArgs};
7-
use rustc_ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
8-
use rustc_ast::{GenericArg, GenericArgs};
9-
use rustc_ast::{Path, PathSegment, QSelf};
6+
use rustc_ast::{
7+
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocTyConstraint,
8+
AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
9+
Path, PathSegment, QSelf,
10+
};
1011
use rustc_errors::{pluralize, Applicability, PResult};
1112
use rustc_span::source_map::{BytePos, Span};
1213
use rustc_span::symbol::{kw, sym, Ident};
@@ -78,7 +79,7 @@ impl<'a> Parser<'a> {
7879
}
7980

8081
let qself = QSelf { ty, path_span, position: path.segments.len() };
81-
self.parse_path_segments(&mut path.segments, style)?;
82+
self.parse_path_segments(&mut path.segments, style, None)?;
8283

8384
Ok((
8485
qself,
@@ -119,6 +120,10 @@ impl<'a> Parser<'a> {
119120
true
120121
}
121122

123+
pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
124+
self.parse_path_inner(style, None)
125+
}
126+
122127
/// Parses simple paths.
123128
///
124129
/// `path = [::] segment+`
@@ -129,7 +134,11 @@ impl<'a> Parser<'a> {
129134
/// `a::b::C::<D>` (with disambiguator)
130135
/// `Fn(Args)` (without disambiguator)
131136
/// `Fn::(Args)` (with disambiguator)
132-
pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
137+
pub(super) fn parse_path_inner(
138+
&mut self,
139+
style: PathStyle,
140+
ty_generics: Option<&Generics>,
141+
) -> PResult<'a, Path> {
133142
maybe_whole!(self, NtPath, |path| {
134143
if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
135144
{
@@ -152,7 +161,7 @@ impl<'a> Parser<'a> {
152161
if self.eat(&token::ModSep) {
153162
segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
154163
}
155-
self.parse_path_segments(&mut segments, style)?;
164+
self.parse_path_segments(&mut segments, style, ty_generics)?;
156165

157166
Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None })
158167
}
@@ -161,9 +170,10 @@ impl<'a> Parser<'a> {
161170
&mut self,
162171
segments: &mut Vec<PathSegment>,
163172
style: PathStyle,
173+
ty_generics: Option<&Generics>,
164174
) -> PResult<'a, ()> {
165175
loop {
166-
let segment = self.parse_path_segment(style)?;
176+
let segment = self.parse_path_segment(style, ty_generics)?;
167177
if style == PathStyle::Expr {
168178
// In order to check for trailing angle brackets, we must have finished
169179
// recursing (`parse_path_segment` can indirectly call this function),
@@ -191,7 +201,11 @@ impl<'a> Parser<'a> {
191201
}
192202
}
193203

194-
pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
204+
pub(super) fn parse_path_segment(
205+
&mut self,
206+
style: PathStyle,
207+
ty_generics: Option<&Generics>,
208+
) -> PResult<'a, PathSegment> {
195209
let ident = self.parse_path_segment_ident()?;
196210
let is_args_start = |token: &Token| {
197211
matches!(
@@ -229,18 +243,21 @@ impl<'a> Parser<'a> {
229243
let lo = self.token.span;
230244
let args = if self.eat_lt() {
231245
// `<'a, T, A = U>`
232-
let args =
233-
self.parse_angle_args_with_leading_angle_bracket_recovery(style, lo)?;
246+
let args = self.parse_angle_args_with_leading_angle_bracket_recovery(
247+
style,
248+
lo,
249+
ty_generics,
250+
)?;
234251
self.expect_gt()?;
235252
let span = lo.to(self.prev_token.span);
236253
AngleBracketedArgs { args, span }.into()
237254
} else {
238255
// `(T, U) -> R`
239256
let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
240257
let inputs_span = lo.to(self.prev_token.span);
241-
let span = ident.span.to(self.prev_token.span);
242258
let output =
243259
self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?;
260+
let span = ident.span.to(self.prev_token.span);
244261
ParenthesizedArgs { span, inputs, inputs_span, output }.into()
245262
};
246263

@@ -275,6 +292,7 @@ impl<'a> Parser<'a> {
275292
&mut self,
276293
style: PathStyle,
277294
lo: Span,
295+
ty_generics: Option<&Generics>,
278296
) -> PResult<'a, Vec<AngleBracketedArg>> {
279297
// We need to detect whether there are extra leading left angle brackets and produce an
280298
// appropriate error and suggestion. This cannot be implemented by looking ahead at
@@ -350,7 +368,7 @@ impl<'a> Parser<'a> {
350368
let snapshot = if is_first_invocation { Some(self.clone()) } else { None };
351369

352370
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
353-
match self.parse_angle_args() {
371+
match self.parse_angle_args(ty_generics) {
354372
Ok(args) => Ok(args),
355373
Err(mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
356374
// Swap `self` with our backup of the parser state before attempting to parse
@@ -403,7 +421,7 @@ impl<'a> Parser<'a> {
403421
.emit();
404422

405423
// Try again without unmatched angle bracket characters.
406-
self.parse_angle_args()
424+
self.parse_angle_args(ty_generics)
407425
}
408426
}
409427
Err(e) => Err(e),
@@ -412,9 +430,12 @@ impl<'a> Parser<'a> {
412430

413431
/// Parses (possibly empty) list of generic arguments / associated item constraints,
414432
/// possibly including trailing comma.
415-
pub(super) fn parse_angle_args(&mut self) -> PResult<'a, Vec<AngleBracketedArg>> {
433+
pub(super) fn parse_angle_args(
434+
&mut self,
435+
ty_generics: Option<&Generics>,
436+
) -> PResult<'a, Vec<AngleBracketedArg>> {
416437
let mut args = Vec::new();
417-
while let Some(arg) = self.parse_angle_arg()? {
438+
while let Some(arg) = self.parse_angle_arg(ty_generics)? {
418439
args.push(arg);
419440
if !self.eat(&token::Comma) {
420441
if !self.token.kind.should_end_const_arg() {
@@ -431,9 +452,12 @@ impl<'a> Parser<'a> {
431452
}
432453

433454
/// Parses a single argument in the angle arguments `<...>` of a path segment.
434-
fn parse_angle_arg(&mut self) -> PResult<'a, Option<AngleBracketedArg>> {
455+
fn parse_angle_arg(
456+
&mut self,
457+
ty_generics: Option<&Generics>,
458+
) -> PResult<'a, Option<AngleBracketedArg>> {
435459
let lo = self.token.span;
436-
let arg = self.parse_generic_arg()?;
460+
let arg = self.parse_generic_arg(ty_generics)?;
437461
match arg {
438462
Some(arg) => {
439463
if self.check(&token::Colon) | self.check(&token::Eq) {
@@ -476,7 +500,7 @@ impl<'a> Parser<'a> {
476500
/// That is, parse `<term>` in `Item = <term>`.
477501
/// Right now, this only admits types in `<term>`.
478502
fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
479-
let arg = self.parse_generic_arg()?;
503+
let arg = self.parse_generic_arg(None)?;
480504
let span = ident.span.to(self.prev_token.span);
481505
match arg {
482506
Some(GenericArg::Type(ty)) => return Ok(ty),
@@ -563,7 +587,10 @@ impl<'a> Parser<'a> {
563587

564588
/// Parse a generic argument in a path segment.
565589
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
566-
pub(super) fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
590+
pub(super) fn parse_generic_arg(
591+
&mut self,
592+
ty_generics: Option<&Generics>,
593+
) -> PResult<'a, Option<GenericArg>> {
567594
let start = self.token.span;
568595
let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
569596
// Parse lifetime argument.
@@ -580,25 +607,8 @@ impl<'a> Parser<'a> {
580607
return self.recover_const_arg(start, err).map(Some);
581608
}
582609
}
583-
} else if self.eat_keyword_noexpect(kw::Const) {
584-
// Detect and recover from the old, pre-RFC2000 syntax for const generics.
585-
let mut err = self.struct_span_err(
586-
start,
587-
"expected lifetime, type, or constant, found keyword `const`",
588-
);
589-
if self.check_const_arg() {
590-
err.span_suggestion_verbose(
591-
start.until(self.token.span),
592-
"the `const` keyword is only needed in the definition of the type",
593-
String::new(),
594-
Applicability::MaybeIncorrect,
595-
);
596-
err.emit();
597-
GenericArg::Const(self.parse_const_arg()?)
598-
} else {
599-
let after_kw_const = self.token.span;
600-
return self.recover_const_arg(after_kw_const, err).map(Some);
601-
}
610+
} else if self.token.is_keyword(kw::Const) {
611+
return self.recover_const_param_declaration(ty_generics);
602612
} else {
603613
return Ok(None);
604614
};

0 commit comments

Comments
 (0)