1
Fork 0

Rollup merge of #138898 - fmease:decrustify-parser-post-ty-ascr, r=compiler-errors

Mostly parser: Eliminate code that's been dead / semi-dead since the removal of type ascription syntax

**Disclaimer**: This PR is intended to mostly clean up code as opposed to bringing about behavioral changes. Therefore it doesn't aim to address any of the 'FIXME: remove after a month [dated: 2023-05-02]: "type ascription syntax has been removed, see issue [#]101728"'.

---

By commit:

1. Removes truly dead code:
   * Since 1.71 (#109128) `let _ = { f: x };` is a syntax error as opposed to a semantic error which allows the parse-time diagnostic (suggestion) "*struct literal body without path // you might have forgotten […]*" to kick in.
   * The analysis-time diagnostic (suggestion) from <=1.70 "*cannot find value \`f\` in this scope // you might have forgotten […]*" is therefore no longer reachable.
2. Updates `is_certainly_not_a_block` to be in line with the current grammar:
   * The seq. `{ ident:` is definitely not the start of a block. Before the removal of ty ascr, `{ ident: ty_start` would begin a block expr.
   * This shouldn't make more code compile IINM, it should *ultimately* only affect diagnostics.
   * For example, `if T { f: () } {}` will now be interpreted as an `if` with struct lit `T { f: () }` as its *condition* (which is banned in the parser anyway) as opposed to just `T` (with the *consequent* being `f : ()` which is also invalid (since 1.71)). The diagnostics are almost the same because we have two separate parse recovery procedures + diagnostics: `StructLiteralNeedingParens` (*invalid struct lit*) before and `StructLiteralNotAllowedHere` (*struct lits aren't allowed here*) now, as you can see from the diff.
   * (As an aside, even before this PR, fn `maybe_suggest_struct_literal` should've just used the much older & clearer `StructLiteralNotAllowedHere`)
   * NB: This does sadly regress the compiler output for `tests/ui/parser/type-ascription-in-pattern.rs` but that can be fixed in follow-up PRs. It's not super important IMO and a natural consequence.
3. Removes code that's become dead due to the prior commit.
   * Basically reverts #106620 + #112475 (without regressing rustc's output!).
   * Now the older & more robust parse recovery procedure (cc `StructLiteralNotAllowedHere`) takes care of the cases the removed code used to handle.
   * This automatically fixes the suggestions for \[[playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=7e2030163b11ee96d17adc3325b01780)\]:
     * `if Ty::<i32> { f: K }.m() {}`: `if Ty::<i32> { SomeStruct { f: K } }.m() {}` (broken) → ` if (Ty::<i32> { f: K }).m() {}`
     * `if <T as Trait>::Out { f: K::<> }.m() {}`: `if <T as Trait>(::Out { f: K::<> }).m() {}` (broken) → `if (<T as Trait>::Out { f: K::<> }).m() {}`
4. Merge and simplify UI tests pertaining to this issue, so it's easier to add more regression tests like for the two cases mentioned above.
5. Merge UI tests and add the two regression tests.

Best reviewed commit by commit (on request I'll partially squash after approval).
This commit is contained in:
Stuart Cook 2025-03-26 19:40:28 +11:00 committed by GitHub
commit 30344f7fa3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 411 additions and 616 deletions

View file

@ -545,14 +545,6 @@ pub struct Block {
pub rules: BlockCheckMode, pub rules: BlockCheckMode,
pub span: Span, pub span: Span,
pub tokens: Option<LazyAttrTokenStream>, pub tokens: Option<LazyAttrTokenStream>,
/// The following *isn't* a parse error, but will cause multiple errors in following stages.
/// ```compile_fail
/// let x = {
/// foo: var
/// };
/// ```
/// #34255
pub could_be_bare_literal: bool,
} }
/// A match pattern. /// A match pattern.

View file

@ -1222,7 +1222,7 @@ fn walk_mt<T: MutVisitor>(vis: &mut T, MutTy { ty, mutbl: _ }: &mut MutTy) {
} }
pub fn walk_block<T: MutVisitor>(vis: &mut T, block: &mut P<Block>) { pub fn walk_block<T: MutVisitor>(vis: &mut T, block: &mut P<Block>) {
let Block { id, stmts, rules: _, span, tokens, could_be_bare_literal: _ } = block.deref_mut(); let Block { id, stmts, rules: _, span, tokens } = 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));
visit_lazy_tts(vis, tokens); visit_lazy_tts(vis, tokens);

View file

@ -1067,7 +1067,7 @@ pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef)
} }
pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) -> V::Result { pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) -> V::Result {
let Block { stmts, id: _, rules: _, span: _, tokens: _, could_be_bare_literal: _ } = block; let Block { stmts, id: _, rules: _, span: _, tokens: _ } = block;
walk_list!(visitor, visit_stmt, stmts); walk_list!(visitor, visit_stmt, stmts);
V::Result::output() V::Result::output()
} }

