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 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.
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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(
|
||||||
|
@ -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)));
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user