Auto merge of #149136 - BoxyUwU:mgca_explicit_anon_consts, r=oli-obk
MGCA: Syntactically distinguish anon const const args r? oli-obk tracking issue: rust-lang/rust#132980 This PR requires that when `feature(min_generic_const_args)` is enabled, anon const const args are *syntactically* distinguishable from other kinds of args. We use `const { ... }` in const argument position to denote an anon const: ```rust #![feature(min_generic_const_args)] // no longer allowed as `1 + 1` is represented via an anon const and // there is no syntactic marker type Foo = [(); 1 + 1]; // allowed, `const { ... }` indicates an anon const representation type Foo = [(); const { 1 + 1 }]; ``` This restriction is only placed when mgca is enabled. There should be no effect on stable. This restriction is not enforced for unbraced literals which we continue to implicitly wrap in an anon const: `tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs` This restriction allows us to create `DefId`s for anon consts only when actually required. When it is syntactically ambiguous whether a const argument is an anon const or not we are forced to conservatively create a `DefId` for every const argument even if it doesn't wind up needing one. This works fine on stable but under `mgca` we can wind up with anon consts nested inside non-anon-const const arguments resulting in a broken `DefId` tree. See rust-lang/rust#148838 where an anon const arg inside of a path arg winds up with a parent of a conservatively created `DefId` that doesn't actually correspond to an anon const, resulting in an ICE. With rust-lang/rust#149114 every field initialiser in a const argument would become a place where there could *possibly* be an anon const. This would also get worse once we support tuple constructors- now every function argument is a place where there could possibly be an anon const. We introduce this restriction to avoid creating massive amounts of unused `DefId`s that make the parent tree significantly more complicated, and to avoid having to paper over this issue in things like `generics_of`. Fixes rust-lang/rust#148838 It also must be syntactically clear from context whether `'_` means an inference lifetime or an elided lifetime parameter. This restriction will allow us to properly resolve `'_` in const arguments in mgca. This PR doesn't actually fix handle this, but we could do so trivially after this lands.
This commit is contained in:
commit
dc47a69ed9
48 changed files with 779 additions and 252 deletions
|
|
@ -141,16 +141,11 @@ impl Path {
|
|||
/// Check if this path is potentially a trivial const arg, i.e., one that can _potentially_
|
||||
/// be represented without an anon const in the HIR.
|
||||
///
|
||||
/// If `allow_mgca_arg` is true (as should be the case in most situations when
|
||||
/// `#![feature(min_generic_const_args)]` is enabled), then this always returns true
|
||||
/// because all paths are valid.
|
||||
///
|
||||
/// Otherwise, it returns true iff the path has exactly one segment, and it has no generic args
|
||||
/// Returns true iff the path has exactly one segment, and it has no generic args
|
||||
/// (i.e., it is _potentially_ a const parameter).
|
||||
#[tracing::instrument(level = "debug", ret)]
|
||||
pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool {
|
||||
allow_mgca_arg
|
||||
|| self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none())
|
||||
pub fn is_potential_trivial_const_arg(&self) -> bool {
|
||||
self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1385,6 +1380,15 @@ pub enum UnsafeSource {
|
|||
UserProvided,
|
||||
}
|
||||
|
||||
/// Track whether under `feature(min_generic_const_args)` this anon const
|
||||
/// was explicitly disambiguated as an anon const or not through the use of
|
||||
/// `const { ... }` syntax.
|
||||
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Walkable)]
|
||||
pub enum MgcaDisambiguation {
|
||||
AnonConst,
|
||||
Direct,
|
||||
}
|
||||
|
||||
/// A constant (expression) that's not an item or associated item,
|
||||
/// but needs its own `DefId` for type-checking, const-eval, etc.
|
||||
/// These are usually found nested inside types (e.g., array lengths)
|
||||
|
|
@ -1394,6 +1398,7 @@ pub enum UnsafeSource {
|
|||
pub struct AnonConst {
|
||||
pub id: NodeId,
|
||||
pub value: Box<Expr>,
|
||||
pub mgca_disambiguation: MgcaDisambiguation,
|
||||
}
|
||||
|
||||
/// An expression.
|
||||
|
|
@ -1412,26 +1417,20 @@ impl Expr {
|
|||
///
|
||||
/// This will unwrap at most one block level (curly braces). After that, if the expression
|
||||
/// is a path, it mostly dispatches to [`Path::is_potential_trivial_const_arg`].
|
||||
/// See there for more info about `allow_mgca_arg`.
|
||||
///
|
||||
/// The only additional thing to note is that when `allow_mgca_arg` is false, this function
|
||||
/// will only allow paths with no qself, before dispatching to the `Path` function of
|
||||
/// the same name.
|
||||
/// This function will only allow paths with no qself, before dispatching to the `Path`
|
||||
/// function of the same name.
|
||||
///
|
||||
/// Does not ensure that the path resolves to a const param/item, the caller should check this.
|
||||
/// This also does not consider macros, so it's only correct after macro-expansion.
|
||||
pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool {
|
||||
pub fn is_potential_trivial_const_arg(&self) -> bool {
|
||||
let this = self.maybe_unwrap_block();
|
||||
if allow_mgca_arg {
|
||||
matches!(this.kind, ExprKind::Path(..))
|
||||
if let ExprKind::Path(None, path) = &this.kind
|
||||
&& path.is_potential_trivial_const_arg()
|
||||
{
|
||||
true
|
||||
} else {
|
||||
if let ExprKind::Path(None, path) = &this.kind
|
||||
&& path.is_potential_trivial_const_arg(allow_mgca_arg)
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -415,6 +415,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
UnsafeBinderCastKind,
|
||||
BinOpKind,
|
||||
BlockCheckMode,
|
||||
MgcaDisambiguation,
|
||||
BorrowKind,
|
||||
BoundAsyncness,
|
||||
BoundConstness,
|
||||
|
|
|
|||
|
|
@ -489,7 +489,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
arg
|
||||
};
|
||||
|
||||
let anon_const = AnonConst { id: node_id, value: const_value };
|
||||
let anon_const = AnonConst {
|
||||
id: node_id,
|
||||
value: const_value,
|
||||
mgca_disambiguation: MgcaDisambiguation::AnonConst,
|
||||
};
|
||||
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
|
||||
} else {
|
||||
real_args.push(arg);
|
||||
|
|
|
|||
|
|
@ -1219,7 +1219,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
.and_then(|partial_res| partial_res.full_res())
|
||||
{
|
||||
if !res.matches_ns(Namespace::TypeNS)
|
||||
&& path.is_potential_trivial_const_arg(false)
|
||||
&& path.is_potential_trivial_const_arg()
|
||||
{
|
||||
debug!(
|
||||
"lower_generic_arg: Lowering type argument as const argument: {:?}",
|
||||
|
|
@ -2287,11 +2287,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
) -> &'hir hir::ConstArg<'hir> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
let ct_kind = if path
|
||||
.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
|
||||
&& (tcx.features().min_generic_const_args()
|
||||
|| matches!(res, Res::Def(DefKind::ConstParam, _)))
|
||||
{
|
||||
let is_trivial_path = path.is_potential_trivial_const_arg()
|
||||
&& matches!(res, Res::Def(DefKind::ConstParam, _));
|
||||
let ct_kind = if is_trivial_path || tcx.features().min_generic_const_args() {
|
||||
let qpath = self.lower_qpath(
|
||||
ty_id,
|
||||
&None,
|
||||
|
|
@ -2370,6 +2368,53 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> {
|
||||
let overly_complex_const = |this: &mut Self| {
|
||||
let e = this.dcx().struct_span_err(
|
||||
expr.span,
|
||||
"complex const arguments must be placed inside of a `const` block",
|
||||
);
|
||||
|
||||
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(expr.span, e.emit()) }
|
||||
};
|
||||
|
||||
match &expr.kind {
|
||||
ExprKind::Path(qself, path) => {
|
||||
let qpath = self.lower_qpath(
|
||||
expr.id,
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Explicit,
|
||||
AllowReturnTypeNotation::No,
|
||||
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) }
|
||||
}
|
||||
ExprKind::Underscore => ConstArg {
|
||||
hir_id: self.lower_node_id(expr.id),
|
||||
kind: hir::ConstArgKind::Infer(expr.span, ()),
|
||||
},
|
||||
ExprKind::Block(block, _) => {
|
||||
if let [stmt] = block.stmts.as_slice()
|
||||
&& let StmtKind::Expr(expr) = &stmt.kind
|
||||
&& matches!(
|
||||
expr.kind,
|
||||
ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..)
|
||||
)
|
||||
{
|
||||
return self.lower_expr_to_const_arg_direct(expr);
|
||||
}
|
||||
|
||||
overly_complex_const(self)
|
||||
}
|
||||
_ => overly_complex_const(self),
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`hir::ConstArg`] for when to use this function vs
|
||||
/// [`Self::lower_anon_const_to_anon_const`].
|
||||
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> {
|
||||
|
|
@ -2379,6 +2424,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// We cannot change parsing depending on feature gates available,
|
||||
// we can only require feature gates to be active as a delayed check.
|
||||
// Thus we just parse anon consts generally and make the real decision
|
||||
// making in ast lowering.
|
||||
// FIXME(min_generic_const_args): revisit once stable
|
||||
if tcx.features().min_generic_const_args() {
|
||||
return match anon.mgca_disambiguation {
|
||||
MgcaDisambiguation::AnonConst => {
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
|
||||
}
|
||||
MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value),
|
||||
};
|
||||
}
|
||||
|
||||
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
|
||||
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
|
||||
let expr = if let ExprKind::Block(block, _) = &anon.value.kind
|
||||
|
|
@ -2390,12 +2451,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
} else {
|
||||
&anon.value
|
||||
};
|
||||
|
||||
let maybe_res =
|
||||
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
|
||||
if let ExprKind::Path(qself, path) = &expr.kind
|
||||
&& path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
|
||||
&& (tcx.features().min_generic_const_args()
|
||||
|| matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))))
|
||||
&& path.is_potential_trivial_const_arg()
|
||||
&& matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))
|
||||
{
|
||||
let qpath = self.lower_qpath(
|
||||
expr.id,
|
||||
|
|
@ -2403,7 +2464,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
path,
|
||||
ParamMode::Explicit,
|
||||
AllowReturnTypeNotation::No,
|
||||
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -517,6 +517,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
|
||||
gate_all!(postfix_match, "postfix match is experimental");
|
||||
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
|
||||
gate_all!(min_generic_const_args, "unbraced const blocks as const args are experimental");
|
||||
gate_all!(global_registration, "global registration is experimental");
|
||||
gate_all!(return_type_notation, "return type notation is experimental");
|
||||
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ mod llvm_enzyme {
|
|||
use rustc_ast::{
|
||||
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemKind, BindingMode,
|
||||
FnRetTy, FnSig, GenericArg, GenericArgs, GenericParamKind, Generics, ItemKind,
|
||||
MetaItemInner, PatKind, Path, PathSegment, TyKind, Visibility,
|
||||
MetaItemInner, MgcaDisambiguation, PatKind, Path, PathSegment, TyKind, Visibility,
|
||||
};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
|
|
@ -558,7 +558,11 @@ mod llvm_enzyme {
|
|||
}
|
||||
GenericParamKind::Const { .. } => {
|
||||
let expr = ecx.expr_path(ast::Path::from_ident(p.ident));
|
||||
let anon_const = AnonConst { id: ast::DUMMY_NODE_ID, value: expr };
|
||||
let anon_const = AnonConst {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
value: expr,
|
||||
mgca_disambiguation: MgcaDisambiguation::Direct,
|
||||
};
|
||||
Some(AngleBracketedArg::Arg(GenericArg::Const(anon_const)))
|
||||
}
|
||||
GenericParamKind::Lifetime { .. } => None,
|
||||
|
|
@ -813,6 +817,7 @@ mod llvm_enzyme {
|
|||
let anon_const = rustc_ast::AnonConst {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
value: ecx.expr_usize(span, 1 + x.width as usize),
|
||||
mgca_disambiguation: MgcaDisambiguation::Direct,
|
||||
};
|
||||
TyKind::Array(ty.clone(), anon_const)
|
||||
};
|
||||
|
|
@ -827,6 +832,7 @@ mod llvm_enzyme {
|
|||
let anon_const = rustc_ast::AnonConst {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
value: ecx.expr_usize(span, x.width as usize),
|
||||
mgca_disambiguation: MgcaDisambiguation::Direct,
|
||||
};
|
||||
let kind = TyKind::Array(ty.clone(), anon_const);
|
||||
let ty =
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token};
|
||||
use rustc_ast::{AnonConst, DUMMY_NODE_ID, MgcaDisambiguation, Ty, TyPat, TyPatKind, ast, token};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
|
||||
use rustc_parse::exp;
|
||||
|
|
@ -60,8 +60,20 @@ fn ty_pat(kind: TyPatKind, span: Span) -> TyPat {
|
|||
fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> TyPat {
|
||||
let kind = match pat.kind {
|
||||
ast::PatKind::Range(start, end, include_end) => TyPatKind::Range(
|
||||
start.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })),
|
||||
end.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })),
|
||||
start.map(|value| {
|
||||
Box::new(AnonConst {
|
||||
id: DUMMY_NODE_ID,
|
||||
value,
|
||||
mgca_disambiguation: MgcaDisambiguation::Direct,
|
||||
})
|
||||
}),
|
||||
end.map(|value| {
|
||||
Box::new(AnonConst {
|
||||
id: DUMMY_NODE_ID,
|
||||
value,
|
||||
mgca_disambiguation: MgcaDisambiguation::Direct,
|
||||
})
|
||||
}),
|
||||
include_end,
|
||||
),
|
||||
ast::PatKind::Or(variants) => {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use rustc_ast::token::Delimiter;
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::util::literal;
|
||||
use rustc_ast::{
|
||||
self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind,
|
||||
UnOp, attr, token, tokenstream,
|
||||
self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind,
|
||||
MgcaDisambiguation, PatKind, UnOp, attr, token, tokenstream,
|
||||
};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
|
||||
|
|
@ -101,6 +101,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
attrs: AttrVec::new(),
|
||||
tokens: None,
|
||||
}),
|
||||
mgca_disambiguation: MgcaDisambiguation::Direct,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_ast::{self as ast, AsmMacro};
|
||||
use rustc_ast::{self as ast, AsmMacro, MgcaDisambiguation};
|
||||
use rustc_span::{Span, Symbol, kw};
|
||||
|
||||
use super::{ExpKeywordPair, ForceCollect, IdentIsRaw, Trailing, UsePreAttrPos};
|
||||
|
|
@ -149,7 +149,7 @@ fn parse_asm_operand<'a>(
|
|||
let block = p.parse_block()?;
|
||||
ast::InlineAsmOperand::Label { block }
|
||||
} else if p.eat_keyword(exp!(Const)) {
|
||||
let anon_const = p.parse_expr_anon_const()?;
|
||||
let anon_const = p.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?;
|
||||
ast::InlineAsmOperand::Const { anon_const }
|
||||
} else if p.eat_keyword(exp!(Sym)) {
|
||||
let expr = p.parse_expr()?;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind};
|
|||
use rustc_ast::util::parser::AssocOp;
|
||||
use rustc_ast::{
|
||||
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode,
|
||||
Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat,
|
||||
PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind,
|
||||
Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind,
|
||||
MgcaDisambiguation, Param, Pat, PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
|
@ -31,16 +31,15 @@ use crate::errors::{
|
|||
AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType,
|
||||
AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi,
|
||||
ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
|
||||
ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything,
|
||||
DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
||||
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
|
||||
HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
|
||||
IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody,
|
||||
QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
|
||||
StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma,
|
||||
TernaryOperator, TernaryOperatorSuggestion, UnexpectedConstInGenericParam,
|
||||
UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets,
|
||||
UseEqInstead, WrapType,
|
||||
DocCommentDoesNotDocumentAnything, DocCommentOnParamType, DoubleColonInBound,
|
||||
ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets,
|
||||
GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, HelpUseLatestEdition,
|
||||
InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse,
|
||||
PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst,
|
||||
StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt,
|
||||
SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, TernaryOperatorSuggestion,
|
||||
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
|
||||
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
|
||||
};
|
||||
use crate::parser::FnContext;
|
||||
use crate::parser::attr::InnerAttrPolicy;
|
||||
|
|
@ -2558,36 +2557,6 @@ impl<'a> Parser<'a> {
|
|||
Ok(false) // Don't continue.
|
||||
}
|
||||
|
||||
/// Attempt to parse a generic const argument that has not been enclosed in braces.
|
||||
/// There are a limited number of expressions that are permitted without being encoded
|
||||
/// in braces:
|
||||
/// - Literals.
|
||||
/// - Single-segment paths (i.e. standalone generic const parameters).
|
||||
/// All other expressions that can be parsed will emit an error suggesting the expression be
|
||||
/// wrapped in braces.
|
||||
pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, Box<Expr>> {
|
||||
let start = self.token.span;
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
let (expr, _) =
|
||||
self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| {
|
||||
err.span_label(
|
||||
start.shrink_to_lo(),
|
||||
"while parsing a const generic argument starting here",
|
||||
);
|
||||
err
|
||||
})?;
|
||||
if !self.expr_is_valid_const_arg(&expr) {
|
||||
self.dcx().emit_err(ConstGenericWithoutBraces {
|
||||
span: expr.span,
|
||||
sugg: ConstGenericWithoutBracesSugg {
|
||||
left: expr.span.shrink_to_lo(),
|
||||
right: expr.span.shrink_to_hi(),
|
||||
},
|
||||
});
|
||||
}
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option<GenericArg> {
|
||||
let snapshot = self.create_snapshot_for_diagnostic();
|
||||
let param = match self.parse_const_param(AttrVec::new()) {
|
||||
|
|
@ -2623,7 +2592,11 @@ impl<'a> Parser<'a> {
|
|||
self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg });
|
||||
|
||||
let value = self.mk_expr_err(param.span(), guar);
|
||||
Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }))
|
||||
Some(GenericArg::Const(AnonConst {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
value,
|
||||
mgca_disambiguation: MgcaDisambiguation::Direct,
|
||||
}))
|
||||
}
|
||||
|
||||
pub(super) fn recover_const_param_declaration(
|
||||
|
|
@ -2707,7 +2680,11 @@ impl<'a> Parser<'a> {
|
|||
);
|
||||
let guar = err.emit();
|
||||
let value = self.mk_expr_err(start.to(expr.span), guar);
|
||||
return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
|
||||
return Ok(GenericArg::Const(AnonConst {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
value,
|
||||
mgca_disambiguation: MgcaDisambiguation::Direct,
|
||||
}));
|
||||
} else if snapshot.token == token::Colon
|
||||
&& expr.span.lo() == snapshot.token.span.hi()
|
||||
&& matches!(expr.kind, ExprKind::Path(..))
|
||||
|
|
@ -2776,7 +2753,11 @@ impl<'a> Parser<'a> {
|
|||
);
|
||||
let guar = err.emit();
|
||||
let value = self.mk_expr_err(span, guar);
|
||||
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
|
||||
GenericArg::Const(AnonConst {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
value,
|
||||
mgca_disambiguation: MgcaDisambiguation::Direct,
|
||||
})
|
||||
}
|
||||
|
||||
/// Some special error handling for the "top-level" patterns in a match arm,
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ use rustc_ast::visit::{Visitor, walk_expr};
|
|||
use rustc_ast::{
|
||||
self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind,
|
||||
BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl,
|
||||
FnRetTy, Label, MacCall, MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind,
|
||||
UnOp, UnsafeBinderCastKind, YieldKind,
|
||||
FnRetTy, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, RangeLimits,
|
||||
StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
|
||||
};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
|
||||
|
|
@ -85,8 +85,15 @@ impl<'a> Parser<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> {
|
||||
self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value })
|
||||
pub fn parse_expr_anon_const(
|
||||
&mut self,
|
||||
mgca_disambiguation: impl FnOnce(&Self, &Expr) -> MgcaDisambiguation,
|
||||
) -> PResult<'a, AnonConst> {
|
||||
self.parse_expr().map(|value| AnonConst {
|
||||
id: DUMMY_NODE_ID,
|
||||
mgca_disambiguation: mgca_disambiguation(self, &value),
|
||||
value,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_expr_catch_underscore(
|
||||
|
|
@ -1615,7 +1622,18 @@ impl<'a> Parser<'a> {
|
|||
let first_expr = self.parse_expr()?;
|
||||
if self.eat(exp!(Semi)) {
|
||||
// Repeating array syntax: `[ 0; 512 ]`
|
||||
let count = self.parse_expr_anon_const()?;
|
||||
let count = if self.token.is_keyword(kw::Const)
|
||||
&& self.look_ahead(1, |t| *t == token::OpenBrace)
|
||||
{
|
||||
// While we could just disambiguate `Direct` from `AnonConst` by
|
||||
// treating all const block exprs as `AnonConst`, that would
|
||||
// complicate the DefCollector and likely all other visitors.
|
||||
// So we strip the const blockiness and just store it as a block
|
||||
// in the AST with the extra disambiguator on the AnonConst
|
||||
self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?
|
||||
} else {
|
||||
self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?
|
||||
};
|
||||
self.expect(close)?;
|
||||
ExprKind::Repeat(first_expr, count)
|
||||
} else if self.eat(exp!(Comma)) {
|
||||
|
|
|
|||
|
|
@ -1431,7 +1431,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
let rhs = if self.eat(exp!(Eq)) {
|
||||
if attr::contains_name(attrs, sym::type_const) {
|
||||
Some(ConstItemRhs::TypeConst(self.parse_expr_anon_const()?))
|
||||
Some(ConstItemRhs::TypeConst(self.parse_const_arg()?))
|
||||
} else {
|
||||
Some(ConstItemRhs::Body(self.parse_expr()?))
|
||||
}
|
||||
|
|
@ -1650,8 +1650,11 @@ impl<'a> Parser<'a> {
|
|||
VariantData::Unit(DUMMY_NODE_ID)
|
||||
};
|
||||
|
||||
let disr_expr =
|
||||
if this.eat(exp!(Eq)) { Some(this.parse_expr_anon_const()?) } else { None };
|
||||
let disr_expr = if this.eat(exp!(Eq)) {
|
||||
Some(this.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let vr = ast::Variant {
|
||||
ident,
|
||||
|
|
@ -1864,7 +1867,7 @@ impl<'a> Parser<'a> {
|
|||
if p.token == token::Eq {
|
||||
let mut snapshot = p.create_snapshot_for_diagnostic();
|
||||
snapshot.bump();
|
||||
match snapshot.parse_expr_anon_const() {
|
||||
match snapshot.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst) {
|
||||
Ok(const_expr) => {
|
||||
let sp = ty.span.shrink_to_hi().to(const_expr.value.span);
|
||||
p.psess.gated_spans.gate(sym::default_field_values, sp);
|
||||
|
|
@ -2066,7 +2069,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
let default = if self.token == token::Eq {
|
||||
self.bump();
|
||||
let const_expr = self.parse_expr_anon_const()?;
|
||||
let const_expr = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?;
|
||||
let sp = ty.span.shrink_to_hi().to(const_expr.value.span);
|
||||
self.psess.gated_spans.gate(sym::default_field_values, sp);
|
||||
Some(const_expr)
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ use rustc_ast::tokenstream::{
|
|||
};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID,
|
||||
DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit,
|
||||
Visibility, VisibilityKind,
|
||||
self as ast, AnonConst, AttrArgs, AttrId, BlockCheckMode, ByRef, Const, CoroutineKind,
|
||||
DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, MgcaDisambiguation,
|
||||
Mutability, Recovered, Safety, StrLit, Visibility, VisibilityKind,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
|
@ -727,7 +727,10 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn check_const_arg(&mut self) -> bool {
|
||||
self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const)
|
||||
let is_mcg_arg = self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const);
|
||||
let is_mgca_arg = self.is_keyword_ahead(0, &[kw::Const])
|
||||
&& self.look_ahead(1, |t| *t == token::OpenBrace);
|
||||
is_mcg_arg || is_mgca_arg
|
||||
}
|
||||
|
||||
fn check_const_closure(&self) -> bool {
|
||||
|
|
@ -1299,6 +1302,20 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_mgca_const_block(&mut self, gate_syntax: bool) -> PResult<'a, AnonConst> {
|
||||
self.expect_keyword(exp!(Const))?;
|
||||
let kw_span = self.token.span;
|
||||
let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?;
|
||||
if gate_syntax {
|
||||
self.psess.gated_spans.gate(sym::min_generic_const_args, kw_span.to(value.span));
|
||||
}
|
||||
Ok(AnonConst {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
value,
|
||||
mgca_disambiguation: MgcaDisambiguation::AnonConst,
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses inline const expressions.
|
||||
fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, Box<Expr>> {
|
||||
self.expect_keyword(exp!(Const))?;
|
||||
|
|
@ -1306,6 +1323,7 @@ impl<'a> Parser<'a> {
|
|||
let anon_const = AnonConst {
|
||||
id: DUMMY_NODE_ID,
|
||||
value: self.mk_expr(blk.span, ExprKind::Block(blk, None)),
|
||||
mgca_disambiguation: MgcaDisambiguation::AnonConst,
|
||||
};
|
||||
let blk_span = anon_const.value.span;
|
||||
let kind = if pat {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ use ast::token::IdentIsRaw;
|
|||
use rustc_ast::token::{self, MetaVarKind, Token, TokenKind};
|
||||
use rustc_ast::{
|
||||
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint,
|
||||
AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
|
||||
Path, PathSegment, QSelf,
|
||||
AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, MgcaDisambiguation,
|
||||
ParenthesizedArgs, Path, PathSegment, QSelf,
|
||||
};
|
||||
use rustc_errors::{Applicability, Diag, PResult};
|
||||
use rustc_span::{BytePos, Ident, Span, kw, sym};
|
||||
|
|
@ -16,12 +16,13 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
|
|||
use super::{Parser, Restrictions, TokenType};
|
||||
use crate::ast::{PatKind, TyKind};
|
||||
use crate::errors::{
|
||||
self, AttributeOnEmptyType, AttributeOnGenericArg, FnPathFoundNamedParams,
|
||||
PathFoundAttributeInParams, PathFoundCVariadicParams, PathSingleColon, PathTripleColon,
|
||||
self, AttributeOnEmptyType, AttributeOnGenericArg, ConstGenericWithoutBraces,
|
||||
ConstGenericWithoutBracesSugg, FnPathFoundNamedParams, PathFoundAttributeInParams,
|
||||
PathFoundCVariadicParams, PathSingleColon, PathTripleColon,
|
||||
};
|
||||
use crate::exp;
|
||||
use crate::parser::{
|
||||
CommaRecoveryMode, ExprKind, FnContext, FnParseMode, RecoverColon, RecoverComma,
|
||||
CommaRecoveryMode, Expr, ExprKind, FnContext, FnParseMode, RecoverColon, RecoverComma,
|
||||
};
|
||||
|
||||
/// Specifies how to parse a path.
|
||||
|
|
@ -870,12 +871,75 @@ impl<'a> Parser<'a> {
|
|||
/// the caller.
|
||||
pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> {
|
||||
// Parse const argument.
|
||||
let value = if self.token.kind == token::OpenBrace {
|
||||
self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?
|
||||
let (value, mgca_disambiguation) = if self.token.kind == token::OpenBrace {
|
||||
let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?;
|
||||
(value, MgcaDisambiguation::Direct)
|
||||
} else if self.token.is_keyword(kw::Const) {
|
||||
// While we could just disambiguate `Direct` from `AnonConst` by
|
||||
// treating all const block exprs as `AnonConst`, that would
|
||||
// complicate the DefCollector and likely all other visitors.
|
||||
// So we strip the const blockiness and just store it as a block
|
||||
// in the AST with the extra disambiguator on the AnonConst
|
||||
let value = self.parse_mgca_const_block(true)?;
|
||||
(value.value, MgcaDisambiguation::AnonConst)
|
||||
} else {
|
||||
self.handle_unambiguous_unbraced_const_arg()?
|
||||
self.parse_unambiguous_unbraced_const_arg()?
|
||||
};
|
||||
Ok(AnonConst { id: ast::DUMMY_NODE_ID, value })
|
||||
Ok(AnonConst { id: ast::DUMMY_NODE_ID, value, mgca_disambiguation })
|
||||
}
|
||||
|
||||
/// Attempt to parse a const argument that has not been enclosed in braces.
|
||||
/// There are a limited number of expressions that are permitted without being
|
||||
/// enclosed in braces:
|
||||
/// - Literals.
|
||||
/// - Single-segment paths (i.e. standalone generic const parameters).
|
||||
/// All other expressions that can be parsed will emit an error suggesting the expression be
|
||||
/// wrapped in braces.
|
||||
pub(super) fn parse_unambiguous_unbraced_const_arg(
|
||||
&mut self,
|
||||
) -> PResult<'a, (Box<Expr>, MgcaDisambiguation)> {
|
||||
let start = self.token.span;
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
let (expr, _) =
|
||||
self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| {
|
||||
err.span_label(
|
||||
start.shrink_to_lo(),
|
||||
"while parsing a const generic argument starting here",
|
||||
);
|
||||
err
|
||||
})?;
|
||||
if !self.expr_is_valid_const_arg(&expr) {
|
||||
self.dcx().emit_err(ConstGenericWithoutBraces {
|
||||
span: expr.span,
|
||||
sugg: ConstGenericWithoutBracesSugg {
|
||||
left: expr.span.shrink_to_lo(),
|
||||
right: expr.span.shrink_to_hi(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let mgca_disambiguation = self.mgca_direct_lit_hack(&expr);
|
||||
Ok((expr, mgca_disambiguation))
|
||||
}
|
||||
|
||||
/// Under `min_generic_const_args` we still allow *some* anon consts to be written without
|
||||
/// a `const` block as it makes things quite a lot nicer. This function is useful for contexts
|
||||
/// where we would like to use `MgcaDisambiguation::Direct` but need to fudge it to be `AnonConst`
|
||||
/// in the presence of literals.
|
||||
//
|
||||
/// FIXME(min_generic_const_args): In the long term it would be nice to have a way to directly
|
||||
/// represent literals in `hir::ConstArgKind` so that we can remove this special case by not
|
||||
/// needing an anon const.
|
||||
pub fn mgca_direct_lit_hack(&self, expr: &Expr) -> MgcaDisambiguation {
|
||||
match &expr.kind {
|
||||
ast::ExprKind::Lit(_) => MgcaDisambiguation::AnonConst,
|
||||
ast::ExprKind::Unary(ast::UnOp::Neg, expr)
|
||||
if matches!(expr.kind, ast::ExprKind::Lit(_)) =>
|
||||
{
|
||||
MgcaDisambiguation::AnonConst
|
||||
}
|
||||
_ => MgcaDisambiguation::Direct,
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a generic argument in a path segment.
|
||||
|
|
@ -976,7 +1040,11 @@ impl<'a> Parser<'a> {
|
|||
GenericArg::Type(_) => GenericArg::Type(self.mk_ty(attr_span, TyKind::Err(guar))),
|
||||
GenericArg::Const(_) => {
|
||||
let error_expr = self.mk_expr(attr_span, ExprKind::Err(guar));
|
||||
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: error_expr })
|
||||
GenericArg::Const(AnonConst {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
value: error_expr,
|
||||
mgca_disambiguation: MgcaDisambiguation::Direct,
|
||||
})
|
||||
}
|
||||
GenericArg::Lifetime(lt) => GenericArg::Lifetime(lt),
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token, TokenKind};
|
|||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnPtrTy, FnRetTy,
|
||||
GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability,
|
||||
Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty,
|
||||
TyKind, UnsafeBinderTy,
|
||||
GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MgcaDisambiguation,
|
||||
MutTy, Mutability, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers,
|
||||
TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy,
|
||||
};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::{Applicability, Diag, E0516, PResult};
|
||||
|
|
@ -658,7 +658,19 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
|
||||
let ty = if self.eat(exp!(Semi)) {
|
||||
let mut length = self.parse_expr_anon_const()?;
|
||||
let mut length = if self.token.is_keyword(kw::Const)
|
||||
&& self.look_ahead(1, |t| *t == token::OpenBrace)
|
||||
{
|
||||
// While we could just disambiguate `Direct` from `AnonConst` by
|
||||
// treating all const block exprs as `AnonConst`, that would
|
||||
// complicate the DefCollector and likely all other visitors.
|
||||
// So we strip the const blockiness and just store it as a block
|
||||
// in the AST with the extra disambiguator on the AnonConst
|
||||
self.parse_mgca_const_block(false)?
|
||||
} else {
|
||||
self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?
|
||||
};
|
||||
|
||||
if let Err(e) = self.expect(exp!(CloseBracket)) {
|
||||
// Try to recover from `X<Y, ...>` when `X::<Y, ...>` works
|
||||
self.check_mistyped_turbofish_with_multiple_type_params(e, &mut length.value)?;
|
||||
|
|
@ -699,8 +711,9 @@ impl<'a> Parser<'a> {
|
|||
_ = self.eat(exp!(Comma)) || self.eat(exp!(Colon)) || self.eat(exp!(Star));
|
||||
let suggestion_span = self.prev_token.span.with_lo(hi);
|
||||
|
||||
// FIXME(mgca): recovery is broken for `const {` args
|
||||
// we first try to parse pattern like `[u8 5]`
|
||||
let length = match self.parse_expr_anon_const() {
|
||||
let length = match self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct) {
|
||||
Ok(length) => length,
|
||||
Err(e) => {
|
||||
e.cancel();
|
||||
|
|
@ -788,7 +801,7 @@ impl<'a> Parser<'a> {
|
|||
/// an error type.
|
||||
fn parse_typeof_ty(&mut self, lo: Span) -> PResult<'a, TyKind> {
|
||||
self.expect(exp!(OpenParen))?;
|
||||
let _expr = self.parse_expr_anon_const()?;
|
||||
let _expr = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?;
|
||||
self.expect(exp!(CloseParen))?;
|
||||
let span = lo.to(self.prev_token.span);
|
||||
let guar = self
|
||||
|
|
|
|||
|
|
@ -1222,7 +1222,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc
|
|||
if let TyKind::Path(None, ref path) = ty.kind
|
||||
// We cannot disambiguate multi-segment paths right now as that requires type
|
||||
// checking.
|
||||
&& path.is_potential_trivial_const_arg(false)
|
||||
&& path.is_potential_trivial_const_arg()
|
||||
{
|
||||
let mut check_ns = |ns| {
|
||||
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
|
||||
|
|
@ -4840,9 +4840,12 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
constant, anon_const_kind
|
||||
);
|
||||
|
||||
let is_trivial_const_arg = constant
|
||||
.value
|
||||
.is_potential_trivial_const_arg(self.r.tcx.features().min_generic_const_args());
|
||||
let is_trivial_const_arg = if self.r.tcx.features().min_generic_const_args() {
|
||||
matches!(constant.mgca_disambiguation, MgcaDisambiguation::Direct)
|
||||
} else {
|
||||
constant.value.is_potential_trivial_const_arg()
|
||||
};
|
||||
|
||||
self.resolve_anon_const_manual(is_trivial_const_arg, anon_const_kind, |this| {
|
||||
this.resolve_expr(&constant.value, None)
|
||||
})
|
||||
|
|
@ -5023,9 +5026,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
// Constant arguments need to be treated as AnonConst since
|
||||
// that is how they will be later lowered to HIR.
|
||||
if const_args.contains(&idx) {
|
||||
let is_trivial_const_arg = argument.is_potential_trivial_const_arg(
|
||||
self.r.tcx.features().min_generic_const_args(),
|
||||
);
|
||||
// FIXME(mgca): legacy const generics doesn't support mgca but maybe
|
||||
// that's okay.
|
||||
let is_trivial_const_arg = argument.is_potential_trivial_const_arg();
|
||||
self.resolve_anon_const_manual(
|
||||
is_trivial_const_arg,
|
||||
AnonConstKind::ConstArg(IsRepeatExpr::No),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ trait Parent0<T> {
|
|||
const K: ();
|
||||
}
|
||||
|
||||
fn take0(_: impl Trait0<K = { () }>) {}
|
||||
fn take0(_: impl Trait0<K = const { }>) {}
|
||||
//~^ ERROR ambiguous associated constant `K` in bounds of `Trait0`
|
||||
|
||||
trait Trait1: Parent1 + Parent2 {}
|
||||
|
|
|
|||
|
|
@ -7,14 +7,14 @@ LL | const K: ();
|
|||
| ambiguous `K` from `Parent0<u32>`
|
||||
| ambiguous `K` from `Parent0<i32>`
|
||||
...
|
||||
LL | fn take0(_: impl Trait0<K = { () }>) {}
|
||||
| ^^^^^^^^^^ ambiguous associated constant `K`
|
||||
LL | fn take0(_: impl Trait0<K = const { }>) {}
|
||||
| ^^^^^^^^^^^^^ ambiguous associated constant `K`
|
||||
|
|
||||
= help: consider introducing a new type parameter `T` and adding `where` constraints:
|
||||
where
|
||||
T: Trait0,
|
||||
T: Parent0<u32>::K = { () },
|
||||
T: Parent0<i32>::K = { () }
|
||||
T: Parent0<u32>::K = { },
|
||||
T: Parent0<i32>::K = { }
|
||||
|
||||
error[E0222]: ambiguous associated constant `C` in bounds of `Trait1`
|
||||
--> $DIR/assoc-const-eq-ambiguity.rs:26:25
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ trait Trait<T: ConstParamTy_> {
|
|||
fn take(
|
||||
_: impl Trait<
|
||||
<<for<'a> fn(&'a str) -> &'a str as Project>::Out as Discard>::Out,
|
||||
K = { () }
|
||||
K = const { () }
|
||||
>,
|
||||
) {}
|
||||
//~^^^ ERROR higher-ranked subtype error
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
error: higher-ranked subtype error
|
||||
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13
|
||||
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:19
|
||||
|
|
||||
LL | K = { () }
|
||||
| ^^^^^^
|
||||
LL | K = const { () }
|
||||
| ^^^^^^
|
||||
|
||||
error: higher-ranked subtype error
|
||||
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13
|
||||
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:19
|
||||
|
|
||||
LL | K = { () }
|
||||
| ^^^^^^
|
||||
LL | K = const { () }
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ trait Trait<T: ConstParamTy_> {
|
|||
fn take(
|
||||
_: impl Trait<
|
||||
<for<'a> fn(&'a str) -> &'a str as Discard>::Out,
|
||||
K = { () }
|
||||
K = const { }
|
||||
>,
|
||||
) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ trait Trait<'a> {
|
|||
const K: &'a ();
|
||||
}
|
||||
|
||||
fn take(_: impl for<'r> Trait<'r, K = { &() }>) {}
|
||||
fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {}
|
||||
//~^ ERROR the type of the associated constant `K` cannot capture late-bound generic parameters
|
||||
//~| NOTE its type cannot capture the late-bound lifetime parameter `'r`
|
||||
//~| NOTE the late-bound lifetime parameter `'r` is defined here
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
error: the type of the associated constant `K` cannot capture late-bound generic parameters
|
||||
--> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:11:35
|
||||
|
|
||||
LL | fn take(_: impl for<'r> Trait<'r, K = { &() }>) {}
|
||||
LL | fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {}
|
||||
| -- ^ its type cannot capture the late-bound lifetime parameter `'r`
|
||||
| |
|
||||
| the late-bound lifetime parameter `'r` is defined here
|
||||
|
|
|
|||
|
|
@ -15,31 +15,33 @@ trait Trait<'a, T: 'a + ConstParamTy_, const N: usize> {
|
|||
const K: &'a [T; N];
|
||||
}
|
||||
|
||||
fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
|
||||
//~^ ERROR the type of the associated constant `K` must not depend on generic parameters
|
||||
//~| NOTE its type must not depend on the lifetime parameter `'r`
|
||||
//~| NOTE the lifetime parameter `'r` is defined here
|
||||
//~| NOTE `K` has type `&'r [A; Q]`
|
||||
//~| ERROR the type of the associated constant `K` must not depend on generic parameters
|
||||
//~| NOTE its type must not depend on the type parameter `A`
|
||||
//~| NOTE the type parameter `A` is defined here
|
||||
//~| NOTE `K` has type `&'r [A; Q]`
|
||||
//~| ERROR the type of the associated constant `K` must not depend on generic parameters
|
||||
//~| NOTE its type must not depend on the const parameter `Q`
|
||||
//~| NOTE the const parameter `Q` is defined here
|
||||
//~| NOTE `K` has type `&'r [A; Q]`
|
||||
fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(
|
||||
//~^ NOTE the lifetime parameter `'r` is defined here
|
||||
//~| NOTE the type parameter `A` is defined here
|
||||
//~| NOTE the const parameter `Q` is defined here
|
||||
_: impl Trait<'r, A, Q, K = const { loop {} }>
|
||||
//~^ ERROR the type of the associated constant `K` must not depend on generic parameters
|
||||
//~| NOTE its type must not depend on the lifetime parameter `'r`
|
||||
//~| NOTE `K` has type `&'r [A; Q]`
|
||||
//~| ERROR the type of the associated constant `K` must not depend on generic parameters
|
||||
//~| NOTE its type must not depend on the type parameter `A`
|
||||
//~| NOTE `K` has type `&'r [A; Q]`
|
||||
//~| ERROR the type of the associated constant `K` must not depend on generic parameters
|
||||
//~| NOTE its type must not depend on the const parameter `Q`
|
||||
//~| NOTE `K` has type `&'r [A; Q]`
|
||||
) {}
|
||||
|
||||
trait Project: ConstParamTy_ {
|
||||
#[type_const]
|
||||
const SELF: Self;
|
||||
}
|
||||
|
||||
fn take1(_: impl Project<SELF = {}>) {}
|
||||
fn take1(_: impl Project<SELF = const {}>) {}
|
||||
//~^ ERROR the type of the associated constant `SELF` must not depend on `impl Trait`
|
||||
//~| NOTE its type must not depend on `impl Trait`
|
||||
//~| NOTE the `impl Trait` is specified here
|
||||
|
||||
fn take2<P: Project<SELF = {}>>(_: P) {}
|
||||
fn take2<P: Project<SELF = const {}>>(_: P) {}
|
||||
//~^ ERROR the type of the associated constant `SELF` must not depend on generic parameters
|
||||
//~| NOTE its type must not depend on the type parameter `P`
|
||||
//~| NOTE the type parameter `P` is defined here
|
||||
|
|
@ -48,7 +50,7 @@ fn take2<P: Project<SELF = {}>>(_: P) {}
|
|||
trait Iface<'r>: ConstParamTy_ {
|
||||
//~^ NOTE the lifetime parameter `'r` is defined here
|
||||
//~| NOTE the lifetime parameter `'r` is defined here
|
||||
type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
||||
type Assoc<const Q: usize>: Trait<'r, Self, Q, K = const { loop {} }>
|
||||
//~^ ERROR the type of the associated constant `K` must not depend on generic parameters
|
||||
//~| ERROR the type of the associated constant `K` must not depend on generic parameters
|
||||
//~| NOTE its type must not depend on the lifetime parameter `'r`
|
||||
|
|
|
|||
|
|
@ -1,42 +1,49 @@
|
|||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:18:77
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:22:29
|
||||
|
|
||||
LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
|
||||
| -- the lifetime parameter `'r` is defined here ^ its type must not depend on the lifetime parameter `'r`
|
||||
LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(
|
||||
| -- the lifetime parameter `'r` is defined here
|
||||
...
|
||||
LL | _: impl Trait<'r, A, Q, K = const { loop {} }>
|
||||
| ^ its type must not depend on the lifetime parameter `'r`
|
||||
|
|
||||
= note: `K` has type `&'r [A; Q]`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:18:77
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:22:29
|
||||
|
|
||||
LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
|
||||
| - the type parameter `A` is defined here ^ its type must not depend on the type parameter `A`
|
||||
LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(
|
||||
| - the type parameter `A` is defined here
|
||||
...
|
||||
LL | _: impl Trait<'r, A, Q, K = const { loop {} }>
|
||||
| ^ its type must not depend on the type parameter `A`
|
||||
|
|
||||
= note: `K` has type `&'r [A; Q]`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:18:77
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:22:29
|
||||
|
|
||||
LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
|
||||
| - ^ its type must not depend on the const parameter `Q`
|
||||
| |
|
||||
| the const parameter `Q` is defined here
|
||||
LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(
|
||||
| - the const parameter `Q` is defined here
|
||||
...
|
||||
LL | _: impl Trait<'r, A, Q, K = const { loop {} }>
|
||||
| ^ its type must not depend on the const parameter `Q`
|
||||
|
|
||||
= note: `K` has type `&'r [A; Q]`
|
||||
|
||||
error: the type of the associated constant `SELF` must not depend on `impl Trait`
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:37:26
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:39:26
|
||||
|
|
||||
LL | fn take1(_: impl Project<SELF = {}>) {}
|
||||
| -------------^^^^------
|
||||
LL | fn take1(_: impl Project<SELF = const {}>) {}
|
||||
| -------------^^^^------------
|
||||
| | |
|
||||
| | its type must not depend on `impl Trait`
|
||||
| the `impl Trait` is specified here
|
||||
|
||||
error: the type of the associated constant `SELF` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:42:21
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:44:21
|
||||
|
|
||||
LL | fn take2<P: Project<SELF = {}>>(_: P) {}
|
||||
LL | fn take2<P: Project<SELF = const {}>>(_: P) {}
|
||||
| - ^^^^ its type must not depend on the type parameter `P`
|
||||
| |
|
||||
| the type parameter `P` is defined here
|
||||
|
|
@ -44,28 +51,28 @@ LL | fn take2<P: Project<SELF = {}>>(_: P) {}
|
|||
= note: `SELF` has type `P`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:51:52
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:53:52
|
||||
|
|
||||
LL | trait Iface<'r>: ConstParamTy_ {
|
||||
| -- the lifetime parameter `'r` is defined here
|
||||
...
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = const { loop {} }>
|
||||
| ^ its type must not depend on the lifetime parameter `'r`
|
||||
|
|
||||
= note: `K` has type `&'r [Self; Q]`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on `Self`
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:51:52
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:53:52
|
||||
|
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = const { loop {} }>
|
||||
| ^ its type must not depend on `Self`
|
||||
|
|
||||
= note: `K` has type `&'r [Self; Q]`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:51:52
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:53:52
|
||||
|
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = const { loop {} }>
|
||||
| - ^ its type must not depend on the const parameter `Q`
|
||||
| |
|
||||
| the const parameter `Q` is defined here
|
||||
|
|
@ -73,30 +80,30 @@ LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
|||
= note: `K` has type `&'r [Self; Q]`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:51:52
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:53:52
|
||||
|
|
||||
LL | trait Iface<'r>: ConstParamTy_ {
|
||||
| -- the lifetime parameter `'r` is defined here
|
||||
...
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = const { loop {} }>
|
||||
| ^ its type must not depend on the lifetime parameter `'r`
|
||||
|
|
||||
= note: `K` has type `&'r [Self; Q]`
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on `Self`
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:51:52
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:53:52
|
||||
|
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = const { loop {} }>
|
||||
| ^ its type must not depend on `Self`
|
||||
|
|
||||
= note: `K` has type `&'r [Self; Q]`
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:51:52
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:53:52
|
||||
|
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = const { loop {} }>
|
||||
| - ^ its type must not depend on the const parameter `Q`
|
||||
| |
|
||||
| the const parameter `Q` is defined here
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ impl Foo for Bar {
|
|||
const N: usize = 3;
|
||||
}
|
||||
|
||||
const TEST:usize = 3;
|
||||
const TEST: usize = 3;
|
||||
|
||||
|
||||
fn foo<F: Foo<N=3usize>>() {}
|
||||
fn foo<F: Foo<N = 3usize>>() {}
|
||||
|
||||
fn main() {
|
||||
foo::<Bar>()
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ pub trait Trait {
|
|||
|
||||
pub fn foo<
|
||||
T: Trait<
|
||||
ASSOC = {
|
||||
ASSOC = const {
|
||||
let a = 10_usize;
|
||||
let b: &'_ usize = &a;
|
||||
*b
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
//@ revisions: stock gce
|
||||
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
#![cfg_attr(gce, feature(generic_const_exprs))]
|
||||
|
||||
trait TraitWAssocConst {
|
||||
#[type_const]
|
||||
const A: usize;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 1`
|
||||
--> $DIR/const-projection-err.rs:16:11
|
||||
--> $DIR/const-projection-err.rs:12:11
|
||||
|
|
||||
LL | foo::<T>();
|
||||
| ^ expected `0`, found `1`
|
||||
| ^ expected `1`, found `0`
|
||||
|
|
||||
= note: expected constant `1`
|
||||
found constant `0`
|
||||
note: required by a bound in `foo`
|
||||
--> $DIR/const-projection-err.rs:13:28
|
||||
--> $DIR/const-projection-err.rs:9:28
|
||||
|
|
||||
LL | fn foo<T: TraitWAssocConst<A = 1>>() {}
|
||||
| ^^^^^ required by this bound in `foo`
|
||||
|
|
@ -81,7 +81,9 @@ fn uncallable(_: impl Iterator<Item = i32, Item = u32>) {}
|
|||
|
||||
fn uncallable_const(_: impl Trait<ASSOC = 3, ASSOC = 4>) {}
|
||||
|
||||
fn uncallable_rtn(_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
|
||||
fn uncallable_rtn(
|
||||
_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>
|
||||
) {}
|
||||
|
||||
type MustFail = dyn Iterator<Item = i32, Item = u32>;
|
||||
//~^ ERROR [E0719]
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ LL | iter::empty::<String>()
|
|||
| ----------------------- return type was inferred to be `std::iter::Empty<String>` here
|
||||
|
||||
error[E0271]: expected `IntoIter<u32, 1>` to be an iterator that yields `i32`, but it yields `u32`
|
||||
--> $DIR/duplicate-bound-err.rs:110:17
|
||||
--> $DIR/duplicate-bound-err.rs:112:17
|
||||
|
|
||||
LL | fn foo() -> impl Iterator<Item = i32, Item = u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
|
||||
|
|
@ -109,7 +109,7 @@ LL | [2u32].into_iter()
|
|||
| ------------------ return type was inferred to be `std::array::IntoIter<u32, 1>` here
|
||||
|
||||
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
|
||||
--> $DIR/duplicate-bound-err.rs:86:42
|
||||
--> $DIR/duplicate-bound-err.rs:88:42
|
||||
|
|
||||
LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
|
|
@ -117,7 +117,7 @@ LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
|
|||
| `Item` bound here first
|
||||
|
||||
error: conflicting associated type bounds for `Item`
|
||||
--> $DIR/duplicate-bound-err.rs:86:17
|
||||
--> $DIR/duplicate-bound-err.rs:88:17
|
||||
|
|
||||
LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
|
||||
| ^^^^^^^^^^^^^----------^^----------^
|
||||
|
|
@ -126,7 +126,7 @@ LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
|
|||
| `Item` is specified to be `i32` here
|
||||
|
||||
error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified
|
||||
--> $DIR/duplicate-bound-err.rs:95:43
|
||||
--> $DIR/duplicate-bound-err.rs:97:43
|
||||
|
|
||||
LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
|
||||
| ------------ ^^^^^^^^^^^^ re-bound here
|
||||
|
|
@ -134,7 +134,7 @@ LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
|
|||
| `ASSOC` bound here first
|
||||
|
||||
error: conflicting associated type bounds for `ASSOC`
|
||||
--> $DIR/duplicate-bound-err.rs:95:18
|
||||
--> $DIR/duplicate-bound-err.rs:97:18
|
||||
|
|
||||
LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
|
||||
| ^^^^^^^^^^^------------^^------------^
|
||||
|
|
@ -143,7 +143,7 @@ LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
|
|||
| `ASSOC` is specified to be `3` here
|
||||
|
||||
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
|
||||
--> $DIR/duplicate-bound-err.rs:99:43
|
||||
--> $DIR/duplicate-bound-err.rs:101:43
|
||||
|
|
||||
LL | type MustFail3 = dyn Iterator<Item = i32, Item = i32>;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
|
|
@ -151,7 +151,7 @@ LL | type MustFail3 = dyn Iterator<Item = i32, Item = i32>;
|
|||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified
|
||||
--> $DIR/duplicate-bound-err.rs:102:43
|
||||
--> $DIR/duplicate-bound-err.rs:104:43
|
||||
|
|
||||
LL | type MustFail4 = dyn Trait2<ASSOC = 3u32, ASSOC = 3u32>;
|
||||
| ------------ ^^^^^^^^^^^^ re-bound here
|
||||
|
|
@ -159,19 +159,19 @@ LL | type MustFail4 = dyn Trait2<ASSOC = 3u32, ASSOC = 3u32>;
|
|||
| `ASSOC` bound here first
|
||||
|
||||
error[E0271]: expected `impl Iterator<Item = u32>` to be an iterator that yields `i32`, but it yields `u32`
|
||||
--> $DIR/duplicate-bound-err.rs:110:17
|
||||
--> $DIR/duplicate-bound-err.rs:112:17
|
||||
|
|
||||
LL | fn foo() -> impl Iterator<Item = i32, Item = u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
|
||||
|
|
||||
note: required by a bound in `Trait3::foo::{anon_assoc#0}`
|
||||
--> $DIR/duplicate-bound-err.rs:106:31
|
||||
--> $DIR/duplicate-bound-err.rs:108:31
|
||||
|
|
||||
LL | fn foo() -> impl Iterator<Item = i32, Item = u32>;
|
||||
| ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}`
|
||||
|
||||
error[E0271]: expected `Empty<u32>` to be an iterator that yields `i32`, but it yields `u32`
|
||||
--> $DIR/duplicate-bound-err.rs:118:16
|
||||
--> $DIR/duplicate-bound-err.rs:120:16
|
||||
|
|
||||
LL | uncallable(iter::empty::<u32>());
|
||||
| ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
|
||||
|
|
@ -185,7 +185,7 @@ LL | fn uncallable(_: impl Iterator<Item = i32, Item = u32>) {}
|
|||
| ^^^^^^^^^^ required by this bound in `uncallable`
|
||||
|
||||
error[E0271]: expected `Empty<i32>` to be an iterator that yields `u32`, but it yields `i32`
|
||||
--> $DIR/duplicate-bound-err.rs:119:16
|
||||
--> $DIR/duplicate-bound-err.rs:121:16
|
||||
|
|
||||
LL | uncallable(iter::empty::<i32>());
|
||||
| ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
|
||||
|
|
@ -199,7 +199,7 @@ LL | fn uncallable(_: impl Iterator<Item = i32, Item = u32>) {}
|
|||
| ^^^^^^^^^^ required by this bound in `uncallable`
|
||||
|
||||
error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4`
|
||||
--> $DIR/duplicate-bound-err.rs:120:22
|
||||
--> $DIR/duplicate-bound-err.rs:122:22
|
||||
|
|
||||
LL | uncallable_const(());
|
||||
| ---------------- ^^ expected `4`, found `3`
|
||||
|
|
@ -215,7 +215,7 @@ LL | fn uncallable_const(_: impl Trait<ASSOC = 3, ASSOC = 4>) {}
|
|||
| ^^^^^^^^^ required by this bound in `uncallable_const`
|
||||
|
||||
error[E0271]: type mismatch resolving `<u32 as Trait>::ASSOC == 3`
|
||||
--> $DIR/duplicate-bound-err.rs:121:22
|
||||
--> $DIR/duplicate-bound-err.rs:123:22
|
||||
|
|
||||
LL | uncallable_const(4u32);
|
||||
| ---------------- ^^^^ expected `3`, found `4`
|
||||
|
|
@ -231,7 +231,7 @@ LL | fn uncallable_const(_: impl Trait<ASSOC = 3, ASSOC = 4>) {}
|
|||
| ^^^^^^^^^ required by this bound in `uncallable_const`
|
||||
|
||||
error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4`
|
||||
--> $DIR/duplicate-bound-err.rs:122:20
|
||||
--> $DIR/duplicate-bound-err.rs:124:20
|
||||
|
|
||||
LL | uncallable_rtn(());
|
||||
| -------------- ^^ expected `4`, found `3`
|
||||
|
|
@ -241,13 +241,15 @@ LL | uncallable_rtn(());
|
|||
= note: expected constant `4`
|
||||
found constant `3`
|
||||
note: required by a bound in `uncallable_rtn`
|
||||
--> $DIR/duplicate-bound-err.rs:84:75
|
||||
--> $DIR/duplicate-bound-err.rs:85:61
|
||||
|
|
||||
LL | fn uncallable_rtn(_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
|
||||
| ^^^^^^^^^ required by this bound in `uncallable_rtn`
|
||||
LL | fn uncallable_rtn(
|
||||
| -------------- required by a bound in this function
|
||||
LL | _: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>
|
||||
| ^^^^^^^^^ required by this bound in `uncallable_rtn`
|
||||
|
||||
error[E0271]: type mismatch resolving `<u32 as Trait>::ASSOC == 3`
|
||||
--> $DIR/duplicate-bound-err.rs:123:20
|
||||
--> $DIR/duplicate-bound-err.rs:125:20
|
||||
|
|
||||
LL | uncallable_rtn(17u32);
|
||||
| -------------- ^^^^^ expected `3`, found `4`
|
||||
|
|
@ -257,10 +259,12 @@ LL | uncallable_rtn(17u32);
|
|||
= note: expected constant `3`
|
||||
found constant `4`
|
||||
note: required by a bound in `uncallable_rtn`
|
||||
--> $DIR/duplicate-bound-err.rs:84:48
|
||||
--> $DIR/duplicate-bound-err.rs:85:34
|
||||
|
|
||||
LL | fn uncallable_rtn(_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
|
||||
| ^^^^^^^^^ required by this bound in `uncallable_rtn`
|
||||
LL | fn uncallable_rtn(
|
||||
| -------------- required by a bound in this function
|
||||
LL | _: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>
|
||||
| ^^^^^^^^^ required by this bound in `uncallable_rtn`
|
||||
|
||||
error: aborting due to 25 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -224,7 +224,9 @@ fn uncallable_const(_: impl Trait<ASSOC = 3, ASSOC = 4>) {}
|
|||
|
||||
fn callable_const(_: impl Trait<ASSOC = 3, ASSOC = 3>) {}
|
||||
|
||||
fn uncallable_rtn(_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
|
||||
fn uncallable_rtn(
|
||||
_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>
|
||||
) {}
|
||||
|
||||
fn callable_rtn(_: impl Trait<foo(..): Send, foo(..): Send, foo(..): Eq>) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ impl<T> AssocConst for (T,) {
|
|||
|
||||
trait Trait {}
|
||||
|
||||
impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
|
||||
impl<U> Trait for () where (U,): AssocConst<A = 0> {}
|
||||
//~^ ERROR associated const equality is incomplete
|
||||
//~| ERROR the type parameter `U` is not constrained by the impl trait
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error[E0658]: associated const equality is incomplete
|
||||
--> $DIR/unconstrained_impl_param.rs:15:45
|
||||
|
|
||||
LL | impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
|
||||
| ^^^^^^^^^
|
||||
LL | impl<U> Trait for () where (U,): AssocConst<A = 0> {}
|
||||
| ^^^^^
|
||||
|
|
||||
= 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
|
||||
|
|
@ -11,7 +11,7 @@ LL | impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
|
|||
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
|
||||
--> $DIR/unconstrained_impl_param.rs:15:6
|
||||
|
|
||||
LL | impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
|
||||
LL | impl<U> Trait for () where (U,): AssocConst<A = 0> {}
|
||||
| ^ unconstrained type parameter
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
|
|
|
|||
70
tests/ui/const-generics/mgca/explicit_anon_consts.rs
Normal file
70
tests/ui/const-generics/mgca/explicit_anon_consts.rs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#![feature(associated_const_equality, generic_const_items, min_generic_const_args)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
struct Foo<const N: usize>;
|
||||
|
||||
type Adt1<const N: usize> = Foo<N>;
|
||||
type Adt2<const N: usize> = Foo<{ N }>;
|
||||
type Adt3<const N: usize> = Foo<const { N }>;
|
||||
//~^ ERROR: generic parameters may not be used in const operations
|
||||
type Adt4<const N: usize> = Foo<{ 1 + 1 }>;
|
||||
//~^ ERROR: complex const arguments must be placed inside of a `const` block
|
||||
type Adt5<const N: usize> = Foo<const { 1 + 1 }>;
|
||||
|
||||
type Arr<const N: usize> = [(); N];
|
||||
type Arr2<const N: usize> = [(); { N }];
|
||||
type Arr3<const N: usize> = [(); const { N }];
|
||||
//~^ ERROR: generic parameters may not be used in const operations
|
||||
type Arr4<const N: usize> = [(); 1 + 1];
|
||||
//~^ ERROR: complex const arguments must be placed inside of a `const` block
|
||||
type Arr5<const N: usize> = [(); const { 1 + 1 }];
|
||||
|
||||
fn repeats<const N: usize>() {
|
||||
let _1 = [(); N];
|
||||
let _2 = [(); { N }];
|
||||
let _3 = [(); const { N }];
|
||||
//~^ ERROR: generic parameters may not be used in const operations
|
||||
let _4 = [(); 1 + 1];
|
||||
//~^ ERROR: complex const arguments must be placed inside of a `const` block
|
||||
let _5 = [(); const { 1 + 1 }];
|
||||
}
|
||||
|
||||
#[type_const]
|
||||
const ITEM1<const N: usize>: usize = N;
|
||||
#[type_const]
|
||||
const ITEM2<const N: usize>: usize = { N };
|
||||
#[type_const]
|
||||
const ITEM3<const N: usize>: usize = const { N };
|
||||
//~^ ERROR: generic parameters may not be used in const operations
|
||||
#[type_const]
|
||||
const ITEM4<const N: usize>: usize = { 1 + 1 };
|
||||
//~^ ERROR: complex const arguments must be placed inside of a `const` block
|
||||
#[type_const]
|
||||
const ITEM5<const N: usize>: usize = const { 1 + 1};
|
||||
|
||||
trait Trait {
|
||||
#[type_const]
|
||||
const ASSOC: usize;
|
||||
}
|
||||
|
||||
fn ace_bounds<
|
||||
const N: usize,
|
||||
// We skip the T1 case because it doesn't resolve
|
||||
// T1: Trait<ASSOC = N>,
|
||||
T2: Trait<ASSOC = { N }>,
|
||||
T3: Trait<ASSOC = const { N }>,
|
||||
//~^ ERROR: generic parameters may not be used in const operations
|
||||
T4: Trait<ASSOC = { 1 + 1 }>,
|
||||
//~^ ERROR: complex const arguments must be placed inside of a `const` block
|
||||
T5: Trait<ASSOC = const { 1 + 1 }>,
|
||||
>() {}
|
||||
|
||||
struct Default1<const N: usize, const M: usize = N>;
|
||||
struct Default2<const N: usize, const M: usize = { N }>;
|
||||
struct Default3<const N: usize, const M: usize = const { N }>;
|
||||
//~^ ERROR: generic parameters may not be used in const operations
|
||||
struct Default4<const N: usize, const M: usize = { 1 + 1 }>;
|
||||
//~^ ERROR: complex const arguments must be placed inside of a `const` block
|
||||
struct Default5<const N: usize, const M: usize = const { 1 + 1}>;
|
||||
|
||||
fn main() {}
|
||||
92
tests/ui/const-generics/mgca/explicit_anon_consts.stderr
Normal file
92
tests/ui/const-generics/mgca/explicit_anon_consts.stderr
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/explicit_anon_consts.rs:8:41
|
||||
|
|
||||
LL | type Adt3<const N: usize> = Foo<const { N }>;
|
||||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments here, i.e. `N`
|
||||
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/explicit_anon_consts.rs:16:42
|
||||
|
|
||||
LL | type Arr3<const N: usize> = [(); const { N }];
|
||||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments here, i.e. `N`
|
||||
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/explicit_anon_consts.rs:25:27
|
||||
|
|
||||
LL | let _3 = [(); const { N }];
|
||||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments here, i.e. `N`
|
||||
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/explicit_anon_consts.rs:37:46
|
||||
|
|
||||
LL | const ITEM3<const N: usize>: usize = const { N };
|
||||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments here, i.e. `N`
|
||||
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/explicit_anon_consts.rs:55:31
|
||||
|
|
||||
LL | T3: Trait<ASSOC = const { N }>,
|
||||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments here, i.e. `N`
|
||||
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/explicit_anon_consts.rs:64:58
|
||||
|
|
||||
LL | struct Default3<const N: usize, const M: usize = const { N }>;
|
||||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments here, i.e. `N`
|
||||
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: complex const arguments must be placed inside of a `const` block
|
||||
--> $DIR/explicit_anon_consts.rs:10:33
|
||||
|
|
||||
LL | type Adt4<const N: usize> = Foo<{ 1 + 1 }>;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: complex const arguments must be placed inside of a `const` block
|
||||
--> $DIR/explicit_anon_consts.rs:18:34
|
||||
|
|
||||
LL | type Arr4<const N: usize> = [(); 1 + 1];
|
||||
| ^^^^^
|
||||
|
||||
error: complex const arguments must be placed inside of a `const` block
|
||||
--> $DIR/explicit_anon_consts.rs:27:19
|
||||
|
|
||||
LL | let _4 = [(); 1 + 1];
|
||||
| ^^^^^
|
||||
|
||||
error: complex const arguments must be placed inside of a `const` block
|
||||
--> $DIR/explicit_anon_consts.rs:40:38
|
||||
|
|
||||
LL | const ITEM4<const N: usize>: usize = { 1 + 1 };
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: complex const arguments must be placed inside of a `const` block
|
||||
--> $DIR/explicit_anon_consts.rs:57:23
|
||||
|
|
||||
LL | T4: Trait<ASSOC = { 1 + 1 }>,
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: complex const arguments must be placed inside of a `const` block
|
||||
--> $DIR/explicit_anon_consts.rs:66:50
|
||||
|
|
||||
LL | struct Default4<const N: usize, const M: usize = { 1 + 1 }>;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
//@ check-pass
|
||||
|
||||
// We allow for literals to implicitly be anon consts still regardless
|
||||
// of whether a const block is placed around them or not
|
||||
|
||||
#![feature(min_generic_const_args, associated_const_equality)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
trait Trait {
|
||||
#[type_const]
|
||||
const ASSOC: isize;
|
||||
}
|
||||
|
||||
fn ace<T: Trait<ASSOC = 1, ASSOC = -1>>() {}
|
||||
fn repeat_count() {
|
||||
[(); 1];
|
||||
}
|
||||
type ArrLen = [(); 1];
|
||||
struct Foo<const N: isize>;
|
||||
type NormalArg = (Foo<1>, Foo<-1>);
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
//@ check-pass
|
||||
|
||||
#![feature(min_generic_const_args)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
struct Foo<const N: usize>;
|
||||
|
||||
trait Trait {
|
||||
#[type_const]
|
||||
const ASSOC: usize;
|
||||
}
|
||||
|
||||
type Arr<const N: usize> = [(); {{{ N }}}];
|
||||
type Arr2<T> = [(); {{{ <T as Trait>::ASSOC }}}];
|
||||
type Ty<const N: usize> = Foo<{{{ N }}}>;
|
||||
type Ty2<T> = Foo<{{{ <T as Trait>::ASSOC }}}>;
|
||||
struct Default<const N: usize, const M: usize = {{{ N }}}>;
|
||||
struct Default2<T: Trait, const M: usize = {{{ <T as Trait>::ASSOC }}}>(T);
|
||||
|
||||
fn repeat<T: Trait, const N: usize>() {
|
||||
let _1 = [(); {{{ N }}}];
|
||||
let _2 = [(); {{{ <T as Trait>::ASSOC }}}];
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -4,9 +4,9 @@
|
|||
struct S;
|
||||
|
||||
// FIXME(mgca): need support for ctors without anon const
|
||||
// (we use double-braces to trigger an anon const here)
|
||||
// (we use a const-block to trigger an anon const here)
|
||||
#[type_const]
|
||||
const FREE: S = { { S } };
|
||||
const FREE: S = const { S };
|
||||
//~^ ERROR `S` must implement `ConstParamTy` to be used as the type of a const generic parameter
|
||||
|
||||
trait Tr {
|
||||
|
|
@ -17,9 +17,9 @@ trait Tr {
|
|||
|
||||
impl Tr for S {
|
||||
// FIXME(mgca): need support for ctors without anon const
|
||||
// (we use double-braces to trigger an anon const here)
|
||||
// (we use a const-block to trigger an anon const here)
|
||||
#[type_const]
|
||||
const N: S = { { S } };
|
||||
const N: S = const { S };
|
||||
//~^ ERROR `S` must implement `ConstParamTy` to be used as the type of a const generic parameter
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
error[E0741]: `S` must implement `ConstParamTy` to be used as the type of a const generic parameter
|
||||
--> $DIR/type_const-not-constparamty.rs:9:13
|
||||
|
|
||||
LL | const FREE: S = { { S } };
|
||||
LL | const FREE: S = const { S };
|
||||
| ^
|
||||
|
|
||||
help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct
|
||||
|
|
@ -13,7 +13,7 @@ LL | struct S;
|
|||
error[E0741]: `S` must implement `ConstParamTy` to be used as the type of a const generic parameter
|
||||
--> $DIR/type_const-not-constparamty.rs:22:14
|
||||
|
|
||||
LL | const N: S = { { S } };
|
||||
LL | const N: S = const { S };
|
||||
| ^
|
||||
|
|
||||
help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
#![feature(min_generic_const_args, generic_const_items)]
|
||||
|
||||
#[type_const]
|
||||
const FREE1<T>: usize = std::mem::size_of::<T>();
|
||||
const FREE1<T>: usize = const { std::mem::size_of::<T>() };
|
||||
//~^ ERROR generic parameters may not be used in const operations
|
||||
#[type_const]
|
||||
const FREE2<const I: usize>: usize = I + 1;
|
||||
const FREE2<const I: usize>: usize = const { I + 1 };
|
||||
//~^ ERROR generic parameters may not be used in const operations
|
||||
|
||||
pub trait Tr<const X: usize> {
|
||||
|
|
@ -21,13 +21,13 @@ pub struct S;
|
|||
|
||||
impl<const X: usize> Tr<X> for S {
|
||||
#[type_const]
|
||||
const N1<T>: usize = std::mem::size_of::<T>();
|
||||
const N1<T>: usize = const { std::mem::size_of::<T>() };
|
||||
//~^ ERROR generic parameters may not be used in const operations
|
||||
#[type_const]
|
||||
const N2<const I: usize>: usize = I + 1;
|
||||
const N2<const I: usize>: usize = const { I + 1 };
|
||||
//~^ ERROR generic parameters may not be used in const operations
|
||||
#[type_const]
|
||||
const N3: usize = 2 & X;
|
||||
const N3: usize = const { 2 & X };
|
||||
//~^ ERROR generic parameters may not be used in const operations
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,44 +1,44 @@
|
|||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/type_const-on-generic-expr.rs:5:45
|
||||
--> $DIR/type_const-on-generic-expr.rs:5:53
|
||||
|
|
||||
LL | const FREE1<T>: usize = std::mem::size_of::<T>();
|
||||
| ^ cannot perform const operation using `T`
|
||||
LL | const FREE1<T>: usize = const { std::mem::size_of::<T>() };
|
||||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/type_const-on-generic-expr.rs:8:38
|
||||
--> $DIR/type_const-on-generic-expr.rs:8:46
|
||||
|
|
||||
LL | const FREE2<const I: usize>: usize = I + 1;
|
||||
| ^ cannot perform const operation using `I`
|
||||
LL | const FREE2<const I: usize>: usize = const { I + 1 };
|
||||
| ^ cannot perform const operation using `I`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments here, i.e. `I`
|
||||
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/type_const-on-generic-expr.rs:24:46
|
||||
--> $DIR/type_const-on-generic-expr.rs:24:54
|
||||
|
|
||||
LL | const N1<T>: usize = std::mem::size_of::<T>();
|
||||
| ^ cannot perform const operation using `T`
|
||||
LL | const N1<T>: usize = const { std::mem::size_of::<T>() };
|
||||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/type_const-on-generic-expr.rs:27:39
|
||||
--> $DIR/type_const-on-generic-expr.rs:27:47
|
||||
|
|
||||
LL | const N2<const I: usize>: usize = I + 1;
|
||||
| ^ cannot perform const operation using `I`
|
||||
LL | const N2<const I: usize>: usize = const { I + 1 };
|
||||
| ^ cannot perform const operation using `I`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments here, i.e. `I`
|
||||
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/type_const-on-generic-expr.rs:30:27
|
||||
--> $DIR/type_const-on-generic-expr.rs:30:35
|
||||
|
|
||||
LL | const N3: usize = 2 & X;
|
||||
| ^ cannot perform const operation using `X`
|
||||
LL | const N3: usize = const { 2 & X };
|
||||
| ^ cannot perform const operation using `X`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments here, i.e. `X`
|
||||
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
#![feature(adt_const_params)]
|
||||
|
||||
#[derive(Eq, PartialEq, std::marker::ConstParamTy)]
|
||||
struct Inner<const N: usize>;
|
||||
|
||||
struct Foo<
|
||||
const PARAM_TY: Inner<const { 1 }>,
|
||||
//~^ ERROR: unbraced const blocks as const args are experimental
|
||||
const DEFAULT: usize = const { 1 },
|
||||
//~^ ERROR: unbraced const blocks as const args are experimental
|
||||
>;
|
||||
|
||||
type Array = [(); const { 1 }];
|
||||
type NormalTy = Inner<const { 1 }>;
|
||||
//~^ ERROR: unbraced const blocks as const args are experimental
|
||||
|
||||
fn repeat() {
|
||||
[1_u8; const { 1 }];
|
||||
}
|
||||
|
||||
fn body_ty() {
|
||||
let _: Inner<const { 1 }>;
|
||||
//~^ ERROR: unbraced const blocks as const args are experimental
|
||||
}
|
||||
|
||||
fn generic<const N: usize>() {
|
||||
if false {
|
||||
generic::<const { 1 }>();
|
||||
//~^ ERROR: unbraced const blocks as const args are experimental
|
||||
}
|
||||
}
|
||||
|
||||
const NON_TYPE_CONST: usize = const { 1 };
|
||||
|
||||
#[type_const]
|
||||
//~^ ERROR: the `#[type_const]` attribute is an experimental feature
|
||||
const TYPE_CONST: usize = const { 1 };
|
||||
//~^ ERROR: unbraced const blocks as const args are experimental
|
||||
|
||||
static STATIC: usize = const { 1 };
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
error[E0658]: unbraced const blocks as const args are experimental
|
||||
--> $DIR/unbraced_const_block_const_arg_gated.rs:7:33
|
||||
|
|
||||
LL | const PARAM_TY: Inner<const { 1 }>,
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
|
||||
= help: add `#![feature(min_generic_const_args)]` 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[E0658]: unbraced const blocks as const args are experimental
|
||||
--> $DIR/unbraced_const_block_const_arg_gated.rs:9:34
|
||||
|
|
||||
LL | const DEFAULT: usize = const { 1 },
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
|
||||
= help: add `#![feature(min_generic_const_args)]` 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[E0658]: unbraced const blocks as const args are experimental
|
||||
--> $DIR/unbraced_const_block_const_arg_gated.rs:14:29
|
||||
|
|
||||
LL | type NormalTy = Inner<const { 1 }>;
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
|
||||
= help: add `#![feature(min_generic_const_args)]` 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[E0658]: unbraced const blocks as const args are experimental
|
||||
--> $DIR/unbraced_const_block_const_arg_gated.rs:22:24
|
||||
|
|
||||
LL | let _: Inner<const { 1 }>;
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
|
||||
= help: add `#![feature(min_generic_const_args)]` 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[E0658]: unbraced const blocks as const args are experimental
|
||||
--> $DIR/unbraced_const_block_const_arg_gated.rs:28:25
|
||||
|
|
||||
LL | generic::<const { 1 }>();
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
|
||||
= help: add `#![feature(min_generic_const_args)]` 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[E0658]: unbraced const blocks as const args are experimental
|
||||
--> $DIR/unbraced_const_block_const_arg_gated.rs:37:33
|
||||
|
|
||||
LL | const TYPE_CONST: usize = const { 1 };
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
|
||||
= help: add `#![feature(min_generic_const_args)]` 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[E0658]: the `#[type_const]` attribute is an experimental feature
|
||||
--> $DIR/unbraced_const_block_const_arg_gated.rs:35:1
|
||||
|
|
||||
LL | #[type_const]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
|
||||
= help: add `#![feature(min_generic_const_args)]` 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 7 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
@ -9,6 +9,6 @@ trait Trait {
|
|||
//~^ ERROR using function pointers as const generic parameters is forbidden
|
||||
}
|
||||
|
||||
fn take(_: impl Trait<F = { || {} }>) {}
|
||||
fn take(_: impl Trait<F = const { || {} }>) {}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ impl<TA> Pins<TA> for NoPin {}
|
|||
|
||||
pub trait PinA<PER> {
|
||||
#[type_const]
|
||||
const A: &'static () = &();
|
||||
const A: &'static () = const { &() };
|
||||
}
|
||||
|
||||
pub trait Pins<USART> {}
|
||||
|
||||
impl<USART, T> Pins<USART> for T where T: PinA<USART, A = { &() }> {}
|
||||
impl<USART, T> Pins<USART> for T where T: PinA<USART, A = const { &() }> {}
|
||||
//~^ ERROR conflicting implementations of trait `Pins<_>` for type `NoPin`
|
||||
|
||||
pub fn main() {}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ error[E0119]: conflicting implementations of trait `Pins<_>` for type `NoPin`
|
|||
LL | impl<TA> Pins<TA> for NoPin {}
|
||||
| --------------------------- first implementation here
|
||||
...
|
||||
LL | impl<USART, T> Pins<USART> for T where T: PinA<USART, A = { &() }> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin`
|
||||
LL | impl<USART, T> Pins<USART> for T where T: PinA<USART, A = const { &() }> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin`
|
||||
|
|
||||
= note: downstream crates may implement trait `PinA<_>` for type `NoPin`
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ impl Owner for () {
|
|||
#[type_const]
|
||||
const C<const N: u32>: u32 = N;
|
||||
#[type_const]
|
||||
const K<const N: u32>: u32 = 99 + 1;
|
||||
const K<const N: u32>: u32 = const { 99 + 1 };
|
||||
// FIXME(mgca): re-enable once we properly support ctors and generics on paths
|
||||
// #[type_const]
|
||||
// const Q<T>: Maybe<T> = Maybe::Nothing;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue