Skip to content

Commit 12ce6e9

Browse files
committed
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`.
1 parent fcce644 commit 12ce6e9

File tree

13 files changed

+67
-5
lines changed

13 files changed

+67
-5
lines changed

compiler/rustc_ast/src/ast.rs

+8
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,14 @@ pub struct Block {
565565
pub rules: BlockCheckMode,
566566
pub span: Span,
567567
pub tokens: Option<LazyTokenStream>,
568+
/// The following *isn't* a parse error, but will cause multiple errors in following stages.
569+
/// ```
570+
/// let x = {
571+
/// foo: var
572+
/// };
573+
/// ```
574+
/// #34255
575+
pub could_be_bare_literal: bool,
568576
}
569577

570578
/// A match pattern.

compiler/rustc_ast/src/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,7 @@ pub fn noop_visit_mt<T: MutVisitor>(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mu
949949
}
950950

951951
pub fn noop_visit_block<T: MutVisitor>(block: &mut P<Block>, vis: &mut T) {
952-
let Block { id, stmts, rules: _, span, tokens } = block.deref_mut();
952+
let Block { id, stmts, rules: _, span, tokens, could_be_bare_literal: _ } = block.deref_mut();
953953
vis.visit_id(id);
954954
stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt));
955955
vis.visit_span(span);

compiler/rustc_builtin_macros/src/deriving/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
102102
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
103103
span,
104104
tokens: None,
105+
could_be_bare_literal: false,
105106
}))
106107
}
107108

compiler/rustc_builtin_macros/src/format.rs

+1
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,7 @@ impl<'a, 'b> Context<'a, 'b> {
867867
rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
868868
span: self.macsp,
869869
tokens: None,
870+
could_be_bare_literal: false,
870871
}));
871872

872873
let ident = Ident::from_str_and_span("args", self.macsp);

compiler/rustc_expand/src/build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ impl<'a> ExtCtxt<'a> {
197197
rules: BlockCheckMode::Default,
198198
span,
199199
tokens: None,
200+
could_be_bare_literal: false,
200201
})
201202
}
202203

compiler/rustc_interface/src/util.rs

+1
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
810810
id: resolver.next_node_id(),
811811
span: rustc_span::DUMMY_SP,
812812
tokens: None,
813+
could_be_bare_literal: false,
813814
}
814815
}
815816

compiler/rustc_parse/src/parser/diagnostics.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -446,11 +446,13 @@ impl<'a> Parser<'a> {
446446
)
447447
.emit();
448448
*self = snapshot;
449-
Ok(self.mk_block(
449+
let mut tail = self.mk_block(
450450
vec![self.mk_stmt_err(expr.span)],
451451
s,
452452
lo.to(self.prev_token.span),
453-
))
453+
);
454+
tail.could_be_bare_literal = true;
455+
Ok(tail)
454456
}
455457
(Err(mut err), Ok(tail)) => {
456458
// We have a block tail that contains a somehow valid type ascription expr.
@@ -463,7 +465,10 @@ impl<'a> Parser<'a> {
463465
self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
464466
Err(err)
465467
}
466-
(Ok(_), Ok(tail)) => Ok(tail),
468+
(Ok(_), Ok(mut tail)) => {
469+
tail.could_be_bare_literal = true;
470+
Ok(tail)
471+
}
467472
});
468473
}
469474
None

compiler/rustc_parse/src/parser/stmt.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,14 @@ impl<'a> Parser<'a> {
574574
}
575575

576576
pub(super) fn mk_block(&self, stmts: Vec<Stmt>, rules: BlockCheckMode, span: Span) -> P<Block> {
577-
P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None })
577+
P(Block {
578+
stmts,
579+
id: DUMMY_NODE_ID,
580+
rules,
581+
span,
582+
tokens: None,
583+
could_be_bare_literal: false,
584+
})
578585
}
579586