View file

@ -395,7 +395,6 @@ mod llvm_enzyme {
tokens: None, tokens: None,
rules: unsf, rules: unsf,
span, span,
could_be_bare_literal: false,
}; };
let unsf_expr = ecx.expr_block(P(unsf_block)); let unsf_expr = ecx.expr_block(P(unsf_block));
let blackbox_call_expr = ecx.expr_path(ecx.path(span, blackbox_path)); let blackbox_call_expr = ecx.expr_path(ecx.path(span, blackbox_path));

View file

@ -110,7 +110,6 @@ 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

@ -286,7 +286,6 @@ impl<'a> ExtCtxt<'a> {
rules: BlockCheckMode::Default, rules: BlockCheckMode::Default,
span, span,
tokens: None, tokens: None,
could_be_bare_literal: false,
}) })
} }

View file

@ -757,10 +757,6 @@ parse_struct_literal_body_without_path =
struct literal body without path struct literal body without path
.suggestion = you might have forgotten to add the struct literal inside the block .suggestion = you might have forgotten to add the struct literal inside the block
parse_struct_literal_needing_parens =
invalid struct literal
.suggestion = you might need to surround the struct literal with parentheses
parse_struct_literal_not_allowed_here = struct literals are not allowed here parse_struct_literal_not_allowed_here = struct literals are not allowed here
.suggestion = surround the struct literal with parentheses .suggestion = surround the struct literal with parentheses

View file

@ -1272,24 +1272,6 @@ pub(crate) struct StructLiteralBodyWithoutPathSugg {
pub after: Span, pub after: Span,
} }
#[derive(Diagnostic)]
#[diag(parse_struct_literal_needing_parens)]
pub(crate) struct StructLiteralNeedingParens {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub sugg: StructLiteralNeedingParensSugg,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
pub(crate) struct StructLiteralNeedingParensSugg {
#[suggestion_part(code = "(")]
pub before: Span,
#[suggestion_part(code = ")")]
pub after: Span,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(parse_unmatched_angle_brackets)] #[diag(parse_unmatched_angle_brackets)]
pub(crate) struct UnmatchedAngleBrackets { pub(crate) struct UnmatchedAngleBrackets {

View file

@ -40,9 +40,8 @@ use crate::errors::{
HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait, HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody, IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody,
QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma,
SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
}; };
use crate::parser::attr::InnerAttrPolicy; use crate::parser::attr::InnerAttrPolicy;
@ -949,7 +948,6 @@ impl<'a> Parser<'a> {
lo: Span, lo: Span,
s: BlockCheckMode, s: BlockCheckMode,
maybe_struct_name: token::Token, maybe_struct_name: token::Token,
can_be_struct_literal: bool,
) -> Option<PResult<'a, P<Block>>> { ) -> Option<PResult<'a, P<Block>>> {
if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) { if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) {
// We might be having a struct literal where people forgot to include the path: // We might be having a struct literal where people forgot to include the path:
@ -975,47 +973,23 @@ impl<'a> Parser<'a> {
// fn foo() -> Foo { Path { // fn foo() -> Foo { Path {
// field: value, // field: value,
// } } // } }
let guar = err.delay_as_bug(); err.cancel();
self.restore_snapshot(snapshot); self.restore_snapshot(snapshot);
let mut tail = self.mk_block( let guar = self.dcx().emit_err(StructLiteralBodyWithoutPath {
span: expr.span,
sugg: StructLiteralBodyWithoutPathSugg {
before: expr.span.shrink_to_lo(),
after: expr.span.shrink_to_hi(),
},
});
Ok(self.mk_block(
thin_vec![self.mk_stmt_err(expr.span, guar)], thin_vec![self.mk_stmt_err(expr.span, guar)],
s, s,
lo.to(self.prev_token.span), lo.to(self.prev_token.span),
); ))
tail.could_be_bare_literal = true;
if maybe_struct_name.is_ident() && can_be_struct_literal {
// Account for `if Example { a: one(), }.is_pos() {}`.
// expand `before` so that we take care of module path such as:
// `foo::Bar { ... } `
// we expect to suggest `(foo::Bar { ... })` instead of `foo::(Bar { ... })`
let sm = self.psess.source_map();
let before = maybe_struct_name.span.shrink_to_lo();
if let Ok(extend_before) = sm.span_extend_prev_while(before, |t| {
t.is_alphanumeric() || t == ':' || t == '_'
}) {
Err(self.dcx().create_err(StructLiteralNeedingParens {
span: maybe_struct_name.span.to(expr.span),
sugg: StructLiteralNeedingParensSugg {
before: extend_before.shrink_to_lo(),
after: expr.span.shrink_to_hi(),
},
}))
} else {
return None;
}
} else {
self.dcx().emit_err(StructLiteralBodyWithoutPath {
span: expr.span,
sugg: StructLiteralBodyWithoutPathSugg {
before: expr.span.shrink_to_lo(),
after: expr.span.shrink_to_hi(),
},
});
Ok(tail)
}
} }
(Err(err), Ok(tail)) => { (Err(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 expr.
err.cancel(); err.cancel();
Ok(tail) Ok(tail)
} }
@ -1025,10 +999,7 @@ impl<'a> Parser<'a> {
self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes); self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);
Err(err) Err(err)
} }
(Ok(_), Ok(mut tail)) => { (Ok(_), Ok(tail)) => Ok(tail),
tail.could_be_bare_literal = true;
Ok(tail)
}
}); });
} }
None None

