Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect bare blocks with type ascription that were meant to be a struct literal #88598

Merged
merged 1 commit into from
Sep 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,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.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/deriving/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}))
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,7 @@ impl<'a, 'b> Context<'a, 'b> {
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);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_expand/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ impl<'a> ExtCtxt<'a> {
rules: BlockCheckMode::Default,
span,
tokens: None,
could_be_bare_literal: false,
})
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
id: resolver.next_node_id(),
span: rustc_span::DUMMY_SP,
tokens: None,
could_be_bare_literal: false,
}
}

Expand Down
11 changes: 8 additions & 3 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,11 +446,13 @@ impl<'a> Parser<'a> {
)
.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.
Expand All @@ -463,7 +465,10 @@ impl<'a> Parser<'a> {
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
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_parse/src/parser/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,14 @@ impl<'a> Parser<'a> {
}

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 {
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>)>,

Expand Down Expand Up @@ -1859,6 +1864,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
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,
Expand Down Expand Up @@ -2242,6 +2248,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
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 {
Expand All @@ -2255,6 +2270,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {

self.visit_stmt(stmt);
}
self.diagnostic_metadata.current_block_could_be_bare_struct_literal = prev;

// Move back up.
self.parent_scope.module = orig_module;
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,16 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
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(
Expand Down
1 change: 1 addition & 0 deletions src/test/ui-fulldeps/pprust-expr-roundtrip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
}
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/type/ascription/issue-34255-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/tools/rustfmt/src/closures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down