Skip to content

Commit

Permalink
Auto merge of rust-lang#88598 - estebank:type-ascription-can-die-in-a…
Browse files Browse the repository at this point in the history
…-fire, r=wesleywiser

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

Address part of rust-lang#34255.

Potential improvement: silence the other knock down errors in `issue-34255-1.rs`.
  • Loading branch information
bors committed Sep 4, 2021
2 parents 03c775c + 12ce6e9 commit b4e8596
Show file tree
Hide file tree
Showing 13 changed files with 67 additions and 5 deletions.
8 changes: 8 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/mut_visit.rs
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
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
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
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
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
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
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
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 @@ -1871,6 +1876,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 @@ -2254,6 +2260,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 @@ -2267,6 +2282,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
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
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
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
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

0 comments on commit b4e8596

Please sign in to comment.