View file

@ -2296,7 +2296,7 @@ impl<'a> Parser<'a> {
}); });
} }
let (attrs, blk) = self.parse_block_common(lo, blk_mode, true, None)?; let (attrs, blk) = self.parse_block_common(lo, blk_mode, None)?;
Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs)) Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs))
} }
@ -3474,19 +3474,9 @@ impl<'a> Parser<'a> {
} }
fn is_certainly_not_a_block(&self) -> bool { fn is_certainly_not_a_block(&self) -> bool {
// `{ ident, ` and `{ ident: ` cannot start a block.
self.look_ahead(1, |t| t.is_ident()) self.look_ahead(1, |t| t.is_ident())
&& ( && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon)
// `{ ident, ` cannot start a block.
self.look_ahead(2, |t| t == &token::Comma)
|| self.look_ahead(2, |t| t == &token::Colon)
&& (
// `{ ident: token, ` cannot start a block.
self.look_ahead(4, |t| t == &token::Comma)
// `{ ident: ` cannot start a block unless it's a type ascription
// `ident: Type`.
|| self.look_ahead(3, |t| !t.can_begin_type())
)
)
} }
fn maybe_parse_struct_expr( fn maybe_parse_struct_expr(

View file

@ -2538,7 +2538,7 @@ impl<'a> Parser<'a> {
*sig_hi = self.prev_token.span; *sig_hi = self.prev_token.span;
(AttrVec::new(), None) (AttrVec::new(), None)
} else if self.check(exp!(OpenBrace)) || self.token.is_whole_block() { } else if self.check(exp!(OpenBrace)) || self.token.is_whole_block() {
self.parse_block_common(self.token.span, BlockCheckMode::Default, false, None) self.parse_block_common(self.token.span, BlockCheckMode::Default, None)
.map(|(attrs, body)| (attrs, Some(body)))? .map(|(attrs, body)| (attrs, Some(body)))?
} else if self.token == token::Eq { } else if self.token == token::Eq {
// Recover `fn foo() = $expr;`. // Recover `fn foo() = $expr;`.

View file

@ -668,7 +668,7 @@ impl<'a> Parser<'a> {
&mut self, &mut self,
loop_header: Option<Span>, loop_header: Option<Span>,
) -> PResult<'a, (AttrVec, P<Block>)> { ) -> PResult<'a, (AttrVec, P<Block>)> {
self.parse_block_common(self.token.span, BlockCheckMode::Default, true, loop_header) self.parse_block_common(self.token.span, BlockCheckMode::Default, loop_header)
} }
/// Parses a block. Inner attributes are allowed, block labels are not. /// Parses a block. Inner attributes are allowed, block labels are not.
@ -679,7 +679,6 @@ impl<'a> Parser<'a> {
&mut self, &mut self,
lo: Span, lo: Span,
blk_mode: BlockCheckMode, blk_mode: BlockCheckMode,
can_be_struct_literal: bool,
loop_header: Option<Span>, loop_header: Option<Span>,
) -> PResult<'a, (AttrVec, P<Block>)> { ) -> PResult<'a, (AttrVec, P<Block>)> {
maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block)); maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block));
@ -691,12 +690,7 @@ impl<'a> Parser<'a> {
} }
let attrs = self.parse_inner_attributes()?; let attrs = self.parse_inner_attributes()?;
let tail = match self.maybe_suggest_struct_literal( let tail = match self.maybe_suggest_struct_literal(lo, blk_mode, maybe_ident) {
lo,
blk_mode,
maybe_ident,
can_be_struct_literal,
) {
Some(tail) => tail?, Some(tail) => tail?,
None => self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?, None => self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?,
}; };
@ -1043,14 +1037,7 @@ impl<'a> Parser<'a> {
rules: BlockCheckMode, rules: BlockCheckMode,
span: Span, span: Span,
) -> P<Block> { ) -> P<Block> {
P(Block { P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None })
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

@ -675,11 +675,6 @@ struct DiagMetadata<'ast> {
/// they are used (in a `break` or `continue` statement) /// they are used (in a `break` or `continue` statement)
unused_labels: FxIndexMap<NodeId, Span>, unused_labels: FxIndexMap<NodeId, 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>)>,
@ -4661,13 +4656,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
self.ribs[ValueNS].push(Rib::new(RibKind::Normal)); self.ribs[ValueNS].push(Rib::new(RibKind::Normal));
} }
let prev = self.diag_metadata.current_block_could_be_bare_struct_literal.take();
if let (true, [Stmt { kind: StmtKind::Expr(expr), .. }]) =
(block.could_be_bare_literal, &block.stmts[..])
&& let ExprKind::Type(..) = expr.kind
{
self.diag_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
@ -4681,7 +4669,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
self.visit_stmt(stmt); self.visit_stmt(stmt);
} }
self.diag_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

