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:
bors 2021-09-04 01:40:36 +00:00
commit b4e8596e3e
13 changed files with 67 additions and 5 deletions

View File

@ -558,6 +558,14 @@ pub struct Block {
pub rules: BlockCheckMode, pub rules: BlockCheckMode,
pub span: Span, pub span: Span,
pub tokens: Option<LazyTokenStream>, 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. /// A match pattern.

View File

@ -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) { 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); vis.visit_id(id);
stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt));
vis.visit_span(span); vis.visit_span(span);

View File

@ -102,6 +102,7 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
span, span,
tokens: None, tokens: None,
could_be_bare_literal: false,
})) }))
} }

View File

@ -867,6 +867,7 @@ fn into_expr(self) -> P<ast::Expr> {
rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated), rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
span: self.macsp, span: self.macsp,
tokens: None, tokens: None,
could_be_bare_literal: false,
})); }));
let ident = Ident::from_str_and_span("args", self.macsp); let ident = Ident::from_str_and_span("args", self.macsp);

View File

@ -197,6 +197,7 @@ pub fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block> {
rules: BlockCheckMode::Default, rules: BlockCheckMode::Default,
span, span,
tokens: None, tokens: None,
could_be_bare_literal: false,
}) })
} }

View File

@ -810,6 +810,7 @@ fn stmt_to_block(
id: resolver.next_node_id(), id: resolver.next_node_id(),
span: rustc_span::DUMMY_SP, span: rustc_span::DUMMY_SP,
tokens: None, tokens: None,
could_be_bare_literal: false,
} }
} }

View File

@ -446,11 +446,13 @@ pub fn maybe_suggest_struct_literal(
) )
.emit(); .emit();
*self = snapshot; *self = snapshot;
Ok(self.mk_block( let mut tail = self.mk_block(
vec![self.mk_stmt_err(expr.span)], vec![self.mk_stmt_err(expr.span)],
s, s,
lo.to(self.prev_token.span), lo.to(self.prev_token.span),
)) );
tail.could_be_bare_literal = true;
Ok(tail)
} }
(Err(mut err), Ok(tail)) => { (Err(mut err), Ok(tail)) => {
// We have a block tail that contains a somehow valid type ascription expr. // 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); self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
Err(err) Err(err)
} }
(Ok(_), Ok(tail)) => Ok(tail), (Ok(_), Ok(mut tail)) => {
tail.could_be_bare_literal = true;
Ok(tail)
}
}); });
} }
None None

View File

@ -574,7 +574,14 @@ pub fn parse_full_stmt(
} }
pub(super) fn mk_block(&self, stmts: Vec<Stmt>, rules: BlockCheckMode, span: Span) -> P<Block> { 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 { pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {

View File

@ -383,6 +383,11 @@ struct DiagnosticMetadata<'ast> {
/// Only used for better errors on `fn(): fn()`. /// Only used for better errors on `fn(): fn()`.
current_type_ascription: Vec<Span>, 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>;`. /// Only used for better errors on `let <pat>: <expr, not type>;`.
current_let_binding: Option<(Span, Option<Span>, Option<Span>)>, current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
@ -1871,6 +1876,7 @@ fn smart_resolve_path_fragment(
let instead = res.is_some(); let instead = res.is_some();
let suggestion = let suggestion =
if res.is_none() { this.report_missing_type_error(path) } else { None }; if res.is_none() { this.report_missing_type_error(path) } else { None };
// get_from_node_id
this.r.use_injections.push(UseError { this.r.use_injections.push(UseError {
err, err,
@ -2254,6 +2260,15 @@ fn resolve_block(&mut self, block: &'ast Block) {
self.ribs[ValueNS].push(Rib::new(NormalRibKind)); 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. // Descend into the block.
for stmt in &block.stmts { for stmt in &block.stmts {
if let StmtKind::Item(ref item) = stmt.kind { 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.visit_stmt(stmt);
} }
self.diagnostic_metadata.current_block_could_be_bare_struct_literal = prev;
// Move back up. // Move back up.
self.parent_scope.module = orig_module; self.parent_scope.module = orig_module;

View File

@ -207,6 +207,16 @@ pub(crate) fn smart_resolve_report_errors(
let code = source.error_code(res.is_some()); let code = source.error_code(res.is_some());
let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code); 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) { match (source, self.diagnostic_metadata.in_if_condition) {
(PathSource::Expr(_), Some(Expr { span, kind: ExprKind::Assign(..), .. })) => { (PathSource::Expr(_), Some(Expr { span, kind: ExprKind::Assign(..), .. })) => {
err.span_suggestion_verbose( err.span_suggestion_verbose(

View File

@ -106,6 +106,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
rules: BlockCheckMode::Default, rules: BlockCheckMode::Default,
span: DUMMY_SP, span: DUMMY_SP,
tokens: None, tokens: None,
could_be_bare_literal: false,
}); });
iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None))); iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
} }

View File

@ -3,6 +3,16 @@ error[E0425]: cannot find value `input_cells` in this scope
| |
LL | input_cells: Vec::new() LL | input_cells: Vec::new()
| ^^^^^^^^^^^ a field by this name exists in `Self` | ^^^^^^^^^^^ 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 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-34255-1.rs:7:27 --> $DIR/issue-34255-1.rs:7:27

View File

@ -160,6 +160,7 @@ fn rewrite_closure_with_block(
.first() .first()
.map(|attr| attr.span.to(body.span)) .map(|attr| attr.span.to(body.span))
.unwrap_or(body.span), .unwrap_or(body.span),
could_be_bare_literal: false,
}; };
let block = crate::expr::rewrite_block_with_visitor( let block = crate::expr::rewrite_block_with_visitor(
context, context,