Improve diagnostics for const a: = expr;

This commit is contained in:
Maybe Waffle
2022-08-05 15:41:42 +04:00
parent 1f5d8d49eb
commit 743ad07c4b
16 changed files with 109 additions and 66 deletions

View File

@@ -1179,10 +1179,11 @@ impl<'a> Parser<'a> {
// Parse the type of a `const` or `static mut?` item.
// That is, the `":" $ty` fragment.
let ty = if self.eat(&token::Colon) {
self.parse_ty()?
} else {
self.recover_missing_const_type(id, m)
let ty = match (self.eat(&token::Colon), self.check(&token::Eq) | self.check(&token::Semi))
{
// If there wasn't a `:` or the colon was followed by a `=` or `;` recover a missing type.
(true, false) => self.parse_ty()?,
(colon, _) => self.recover_missing_const_type(colon, m),
};
let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
@@ -1190,9 +1191,9 @@ impl<'a> Parser<'a> {
Ok((id, ty, expr))
}
/// We were supposed to parse `:` but the `:` was missing.
/// We were supposed to parse `":" $ty` but the `:` or the type was missing.
/// This means that the type is missing.
fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<Ty> {
fn recover_missing_const_type(&mut self, colon_present: bool, m: Option<Mutability>) -> P<Ty> {
// Construct the error and stash it away with the hope
// that typeck will later enrich the error with a type.
let kind = match m {
@@ -1200,18 +1201,25 @@ impl<'a> Parser<'a> {
Some(Mutability::Not) => "static",
None => "const",
};
let mut err = self.struct_span_err(id.span, &format!("missing type for `{kind}` item"));
let colon = match colon_present {
true => "",
false => ":",
};
let span = self.prev_token.span.shrink_to_hi();
let mut err = self.struct_span_err(span, &format!("missing type for `{kind}` item"));
err.span_suggestion(
id.span,
span,
"provide a type for the item",
format!("{id}: <type>"),
format!("{colon} <type>"),
Applicability::HasPlaceholders,
);
err.stash(id.span, StashKey::ItemNoType);
err.stash(span, StashKey::ItemNoType);
// The user intended that the type be inferred,
// so treat this as if the user wrote e.g. `const A: _ = expr;`.
P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID, tokens: None })
P(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None })
}
/// Parses an enum declaration.

View File

@@ -801,6 +801,9 @@ fn infer_placeholder_type<'a>(
match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
Some(mut err) => {
if !ty.references_error() {
// Only suggest adding `:` if it was missing (and suggested by parsing diagnostic)
let colon = if span == item_ident.span.shrink_to_hi() { ":" } else { "" };
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
// We are typeck and have the real type, so remove that and suggest the actual type.
// FIXME(eddyb) this looks like it should be functionality on `Diagnostic`.
@@ -816,7 +819,7 @@ fn infer_placeholder_type<'a>(
err.span_suggestion(
span,
&format!("provide a type for the {item}", item = kind),
format!("{}: {}", item_ident, sugg_ty),
format!("{colon} {sugg_ty}"),
Applicability::MachineApplicable,
);
} else {