Parse `-> Ty | OtherTy`.
Parse type ascription in top level patterns.
Err,
/// Placeholder for a `va_list`.
CVarArgs,
+ /// Placeholder for "anonymous enums", which don't exist, but keeping their
+ /// information around lets us produce better diagnostics.
+ AnonEnum(Vec<P<Ty>>),
}
impl TyKind {
vis.visit_fn_decl(decl);
vis.visit_span(decl_span);
}
- TyKind::Tup(tys) => visit_vec(tys, |ty| vis.visit_ty(ty)),
+ TyKind::AnonEnum(tys) | TyKind::Tup(tys) => visit_vec(tys, |ty| vis.visit_ty(ty)),
TyKind::Paren(ty) => vis.visit_ty(ty),
TyKind::Path(qself, path) => {
vis.visit_qself(qself);
walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref);
visitor.visit_ty(&mutable_type.ty)
}
- TyKind::Tup(tuple_element_types) => {
- walk_list!(visitor, visit_ty, tuple_element_types);
+ TyKind::AnonEnum(tys) | TyKind::Tup(tys) => {
+ walk_list!(visitor, visit_ty, tys);
}
TyKind::BareFn(function_declaration) => {
walk_list!(visitor, visit_generic_param, &function_declaration.generic_params);
let kind = match &t.kind {
TyKind::Infer => hir::TyKind::Infer,
TyKind::Err => hir::TyKind::Err,
+ TyKind::AnonEnum(_) => hir::TyKind::Err,
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
TyKind::Ref(region, mt) => {
}
self.pclose();
}
+ ast::TyKind::AnonEnum(elts) => {
+ self.strsep("|", false, Inconsistent, elts, |s, ty| s.print_type(ty));
+ }
ast::TyKind::Paren(typ) => {
self.popen();
self.print_type(typ);
/// Some special error handling for the "top-level" patterns in a match arm,
/// `for` loop, `let`, &c. (in contrast to subpatterns within such).
- pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
+ pub(crate) fn maybe_recover_colon_colon_in_pat_typo_or_anon_enum(
&mut self,
mut first_pat: P<Pat>,
expected: Expected,
if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
|| !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
{
+ let mut snapshot_type = self.create_snapshot_for_diagnostic();
+ snapshot_type.bump(); // `:`
+ match snapshot_type.parse_ty() {
+ Err(inner_err) => {
+ inner_err.cancel();
+ }
+ Ok(ty) => {
+ let Err(mut err) = self.expected_one_of_not_found(&[], &[]) else {
+ return first_pat;
+ };
+ err.span_label(ty.span, "specifying the type of a pattern isn't supported");
+ self.restore_snapshot(snapshot_type);
+ let span = first_pat.span.to(ty.span);
+ first_pat = self.mk_pat(span, PatKind::Wild);
+ err.emit();
+ }
+ }
return first_pat;
}
// The pattern looks like it might be a path with a `::` -> `:` typo:
// `match foo { bar:baz => {} }`
- let span = self.token.span;
+ let colon_span = self.token.span;
// We only emit "unexpected `:`" error here if we can successfully parse the
// whole pattern correctly in that case.
- let snapshot = self.create_snapshot_for_diagnostic();
+ let mut snapshot_pat = self.create_snapshot_for_diagnostic();
+ let mut snapshot_type = self.create_snapshot_for_diagnostic();
// Create error for "unexpected `:`".
match self.expected_one_of_not_found(&[], &[]) {
Err(mut err) => {
- self.bump(); // Skip the `:`.
- match self.parse_pat_no_top_alt(expected) {
+ snapshot_pat.bump(); // Skip the `:`.
+ snapshot_type.bump(); // Skip the `:`.
+ match snapshot_pat.parse_pat_no_top_alt(expected) {
Err(inner_err) => {
- // Carry on as if we had not done anything, callers will emit a
- // reasonable error.
inner_err.cancel();
- err.cancel();
- self.restore_snapshot(snapshot);
}
Ok(mut pat) => {
// We've parsed the rest of the pattern.
_ => {}
}
if show_sugg {
- err.span_suggestion(
- span,
+ err.span_suggestion_verbose(
+ colon_span.until(self.look_ahead(1, |t| t.span)),
"maybe write a path separator here",
"::",
Applicability::MaybeIncorrect,
} else {
first_pat = self.mk_pat(new_span, PatKind::Wild);
}
- err.emit();
+ self.restore_snapshot(snapshot_pat);
}
}
+ match snapshot_type.parse_ty() {
+ Err(inner_err) => {
+ inner_err.cancel();
+ }
+ Ok(ty) => {
+ err.span_label(ty.span, "specifying the type of a pattern isn't supported");
+ self.restore_snapshot(snapshot_type);
+ }
+ }
+ err.emit();
}
_ => {
// Carry on as if we had not done anything. This should be unreachable.
- self.restore_snapshot(snapshot);
}
};
first_pat
// Check if the user wrote `foo:bar` instead of `foo::bar`.
if ra == RecoverColon::Yes {
- first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected);
+ first_pat =
+ self.maybe_recover_colon_colon_in_pat_typo_or_anon_enum(first_pat, expected);
}
if let Some(leading_vert_span) = leading_vert_span {
self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
};
+use rustc_ast_pretty::pprust;
use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym, Ident};
No,
}
-#[derive(PartialEq)]
+#[derive(PartialEq, Clone, Copy)]
pub(super) enum RecoverQPath {
Yes,
No,
}
+#[derive(PartialEq, Clone, Copy)]
pub(super) enum RecoverQuestionMark {
Yes,
No,
}
+#[derive(PartialEq, Clone, Copy)]
+pub(super) enum RecoverAnonEnum {
+ Yes,
+ No,
+}
+
/// Signals whether parsing a type should recover `->`.
///
/// More specifically, when parsing a function like:
}
// Is `...` (`CVarArgs`) legal at this level of type parsing?
-#[derive(PartialEq)]
+#[derive(PartialEq, Clone, Copy)]
enum AllowCVariadic {
Yes,
No,
RecoverReturnSign::Yes,
None,
RecoverQuestionMark::Yes,
+ RecoverAnonEnum::No,
)
}
RecoverReturnSign::Yes,
Some(ty_params),
RecoverQuestionMark::Yes,
+ RecoverAnonEnum::No,
)
}
RecoverReturnSign::Yes,
None,
RecoverQuestionMark::Yes,
+ RecoverAnonEnum::Yes,
)
}
RecoverReturnSign::Yes,
None,
RecoverQuestionMark::Yes,
+ RecoverAnonEnum::No,
)
}
RecoverReturnSign::Yes,
None,
RecoverQuestionMark::No,
+ RecoverAnonEnum::No,
)
}
RecoverReturnSign::Yes,
None,
RecoverQuestionMark::No,
+ RecoverAnonEnum::No,
)
}
RecoverReturnSign::OnlyFatArrow,
None,
RecoverQuestionMark::Yes,
+ RecoverAnonEnum::No,
)
}
recover_return_sign,
None,
RecoverQuestionMark::Yes,
+ RecoverAnonEnum::Yes,
)?;
FnRetTy::Ty(ty)
} else if recover_return_sign.can_recover(&self.token.kind) {
recover_return_sign,
None,
RecoverQuestionMark::Yes,
+ RecoverAnonEnum::Yes,
)?;
FnRetTy::Ty(ty)
} else {
recover_return_sign: RecoverReturnSign,
ty_generics: Option<&Generics>,
recover_question_mark: RecoverQuestionMark,
+ recover_anon_enum: RecoverAnonEnum,
) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
let mut ty = self.mk_ty(span, kind);
// Try to recover from use of `+` with incorrect priority.
- if matches!(allow_plus, AllowPlus::Yes) {
+ if allow_plus == AllowPlus::Yes {
self.maybe_recover_from_bad_type_plus(&ty)?;
} else {
self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty);
}
- if let RecoverQuestionMark::Yes = recover_question_mark {
+ if RecoverQuestionMark::Yes == recover_question_mark {
ty = self.maybe_recover_from_question_mark(ty);
}
+ if recover_anon_enum == RecoverAnonEnum::Yes
+ && self.check_noexpect(&token::BinOp(token::Or))
+ && self.look_ahead(1, |t| t.can_begin_type())
+ {
+ let mut pipes = vec![self.token.span];
+ let mut types = vec![ty];
+ loop {
+ if !self.eat(&token::BinOp(token::Or)) {
+ break;
+ }
+ pipes.push(self.prev_token.span);
+ types.push(self.parse_ty_common(
+ allow_plus,
+ allow_c_variadic,
+ recover_qpath,
+ recover_return_sign,
+ ty_generics,
+ recover_question_mark,
+ RecoverAnonEnum::No,
+ )?);
+ }
+ let mut err = self.struct_span_err(pipes, "anonymous enums are not supported");
+ for ty in &types {
+ err.span_label(ty.span, "");
+ }
+ err.help(&format!(
+ "create a named `enum` and use it here instead:\nenum Name {{\n{}\n}}",
+ types
+ .iter()
+ .enumerate()
+ .map(|(i, t)| format!(
+ " Variant{}({}),",
+ i + 1, // Lets not confuse people with zero-indexing :)
+ pprust::to_string(|s| s.print_type(&t)),
+ ))
+ .collect::<Vec<_>>()
+ .join("\n"),
+ ));
+ err.emit();
+ return Ok(self.mk_ty(lo.to(self.prev_token.span), TyKind::AnonEnum(types)));
+ }
if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
}
[
Slice,
Array,
+ AnonEnum,
Ptr,
Ref,
BareFn,
})
}
ast::TyKind::CVarArgs => Some("...".to_owned()),
- ast::TyKind::Err => Some(context.snippet(self.span).to_owned()),
+ ast::TyKind::AnonEnum(_) | ast::TyKind::Err => {
+ Some(context.snippet(self.span).to_owned())
+ }
ast::TyKind::Typeof(ref anon_const) => rewrite_call(
context,
"typeof",
--- /dev/null
+fn foo(x: bool | i32) -> i32 | f64 {
+//~^ ERROR anonymous enums are not supported
+//~| ERROR anonymous enums are not supported
+ match x {
+ x: i32 => x, //~ ERROR expected
+ //~^ ERROR failed to resolve
+ true => 42.,
+ false => 0.333,
+ }
+}
+
+fn main() {
+ match foo(true) {
+ 42: i32 => (), //~ ERROR expected
+ _: f64 => (), //~ ERROR expected
+ x: i32 => (), //~ ERROR expected
+ //~^ ERROR failed to resolve
+ }
+}
--- /dev/null
+error: anonymous enums are not supported
+ --> $DIR/anon-enums.rs:1:16
+ |
+LL | fn foo(x: bool | i32) -> i32 | f64 {
+ | ---- ^ ---
+ |
+ = help: create a named `enum` and use it here instead:
+ enum Name {
+ Variant1(bool),
+ Variant2(i32),
+ }
+
+error: anonymous enums are not supported
+ --> $DIR/anon-enums.rs:1:30
+ |
+LL | fn foo(x: bool | i32) -> i32 | f64 {
+ | --- ^ ---
+ |
+ = help: create a named `enum` and use it here instead:
+ enum Name {
+ Variant1(i32),
+ Variant2(f64),
+ }
+
+error: expected one of `@` or `|`, found `:`
+ --> $DIR/anon-enums.rs:5:10
+ |
+LL | x: i32 => x,
+ | ^ --- specifying the type of a pattern isn't supported
+ | |
+ | expected one of `@` or `|`
+ |
+help: maybe write a path separator here
+ |
+LL | x::i32 => x,
+ | ~~
+
+error: expected one of `...`, `..=`, `..`, or `|`, found `:`
+ --> $DIR/anon-enums.rs:14:11
+ |
+LL | 42: i32 => (),
+ | ^ --- specifying the type of a pattern isn't supported
+ | |
+ | expected one of `...`, `..=`, `..`, or `|`
+
+error: expected `|`, found `:`
+ --> $DIR/anon-enums.rs:15:10
+ |
+LL | _: f64 => (),
+ | ^ --- specifying the type of a pattern isn't supported
+ | |
+ | expected `|`
+
+error: expected one of `@` or `|`, found `:`
+ --> $DIR/anon-enums.rs:16:10
+ |
+LL | x: i32 => (),
+ | ^ --- specifying the type of a pattern isn't supported
+ | |
+ | expected one of `@` or `|`
+ |
+help: maybe write a path separator here
+ |
+LL | x::i32 => (),
+ | ~~
+
+error[E0433]: failed to resolve: use of undeclared crate or module `x`
+ --> $DIR/anon-enums.rs:5:9
+ |
+LL | x: i32 => x,
+ | ^ use of undeclared crate or module `x`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `x`
+ --> $DIR/anon-enums.rs:16:9
+ |
+LL | x: i32 => (),
+ | ^ use of undeclared crate or module `x`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
--> $DIR/issue-87086-colon-path-sep.rs:17:12
|
LL | Foo:Bar => {}
- | ^
+ | ^--- specifying the type of a pattern isn't supported
| |
| expected one of `@` or `|`
- | help: maybe write a path separator here: `::`
+ |
+help: maybe write a path separator here
+ |
+LL | Foo::Bar => {}
+ | ~~
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:23:17
|
LL | qux::Foo:Bar => {}
- | ^
+ | ^--- specifying the type of a pattern isn't supported
| |
| expected one of 8 possible tokens
- | help: maybe write a path separator here: `::`
+ |
+help: maybe write a path separator here
+ |
+LL | qux::Foo::Bar => {}
+ | ~~
error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:29:12
|
LL | qux:Foo::Baz => {}
- | ^
+ | ^-------- specifying the type of a pattern isn't supported
| |
| expected one of `@` or `|`
- | help: maybe write a path separator here: `::`
+ |
+help: maybe write a path separator here
+ |
+LL | qux::Foo::Baz => {}
+ | ~~
error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:35:12
|
LL | qux: Foo::Baz if true => {}
- | ^
+ | ^ -------- specifying the type of a pattern isn't supported
| |
| expected one of `@` or `|`
- | help: maybe write a path separator here: `::`
+ |
+help: maybe write a path separator here
+ |
+LL | qux::Foo::Baz if true => {}
+ | ~~
error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:40:15
|
LL | if let Foo:Bar = f() {
- | ^
+ | ^--- specifying the type of a pattern isn't supported
| |
| expected one of `@` or `|`
- | help: maybe write a path separator here: `::`
+ |
+help: maybe write a path separator here
+ |
+LL | if let Foo::Bar = f() {
+ | ~~
error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:48:16
|
LL | ref qux: Foo::Baz => {}
- | ^
+ | ^ -------- specifying the type of a pattern isn't supported
| |
| expected one of `@` or `|`
- | help: maybe write a path separator here: `::`
+ |
+help: maybe write a path separator here
+ |
+LL | ref qux::Foo::Baz => {}
+ | ~~
error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:57:16
|
LL | mut qux: Foo::Baz => {}
- | ^
+ | ^ -------- specifying the type of a pattern isn't supported
| |
| expected one of `@` or `|`
- | help: maybe write a path separator here: `::`
+ |
+help: maybe write a path separator here
+ |
+LL | mut qux::Foo::Baz => {}
+ | ~~
error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:68:12
|
LL | Foo:Bar::Baz => {}
- | ^
+ | ^-------- specifying the type of a pattern isn't supported
| |
| expected one of `@` or `|`
- | help: maybe write a path separator here: `::`
+ |
+help: maybe write a path separator here
+ |
+LL | Foo::Bar::Baz => {}
+ | ~~
error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:75:12
|
LL | Foo:Bar => {}
- | ^
+ | ^--- specifying the type of a pattern isn't supported
| |
| expected one of `@` or `|`
- | help: maybe write a path separator here: `::`
+ |
+help: maybe write a path separator here
+ |
+LL | Foo::Bar => {}
+ | ~~
error[E0433]: failed to resolve: `Bar` is a variant, not a module
--> $DIR/issue-87086-colon-path-sep.rs:68:13