Better message for invalid keyword placement in fn

After this commit, `unsafe async fn ...` now suggests the `async unsafe` fix
instead of misunderstanding the issue.

This is not perfect for repeated keywords (`const async const`) and for
keywords that are misplaced after `extern "some abi"` because of the way
`check_fn_font_matter` works, but changing it breaks so many tests and
diagnostics it has been judged too high a cost for this PR.
This commit is contained in:
Alexis Bourget 2021-08-02 11:10:19 +02:00
parent f381e77d35
commit 690cbb79b3
13 changed files with 184 additions and 4 deletions

View file

@ -1771,8 +1771,14 @@ impl<'a> Parser<'a> {
pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
let sp_start = self.token.span;
let constness = self.parse_constness();
let async_start_sp = self.token.span;
let asyncness = self.parse_asyncness();
let unsafe_start_sp = self.token.span;
let unsafety = self.parse_unsafety();
let ext_start_sp = self.token.span;
let ext = self.parse_extern();
if let Async::Yes { span, .. } = asyncness {
@ -1787,8 +1793,35 @@ impl<'a> Parser<'a> {
Ok(true) => {}
Ok(false) => unreachable!(),
Err(mut err) => {
// Qualifier keywords ordering check
// This will allow the machine fix to directly place the keyword in the correct place
let current_qual_sp = if self.check_keyword(kw::Const) {
Some(async_start_sp)
} else if self.check_keyword(kw::Async) {
Some(unsafe_start_sp)
} else if self.check_keyword(kw::Unsafe) {
Some(ext_start_sp)
} else {
None
};
if let Some(current_qual_sp) = current_qual_sp {
let current_qual_sp = current_qual_sp.to(self.prev_token.span);
if let Ok(current_qual) = self.span_to_snippet(current_qual_sp) {
let invalid_qual_sp = self.token.uninterpolated_span();
let invalid_qual = self.span_to_snippet(invalid_qual_sp).unwrap();
err.span_suggestion(
current_qual_sp.to(invalid_qual_sp),
&format!("`{}` must come before `{}`", invalid_qual, current_qual),
format!("{} {}", invalid_qual, current_qual),
Applicability::MachineApplicable,
).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
}
}
// Recover incorrect visibility order such as `async pub`.
if self.check_keyword(kw::Pub) {
else if self.check_keyword(kw::Pub) {
let sp = sp_start.to(self.prev_token.span);
if let Ok(snippet) = self.span_to_snippet(sp) {
let vis = match self.parse_visibility(FollowedByType::No) {