580587
pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {

compiler/rustc_resolve/src/late.rs

+16
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,11 @@ struct DiagnosticMetadata<'ast> {
383383
/// Only used for better errors on `fn(): fn()`.
384384
current_type_ascription: Vec<Span>,
385385

386+
/// Only used for better errors on `let x = { foo: bar };`.
387+
/// In the case of a parse error with `let x = { foo: bar, };`, this isn't needed, it's only
388+
/// needed for cases where this parses as a correct type ascription.
389+
current_block_could_be_bare_struct_literal: Option<Span>,
390+
386391
/// Only used for better errors on `let <pat>: <expr, not type>;`.
387392
current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
388393

@@ -1859,6 +1864,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
18591864
let instead = res.is_some();
18601865
let suggestion =
18611866
if res.is_none() { this.report_missing_type_error(path) } else { None };
1867+
// get_from_node_id
18621868

18631869
this.r.use_injections.push(UseError {
18641870
err,
@@ -2242,6 +2248,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
22422248
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
22432249
}
22442250

2251+
let prev = self.diagnostic_metadata.current_block_could_be_bare_struct_literal.take();
2252+
if let (true, [Stmt { kind: StmtKind::Expr(expr), .. }]) =
2253+
(block.could_be_bare_literal, &block.stmts[..])
2254+
{
2255+
if let ExprKind::Type(..) = expr.kind {
2256+
self.diagnostic_metadata.current_block_could_be_bare_struct_literal =
2257+
Some(block.span);
2258+
}
2259+
}
22452260
// Descend into the block.
22462261
for stmt in &block.stmts {
22472262
if let StmtKind::Item(ref item) = stmt.kind {
@@ -2255,6 +2270,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
22552270

22562271
self.visit_stmt(stmt);
22572272
}
2273+
self.diagnostic_metadata.current_block_could_be_bare_struct_literal = prev;
22582274

22592275
// Move back up.
22602276
self.parent_scope.module = orig_module;

compiler/rustc_resolve/src/late/diagnostics.rs

+10
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,16 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
207207
let code = source.error_code(res.is_some());
208208
let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
209209

210+
if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal {
211+
err.multipart_suggestion(
212+
"you might have meant to write a `struct` literal",
213+
vec![
214+
(span.shrink_to_lo(), "{ SomeStruct ".to_string()),
215+
(span.shrink_to_hi(), "}".to_string()),
216+
],
217+
Applicability::HasPlaceholders,
218+
);
219+
}
210220
match (source, self.diagnostic_metadata.in_if_condition) {
211221
(PathSource::Expr(_), Some(Expr { span, kind: ExprKind::Assign(..), .. })) => {
212222
err.span_suggestion_verbose(

src/test/ui-fulldeps/pprust-expr-roundtrip.rs

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
106106
rules: BlockCheckMode::Default,
107107
span: DUMMY_SP,
108108
tokens: None,
109+
could_be_bare_literal: false,
109110
});
110111
iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
111112
}

src/test/ui/type/ascription/issue-34255-1.stderr

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ error[E0425]: cannot find value `input_cells` in this scope
33
|
44
LL | input_cells: Vec::new()
55
| ^^^^^^^^^^^ a field by this name exists in `Self`
6+
|
7+
help: you might have meant to write a `struct` literal
8+
|
9+
LL ~ pub fn new() -> Self { SomeStruct {
10+
LL | input_cells: Vec::new()
11+
LL |
12+
LL |
13+
LL |
14+
LL ~ }}
15+
|
616

717
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
818
--> $DIR/issue-34255-1.rs:7:27

src/tools/rustfmt/src/closures.rs

+1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ fn rewrite_closure_with_block(
160160
.first()
161161
.map(|attr| attr.span.to(body.span))
162162
.unwrap_or(body.span),
163+
could_be_bare_literal: false,
163164
};
164165
let block = crate::expr::rewrite_block_with_visitor(
165166
context,

0 commit comments

Comments
 (0)