Auto merge of #88598 - estebank:type-ascription-can-die-in-a-fire, r=wesleywiser
Detect bare blocks with type ascription that were meant to be a `struct` literal Address part of #34255. Potential improvement: silence the other knock down errors in `issue-34255-1.rs`.
This commit is contained in:
commit
b4e8596e3e
@ -558,6 +558,14 @@ pub struct Block {
|
||||
pub rules: BlockCheckMode,
|
||||
pub span: Span,
|
||||
pub tokens: Option<LazyTokenStream>,
|
||||
/// The following *isn't* a parse error, but will cause multiple errors in following stages.
|
||||
/// ```
|
||||
/// let x = {
|
||||
/// foo: var
|
||||
/// };
|
||||
/// ```
|
||||
/// #34255
|
||||
pub could_be_bare_literal: bool,
|
||||
}
|
||||
|
||||
/// A match pattern.
|
||||
|
@ -949,7 +949,7 @@ pub fn noop_visit_mt<T: MutVisitor>(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mu
|
||||
}
|
||||
|
||||
pub fn noop_visit_block<T: MutVisitor>(block: &mut P<Block>, vis: &mut T) {
|
||||
let Block { id, stmts, rules: _, span, tokens } = block.deref_mut();
|
||||
let Block { id, stmts, rules: _, span, tokens, could_be_bare_literal: _ } = block.deref_mut();
|
||||
vis.visit_id(id);
|
||||
stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt));
|
||||
vis.visit_span(span);
|
||||
|
@ -102,6 +102,7 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
|
||||
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
|
||||
span,
|
||||
tokens: None,
|
||||
could_be_bare_literal: false,
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -867,6 +867,7 @@ fn into_expr(self) -> P<ast::Expr> {
|
||||
rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
|
||||
span: self.macsp,
|
||||
tokens: None,
|
||||
could_be_bare_literal: false,
|
||||
}));
|
||||
|
||||
let ident = Ident::from_str_and_span("args", self.macsp);
|
||||
|
@ -197,6 +197,7 @@ pub fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block> {
|
||||
rules: BlockCheckMode::Default,
|
||||
span,
|
||||
tokens: None,
|
||||
could_be_bare_literal: false,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -810,6 +810,7 @@ fn stmt_to_block(
|
||||
id: resolver.next_node_id(),
|
||||
span: rustc_span::DUMMY_SP,
|
||||
tokens: None,
|
||||
could_be_bare_literal: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,11 +446,13 @@ pub fn maybe_suggest_struct_literal(
|
||||
)
|
||||
.emit();
|
||||
*self = snapshot;
|
||||
Ok(self.mk_block(
|
||||
let mut tail = self.mk_block(
|
||||
vec![self.mk_stmt_err(expr.span)],
|
||||
s,
|
||||
lo.to(self.prev_token.span),
|
||||
))
|
||||
);
|
||||
tail.could_be_bare_literal = true;
|
||||
Ok(tail)
|
||||
}
|
||||
(Err(mut err), Ok(tail)) => {
|
||||
// We have a block tail that contains a somehow valid type ascription expr.
|
||||
@ -463,7 +465,10 @@ pub fn maybe_suggest_struct_literal(
|
||||
self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
|
||||
Err(err)
|
||||
}
|
||||
(Ok(_), Ok(tail)) => Ok(tail),
|
||||
(Ok(_), Ok(mut tail)) => {
|
||||
tail.could_be_bare_literal = true;
|
||||
Ok(tail)
|
||||
}
|
||||
});
|
||||
}
|
||||
None
|
||||
|
@ -574,7 +574,14 @@ pub fn parse_full_stmt(
|
||||
}
|
||||
|
||||
pub(super) fn mk_block(&self, stmts: Vec<Stmt>, rules: BlockCheckMode, span: Span) -> P<Block> {
|
||||
P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None })
|
||||
P(Block {
|
||||
stmts,
|
||||
id: DUMMY_NODE_ID,
|
||||
rules,
|
||||
span,
|
||||
tokens: None,
|
||||
could_be_bare_literal: false,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {
|
||||
|
@ -383,6 +383,11 @@ struct DiagnosticMetadata<'ast> {
|
||||
/// Only used for better errors on `fn(): fn()`.
|
||||
current_type_ascription: Vec<Span>,
|
||||
|
||||
/// Only used for better errors on `let x = { foo: bar };`.
|
||||
/// In the case of a parse error with `let x = { foo: bar, };`, this isn't needed, it's only
|
||||
/// needed for cases where this parses as a correct type ascription.
|
||||
current_block_could_be_bare_struct_literal: Option<Span>,
|
||||
|
||||
/// Only used for better errors on `let <pat>: <expr, not type>;`.
|
||||
current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
|
||||
|
||||
@ -1871,6 +1876,7 @@ fn smart_resolve_path_fragment(
|
||||
let instead = res.is_some();
|
||||
let suggestion =
|
||||
if res.is_none() { this.report_missing_type_error(path) } else { None };
|
||||
// get_from_node_id
|
||||
|
||||
this.r.use_injections.push(UseError {
|
||||
err,
|
||||
@ -2254,6 +2260,15 @@ fn resolve_block(&mut self, block: &'ast Block) {
|
||||
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||
}
|
||||
|
||||
let prev = self.diagnostic_metadata.current_block_could_be_bare_struct_literal.take();
|
||||
if let (true, [Stmt { kind: StmtKind::Expr(expr), .. }]) =
|
||||
(block.could_be_bare_literal, &block.stmts[..])
|
||||
{
|
||||
if let ExprKind::Type(..) = expr.kind {
|
||||
self.diagnostic_metadata.current_block_could_be_bare_struct_literal =
|
||||
Some(block.span);
|
||||
}
|
||||
}
|
||||
// Descend into the block.
|
||||
for stmt in &block.stmts {
|
||||
if let StmtKind::Item(ref item) = stmt.kind {
|
||||
@ -2267,6 +2282,7 @@ fn resolve_block(&mut self, block: &'ast Block) {
|
||||
|
||||
self.visit_stmt(stmt);
|
||||
}
|
||||
self.diagnostic_metadata.current_block_could_be_bare_struct_literal = prev;
|
||||
|
||||
// Move back up.
|
||||
self.parent_scope.module = orig_module;
|
||||
|
@ -207,6 +207,16 @@ pub(crate) fn smart_resolve_report_errors(
|
||||
let code = source.error_code(res.is_some());
|
||||
let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
|
||||
|
||||
if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal {
|
||||
err.multipart_suggestion(
|
||||
"you might have meant to write a `struct` literal",
|
||||
vec![
|
||||
(span.shrink_to_lo(), "{ SomeStruct ".to_string()),
|
||||
(span.shrink_to_hi(), "}".to_string()),
|
||||
],
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
match (source, self.diagnostic_metadata.in_if_condition) {
|
||||
(PathSource::Expr(_), Some(Expr { span, kind: ExprKind::Assign(..), .. })) => {
|
||||
err.span_suggestion_verbose(
|
||||
|
@ -106,6 +106,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
|
||||
rules: BlockCheckMode::Default,
|
||||
span: DUMMY_SP,
|
||||
tokens: None,
|
||||
could_be_bare_literal: false,
|
||||
});
|
||||
iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
|
||||
}
|
||||
|
@ -3,6 +3,16 @@ error[E0425]: cannot find value `input_cells` in this scope
|
||||
|
|
||||
LL | input_cells: Vec::new()
|
||||
| ^^^^^^^^^^^ a field by this name exists in `Self`
|
||||
|
|
||||
help: you might have meant to write a `struct` literal
|
||||
|
|
||||
LL ~ pub fn new() -> Self { SomeStruct {
|
||||
LL | input_cells: Vec::new()
|
||||
LL |
|
||||
LL |
|
||||
LL |
|
||||
LL ~ }}
|
||||
|
|
||||
|
||||
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
|
||||
--> $DIR/issue-34255-1.rs:7:27
|
||||
|
@ -160,6 +160,7 @@ fn rewrite_closure_with_block(
|
||||
.first()
|
||||
.map(|attr| attr.span.to(body.span))
|
||||
.unwrap_or(body.span),
|
||||
could_be_bare_literal: false,
|
||||
};
|
||||
let block = crate::expr::rewrite_block_with_visitor(
|
||||
context,
|
||||
|
Loading…
Reference in New Issue
Block a user