Restrict From<S> for {D,Subd}iagnosticMessage.

Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.

This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.

As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
This commit is contained in:
Nicholas Nethercote 2023-04-20 13:26:58 +10:00
parent a368898de7
commit 6b62f37402
177 changed files with 791 additions and 787 deletions

View file

@ -207,11 +207,11 @@ struct MultiSugg {
impl MultiSugg {
fn emit(self, err: &mut Diagnostic) {
err.multipart_suggestion(&self.msg, self.patches, self.applicability);
err.multipart_suggestion(self.msg, self.patches, self.applicability);
}
fn emit_verbose(self, err: &mut Diagnostic) {
err.multipart_suggestion_verbose(&self.msg, self.patches, self.applicability);
err.multipart_suggestion_verbose(self.msg, self.patches, self.applicability);
}
}
@ -591,13 +591,13 @@ impl<'a> Parser<'a> {
};
self.last_unexpected_token_span = Some(self.token.span);
// FIXME: translation requires list formatting (for `expect`)
let mut err = self.struct_span_err(self.token.span, &msg_exp);
let mut err = self.struct_span_err(self.token.span, msg_exp);
if let TokenKind::Ident(symbol, _) = &self.prev_token.kind {
if ["def", "fun", "func", "function"].contains(&symbol.as_str()) {
err.span_suggestion_short(
self.prev_token.span,
&format!("write `fn` instead of `{symbol}` to declare a function"),
format!("write `fn` instead of `{symbol}` to declare a function"),
"fn",
Applicability::MachineApplicable,
);
@ -695,13 +695,13 @@ impl<'a> Parser<'a> {
err.set_span(span);
err.span_suggestion(
span,
&format!("remove the extra `#`{}", pluralize!(count)),
format!("remove the extra `#`{}", pluralize!(count)),
"",
Applicability::MachineApplicable,
);
err.span_label(
str_span,
&format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)),
format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)),
);
true
}
@ -1360,12 +1360,12 @@ impl<'a> Parser<'a> {
) -> PResult<'a, P<Expr>> {
let mut err = self.struct_span_err(
op_span,
&format!("Rust has no {} {} operator", kind.fixity, kind.op.name()),
format!("Rust has no {} {} operator", kind.fixity, kind.op.name()),
);
err.span_label(op_span, &format!("not a valid {} operator", kind.fixity));
err.span_label(op_span, format!("not a valid {} operator", kind.fixity));
let help_base_case = |mut err: DiagnosticBuilder<'_, _>, base| {
err.help(&format!("use `{}= 1` instead", kind.op.chr()));
err.help(format!("use `{}= 1` instead", kind.op.chr()));
err.emit();
Ok(base)
};
@ -1554,7 +1554,7 @@ impl<'a> Parser<'a> {
_ => this_token_str,
},
);
let mut err = self.struct_span_err(sp, &msg);
let mut err = self.struct_span_err(sp, msg);
let label_exp = format!("expected `{token_str}`");
let sm = self.sess.source_map();
if !sm.is_multiline(prev_sp.until(sp)) {
@ -1705,7 +1705,7 @@ impl<'a> Parser<'a> {
Applicability::MachineApplicable,
);
}
err.span_suggestion(lo.shrink_to_lo(), &format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable);
err.span_suggestion(lo.shrink_to_lo(), format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable);
err.emit();
Ok(self.mk_expr_err(lo.to(hi)))
} else {
@ -2060,7 +2060,7 @@ impl<'a> Parser<'a> {
format!("expected expression, found {}", super::token_descr(&self.token),),
),
};
let mut err = self.struct_span_err(span, &msg);
let mut err = self.struct_span_err(span, msg);
let sp = self.sess.source_map().start_point(self.token.span);
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
@ -2131,7 +2131,7 @@ impl<'a> Parser<'a> {
// arguments after a comma.
let mut err = self.struct_span_err(
self.token.span,
&format!("expected one of `,` or `>`, found {}", super::token_descr(&self.token)),
format!("expected one of `,` or `>`, found {}", super::token_descr(&self.token)),
);
err.span_label(self.token.span, "expected one of `,` or `>`");
match self.recover_const_arg(arg.span(), err) {
@ -2558,7 +2558,7 @@ impl<'a> Parser<'a> {
let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
err.multipart_suggestion(
&format!(
format!(
"try adding parentheses to match on a tuple{}",
if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
),

View file

@ -855,7 +855,7 @@ impl<'a> Parser<'a> {
_ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
}
);
let mut err = self.struct_span_err(span, &msg);
let mut err = self.struct_span_err(span, msg);
let suggest_parens = |err: &mut Diagnostic| {
let suggestions = vec![
@ -1803,7 +1803,7 @@ impl<'a> Parser<'a> {
let token = self.token.clone();
let err = |self_: &Self| {
let msg = format!("unexpected token: {}", super::token_descr(&token));
self_.struct_span_err(token.span, &msg)
self_.struct_span_err(token.span, msg)
};
// On an error path, eagerly consider a lifetime to be an unclosed character lit
if self.token.is_lifetime() {

View file

@ -71,7 +71,7 @@ impl<'a> Parser<'a> {
if !self.eat(term) {
let token_str = super::token_descr(&self.token);
if !self.maybe_consume_incorrect_semicolon(&items) {
let msg = &format!("expected item, found {token_str}");
let msg = format!("expected item, found {token_str}");
let mut err = self.struct_span_err(self.token.span, msg);
let label = if self.is_kw_followed_by_ident(kw::Let) {
"consider using `const` or `static` instead of `let` for global variables"
@ -1429,7 +1429,7 @@ impl<'a> Parser<'a> {
VariantData::Struct(fields, recovered)
} else {
let token_str = super::token_descr(&self.token);
let msg = &format!("expected `where` or `{{` after union name, found {token_str}");
let msg = format!("expected `where` or `{{` after union name, found {token_str}");
let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, "expected `where` or `{` after union name");
return Err(err);
@ -1465,7 +1465,7 @@ impl<'a> Parser<'a> {
self.eat(&token::CloseDelim(Delimiter::Brace));
} else {
let token_str = super::token_descr(&self.token);
let msg = &format!(
let msg = format!(
"expected {}`{{` after struct name, found {}",
if parsed_where { "" } else { "`where`, or " },
token_str
@ -1602,7 +1602,7 @@ impl<'a> Parser<'a> {
let sp = self.prev_token.span.shrink_to_hi();
let mut err = self.struct_span_err(
sp,
&format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
);
// Try to recover extra trailing angle brackets
@ -1740,7 +1740,7 @@ impl<'a> Parser<'a> {
Ok(_) => {
let mut err = self.struct_span_err(
lo.to(self.prev_token.span),
&format!("functions are not allowed in {adt_ty} definitions"),
format!("functions are not allowed in {adt_ty} definitions"),
);
err.help(
"unlike in C++, Java, and C#, functions are declared in `impl` blocks",
@ -1759,7 +1759,7 @@ impl<'a> Parser<'a> {
Ok((ident, _)) => {
let mut err = self.struct_span_err(
lo.with_hi(ident.span.hi()),
&format!("structs are not allowed in {adt_ty} definitions"),
format!("structs are not allowed in {adt_ty} definitions"),
);
err.help("consider creating a new `struct` definition instead of nesting");
err
@ -2228,11 +2228,11 @@ impl<'a> Parser<'a> {
err.span_suggestion(
self.token.uninterpolated_span(),
&format!("`{original_kw}` already used earlier, remove this one"),
format!("`{original_kw}` already used earlier, remove this one"),
"",
Applicability::MachineApplicable,
)
.span_note(original_sp, &format!("`{original_kw}` first seen here"));
.span_note(original_sp, format!("`{original_kw}` first seen here"));
}
// The keyword has not been seen yet, suggest correct placement in the function front matter
else if let Some(WrongKw::Misplaced(correct_pos_sp)) = wrong_kw {
@ -2243,7 +2243,7 @@ impl<'a> Parser<'a> {
err.span_suggestion(
correct_pos_sp.to(misplaced_qual_sp),
&format!("`{misplaced_qual}` must come before `{current_qual}`"),
format!("`{misplaced_qual}` must come before `{current_qual}`"),
format!("{misplaced_qual} {current_qual}"),
Applicability::MachineApplicable,
).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
@ -2267,7 +2267,7 @@ impl<'a> Parser<'a> {
if matches!(orig_vis.kind, VisibilityKind::Inherited) {
err.span_suggestion(
sp_start.to(self.prev_token.span),
&format!("visibility `{vs}` must come before `{snippet}`"),
format!("visibility `{vs}` must come before `{snippet}`"),
format!("{vs} {snippet}"),
Applicability::MachineApplicable,
);

View file

@ -905,7 +905,7 @@ impl<'a> Parser<'a> {
expect_err
.span_suggestion_verbose(
self.prev_token.span.shrink_to_hi().until(self.token.span),
&msg,
msg,
" @ ",
Applicability::MaybeIncorrect,
)
@ -921,7 +921,7 @@ impl<'a> Parser<'a> {
expect_err
.span_suggestion_short(
sp,
&format!("missing `{}`", token_str),
format!("missing `{}`", token_str),
token_str,
Applicability::MaybeIncorrect,
)

View file

@ -444,7 +444,7 @@ impl<'a> Parser<'a> {
super::token_descr(&self_.token)
);
let mut err = self_.struct_span_err(self_.token.span, &msg);
let mut err = self_.struct_span_err(self_.token.span, msg);
err.span_label(self_.token.span, format!("expected {}", expected));
err
});
@ -680,7 +680,7 @@ impl<'a> Parser<'a> {
let expected = Expected::to_string_or_fallback(expected);
let msg = format!("expected {}, found {}", expected, super::token_descr(&self.token));
let mut err = self.struct_span_err(self.token.span, &msg);
let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, format!("expected {}", expected));
let sp = self.sess.source_map().start_point(self.token.span);
@ -978,7 +978,7 @@ impl<'a> Parser<'a> {
break;
}
let token_str = super::token_descr(&self.token);
let msg = &format!("expected `}}`, found {}", token_str);
let msg = format!("expected `}}`, found {}", token_str);
let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, "expected `}`");

View file

@ -679,14 +679,14 @@ impl<'a> Parser<'a> {
);
err.span_suggestion(
eq.to(before_next),
&format!("remove the `=` if `{}` is a type", ident),
format!("remove the `=` if `{}` is a type", ident),
"",
Applicability::MaybeIncorrect,
)
} else {
err.span_label(
self.token.span,
&format!("expected type, found {}", super::token_descr(&self.token)),
format!("expected type, found {}", super::token_descr(&self.token)),
)
};
return Err(err);

View file

@ -634,7 +634,7 @@ impl<'a> Parser<'a> {
e.span_suggestion(
sp.with_hi(sp.lo() + BytePos(marker.len() as u32)),
&format!(
format!(
"add a space before `{}` to use a regular comment",
doc_comment_marker,
),

View file

@ -315,7 +315,7 @@ impl<'a> Parser<'a> {
}
} else {
let msg = format!("expected type, found {}", super::token_descr(&self.token));
let mut err = self.struct_span_err(self.token.span, &msg);
let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, "expected type");
return Err(err);
};