Skip to content

Commit 511dfdb

Browse files
committed
parser: extract recover_missing_kw_before_item
1 parent 7737d0f commit 511dfdb

File tree

1 file changed

+90
-84
lines changed

1 file changed

+90
-84
lines changed

src/librustc_parse/parser/item.rs

Lines changed: 90 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -203,101 +203,107 @@ impl<'a> Parser<'a> {
203203
return Ok(Some(macro_def));
204204
}
205205

206-
// Verify whether we have encountered a struct or method definition where the user forgot to
207-
// add the `struct` or `fn` keyword after writing `pub`: `pub S {}`
208206
if vis.node.is_pub() && self.check_ident() && self.look_ahead(1, |t| *t != token::Not) {
209-
// Space between `pub` keyword and the identifier
210-
//
211-
// pub S {}
212-
// ^^^ `sp` points here
213-
let sp = self.prev_span.between(self.token.span);
214-
let full_sp = self.prev_span.to(self.token.span);
215-
let ident_sp = self.token.span;
216-
if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) {
217-
// possible public struct definition where `struct` was forgotten
218-
let ident = self.parse_ident().unwrap();
219-
let msg = format!("add `struct` here to parse `{}` as a public struct", ident);
220-
let mut err = self.struct_span_err(sp, "missing `struct` for struct definition");
207+
self.recover_missing_kw_before_item()?;
208+
}
209+
self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis)
210+
}
211+
212+
/// Recover on encountering a struct or method definition where the user
213+
/// forgot to add the `struct` or `fn` keyword after writing `pub`: `pub S {}`.
214+
fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> {
215+
// Space between `pub` keyword and the identifier
216+
//
217+
// pub S {}
218+
// ^^^ `sp` points here
219+
let sp = self.prev_span.between(self.token.span);
220+
let full_sp = self.prev_span.to(self.token.span);
221+
let ident_sp = self.token.span;
222+
if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) {
223+
// possible public struct definition where `struct` was forgotten
224+
let ident = self.parse_ident().unwrap();
225+
let msg = format!("add `struct` here to parse `{}` as a public struct", ident);
226+
let mut err = self.struct_span_err(sp, "missing `struct` for struct definition");
227+
err.span_suggestion_short(
228+
sp,
229+
&msg,
230+
" struct ".into(),
231+
Applicability::MaybeIncorrect, // speculative
232+
);
233+
return Err(err);
234+
} else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
235+
let ident = self.parse_ident().unwrap();
236+
self.bump(); // `(`
237+
let kw_name = self.recover_first_param();
238+
self.consume_block(token::Paren, ConsumeClosingDelim::Yes);
239+
let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) {
240+
self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]);
241+
self.bump(); // `{`
242+
("fn", kw_name, false)
243+
} else if self.check(&token::OpenDelim(token::Brace)) {
244+
self.bump(); // `{`
245+
("fn", kw_name, false)
246+
} else if self.check(&token::Colon) {
247+
let kw = "struct";
248+
(kw, kw, false)
249+
} else {
250+
("fn` or `struct", "function or struct", true)
251+
};
252+
253+
let msg = format!("missing `{}` for {} definition", kw, kw_name);
254+
let mut err = self.struct_span_err(sp, &msg);
255+
if !ambiguous {
256+
self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
257+
let suggestion =
258+
format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name);
221259
err.span_suggestion_short(
222260
sp,
223-
&msg,
224-
" struct ".into(),
225-
Applicability::MaybeIncorrect, // speculative
261+
&suggestion,
262+
format!(" {} ", kw),
263+
Applicability::MachineApplicable,
226264
);
227-
return Err(err);
228-
} else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
229-
let ident = self.parse_ident().unwrap();
230-
self.bump(); // `(`
231-
let kw_name = self.recover_first_param();
232-
self.consume_block(token::Paren, ConsumeClosingDelim::Yes);
233-
let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) {
234-
self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]);
235-
self.bump(); // `{`
236-
("fn", kw_name, false)
237-
} else if self.check(&token::OpenDelim(token::Brace)) {
238-
self.bump(); // `{`
239-
("fn", kw_name, false)
240-
} else if self.check(&token::Colon) {
241-
let kw = "struct";
242-
(kw, kw, false)
243-
} else {
244-
("fn` or `struct", "function or struct", true)
245-
};
246-
247-
let msg = format!("missing `{}` for {} definition", kw, kw_name);
248-
let mut err = self.struct_span_err(sp, &msg);
249-
if !ambiguous {
250-
self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
251-
let suggestion =
252-
format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name);
253-
err.span_suggestion_short(
254-
sp,
255-
&suggestion,
256-
format!(" {} ", kw),
257-
Applicability::MachineApplicable,
265+
} else {
266+
if let Ok(snippet) = self.span_to_snippet(ident_sp) {
267+
err.span_suggestion(
268+
full_sp,
269+
"if you meant to call a macro, try",
270+
format!("{}!", snippet),
271+
// this is the `ambiguous` conditional branch
272+
Applicability::MaybeIncorrect,
258273
);
259274
} else {
260-
if let Ok(snippet) = self.span_to_snippet(ident_sp) {
261-
err.span_suggestion(
262-
full_sp,
263-
"if you meant to call a macro, try",
264-
format!("{}!", snippet),
265-
// this is the `ambiguous` conditional branch
266-
Applicability::MaybeIncorrect,
267-
);
268-
} else {
269-
err.help(
270-
"if you meant to call a macro, remove the `pub` \
275+
err.help(
276+
"if you meant to call a macro, remove the `pub` \
271277
and add a trailing `!` after the identifier",
272-
);
273-
}
274-
}
275-
return Err(err);
276-
} else if self.look_ahead(1, |t| *t == token::Lt) {
277-
let ident = self.parse_ident().unwrap();
278-
self.eat_to_tokens(&[&token::Gt]);
279-
self.bump(); // `>`
280-
let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) {
281-
("fn", self.recover_first_param(), false)
282-
} else if self.check(&token::OpenDelim(token::Brace)) {
283-
("struct", "struct", false)
284-
} else {
285-
("fn` or `struct", "function or struct", true)
286-
};
287-
let msg = format!("missing `{}` for {} definition", kw, kw_name);
288-
let mut err = self.struct_span_err(sp, &msg);
289-
if !ambiguous {
290-
err.span_suggestion_short(
291-
sp,
292-
&format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name),
293-
format!(" {} ", kw),
294-
Applicability::MachineApplicable,
295278
);
296279
}
297-
return Err(err);
298280
}
281+
return Err(err);
282+
} else if self.look_ahead(1, |t| *t == token::Lt) {
283+
let ident = self.parse_ident().unwrap();
284+
self.eat_to_tokens(&[&token::Gt]);
285+
self.bump(); // `>`
286+
let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) {
287+
("fn", self.recover_first_param(), false)
288+
} else if self.check(&token::OpenDelim(token::Brace)) {
289+
("struct", "struct", false)
290+
} else {
291+
("fn` or `struct", "function or struct", true)
292+
};
293+
let msg = format!("missing `{}` for {} definition", kw, kw_name);
294+
let mut err = self.struct_span_err(sp, &msg);
295+
if !ambiguous {
296+
err.span_suggestion_short(
297+
sp,
298+
&format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name),
299+
format!(" {} ", kw),
300+
Applicability::MachineApplicable,
301+
);
302+
}
303+
return Err(err);
304+
} else {
305+
Ok(())
299306
}
300-
self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis)
301307
}
302308

303309
pub(super) fn mk_item_with_info(

0 commit comments

Comments
 (0)