mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Remove NtTy.
Notes about tests: - tests/ui/parser/macro/trait-object-macro-matcher.rs: the syntax error is duplicated, because it occurs now when parsing the decl macro input, and also when parsing the expanded decl macro. But this won't show up for normal users due to error de-duplication. - tests/ui/associated-consts/issue-93835.rs: similar, plus there are some additional errors about this very broken code. - The changes to metavariable descriptions in #132629 are now visible in error message for several tests.
This commit is contained in:
@@ -203,7 +203,6 @@ fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
Nonterminal::NtStmt(stmt) => stmt.tokens(),
|
||||
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(),
|
||||
Nonterminal::NtPat(pat) => pat.tokens(),
|
||||
Nonterminal::NtTy(ty) => ty.tokens(),
|
||||
Nonterminal::NtMeta(attr_item) => attr_item.tokens(),
|
||||
Nonterminal::NtPath(path) => path.tokens(),
|
||||
Nonterminal::NtBlock(block) => block.tokens(),
|
||||
@@ -215,7 +214,6 @@ fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||
Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
|
||||
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
|
||||
Nonterminal::NtPat(pat) => pat.tokens_mut(),
|
||||
Nonterminal::NtTy(ty) => ty.tokens_mut(),
|
||||
Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
|
||||
Nonterminal::NtPath(path) => path.tokens_mut(),
|
||||
Nonterminal::NtBlock(block) => block.tokens_mut(),
|
||||
|
||||
@@ -907,7 +907,6 @@ fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
|
||||
}),
|
||||
token::NtPat(pat) => vis.visit_pat(pat),
|
||||
token::NtExpr(expr) => vis.visit_expr(expr),
|
||||
token::NtTy(ty) => vis.visit_ty(ty),
|
||||
token::NtLiteral(expr) => vis.visit_expr(expr),
|
||||
token::NtMeta(item) => {
|
||||
let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut();
|
||||
|
||||
@@ -659,7 +659,6 @@ pub fn can_begin_pattern(&self, pat_kind: NtPatKind) -> bool {
|
||||
| NtMeta(..)
|
||||
| NtPat(..)
|
||||
| NtPath(..)
|
||||
| NtTy(..)
|
||||
),
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Expr { .. } |
|
||||
@@ -688,7 +687,7 @@ pub fn can_begin_type(&self) -> bool {
|
||||
Lifetime(..) | // lifetime bound in trait object
|
||||
Lt | BinOp(Shl) | // associated path
|
||||
PathSep => true, // global path
|
||||
Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
|
||||
Interpolated(ref nt) => matches!(&**nt, NtPath(..)),
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Ty |
|
||||
MetaVarKind::Path
|
||||
@@ -1076,7 +1075,6 @@ pub enum Nonterminal {
|
||||
NtStmt(P<ast::Stmt>),
|
||||
NtPat(P<ast::Pat>),
|
||||
NtExpr(P<ast::Expr>),
|
||||
NtTy(P<ast::Ty>),
|
||||
NtLiteral(P<ast::Expr>),
|
||||
/// Stuff inside brackets for attributes
|
||||
NtMeta(P<ast::AttrItem>),
|
||||
@@ -1174,7 +1172,6 @@ pub fn use_span(&self) -> Span {
|
||||
NtStmt(stmt) => stmt.span,
|
||||
NtPat(pat) => pat.span,
|
||||
NtExpr(expr) | NtLiteral(expr) => expr.span,
|
||||
NtTy(ty) => ty.span,
|
||||
NtMeta(attr_item) => attr_item.span(),
|
||||
NtPath(path) => path.span,
|
||||
}
|
||||
@@ -1188,7 +1185,6 @@ pub fn descr(&self) -> &'static str {
|
||||
NtPat(..) => "pattern",
|
||||
NtExpr(..) => "expression",
|
||||
NtLiteral(..) => "literal",
|
||||
NtTy(..) => "type",
|
||||
NtMeta(..) => "attribute",
|
||||
NtPath(..) => "path",
|
||||
}
|
||||
@@ -1213,7 +1209,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
NtStmt(..) => f.pad("NtStmt(..)"),
|
||||
NtPat(..) => f.pad("NtPat(..)"),
|
||||
NtExpr(..) => f.pad("NtExpr(..)"),
|
||||
NtTy(..) => f.pad("NtTy(..)"),
|
||||
NtLiteral(..) => f.pad("NtLiteral(..)"),
|
||||
NtMeta(..) => f.pad("NtMeta(..)"),
|
||||
NtPath(..) => f.pad("NtPath(..)"),
|
||||
|
||||
@@ -469,7 +469,6 @@ pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
|
||||
}
|
||||
Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt),
|
||||
Nonterminal::NtPat(pat) => TokenStream::from_ast(pat),
|
||||
Nonterminal::NtTy(ty) => TokenStream::from_ast(ty),
|
||||
Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr),
|
||||
Nonterminal::NtPath(path) => TokenStream::from_ast(path),
|
||||
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr),
|
||||
|
||||
@@ -322,6 +322,9 @@ pub(super) fn transcribe<'a>(
|
||||
let kind = token::NtLifetime(*ident, *is_raw);
|
||||
TokenTree::token_alone(kind, sp)
|
||||
}
|
||||
MatchedSingle(ParseNtResult::Ty(ty)) => {
|
||||
mk_delimited(MetaVarKind::Ty, TokenStream::from_ast(ty))
|
||||
}
|
||||
MatchedSingle(ParseNtResult::Vis(vis)) => {
|
||||
mk_delimited(MetaVarKind::Vis, TokenStream::from_ast(vis))
|
||||
}
|
||||
|
||||
@@ -117,12 +117,16 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
|
||||
($self: expr, $allow_qpath_recovery: expr) => {
|
||||
if $allow_qpath_recovery
|
||||
&& $self.may_recover()
|
||||
&& $self.look_ahead(1, |t| t == &token::PathSep)
|
||||
&& let token::Interpolated(nt) = &$self.token.kind
|
||||
&& let token::NtTy(ty) = &**nt
|
||||
&& let Some(token::MetaVarKind::Ty) = $self.token.is_metavar_seq()
|
||||
&& $self.check_noexpect_past_close_delim(&token::PathSep)
|
||||
{
|
||||
let ty = ty.clone();
|
||||
$self.bump();
|
||||
// Reparse the type, then move to recovery.
|
||||
let ty = $self
|
||||
.eat_metavar_seq(token::MetaVarKind::Ty, |this| {
|
||||
this.parse_ty_no_question_mark_recover()
|
||||
})
|
||||
.expect("metavar seq ty");
|
||||
|
||||
return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_token.span, ty);
|
||||
}
|
||||
};
|
||||
@@ -614,6 +618,24 @@ fn check_noexpect(&self, tok: &TokenKind) -> bool {
|
||||
self.token == *tok
|
||||
}
|
||||
|
||||
// Check the first token after the delimiter that closes the current
|
||||
// delimited sequence. (Panics if used in the outermost token stream, which
|
||||
// has no delimiters.) It uses a clone of the relevant tree cursor to skip
|
||||
// past the entire `TokenTree::Delimited` in a single step, avoiding the
|
||||
// need for unbounded token lookahead.
|
||||
//
|
||||
// Primarily used when `self.token` matches
|
||||
// `OpenDelim(Delimiter::Invisible(_))`, to look ahead through the current
|
||||
// metavar expansion.
|
||||
fn check_noexpect_past_close_delim(&self, tok: &TokenKind) -> bool {
|
||||
let mut tree_cursor = self.token_cursor.stack.last().unwrap().clone();
|
||||
tree_cursor.bump();
|
||||
matches!(
|
||||
tree_cursor.curr(),
|
||||
Some(TokenTree::Token(token::Token { kind, .. }, _)) if kind == tok
|
||||
)
|
||||
}
|
||||
|
||||
/// Consumes a token 'tok' if it exists. Returns whether the given token was present.
|
||||
///
|
||||
/// the main purpose of this function is to reduce the cluttering of the suggestions list
|
||||
@@ -1724,6 +1746,7 @@ pub enum ParseNtResult {
|
||||
Tt(TokenTree),
|
||||
Ident(Ident, IdentIsRaw),
|
||||
Lifetime(Ident, IdentIsRaw),
|
||||
Ty(P<ast::Ty>),
|
||||
Vis(P<ast::Visibility>),
|
||||
|
||||
/// This variant will eventually be removed, along with `Token::Interpolate`.
|
||||
|
||||
@@ -51,7 +51,6 @@ fn nt_may_be_ident(nt: &Nonterminal) -> bool {
|
||||
NtStmt(_)
|
||||
| NtPat(_)
|
||||
| NtExpr(_)
|
||||
| NtTy(_)
|
||||
| NtLiteral(_) // `true`, `false`
|
||||
| NtMeta(_)
|
||||
| NtPath(_) => true,
|
||||
@@ -100,7 +99,7 @@ fn nt_may_be_ident(nt: &Nonterminal) -> bool {
|
||||
token::NtLifetime(..) => true,
|
||||
token::Interpolated(nt) => match &**nt {
|
||||
NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
|
||||
NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) => false,
|
||||
NtItem(_) | NtPat(_) | NtMeta(_) | NtPath(_) => false,
|
||||
},
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k {
|
||||
MetaVarKind::Block
|
||||
@@ -187,7 +186,9 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseN
|
||||
NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?)
|
||||
}
|
||||
NonterminalKind::Ty => {
|
||||
NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?)
|
||||
return Ok(ParseNtResult::Ty(
|
||||
self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?,
|
||||
));
|
||||
}
|
||||
// this could be handled like a token, since it is one
|
||||
NonterminalKind::Ident => {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use ast::token::IdentIsRaw;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::token::{self, Delimiter, MetaVarKind, Token, TokenKind};
|
||||
use rustc_ast::{
|
||||
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint,
|
||||
AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
|
||||
@@ -196,13 +196,14 @@ pub(super) fn parse_path_inner(
|
||||
|
||||
maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner()));
|
||||
|
||||
if let token::Interpolated(nt) = &self.token.kind {
|
||||
if let token::NtTy(ty) = &**nt {
|
||||
if let ast::TyKind::Path(None, path) = &ty.kind {
|
||||
let path = path.clone();
|
||||
self.bump();
|
||||
return Ok(reject_generics_if_mod_style(self, path));
|
||||
}
|
||||
if let Some(MetaVarKind::Ty) = self.token.is_metavar_seq() {
|
||||
let mut snapshot = self.create_snapshot_for_diagnostic();
|
||||
let ty = snapshot
|
||||
.eat_metavar_seq(MetaVarKind::Ty, |this| this.parse_ty_no_question_mark_recover())
|
||||
.expect("metavar seq ty");
|
||||
if let ast::TyKind::Path(None, path) = ty.into_inner().kind {
|
||||
self.restore_snapshot(snapshot);
|
||||
return Ok(reject_generics_if_mod_style(self, path));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token, TokenKind};
|
||||
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, MetaVarKind, Token, TokenKind};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
|
||||
@@ -18,7 +18,7 @@
|
||||
HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
|
||||
NestedCVariadicType, ReturnTypesUseThinArrow,
|
||||
};
|
||||
use crate::{exp, maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||
use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
|
||||
|
||||
/// Signals whether parsing a type should allow `+`.
|
||||
///
|
||||
@@ -183,7 +183,8 @@ pub(super) fn parse_ty_no_question_mark_recover(&mut self) -> PResult<'a, P<Ty>>
|
||||
)
|
||||
}
|
||||
|
||||
/// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>`
|
||||
/// Parse a type without recovering `:` as `->` to avoid breaking code such
|
||||
/// as `where fn() : for<'a>`.
|
||||
pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
|
||||
self.parse_ty_common(
|
||||
AllowPlus::Yes,
|
||||
@@ -247,7 +248,12 @@ fn parse_ty_common(
|
||||
) -> PResult<'a, P<Ty>> {
|
||||
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
|
||||
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
|
||||
maybe_whole!(self, NtTy, |ty| ty);
|
||||
|
||||
if let Some(ty) =
|
||||
self.eat_metavar_seq(MetaVarKind::Ty, |this| this.parse_ty_no_question_mark_recover())
|
||||
{
|
||||
return Ok(ty);
|
||||
}
|
||||
|
||||
let lo = self.token.span;
|
||||
let mut impl_dyn_multi = false;
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
fn e() {
|
||||
type_ascribe!(p, a<p:p<e=6>>);
|
||||
//~^ ERROR cannot find type `a` in this scope
|
||||
//~| ERROR path separator must be a double colon
|
||||
//~| ERROR cannot find value
|
||||
//~| ERROR associated const equality
|
||||
//~| ERROR cannot find trait `p` in this scope
|
||||
//~| ERROR associated const equality
|
||||
//~| ERROR failed to resolve: use of unresolved module or unlinked crate `p`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
error: path separator must be a double colon
|
||||
--> $DIR/issue-93835.rs:4:25
|
||||
|
|
||||
LL | type_ascribe!(p, a<p:p<e=6>>);
|
||||
| ^
|
||||
|
|
||||
= note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
|
||||
help: use a double colon instead
|
||||
|
|
||||
LL | type_ascribe!(p, a<p::p<e=6>>);
|
||||
| +
|
||||
|
||||
error[E0425]: cannot find value `p` in this scope
|
||||
--> $DIR/issue-93835.rs:4:19
|
||||
|
|
||||
@@ -10,12 +22,6 @@ error[E0412]: cannot find type `a` in this scope
|
||||
LL | type_ascribe!(p, a<p:p<e=6>>);
|
||||
| ^ not found in this scope
|
||||
|
||||
error[E0405]: cannot find trait `p` in this scope
|
||||
--> $DIR/issue-93835.rs:4:26
|
||||
|
|
||||
LL | type_ascribe!(p, a<p:p<e=6>>);
|
||||
| ^ not found in this scope
|
||||
|
||||
error[E0658]: associated const equality is incomplete
|
||||
--> $DIR/issue-93835.rs:4:28
|
||||
|
|
||||
@@ -26,7 +32,26 @@ LL | type_ascribe!(p, a<p:p<e=6>>);
|
||||
= help: add `#![feature(associated_const_equality)]` 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: aborting due to 4 previous errors
|
||||
error[E0658]: associated const equality is incomplete
|
||||
--> $DIR/issue-93835.rs:4:28
|
||||
|
|
||||
LL | type_ascribe!(p, a<p:p<e=6>>);
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
|
||||
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
Some errors have detailed explanations: E0405, E0412, E0425, E0658.
|
||||
For more information about an error, try `rustc --explain E0405`.
|
||||
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `p`
|
||||
--> $DIR/issue-93835.rs:4:24
|
||||
|
|
||||
LL | type_ascribe!(p, a<p:p<e=6>>);
|
||||
| ^ use of unresolved module or unlinked crate `p`
|
||||
|
|
||||
= help: you might be missing a crate named `p`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0412, E0425, E0433, E0658.
|
||||
For more information about an error, try `rustc --explain E0412`.
|
||||
|
||||
@@ -19,7 +19,7 @@ macro_rules! qpath {
|
||||
|
||||
(ty, <$type:ty as $trait:ty>::$name:ident) => {
|
||||
<$type as $trait>::$name
|
||||
//~^ ERROR expected identifier, found `!`
|
||||
//~^ ERROR expected identifier, found metavariable
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error: expected identifier, found `!`
|
||||
error: expected identifier, found metavariable
|
||||
--> $DIR/macro-interpolation.rs:21:19
|
||||
|
|
||||
LL | <$type as $trait>::$name
|
||||
| ^^^^^^ expected identifier
|
||||
| ^^^^^^ expected identifier, found metavariable
|
||||
...
|
||||
LL | let _: qpath!(ty, <str as !>::Owned);
|
||||
| -----------------------------
|
||||
|
||||
@@ -9,8 +9,8 @@ pub enum TokenKind {
|
||||
}
|
||||
};
|
||||
}
|
||||
//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)`
|
||||
//~| ERROR macro expansion ignores type `(String)` and any tokens following
|
||||
//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable
|
||||
//~| ERROR macro expansion ignores `ty` metavariable and any tokens following
|
||||
|
||||
values!(STRING(1) as (String) => cfg(test),);
|
||||
//~^ ERROR expected one of `!` or `::`, found `<eof>`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
error: expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)`
|
||||
error: expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable
|
||||
--> $DIR/syntax-error-recovery.rs:7:26
|
||||
|
|
||||
LL | $token $($inner)? = $value,
|
||||
@@ -10,7 +10,7 @@ LL | values!(STRING(1) as (String) => cfg(test),);
|
||||
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||
= note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: macro expansion ignores type `(String)` and any tokens following
|
||||
error: macro expansion ignores `ty` metavariable and any tokens following
|
||||
--> $DIR/syntax-error-recovery.rs:7:26
|
||||
|
|
||||
LL | $token $($inner)? = $value,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
macro_rules! test_macro {
|
||||
( $( $t:ty ),* $(),*) => {
|
||||
enum SomeEnum {
|
||||
$( $t, )* //~ ERROR expected identifier, found `String`
|
||||
$( $t, )* //~ ERROR expected identifier, found metavariable
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
error: expected identifier, found `String`
|
||||
error: expected identifier, found metavariable
|
||||
--> $DIR/issue-37113.rs:4:16
|
||||
|
|
||||
LL | enum SomeEnum {
|
||||
| -------- while parsing this enum
|
||||
LL | $( $t, )*
|
||||
| ^^ expected identifier
|
||||
| ^^ expected identifier, found metavariable
|
||||
...
|
||||
LL | test_macro!(String,);
|
||||
| -------------------- in this macro invocation
|
||||
|
||||
@@ -10,5 +10,6 @@ macro_rules! m {
|
||||
fn main() {
|
||||
m!('static);
|
||||
//~^ ERROR lifetime in trait object type must be followed by `+`
|
||||
//~| ERROR lifetime in trait object type must be followed by `+`
|
||||
//~| ERROR at least one trait is required for an object type
|
||||
}
|
||||
|
||||
@@ -4,12 +4,20 @@ error: lifetime in trait object type must be followed by `+`
|
||||
LL | m!('static);
|
||||
| ^^^^^^^
|
||||
|
||||
error: lifetime in trait object type must be followed by `+`
|
||||
--> $DIR/trait-object-macro-matcher.rs:11:8
|
||||
|
|
||||
LL | m!('static);
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0224]: at least one trait is required for an object type
|
||||
--> $DIR/trait-object-macro-matcher.rs:11:8
|
||||
|
|
||||
LL | m!('static);
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0224`.
|
||||
|
||||
Reference in New Issue
Block a user