@ -450,7 +450,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect); err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect);
} }
self.suggest_bare_struct_literal(&mut err);
self.suggest_changing_type_to_const_param(&mut err, res, source, span); self.suggest_changing_type_to_const_param(&mut err, res, source, span);
self.explain_functions_in_pattern(&mut err, res, source); self.explain_functions_in_pattern(&mut err, res, source);
@ -1279,19 +1278,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
} }
} }
fn suggest_bare_struct_literal(&mut self, err: &mut Diag<'_>) {
if let Some(span) = self.diag_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,
);
}
}
fn explain_functions_in_pattern( fn explain_functions_in_pattern(
&mut self, &mut self,
err: &mut Diag<'_>, err: &mut Diag<'_>,

View file

@ -176,7 +176,6 @@ 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,

View file

@ -423,7 +423,6 @@ fn rewrite_empty_macro_def_body(
rules: ast::BlockCheckMode::Default, rules: ast::BlockCheckMode::Default,
span, span,
tokens: None, tokens: None,
could_be_bare_literal: false,
}; };
block.rewrite_result(context, shape) block.rewrite_result(context, shape)
} }

View file

@ -3189,7 +3189,6 @@ ui/parser/issues/issue-108495-dec.rs
ui/parser/issues/issue-110014.rs ui/parser/issues/issue-110014.rs
ui/parser/issues/issue-111148.rs ui/parser/issues/issue-111148.rs
ui/parser/issues/issue-111416.rs ui/parser/issues/issue-111416.rs
ui/parser/issues/issue-111692.rs
ui/parser/issues/issue-112188.rs ui/parser/issues/issue-112188.rs
ui/parser/issues/issue-112458.rs ui/parser/issues/issue-112458.rs
ui/parser/issues/issue-113110-non-item-at-module-root.rs ui/parser/issues/issue-113110-non-item-at-module-root.rs

View file

@ -114,7 +114,6 @@ 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

@ -1,32 +0,0 @@
mod module {
#[derive(Eq, PartialEq)]
pub struct Type {
pub x: u8,
pub y: u8,
}
pub const C: u8 = 32u8;
}
fn test(x: module::Type) {
if x == module::Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal
}
}
fn test2(x: module::Type) {
if x ==module::Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal
}
}
fn test3(x: module::Type) {
if x == Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal
}
}
fn test4(x: module::Type) {
if x == demo_module::Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal
}
}
fn main() { }

View file

