Skip to content

Commit 235fe83

Browse files
committed
Auto merge of #41282 - arielb1:missing-impl-item, r=petrochenkov
libsyntax/parse: fix missing kind error reporting Fixes #41161. Fixes #41239.
2 parents 5516bcc + d648c10 commit 235fe83

File tree

9 files changed

+191
-81
lines changed

9 files changed

+191
-81
lines changed

src/libsyntax/ext/expand.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -617,14 +617,14 @@ impl<'a> Parser<'a> {
617617
ExpansionKind::TraitItems => {
618618
let mut items = SmallVector::new();
619619
while self.token != token::Eof {
620-
items.push(self.parse_trait_item()?);
620+
items.push(self.parse_trait_item(&mut false)?);
621621
}
622622
Expansion::TraitItems(items)
623623
}
624624
ExpansionKind::ImplItems => {
625625
let mut items = SmallVector::new();
626626
while self.token != token::Eof {
627-
items.push(self.parse_impl_item()?);
627+
items.push(self.parse_impl_item(&mut false)?);
628628
}
629629
Expansion::ImplItems(items)
630630
}

src/libsyntax/parse/parser.rs

+99-68
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,18 @@ pub enum PathStyle {
8585
Expr,
8686
}
8787

88-
#[derive(Clone, Copy, PartialEq)]
88+
#[derive(Clone, Copy, Debug, PartialEq)]
8989
pub enum SemiColonMode {
9090
Break,
9191
Ignore,
9292
}
9393

94+
#[derive(Clone, Copy, Debug, PartialEq)]
95+
pub enum BlockMode {
96+
Break,
97+
Ignore,
98+
}
99+
94100
/// Possibly accept an `token::Interpolated` expression (a pre-parsed expression
95101
/// dropped into the token stream, which happens while parsing the result of
96102
/// macro expansion). Placement of these is not as complex as I feared it would
@@ -1204,7 +1210,7 @@ impl<'a> Parser<'a> {
12041210
}
12051211

12061212
/// Parse the items in a trait declaration
1207-
pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> {
1213+
pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> {
12081214
maybe_whole!(self, NtTraitItem, |x| x);
12091215
let mut attrs = self.parse_outer_attributes()?;
12101216
let lo = self.span;
@@ -1214,7 +1220,7 @@ impl<'a> Parser<'a> {
12141220
self.expect(&token::Semi)?;
12151221
(ident, TraitItemKind::Type(bounds, default))
12161222
} else if self.is_const_item() {
1217-
self.expect_keyword(keywords::Const)?;
1223+
self.expect_keyword(keywords::Const)?;
12181224
let ident = self.parse_ident()?;
12191225
self.expect(&token::Colon)?;
12201226
let ty = self.parse_ty()?;
@@ -1231,9 +1237,17 @@ impl<'a> Parser<'a> {
12311237
} else if self.token.is_path_start() {
12321238
// trait item macro.
12331239
// code copied from parse_macro_use_or_failure... abstraction!
1240+
let prev_span = self.prev_span;
12341241
let lo = self.span;
12351242
let pth = self.parse_path(PathStyle::Mod)?;
1236-
self.expect(&token::Not)?;
1243+
1244+
if pth.segments.len() == 1 {
1245+
if !self.eat(&token::Not) {
1246+
return Err(self.missing_assoc_item_kind_err("trait", prev_span));
1247+
}
1248+
} else {
1249+
self.expect(&token::Not)?;
1250+
}
12371251

12381252
// eat a matched-delimiter token tree:
12391253
let (delim, tts) = self.expect_delimited_token_tree()?;
@@ -1246,25 +1260,7 @@ impl<'a> Parser<'a> {
12461260
} else {
12471261
let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
12481262
Ok(cua) => cua,
1249-
Err(e) => {
1250-
loop {
1251-
match self.token {
1252-
token::Eof => break,
1253-
token::CloseDelim(token::Brace) |
1254-
token::Semi => {
1255-
self.bump();
1256-
break;
1257-
}
1258-
token::OpenDelim(token::Brace) => {
1259-
self.parse_token_tree();
1260-
break;
1261-
}
1262-
_ => self.bump(),
1263-
}
1264-
}
1265-
1266-
return Err(e);
1267-
}
1263+
Err(e) => return Err(e),
12681264
};
12691265

12701266
let ident = self.parse_ident()?;
@@ -1289,11 +1285,13 @@ impl<'a> Parser<'a> {
12891285
let body = match self.token {
12901286
token::Semi => {
12911287
self.bump();
1288+
*at_end = true;
12921289
debug!("parse_trait_methods(): parsing required method");
12931290
None
12941291
}
12951292
token::OpenDelim(token::Brace) => {
12961293
debug!("parse_trait_methods(): parsing provided method");
1294+
*at_end = true;
12971295
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
12981296
attrs.extend(inner_attrs.iter().cloned());
12991297
Some(body)
@@ -1315,18 +1313,6 @@ impl<'a> Parser<'a> {
13151313
})
13161314
}
13171315

1318-
1319-
/// Parse the items in a trait declaration
1320-
pub fn parse_trait_items(&mut self) -> PResult<'a, Vec<TraitItem>> {
1321-
self.parse_unspanned_seq(
1322-
&token::OpenDelim(token::Brace),
1323-
&token::CloseDelim(token::Brace),
1324-
SeqSep::none(),
1325-
|p| -> PResult<'a, TraitItem> {
1326-
p.parse_trait_item()
1327-
})
1328-
}
1329-
13301316
/// Parse optional return type [ -> TY ] in function decl
13311317
pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> {
13321318
if self.eat(&token::RArrow) {
@@ -3641,22 +3627,33 @@ impl<'a> Parser<'a> {
36413627
//
36423628
// We terminate when we find an unmatched `}` (without consuming it).
36433629
fn recover_stmt(&mut self) {
3644-
self.recover_stmt_(SemiColonMode::Ignore)
3630+
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
36453631
}
3632+
36463633
// If `break_on_semi` is `Break`, then we will stop consuming tokens after
36473634
// finding (and consuming) a `;` outside of `{}` or `[]` (note that this is
36483635
// approximate - it can mean we break too early due to macros, but that
36493636
// shoud only lead to sub-optimal recovery, not inaccurate parsing).
3650-
fn recover_stmt_(&mut self, break_on_semi: SemiColonMode) {
3637+
//
3638+
// If `break_on_block` is `Break`, then we will stop consuming tokens
3639+
// after finding (and consuming) a brace-delimited block.
3640+
fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) {
36513641
let mut brace_depth = 0;
36523642
let mut bracket_depth = 0;
3653-
debug!("recover_stmt_ enter loop");
3643+
let mut in_block = false;
3644+
debug!("recover_stmt_ enter loop (semi={:?}, block={:?})",
3645+
break_on_semi, break_on_block);
36543646
loop {
36553647
debug!("recover_stmt_ loop {:?}", self.token);
36563648
match self.token {
36573649
token::OpenDelim(token::DelimToken::Brace) => {
36583650
brace_depth += 1;
36593651
self.bump();
3652+
if break_on_block == BlockMode::Break &&
3653+
brace_depth == 1 &&
3654+
bracket_depth == 0 {
3655+
in_block = true;
3656+
}
36603657
}
36613658
token::OpenDelim(token::DelimToken::Bracket) => {
36623659
bracket_depth += 1;
@@ -3669,6 +3666,10 @@ impl<'a> Parser<'a> {
36693666
}
36703667
brace_depth -= 1;
36713668
self.bump();
3669+
if in_block && bracket_depth == 0 && brace_depth == 0 {
3670+
debug!("recover_stmt_ return - block end {:?}", self.token);
3671+
return;
3672+
}
36723673
}
36733674
token::CloseDelim(token::DelimToken::Bracket) => {
36743675
bracket_depth -= 1;
@@ -3700,7 +3701,7 @@ impl<'a> Parser<'a> {
37003701
fn parse_stmt_(&mut self, macro_legacy_warnings: bool) -> Option<Stmt> {
37013702
self.parse_stmt_without_recovery(macro_legacy_warnings).unwrap_or_else(|mut e| {
37023703
e.emit();
3703-
self.recover_stmt_(SemiColonMode::Break);
3704+
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
37043705
None
37053706
})
37063707
}
@@ -3974,7 +3975,7 @@ impl<'a> Parser<'a> {
39743975
e.span_suggestion(stmt_span, "try placing this code inside a block", sugg);
39753976
}
39763977
Err(mut e) => {
3977-
self.recover_stmt_(SemiColonMode::Break);
3978+
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
39783979
self.cancel(&mut e);
39793980
}
39803981
_ => ()
@@ -4663,7 +4664,7 @@ impl<'a> Parser<'a> {
46634664
}
46644665

46654666
/// Parse an impl item.
4666-
pub fn parse_impl_item(&mut self) -> PResult<'a, ImplItem> {
4667+
pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> {
46674668
maybe_whole!(self, NtImplItem, |x| x);
46684669

46694670
let mut attrs = self.parse_outer_attributes()?;
@@ -4686,7 +4687,7 @@ impl<'a> Parser<'a> {
46864687
self.expect(&token::Semi)?;
46874688
(name, ast::ImplItemKind::Const(typ, expr))
46884689
} else {
4689-
let (name, inner_attrs, node) = self.parse_impl_method(&vis)?;
4690+
let (name, inner_attrs, node) = self.parse_impl_method(&vis, at_end)?;
46904691
attrs.extend(inner_attrs);
46914692
(name, node)
46924693
};
@@ -4731,43 +4732,50 @@ impl<'a> Parser<'a> {
47314732
}
47324733
}
47334734

4735+
fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span)
4736+
-> DiagnosticBuilder<'a>
4737+
{
4738+
// Given this code `path(`, it seems like this is not
4739+
// setting the visibility of a macro invocation, but rather
4740+
// a mistyped method declaration.
4741+
// Create a diagnostic pointing out that `fn` is missing.
4742+
//
4743+
// x | pub path(&self) {
4744+
// | ^ missing `fn`, `type`, or `const`
4745+
// pub path(
4746+
// ^^ `sp` below will point to this
4747+
let sp = prev_span.between(self.prev_span);
4748+
let mut err = self.diagnostic().struct_span_err(
4749+
sp,
4750+
&format!("missing `fn`, `type`, or `const` for {}-item declaration",
4751+
item_type));
4752+
err.span_label(sp, &"missing `fn`, `type`, or `const`");
4753+
err
4754+
}
4755+
47344756
/// Parse a method or a macro invocation in a trait impl.
4735-
fn parse_impl_method(&mut self, vis: &Visibility)
4757+
fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool)
47364758
-> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
47374759
// code copied from parse_macro_use_or_failure... abstraction!
47384760
if self.token.is_path_start() {
47394761
// Method macro.
47404762

47414763
let prev_span = self.prev_span;
4742-
// Before complaining about trying to set a macro as `pub`,
4743-
// check if `!` comes after the path.
4744-
let err = self.complain_if_pub_macro_diag(&vis, prev_span);
47454764

47464765
let lo = self.span;
47474766
let pth = self.parse_path(PathStyle::Mod)?;
4748-
let bang_err = self.expect(&token::Not);
4749-
if let Err(mut err) = err {
4750-
if let Err(mut bang_err) = bang_err {
4751-
// Given this code `pub path(`, it seems like this is not setting the
4752-
// visibility of a macro invocation, but rather a mistyped method declaration.
4753-
// Create a diagnostic pointing out that `fn` is missing.
4754-
//
4755-
// x | pub path(&self) {
4756-
// | ^ missing `fn` for method declaration
4757-
4758-
err.cancel();
4759-
bang_err.cancel();
4760-
// pub path(
4761-
// ^^ `sp` below will point to this
4762-
let sp = prev_span.between(self.prev_span);
4763-
err = self.diagnostic()
4764-
.struct_span_err(sp, "missing `fn` for method declaration");
4765-
err.span_label(sp, &"missing `fn`");
4767+
if pth.segments.len() == 1 {
4768+
if !self.eat(&token::Not) {
4769+
return Err(self.missing_assoc_item_kind_err("impl", prev_span));
47664770
}
4767-
return Err(err);
4771+
} else {
4772+
self.expect(&token::Not)?;
47684773
}
47694774

4775+
self.complain_if_pub_macro(&vis, prev_span);
4776+
47704777
// eat a matched-delimiter token tree:
4778+
*at_end = true;
47714779
let (delim, tts) = self.expect_delimited_token_tree()?;
47724780
if delim != token::Brace {
47734781
self.expect(&token::Semi)?
@@ -4781,6 +4789,7 @@ impl<'a> Parser<'a> {
47814789
let mut generics = self.parse_generics()?;
47824790
let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?;
47834791
generics.where_clause = self.parse_where_clause()?;
4792+
*at_end = true;
47844793
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
47854794
Ok((ident, inner_attrs, ast::ImplItemKind::Method(ast::MethodSig {
47864795
generics: generics,
@@ -4806,8 +4815,21 @@ impl<'a> Parser<'a> {
48064815

48074816
tps.where_clause = self.parse_where_clause()?;
48084817

4809-
let meths = self.parse_trait_items()?;
4810-
Ok((ident, ItemKind::Trait(unsafety, tps, bounds, meths), None))
4818+
self.expect(&token::OpenDelim(token::Brace))?;
4819+
let mut trait_items = vec![];
4820+
while !self.eat(&token::CloseDelim(token::Brace)) {
4821+
let mut at_end = false;
4822+
match self.parse_trait_item(&mut at_end) {
4823+
Ok(item) => trait_items.push(item),
4824+
Err(mut e) => {
4825+
e.emit();
4826+
if !at_end {
4827+
self.recover_stmt_(SemiColonMode::Break, BlockMode::Break);
4828+
}
4829+
}
4830+
}
4831+
}
4832+
Ok((ident, ItemKind::Trait(unsafety, tps, bounds, trait_items), None))
48114833
}
48124834

48134835
/// Parses items implementations variants
@@ -4882,7 +4904,16 @@ impl<'a> Parser<'a> {
48824904

48834905
let mut impl_items = vec![];
48844906
while !self.eat(&token::CloseDelim(token::Brace)) {
4885-
impl_items.push(self.parse_impl_item()?);
4907+
let mut at_end = false;
4908+
match self.parse_impl_item(&mut at_end) {
4909+
Ok(item) => impl_items.push(item),
4910+
Err(mut e) => {
4911+
e.emit();
4912+
if !at_end {
4913+
self.recover_stmt_(SemiColonMode::Break, BlockMode::Break);
4914+
}
4915+
}
4916+
}
48864917
}
48874918

48884919
Ok((keywords::Invalid.ident(),

src/test/parse-fail/issue-21153.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
// compile-flags: -Z parse-only
1212

13-
trait MyTrait<T>: Iterator {
14-
Item = T; //~ ERROR expected one of `!` or `::`, found `=`
15-
//~| ERROR expected item, found `=`
13+
trait MyTrait<T>: Iterator { //~ ERROR missing `fn`, `type`, or `const`
14+
Item = T;
1615
}

src/test/parse-fail/trait-pub-assoc-const.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
trait Foo {
1212
pub const Foo: u32;
13-
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
13+
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub`
1414
}
1515

1616
fn main() {}

src/test/parse-fail/trait-pub-assoc-ty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
trait Foo {
1212
pub type Foo;
13-
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
13+
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub`
1414
}
1515

1616
fn main() {}

src/test/parse-fail/trait-pub-method.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
trait Foo {
1212
pub fn foo();
13-
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
13+
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub`
1414
}
1515

1616
fn main() {}

src/test/ui/did_you_mean/issue-40006.rs

+12
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,20 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
impl X {
12+
Y
13+
}
14+
1115
struct S;
1216

17+
trait X {
18+
X() {}
19+
fn xxx() { ### }
20+
L = M;
21+
Z = { 2 + 3 };
22+
::Y ();
23+
}
24+
1325
impl S {
1426
pub hello_method(&self) {
1527
println!("Hello");

0 commit comments

Comments
 (0)