@ -1,46 +0,0 @@
error: invalid struct literal
--> $DIR/issue-111692.rs:12:21
|
LL | if x == module::Type { x: module::C, y: 1 } {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: you might need to surround the struct literal with parentheses
|
LL | if x == (module::Type { x: module::C, y: 1 }) {
| + +
error: invalid struct literal
--> $DIR/issue-111692.rs:17:20
|
LL | if x ==module::Type { x: module::C, y: 1 } {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: you might need to surround the struct literal with parentheses
|
LL | if x ==(module::Type { x: module::C, y: 1 }) {
| + +
error: invalid struct literal
--> $DIR/issue-111692.rs:23:13
|
LL | if x == Type { x: module::C, y: 1 } {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: you might need to surround the struct literal with parentheses
|
LL | if x == (Type { x: module::C, y: 1 }) {
| + +
error: invalid struct literal
--> $DIR/issue-111692.rs:28:26
|
LL | if x == demo_module::Type { x: module::C, y: 1 } {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: you might need to surround the struct literal with parentheses
|
LL | if x == (demo_module::Type { x: module::C, y: 1 }) {
| + +
error: aborting due to 4 previous errors

View file

@ -1,13 +0,0 @@
pub struct Example { a: i32 }
impl Example {
fn is_pos(&self) -> bool { self.a > 0 }
}
fn one() -> i32 { 1 }
fn main() {
if Example { a: one(), }.is_pos() { //~ ERROR invalid struct literal
println!("Positive!");
}
}

View file

@ -1,13 +0,0 @@
error: invalid struct literal
--> $DIR/method-call-on-struct-literal-in-if-condition.rs:10:8
|
LL | if Example { a: one(), }.is_pos() {
| ^^^^^^^^^^^^^^^^^^^^^
|
help: you might need to surround the struct literal with parentheses
|
LL | if (Example { a: one(), }).is_pos() {
| + +
error: aborting due to 1 previous error

View file

@ -1,17 +0,0 @@
struct Foo {
x: isize,
}
impl Foo {
fn hi(&self) -> bool {
true
}
}
fn main() {
for x in Foo { //~ ERROR struct literals are not allowed here
x: 3 //~^ ERROR `bool` is not an iterator
}.hi() {
println!("yo");
}
}

View file

@ -1,31 +0,0 @@
error: struct literals are not allowed here
--> $DIR/struct-literal-in-for.rs:12:14
|
LL | for x in Foo {
| ______________^
LL | | x: 3
LL | | }.hi() {
| |_____^
|
help: surround the struct literal with parentheses
|
LL ~ for x in (Foo {
LL | x: 3
LL ~ }).hi() {
|
error[E0277]: `bool` is not an iterator
--> $DIR/struct-literal-in-for.rs:12:14
|
LL | for x in Foo {
| ______________^
LL | | x: 3
LL | | }.hi() {
| |__________^ `bool` is not an iterator
|
= help: the trait `Iterator` is not implemented for `bool`
= note: required for `bool` to implement `IntoIterator`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,22 +0,0 @@
struct Foo {
x: isize,
}
impl Foo {
fn hi(&self) -> bool {
true
}
}
fn main() {
if Foo { //~ ERROR struct literals are not allowed here
x: 3
}.hi() {
println!("yo");
}
if let true = Foo { //~ ERROR struct literals are not allowed here
x: 3
}.hi() {
println!("yo");
}
}

View file

@ -1,34 +0,0 @@
error: struct literals are not allowed here
--> $DIR/struct-literal-in-if.rs:12:8
|
LL | if Foo {
| ________^
LL | | x: 3
LL | | }.hi() {
| |_____^
|
help: surround the struct literal with parentheses
|
LL ~ if (Foo {
LL | x: 3
LL ~ }).hi() {
|
error: struct literals are not allowed here
--> $DIR/struct-literal-in-if.rs:17:19
|
LL | if let true = Foo {
| ___________________^
LL | | x: 3
LL | | }.hi() {
| |_____^
|
help: surround the struct literal with parentheses
|
LL ~ if let true = (Foo {
LL | x: 3
LL ~ }).hi() {
|
error: aborting due to 2 previous errors

View file

@ -1,13 +0,0 @@
struct Foo {
x: isize,
}
fn main() {
match Foo { //~ ERROR struct literals are not allowed here
x: 3
} {
Foo {
x: x
} => {}
}
}

View file

@ -1,18 +0,0 @@
error: struct literals are not allowed here
--> $DIR/struct-literal-in-match-discriminant.rs:6:11
|
LL | match Foo {
| ___________^
LL | | x: 3
LL | | } {
| |_____^
|
help: surround the struct literal with parentheses
|
LL ~ match (Foo {
LL | x: 3
LL ~ }) {
|
error: aborting due to 1 previous error

View file

@ -1,22 +0,0 @@
struct Foo {
x: isize,
}
impl Foo {
fn hi(&self) -> bool {
true
}
}
fn main() {
while Foo { //~ ERROR struct literals are not allowed here
x: 3
}.hi() {
println!("yo");
}
while let true = Foo { //~ ERROR struct literals are not allowed here
x: 3
}.hi() {
println!("yo");
}
}

View file

@ -1,34 +0,0 @@
error: struct literals are not allowed here
--> $DIR/struct-literal-in-while.rs:12:11
|
LL | while Foo {
| ___________^
LL | | x: 3
LL | | }.hi() {
| |_____^
|
help: surround the struct literal with parentheses
|
LL ~ while (Foo {
LL | x: 3
LL ~ }).hi() {
|
error: struct literals are not allowed here
--> $DIR/struct-literal-in-while.rs:17:22
|
LL | while let true = Foo {
| ______________________^
LL | | x: 3
LL | | }.hi() {
| |_____^
|
help: surround the struct literal with parentheses
|
LL ~ while let true = (Foo {
LL | x: 3
LL ~ }).hi() {
|
error: aborting due to 2 previous errors

View file

@ -1,17 +0,0 @@
struct Foo {
x: isize,
}
impl Foo {
fn hi(&self) -> bool {
true
}
}
fn main() {
while || Foo { //~ ERROR struct literals are not allowed here
x: 3 //~^ ERROR mismatched types
}.hi() {
println!("yo");
}
}

View file

@ -1,37 +0,0 @@
error: struct literals are not allowed here
--> $DIR/struct-literal-restrictions-in-lamda.rs:12:14
|
LL | while || Foo {
| ______________^
LL | | x: 3
LL | | }.hi() {
| |_____^
|
help: surround the struct literal with parentheses
|
LL ~ while || (Foo {
LL | x: 3
LL ~ }).hi() {
|
error[E0308]: mismatched types
--> $DIR/struct-literal-restrictions-in-lamda.rs:12:11
|
LL | while || Foo {
| ___________^
LL | | x: 3
LL | | }.hi() {
| |__________^ expected `bool`, found closure
|
= note: expected type `bool`
found closure `{closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 12:13}`
help: use parentheses to call this closure
|
LL ~ while (|| Foo {
LL | x: 3
LL ~ }.hi())() {
|
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -1,25 +0,0 @@
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
enum E {
V { field: bool },
I { field1: bool, field2: usize },
J { field: isize },
K { field: &'static str},
}
fn test_E(x: E) {
let field = true;
if x == E::V { field } {}
//~^ ERROR expected value, found struct variant `E::V`
//~| ERROR mismatched types
if x == E::I { field1: true, field2: 42 } {}
//~^ ERROR struct literals are not allowed here
if x == E::V { field: false } {}
//~^ ERROR struct literals are not allowed here
if x == E::J { field: -42 } {}
//~^ ERROR struct literals are not allowed here
if x == E::K { field: "" } {}
//~^ ERROR struct literals are not allowed here
let y: usize = ();
//~^ ERROR mismatched types
}
fn main() {}

View file

@ -1,76 +0,0 @@
error: struct literals are not allowed here
--> $DIR/struct-literal-variant-in-if.rs:13:13
|
LL | if x == E::I { field1: true, field2: 42 } {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if x == (E::I { field1: true, field2: 42 }) {}
| + +
error: struct literals are not allowed here
--> $DIR/struct-literal-variant-in-if.rs:15:13
|
LL | if x == E::V { field: false } {}
| ^^^^^^^^^^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if x == (E::V { field: false }) {}
| + +
error: struct literals are not allowed here
--> $DIR/struct-literal-variant-in-if.rs:17:13
|
LL | if x == E::J { field: -42 } {}
| ^^^^^^^^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if x == (E::J { field: -42 }) {}
| + +
error: struct literals are not allowed here
--> $DIR/struct-literal-variant-in-if.rs:19:13
|
LL | if x == E::K { field: "" } {}
| ^^^^^^^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if x == (E::K { field: "" }) {}
| + +
error[E0533]: expected value, found struct variant `E::V`
--> $DIR/struct-literal-variant-in-if.rs:10:13
|
LL | if x == E::V { field } {}
| ^^^^ not a value
|
help: you might have meant to create a new value of the struct
|
LL | if x == (E::V { field }) {}
| + +
error[E0308]: mismatched types
--> $DIR/struct-literal-variant-in-if.rs:10:20
|
LL | if x == E::V { field } {}
| ---------------^^^^^--
| | |
| | expected `()`, found `bool`
| expected this to be `()`
error[E0308]: mismatched types
--> $DIR/struct-literal-variant-in-if.rs:21:20
|
LL | let y: usize = ();
| ----- ^^ expected `usize`, found `()`
| |
| expected due to this
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0308, E0533.
For more information about an error, try `rustc --explain E0308`.

View file

@ -0,0 +1,92 @@
fn main() {
if Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here
println!("yo");
}
if let true = Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here
println!("yo");
}
for x in Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here
//~^ ERROR `bool` is not an iterator
println!("yo");
}
while Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here
println!("yo");
}
while let true = Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here
println!("yo");
}
match Foo { x: 3 } { //~ ERROR struct literals are not allowed here
Foo { x: x } => {}
}
let _ = |x: E| {
let field = true;
if x == E::V { field } {}
//~^ ERROR expected value, found struct variant `E::V`
//~| ERROR mismatched types
if x == E::I { field1: true, field2: 42 } {}
//~^ ERROR struct literals are not allowed here
if x == E::V { field: false } {}
//~^ ERROR struct literals are not allowed here
if x == E::J { field: -42 } {}
//~^ ERROR struct literals are not allowed here
if x == E::K { field: "" } {}
//~^ ERROR struct literals are not allowed here
let y: usize = ();
//~^ ERROR mismatched types
};
// Regression test for <https://github.com/rust-lang/rust/issues/43412>.
while || Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here
//~^ ERROR mismatched types
println!("yo");
}
// This uses `one()` over `1` as token `one` may begin a type and thus back when type ascription
// `$expr : $ty` still existed, `{ x: one` could've been the start of a block expr which used to
// make the compiler take a different execution path. Now it no longer makes a difference tho.
// Regression test for <https://github.com/rust-lang/rust/issues/82051>.
if Foo { x: one(), }.hi() { //~ ERROR struct literals are not allowed here
println!("Positive!");
}
const FOO: Foo = Foo { x: 1 };
// Below, test that we correctly parenthesize the struct literals.
// Regression test for <https://github.com/rust-lang/rust/issues/112278>.
if FOO == self::Foo { x: one() } {} //~ ERROR struct literals are not allowed here
if FOO == Foo::<> { x: one() } {} //~ ERROR struct literals are not allowed here
fn env<T: Trait<Out = Foo>>() {
if FOO == <T as Trait>::Out { x: one() } {} //~ ERROR struct literals are not allowed here
//~^ ERROR usage of qualified paths in this context is experimental
}
}
#[derive(PartialEq, Eq)]
struct Foo {
x: isize,
}
impl Foo {
fn hi(&self) -> bool {
true
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
enum E {
V { field: bool },
I { field1: bool, field2: usize },
J { field: isize },
K { field: &'static str},
}
fn one() -> isize { 1 }
trait Trait { type Out; }

View file

@ -0,0 +1,234 @@
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:2:8
|
LL | if Foo { x: 3 }.hi() {
| ^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if (Foo { x: 3 }).hi() {
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:5:19
|
LL | if let true = Foo { x: 3 }.hi() {
| ^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if let true = (Foo { x: 3 }).hi() {
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:9:14
|
LL | for x in Foo { x: 3 }.hi() {
| ^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | for x in (Foo { x: 3 }).hi() {
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:14:11
|
LL | while Foo { x: 3 }.hi() {
| ^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | while (Foo { x: 3 }).hi() {
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:17:22
|
LL | while let true = Foo { x: 3 }.hi() {
| ^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | while let true = (Foo { x: 3 }).hi() {
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:21:11
|
LL | match Foo { x: 3 } {
| ^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | match (Foo { x: 3 }) {
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:30:17
|
LL | if x == E::I { field1: true, field2: 42 } {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if x == (E::I { field1: true, field2: 42 }) {}
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:32:17
|
LL | if x == E::V { field: false } {}
| ^^^^^^^^^^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if x == (E::V { field: false }) {}
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:34:17
|
LL | if x == E::J { field: -42 } {}
| ^^^^^^^^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if x == (E::J { field: -42 }) {}
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:36:17
|
LL | if x == E::K { field: "" } {}
| ^^^^^^^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if x == (E::K { field: "" }) {}
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:43:14
|
LL | while || Foo { x: 3 }.hi() {
| ^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | while || (Foo { x: 3 }).hi() {
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:53:8
|
LL | if Foo { x: one(), }.hi() {
| ^^^^^^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if (Foo { x: one(), }).hi() {
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:61:15
|
LL | if FOO == self::Foo { x: one() } {}
| ^^^^^^^^^^^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if FOO == (self::Foo { x: one() }) {}
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:63:15
|
LL | if FOO == Foo::<> { x: one() } {}
| ^^^^^^^^^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if FOO == (Foo::<> { x: one() }) {}
| + +
error: struct literals are not allowed here
--> $DIR/struct-literals-in-invalid-places.rs:66:19
|
LL | if FOO == <T as Trait>::Out { x: one() } {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if FOO == (<T as Trait>::Out { x: one() }) {}
| + +
error[E0658]: usage of qualified paths in this context is experimental
--> $DIR/struct-literals-in-invalid-places.rs:66:19
|
LL | if FOO == <T as Trait>::Out { x: one() } {}
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #86935 <https://github.com/rust-lang/rust/issues/86935> for more information
= help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0277]: `bool` is not an iterator
--> $DIR/struct-literals-in-invalid-places.rs:9:14
|
LL | for x in Foo { x: 3 }.hi() {
| ^^^^^^^^^^^^^^^^^ `bool` is not an iterator
|
= help: the trait `Iterator` is not implemented for `bool`
= note: required for `bool` to implement `IntoIterator`
error[E0533]: expected value, found struct variant `E::V`
--> $DIR/struct-literals-in-invalid-places.rs:27:17
|
LL | if x == E::V { field } {}
| ^^^^ not a value
|
help: you might have meant to create a new value of the struct
|
LL | if x == (E::V { field }) {}
| + +
error[E0308]: mismatched types
--> $DIR/struct-literals-in-invalid-places.rs:27:24
|
LL | if x == E::V { field } {}
| ---------------^^^^^--
| | |
| | expected `()`, found `bool`
| expected this to be `()`
|
help: you might have meant to return this value
|
LL | if x == E::V { return field; } {}
| ++++++ +
error[E0308]: mismatched types
--> $DIR/struct-literals-in-invalid-places.rs:38:24
|
LL | let y: usize = ();
| ----- ^^ expected `usize`, found `()`
| |
| expected due to this
error[E0308]: mismatched types
--> $DIR/struct-literals-in-invalid-places.rs:43:11
|
LL | while || Foo { x: 3 }.hi() {
| ^^^^^^^^^^^^^^^^^^^^ expected `bool`, found closure
|
= note: expected type `bool`
found closure `{closure@$DIR/struct-literals-in-invalid-places.rs:43:11: 43:13}`
help: use parentheses to call this closure
|
LL | while (|| Foo { x: 3 }.hi())() {
| + +++
error: aborting due to 21 previous errors
Some errors have detailed explanations: E0277, E0308, E0533, E0658.
For more information about an error, try `rustc --explain E0277`.

View file

@ -1,11 +1,10 @@
fn foo(x: bool) -> i32 { fn foo(x: bool) -> i32 {
match x { match x { //~ ERROR struct literals are not allowed here
x: i32 => x, //~ ERROR expected x: i32 => x, //~ ERROR expected
//~^ ERROR mismatched types true => 42., //~ ERROR expected identifier
true => 42., false => 0.333, //~ ERROR expected identifier
false => 0.333,
} }
} } //~ ERROR expected one of
fn main() { fn main() {
match foo(true) { match foo(true) {

View file

@ -1,18 +1,64 @@
error: expected one of `@` or `|`, found `:` error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, `}`, or an operator, found `=>`
--> $DIR/type-ascription-in-pattern.rs:3:10 --> $DIR/type-ascription-in-pattern.rs:3:16
| |
LL | match x {
| - while parsing this struct
LL | x: i32 => x, LL | x: i32 => x,
| ^ --- specifying the type of a pattern isn't supported | -^^ expected one of 8 possible tokens
| | | |
| expected one of `@` or `|` | help: try adding a comma: `,`
error: expected identifier, found keyword `true`
--> $DIR/type-ascription-in-pattern.rs:4:9
| |
help: maybe write a path separator here LL | match x {
| - while parsing this struct
LL | x: i32 => x,
LL | true => 42.,
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `false`
--> $DIR/type-ascription-in-pattern.rs:5:9
| |
LL | x::i32 => x, LL | match x {
| ~~ | - while parsing this struct
...
LL | false => 0.333,
| ^^^^^ expected identifier, found keyword
error: struct literals are not allowed here
--> $DIR/type-ascription-in-pattern.rs:2:11
|
LL | match x {
| ___________^
LL | | x: i32 => x,
LL | | true => 42.,
LL | | false => 0.333,
LL | | }
| |_____^
|
help: surround the struct literal with parentheses
|
LL ~ match (x {
LL | x: i32 => x,
LL | true => 42.,
LL | false => 0.333,
LL ~ })
|
error: expected one of `.`, `?`, `{`, or an operator, found `}`
--> $DIR/type-ascription-in-pattern.rs:7:1
|
LL | match x {
| ----- while parsing this `match` expression
...
LL | }
| - expected one of `.`, `?`, `{`, or an operator
LL | }
| ^ unexpected token
error: expected one of `...`, `..=`, `..`, or `|`, found `:` error: expected one of `...`, `..=`, `..`, or `|`, found `:`
--> $DIR/type-ascription-in-pattern.rs:12:11 --> $DIR/type-ascription-in-pattern.rs:11:11
| |
LL | 42: i32 => (), LL | 42: i32 => (),
| ^ --- specifying the type of a pattern isn't supported | ^ --- specifying the type of a pattern isn't supported
@ -20,7 +66,7 @@ LL | 42: i32 => (),
| expected one of `...`, `..=`, `..`, or `|` | expected one of `...`, `..=`, `..`, or `|`
error: expected `|`, found `:` error: expected `|`, found `:`
--> $DIR/type-ascription-in-pattern.rs:13:10 --> $DIR/type-ascription-in-pattern.rs:12:10
| |
LL | _: f64 => (), LL | _: f64 => (),
| ^ --- specifying the type of a pattern isn't supported | ^ --- specifying the type of a pattern isn't supported
@ -28,7 +74,7 @@ LL | _: f64 => (),
| expected `|` | expected `|`
error: expected one of `@` or `|`, found `:` error: expected one of `@` or `|`, found `:`
--> $DIR/type-ascription-in-pattern.rs:14:10 --> $DIR/type-ascription-in-pattern.rs:13:10
| |
LL | x: i32 => (), LL | x: i32 => (),
| ^ --- specifying the type of a pattern isn't supported | ^ --- specifying the type of a pattern isn't supported
@ -40,15 +86,5 @@ help: maybe write a path separator here
LL | x::i32 => (), LL | x::i32 => (),
| ~~ | ~~
error[E0308]: mismatched types error: aborting due to 8 previous errors
--> $DIR/type-ascription-in-pattern.rs:3:19
|
LL | fn foo(x: bool) -> i32 {
| --- expected `i32` because of return type
LL | match x {
LL | x: i32 => x,
| ^ expected `i32`, found `bool`
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0308`.