Auto merge of #152324 - Keith-Cancel:mgca4, r=BoxyUwU

Update mgca to use `type const` syntax instead of the `#[type_const]` attribute. 

This PR changes the `#[type_const]` attribute to the `type const` syntax for  https://github.com/rust-lang/rust/issues/132980.

This will fixes https://github.com/rust-lang/rust/issues/151273 and similar issues, since we need to check `type const` of items before expansion. The move to add a syntax was mentioned here: https://github.com/rust-lang/rust/pull/151289#issuecomment-3765241397

The first part of this PR adds support by allowing `type const <IDENT>: <TYPE> { = <EXPR> };` syntax in `rustc_parse/src/parser/item.rs`.

The next part since the AST item does not contain enough information to determine if we have a `type const` was rework `ConstItemRhs` into `ConstItemRhsKind` to store the information since we no longer have the attribute acting as a source of extra data/metadata. 

The hir node `ConstItemRhsKind` current shape mostly works, except in the case of `TraitItemKind` where it is an option. I initially went about giving `hir::ConstItemRhsKind` a similar form the AST, but it touches a lot more lines of code and files so because of that, the less invasive option was to add a simple boolean flag to `TraitItemKind`. 

The forth part of this PR includes adding a query I called `is_rhs_type_const` so that we can handle both local and foreign def_ids. 

The fifth aspect of the PR is adding a `mgca_type_const_syntax` feature gate that is checked before expansion. The standard mgca feature gate is ran after expansion. This feature gate allows for conditional compilation (e.g #[cfg(..)]) of the `type const` syntax  in nightly without `min_generic_const_args` being enabled. 

The last bit is updating all the the tests that used the `#[type_const]` attribute to use the new syntax that failed because of the changes. This is the bulk of touched/edited files in the PR. 

r? @BoxyUwU 
@rustbot label +F-associated_const_equality +F-min_generic_const_args
This commit is contained in:
bors 2026-02-09 22:37:29 +00:00
commit 381e9ef09e
204 changed files with 1014 additions and 906 deletions

View file

@ -3869,27 +3869,44 @@ pub struct ConstItem {
pub ident: Ident,
pub generics: Generics,
pub ty: Box<Ty>,
pub rhs: Option<ConstItemRhs>,
pub rhs_kind: ConstItemRhsKind,
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub enum ConstItemRhs {
TypeConst(AnonConst),
Body(Box<Expr>),
pub enum ConstItemRhsKind {
Body { rhs: Option<Box<Expr>> },
TypeConst { rhs: Option<AnonConst> },
}
impl ConstItemRhs {
pub fn span(&self) -> Span {
self.expr().span
impl ConstItemRhsKind {
pub fn new_body(rhs: Box<Expr>) -> Self {
Self::Body { rhs: Some(rhs) }
}
pub fn expr(&self) -> &Expr {
pub fn span(&self) -> Option<Span> {
Some(self.expr()?.span)
}
pub fn expr(&self) -> Option<&Expr> {
match self {
ConstItemRhs::TypeConst(anon_const) => &anon_const.value,
ConstItemRhs::Body(expr) => expr,
Self::Body { rhs: Some(body) } => Some(&body),
Self::TypeConst { rhs: Some(anon) } => Some(&anon.value),
_ => None,
}
}
pub fn has_expr(&self) -> bool {
match self {
Self::Body { rhs: Some(_) } => true,
Self::TypeConst { rhs: Some(_) } => true,
_ => false,
}
}
pub fn is_type_const(&self) -> bool {
matches!(self, &Self::TypeConst { .. })
}
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]

View file

@ -427,7 +427,7 @@ macro_rules! common_visitor_and_walkers {
Const,
ConstBlockItem,
ConstItem,
ConstItemRhs,
ConstItemRhsKind,
Defaultness,
Delegation,
DelegationMac,

View file

@ -288,7 +288,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ident,
generics,
ty,
rhs,
rhs_kind,
define_opaque,
}) => {
let ident = self.lower_ident(*ident);
@ -301,7 +301,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span);
let rhs = this.lower_const_item_rhs(rhs_kind, span);
(ty, rhs)
},
);
@ -941,7 +941,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (ident, generics, kind, has_default) = match &i.kind {
AssocItemKind::Const(box ConstItem {
ident, generics, ty, rhs, define_opaque, ..
ident,
generics,
ty,
rhs_kind,
define_opaque,
..
}) => {
let (generics, kind) = self.lower_generics(
generics,
@ -952,15 +957,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
let rhs = rhs
.as_ref()
.map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span));
hir::TraitItemKind::Const(ty, rhs)
// Trait associated consts don't need an expression/body.
let rhs = if rhs_kind.has_expr() {
Some(this.lower_const_item_rhs(rhs_kind, i.span))
} else {
None
};
hir::TraitItemKind::Const(ty, rhs, rhs_kind.is_type_const().into())
},
);
if define_opaque.is_some() {
if rhs.is_some() {
if rhs_kind.has_expr() {
self.lower_define_opaque(hir_id, &define_opaque);
} else {
self.dcx().span_err(
@ -970,7 +978,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
(*ident, generics, kind, rhs.is_some())
(*ident, generics, kind, rhs_kind.has_expr())
}
AssocItemKind::Fn(box Fn {
sig, ident, generics, body: None, define_opaque, ..
@ -1154,7 +1162,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (ident, (generics, kind)) = match &i.kind {
AssocItemKind::Const(box ConstItem {
ident, generics, ty, rhs, define_opaque, ..
ident,
generics,
ty,
rhs_kind,
define_opaque,
..
}) => (
*ident,
self.lower_generics(
@ -1167,7 +1180,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
this.lower_define_opaque(hir_id, &define_opaque);
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span);
let rhs = this.lower_const_item_rhs(rhs_kind, i.span);
hir::ImplItemKind::Const(ty, rhs)
},
),

View file

@ -2374,15 +2374,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_const_item_rhs(
&mut self,
attrs: &[hir::Attribute],
rhs: Option<&ConstItemRhs>,
rhs_kind: &ConstItemRhsKind,
span: Span,
) -> hir::ConstItemRhs<'hir> {
match rhs {
Some(ConstItemRhs::TypeConst(anon)) => {
match rhs_kind {
ConstItemRhsKind::Body { rhs: Some(body) } => {
hir::ConstItemRhs::Body(self.lower_const_body(span, Some(body)))
}
ConstItemRhsKind::Body { rhs: None } => {
hir::ConstItemRhs::Body(self.lower_const_body(span, None))
}
ConstItemRhsKind::TypeConst { rhs: Some(anon) } => {
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon))
}
None if find_attr!(attrs, AttributeKind::TypeConst(_)) => {
ConstItemRhsKind::TypeConst { rhs: None } => {
let const_arg = ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Error(
@ -2392,10 +2397,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg))
}
Some(ConstItemRhs::Body(body)) => {
hir::ConstItemRhs::Body(self.lower_const_body(span, Some(body)))
}
None => hir::ConstItemRhs::Body(self.lower_const_body(span, None)),
}
}

View file

@ -1361,9 +1361,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
});
}
ItemKind::Const(box ConstItem { defaultness, ident, rhs, .. }) => {
ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => {
self.check_defaultness(item.span, *defaultness);
if rhs.is_none() {
if !rhs_kind.has_expr() {
self.dcx().emit_err(errors::ConstWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
@ -1715,11 +1715,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
if let AssocCtxt::Impl { .. } = ctxt {
match &item.kind {
AssocItemKind::Const(box ConstItem { rhs: None, .. }) => {
self.dcx().emit_err(errors::AssocConstWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
});
AssocItemKind::Const(box ConstItem { rhs_kind, .. }) => {
if !rhs_kind.has_expr() {
self.dcx().emit_err(errors::AssocConstWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
});
}
}
AssocItemKind::Fn(box Fn { body, .. }) => {
if body.is_none() && !self.is_sdylib_interface {

View file

@ -249,6 +249,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => {
self.check_impl_trait(ty, false)
}
ast::ItemKind::Const(box ast::ConstItem {
rhs_kind: ast::ConstItemRhsKind::TypeConst { .. },
..
}) => {
// Make sure this is only allowed if the feature gate is enabled.
// #![feature(min_generic_const_args)]
gate!(&self, min_generic_const_args, i.span, "top-level `type const` are unstable");
}
_ => {}
}
@ -422,6 +430,20 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
false
}
ast::AssocItemKind::Const(box ast::ConstItem {
rhs_kind: ast::ConstItemRhsKind::TypeConst { .. },
..
}) => {
// Make sure this is only allowed if the feature gate is enabled.
// #![feature(min_generic_const_args)]
gate!(
&self,
min_generic_const_args,
i.span,
"associated `type const` are unstable"
);
false
}
_ => false,
};
if let ast::Defaultness::Default(_) = i.kind.defaultness() {
@ -528,6 +550,27 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
}
}
}
// `mgca_type_const_syntax` is part of `min_generic_const_args` so either
// or both are enabled we don't need to emit a feature error.
if let Some(spans) = spans.get(&sym::mgca_type_const_syntax) {
for span in spans {
if visitor.features.min_generic_const_args()
|| visitor.features.mgca_type_const_syntax()
|| span.allows_unstable(sym::min_generic_const_args)
|| span.allows_unstable(sym::mgca_type_const_syntax)
{
continue;
}
feature_err(
&visitor.sess,
sym::min_generic_const_args,
*span,
"`type const` syntax is experimental",
)
.emit();
}
}
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");

View file

@ -221,7 +221,7 @@ impl<'a> State<'a> {
ident,
generics,
ty,
rhs,
rhs_kind,
define_opaque,
}) => {
self.print_item_const(
@ -229,7 +229,7 @@ impl<'a> State<'a> {
None,
generics,
ty,
rhs.as_ref().map(|ct| ct.expr()),
rhs_kind.expr(),
&item.vis,
ast::Safety::Default,
*defaultness,
@ -573,7 +573,7 @@ impl<'a> State<'a> {
ident,
generics,
ty,
rhs,
rhs_kind,
define_opaque,
}) => {
self.print_item_const(
@ -581,7 +581,7 @@ impl<'a> State<'a> {
None,
generics,
ty,
rhs.as_ref().map(|ct| ct.expr()),
rhs_kind.expr(),
vis,
ast::Safety::Default,
*defaultness,

View file

@ -66,15 +66,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for ParenSugarParser {
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcParenSugar;
}
pub(crate) struct TypeConstParser;
impl<S: Stage> NoArgsAttributeParser<S> for TypeConstParser {
const PATH: &[Symbol] = &[sym::type_const];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Const), Allow(Target::AssocConst)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::TypeConst;
}
// Markers
pub(crate) struct MarkerParser;

View file

@ -299,7 +299,6 @@ attribute_parsers!(
Single<WithoutArgs<StdInternalSymbolParser>>,
Single<WithoutArgs<ThreadLocalParser>>,
Single<WithoutArgs<TrackCallerParser>>,
Single<WithoutArgs<TypeConstParser>>,
Single<WithoutArgs<UnsafeSpecializationMarkerParser>>,
// tidy-alphabetical-end
];

View file

@ -43,7 +43,7 @@ pub(crate) fn expand(
// Generate anonymous constant serving as container for the allocator methods.
let const_ty = ecx.ty(sig_span, TyKind::Tup(ThinVec::new()));
let const_body = ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts)));
let const_body = ast::ConstItemRhsKind::new_body(ecx.expr_block(ecx.block(span, stmts)));
let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
let const_item = if is_stmt {
Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item)))

View file

@ -232,7 +232,7 @@ fn generate_default_impl(
span,
underscore,
unit,
ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts))),
ast::ConstItemRhsKind::new_body(ecx.expr_block(ecx.block(span, stmts))),
)
};

View file

@ -47,7 +47,7 @@ pub(crate) fn expand(
// Generate anonymous constant serving as container for the allocator methods.
let const_ty = ecx.ty(ty_span, TyKind::Tup(ThinVec::new()));
let const_body = ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts)));
let const_body = ast::ConstItemRhsKind::new_body(ecx.expr_block(ecx.block(span, stmts)));
let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
let const_item = if is_stmt {
Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item)))

View file

@ -385,7 +385,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> Box<ast::Item> {
cx.attr_nested_word(sym::allow, sym::deprecated, span),
]);
let block = ast::ConstItemRhs::Body(cx.expr_block(
let block = ast::ConstItemRhsKind::new_body(cx.expr_block(
cx.block(span, thin_vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]),
));

View file

@ -289,7 +289,7 @@ pub(crate) fn expand_test_or_bench(
ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
define_opaque: None,
// test::TestDescAndFn {
rhs: Some(ast::ConstItemRhs::Body(
rhs_kind: ast::ConstItemRhsKind::new_body(
cx.expr_struct(
sp,
test_path("TestDescAndFn"),
@ -371,7 +371,7 @@ pub(crate) fn expand_test_or_bench(
field("testfn", test_fn), // }
],
), // }
)),
),
}
.into(),
),

View file

@ -345,7 +345,7 @@ where
let uneval = match constant.const_ {
Const::Ty(_, ct) => match ct.kind() {
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) => None,
// Unevaluated consts in MIR bodies don't have associated MIR (e.g. `#[type_const]`).
// Unevaluated consts in MIR bodies don't have associated MIR (e.g. `type const`).
ty::ConstKind::Unevaluated(_) => None,
// FIXME(mgca): Investigate whether using `None` for `ConstKind::Value` is overly
// strict, and if instead we should be doing some kind of value-based analysis.

View file

@ -394,7 +394,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
typing_env: ty::TypingEnv<'tcx>,
) -> Result<R, ErrorHandled> {
let def = cid.instance.def.def_id();
// #[type_const] don't have bodys
// `type const` don't have bodys
debug_assert!(!tcx.is_type_const(def), "CTFE tried to evaluate type-const: {:?}", def);
let is_static = tcx.is_static(def);

View file

@ -727,7 +727,7 @@ impl<'a> ExtCtxt<'a> {
span: Span,
ident: Ident,
ty: Box<ast::Ty>,
rhs: ast::ConstItemRhs,
rhs_kind: ast::ConstItemRhsKind,
) -> Box<ast::Item> {
let defaultness = ast::Defaultness::Final;
self.item(
@ -740,7 +740,7 @@ impl<'a> ExtCtxt<'a> {
// FIXME(generic_const_items): Pass the generics as a parameter.
generics: ast::Generics::default(),
ty,
rhs: Some(rhs),
rhs_kind,
define_opaque: None,
}
.into(),

View file

@ -888,13 +888,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
EncodeCrossCrate::Yes, experimental!(patchable_function_entry)
),
// Probably temporary component of min_generic_const_args.
// `#[type_const] const ASSOC: usize;`
gated!(
type_const, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes, min_generic_const_args, experimental!(type_const),
),
// The `#[loop_match]` and `#[const_continue]` attributes are part of the
// lang experiment for RFC 3720 tracked in:
//

View file

@ -561,6 +561,8 @@ declare_features! (
(unstable, macro_metavar_expr_concat, "1.81.0", Some(124225)),
/// Allows `#[marker]` on certain traits allowing overlapping implementations.
(unstable, marker_trait_attr, "1.30.0", Some(29864)),
/// Enable mgca `type const` syntax before expansion.
(incomplete, mgca_type_const_syntax, "CURRENT_RUSTC_VERSION", Some(132980)),
/// Enables the generic const args MVP (only bare paths, not arbitrary computation).
(incomplete, min_generic_const_args, "1.84.0", Some(132980)),
/// A minimal, sound subset of specialization intended to be used by the

View file

@ -1298,9 +1298,6 @@ pub enum AttributeKind {
/// Represents `#[track_caller]`
TrackCaller(Span),
/// Represents `#[type_const]`.
TypeConst(Span),
/// Represents `#[type_length_limit]`
TypeLengthLimit { attr_span: Span, limit_span: Span, limit: Limit },

View file

@ -171,7 +171,6 @@ impl AttributeKind {
TargetFeature { .. } => No,
ThreadLocal => No,
TrackCaller(..) => Yes,
TypeConst(..) => Yes,
TypeLengthLimit { .. } => No,
UnstableFeatureBound(..) => No,
Used { .. } => No,

View file

@ -3199,7 +3199,7 @@ impl<'hir> TraitItem<'hir> {
expect_methods_self_kind! {
expect_const, (&'hir Ty<'hir>, Option<ConstItemRhs<'hir>>),
TraitItemKind::Const(ty, rhs), (ty, *rhs);
TraitItemKind::Const(ty, rhs, _), (ty, *rhs);
expect_fn, (&FnSig<'hir>, &TraitFn<'hir>),
TraitItemKind::Fn(ty, trfn), (ty, trfn);
@ -3219,11 +3219,32 @@ pub enum TraitFn<'hir> {
Provided(BodyId),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable_Generic)]
pub enum IsTypeConst {
No,
Yes,
}
impl From<bool> for IsTypeConst {
fn from(value: bool) -> Self {
if value { Self::Yes } else { Self::No }
}
}
impl From<IsTypeConst> for bool {
fn from(value: IsTypeConst) -> Self {
matches!(value, IsTypeConst::Yes)
}
}
/// Represents a trait method or associated constant or type
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TraitItemKind<'hir> {
// FIXME(mgca) eventually want to move the option that is around `ConstItemRhs<'hir>`
// into `ConstItemRhs`, much like `ast::ConstItemRhsKind`, but for now mark whether
// this node is a TypeConst with a flag.
/// An associated constant with an optional value (otherwise `impl`s must contain a value).
Const(&'hir Ty<'hir>, Option<ConstItemRhs<'hir>>),
Const(&'hir Ty<'hir>, Option<ConstItemRhs<'hir>>, IsTypeConst),
/// An associated function with an optional body.
Fn(FnSig<'hir>, TraitFn<'hir>),
/// An associated type with (possibly empty) bounds and optional concrete
@ -4686,7 +4707,7 @@ impl<'hir> OwnerNode<'hir> {
| OwnerNode::TraitItem(TraitItem {
kind:
TraitItemKind::Fn(_, TraitFn::Provided(body))
| TraitItemKind::Const(_, Some(ConstItemRhs::Body(body))),
| TraitItemKind::Const(_, Some(ConstItemRhs::Body(body)), _),
..
})
| OwnerNode::ImplItem(ImplItem {
@ -4913,7 +4934,7 @@ impl<'hir> Node<'hir> {
_ => None,
},
Node::TraitItem(it) => match it.kind {
TraitItemKind::Const(ty, _) => Some(ty),
TraitItemKind::Const(ty, _, _) => Some(ty),
TraitItemKind::Type(_, ty) => ty,
_ => None,
},
@ -4956,7 +4977,7 @@ impl<'hir> Node<'hir> {
| Node::TraitItem(TraitItem {
owner_id,
kind:
TraitItemKind::Const(.., Some(ConstItemRhs::Body(body)))
TraitItemKind::Const(_, Some(ConstItemRhs::Body(body)), _)
| TraitItemKind::Fn(_, TraitFn::Provided(body)),
..
})

View file

@ -1271,7 +1271,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_defaultness(&defaultness));
try_visit!(visitor.visit_id(hir_id));
match *kind {
TraitItemKind::Const(ref ty, default) => {
TraitItemKind::Const(ref ty, default, _) => {
try_visit!(visitor.visit_ty_unambig(ty));
visit_opt!(visitor, visit_const_item_rhs, default);
}

View file

@ -923,7 +923,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
);
check_where_clauses(wfcx, def_id);
if tcx.is_type_const(def_id.into()) {
if tcx.is_type_const(def_id) {
wfcheck::check_type_const(wfcx, def_id, ty, true)?;
}
Ok(())

View file

@ -2060,14 +2060,14 @@ fn compare_type_const<'tcx>(
.dcx()
.struct_span_err(
tcx.def_span(impl_const_item.def_id),
"implementation of `#[type_const]` const must be marked with `#[type_const]`",
"implementation of a `type const` must also be marked as `type const`",
)
.with_span_note(
MultiSpan::from_spans(vec![
tcx.def_span(trait_const_item.def_id),
trait_type_const_span,
]),
"trait declaration of const is marked with `#[type_const]`",
"trait declaration of const is marked as `type const`",
)
.emit());
}

View file

@ -955,7 +955,7 @@ pub(crate) fn check_associated_item(
wfcx.register_wf_obligation(span, loc, ty.into());
let has_value = item.defaultness(tcx).has_value();
if tcx.is_type_const(def_id.into()) {
if tcx.is_type_const(def_id) {
check_type_const(wfcx, def_id, ty, has_value)?;
}

View file

@ -95,6 +95,7 @@ pub(crate) fn provide(providers: &mut Providers) {
const_param_default,
anon_const_kind,
const_of_item,
is_rhs_type_const,
..*providers
};
}
@ -1550,7 +1551,8 @@ fn is_anon_const_rhs_of_const_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId)
let (Node::Item(hir::Item { kind: hir::ItemKind::Const(_, _, _, ct_rhs), .. })
| Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(_, ct_rhs), .. })
| Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Const(_, Some(ct_rhs)), ..
kind: hir::TraitItemKind::Const(_, Some(ct_rhs), _),
..
})) = grandparent_node
else {
return false;
@ -1595,7 +1597,7 @@ fn const_of_item<'tcx>(
let ct_rhs = match tcx.hir_node_by_def_id(def_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(.., ct), .. }) => *ct,
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Const(.., ct), ..
kind: hir::TraitItemKind::Const(_, ct, _), ..
}) => ct.expect("no default value for trait assoc const"),
hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(.., ct), .. }) => *ct,
_ => {
@ -1625,3 +1627,22 @@ fn const_of_item<'tcx>(
ty::EarlyBinder::bind(ct)
}
}
/// Check if a Const or AssocConst is a type const (mgca)
fn is_rhs_type_const<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> bool {
match tcx.hir_node_by_def_id(def) {
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Const(_, _, _, hir::ConstItemRhs::TypeConst(_)),
..
})
| hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Const(_, hir::ConstItemRhs::TypeConst(_)),
..
})
| hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Const(_, _, hir::IsTypeConst::Yes),
..
}) => return true,
_ => return false,
}
}

View file

@ -859,7 +859,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
})
}
Const(_, _) => self.visit_early(trait_item.hir_id(), trait_item.generics, |this| {
Const(_, _, _) => self.visit_early(trait_item.hir_id(), trait_item.generics, |this| {
intravisit::walk_trait_item(this, trait_item)
}),
}

View file

@ -63,7 +63,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
}
TraitItemKind::Const(ty, rhs) => rhs
TraitItemKind::Const(ty, rhs, _) => rhs
.and_then(|rhs| {
ty.is_suggestable_infer_ty().then(|| {
infer_placeholder_type(
@ -420,9 +420,9 @@ fn infer_placeholder_type<'tcx>(
kind: &'static str,
) -> Ty<'tcx> {
let tcx = cx.tcx();
// If the type is omitted on a #[type_const] we can't run
// If the type is omitted on a `type const` we can't run
// type check on since that requires the const have a body
// which type_consts don't.
// which `type const`s don't.
let ty = if tcx.is_type_const(def_id.to_def_id()) {
if let Some(trait_item_def_id) = tcx.trait_item_of(def_id.to_def_id()) {
tcx.type_of(trait_item_def_id).instantiate_identity()
@ -430,7 +430,7 @@ fn infer_placeholder_type<'tcx>(
Ty::new_error_with_message(
tcx,
ty_span,
"constant with #[type_const] requires an explicit type",
"constant with `type const` requires an explicit type",
)
}
} else {

View file

@ -609,14 +609,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if tcx.features().min_generic_const_args() {
let mut err = self.dcx().struct_span_err(
constraint.span,
"use of trait associated const without `#[type_const]`",
"use of trait associated const not defined as `type const`",
);
err.note("the declaration in the trait must be marked with `#[type_const]`");
err.note("the declaration in the trait must begin with `type const` not just `const` alone");
return Err(err.emit());
} else {
let err = self.dcx().span_delayed_bug(
constraint.span,
"use of trait associated const without `#[type_const]`",
"use of trait associated const defined as `type const`",
);
return Err(err);
}

View file

@ -2849,19 +2849,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if tcx.is_type_const(def_id) {
Ok(())
} else {
let mut err = self
.dcx()
.struct_span_err(span, "use of `const` in the type system without `#[type_const]`");
let mut err = self.dcx().struct_span_err(
span,
"use of `const` in the type system not defined as `type const`",
);
if def_id.is_local() {
let name = tcx.def_path_str(def_id);
err.span_suggestion(
tcx.def_span(def_id).shrink_to_lo(),
format!("add `#[type_const]` attribute to `{name}`"),
format!("#[type_const]\n"),
format!("add `type` before `const` for `{name}`"),
format!("type "),
Applicability::MaybeIncorrect,
);
} else {
err.note("only consts marked with `#[type_const]` may be used in types");
err.note("only consts marked defined as `type const` may be used in types");
}
Err(err.emit())
}

View file

@ -139,7 +139,7 @@ pub(super) fn diagnostic_hir_wf_check<'tcx>(
},
hir::Node::TraitItem(item) => match item.kind {
hir::TraitItemKind::Type(_, ty) => ty.into_iter().collect(),
hir::TraitItemKind::Const(ty, _) => vec![ty],
hir::TraitItemKind::Const(ty, _, _) => vec![ty],
ref item => bug!("Unexpected TraitItem {:?}", item),
},
hir::Node::Item(item) => match item.kind {

View file

@ -233,7 +233,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
}
DefKind::Const
if !tcx.generics_of(item_def_id).own_requires_monomorphization()
&& !tcx.is_type_const(item_def_id.into()) =>
&& !tcx.is_type_const(item_def_id) =>
{
// FIXME(generic_const_items): Passing empty instead of identity args is fishy but
// seems to be fine for now. Revisit this!

View file

@ -937,7 +937,7 @@ impl<'a> State<'a> {
self.maybe_print_comment(ti.span.lo());
self.print_attrs(self.attrs(ti.hir_id()));
match ti.kind {
hir::TraitItemKind::Const(ty, default) => {
hir::TraitItemKind::Const(ty, default, _) => {
self.print_associated_const(ti.ident, ti.generics, ty, default);
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(arg_idents)) => {

View file

@ -1058,8 +1058,8 @@ trait UnusedDelimLint {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
use ast::ItemKind::*;
let expr = if let Const(box ast::ConstItem { rhs: Some(rhs), .. }) = &item.kind {
rhs.expr()
let expr = if let Const(box ast::ConstItem { rhs_kind, .. }) = &item.kind {
if let Some(e) = rhs_kind.expr() { e } else { return }
} else if let Static(box ast::StaticItem { expr: Some(expr), .. }) = &item.kind {
expr
} else {

View file

@ -418,6 +418,7 @@ provide! { tcx, def_id, other, cdata,
}
anon_const_kind => { table }
const_of_item => { table }
is_rhs_type_const => { table }
}
pub(in crate::rmeta) fn provide(providers: &mut Providers) {

View file

@ -1630,6 +1630,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let table = tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id);
record!(self.tables.associated_types_for_impl_traits_in_trait_or_impl[def_id] <- table);
}
if let DefKind::AssocConst | DefKind::Const = def_kind {
record!(self.tables.is_rhs_type_const[def_id] <- self.tcx.is_rhs_type_const(def_id));
}
}
for (def_id, impls) in &tcx.crate_inherent_impls(()).0.inherent_impls {

View file

@ -476,6 +476,7 @@ define_tables! {
anon_const_kind: Table<DefIndex, LazyValue<ty::AnonConstKind>>,
const_of_item: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::Const<'static>>>>,
associated_types_for_impl_traits_in_trait_or_impl: Table<DefIndex, LazyValue<DefIdMap<Vec<DefId>>>>,
is_rhs_type_const: Table<DefIndex, LazyValue<bool>>,
}
#[derive(TyEncodable, TyDecodable)]

View file

@ -293,13 +293,13 @@ rustc_queries! {
separate_provide_extern
}
/// Returns the const of the RHS of a (free or assoc) const item, if it is a `#[type_const]`.
/// Returns the const of the RHS of a (free or assoc) const item, if it is a `type const`.
///
/// When a const item is used in a type-level expression, like in equality for an assoc const
/// projection, this allows us to retrieve the typesystem-appropriate representation of the
/// const value.
///
/// This query will ICE if given a const that is not marked with `#[type_const]`.
/// This query will ICE if given a const that is not marked with `type const`.
query const_of_item(def_id: DefId) -> ty::EarlyBinder<'tcx, ty::Const<'tcx>> {
desc { |tcx| "computing the type-level value for `{}`", tcx.def_path_str(def_id) }
cache_on_disk_if { def_id.is_local() }
@ -2764,6 +2764,12 @@ rustc_queries! {
cache_on_disk_if { *cnum == LOCAL_CRATE }
separate_provide_extern
}
query is_rhs_type_const(def_id: DefId) -> bool {
desc { |tcx| "checking whether `{}` is a rhs type const", tcx.def_path_str(def_id) }
cache_on_disk_if { def_id.is_local() }
separate_provide_extern
}
}
rustc_with_all_queries! { define_callbacks! }

View file

@ -845,7 +845,7 @@ impl DynCompatibilityViolation {
format!("it contains generic associated const `{name}`").into()
}
Self::AssocConst(name, AssocConstViolation::NonType, _) => {
format!("it contains associated const `{name}` that's not marked `#[type_const]`")
format!("it contains associated const `{name}` that's not defined as `type const`")
.into()
}
Self::AssocConst(name, AssocConstViolation::TypeReferencesSelf, _) => format!(
@ -999,7 +999,7 @@ pub enum AssocConstViolation {
/// Has own generic parameters (GAC).
Generic,
/// Isn't marked `#[type_const]`.
/// Isn't defined as `type const`.
NonType,
/// Its type mentions the `Self` type parameter.

View file

@ -1890,14 +1890,22 @@ impl<'tcx> TyCtxt<'tcx> {
}
pub fn type_const_span(self, def_id: DefId) -> Option<Span> {
matches!(self.def_kind(def_id), DefKind::Const | DefKind::AssocConst)
.then(|| find_attr!(self.get_all_attrs(def_id), AttributeKind::TypeConst(sp) => *sp))
.flatten()
if !self.is_type_const(def_id) {
return None;
}
Some(self.def_span(def_id))
}
/// Check if the given `def_id` is a const with the `#[type_const]` attribute.
pub fn is_type_const(self, def_id: DefId) -> bool {
self.type_const_span(def_id).is_some()
/// Check if the given `def_id` is a `type const` (mgca)
pub fn is_type_const<I: Copy + IntoQueryParam<DefId>>(self, def_id: I) -> bool {
// No need to call the query directly in this case always false.
if !(matches!(
self.def_kind(def_id.into_query_param()),
DefKind::Const | DefKind::AssocConst
)) {
return false;
}
self.is_rhs_type_const(def_id)
}
/// Returns the movability of the coroutine of `def_id`, or panics
@ -2923,7 +2931,7 @@ impl<'tcx> TyCtxt<'tcx> {
) -> bool {
let generics = self.generics_of(def_id);
// IATs and IACs (inherent associated types/consts with #[type_const]) themselves have a
// IATs and IACs (inherent associated types/consts with `type const`) themselves have a
// weird arg setup (self + own args), but nested items *in* IATs (namely: opaques, i.e.
// ATPITs) do not.
let is_inherent_assoc_ty = matches!(self.def_kind(def_id), DefKind::AssocTy)

View file

@ -578,7 +578,7 @@ fn construct_const<'a, 'tcx>(
})
| Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, _), span, .. })
| Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Const(ty, Some(_)),
kind: hir::TraitItemKind::Const(ty, Some(_), _),
span,
..
}) => (*span, ty.span),

View file

@ -6,9 +6,7 @@ use rustc_ast::ast::*;
use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind};
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
use rustc_ast::util::case::Case;
use rustc_ast::{
attr, {self as ast},
};
use rustc_ast::{self as ast};
use rustc_ast_pretty::pprust;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, PResult, StashKey, inline_fluent, struct_span_code_err};
@ -286,13 +284,13 @@ impl<'a> Parser<'a> {
// CONST ITEM
self.recover_const_mut(const_span);
self.recover_missing_kw_before_item()?;
let (ident, generics, ty, rhs) = self.parse_const_item(attrs)?;
let (ident, generics, ty, rhs_kind) = self.parse_const_item(false)?;
ItemKind::Const(Box::new(ConstItem {
defaultness: def_(),
ident,
generics,
ty,
rhs,
rhs_kind,
define_opaque: None,
}))
} else if let Some(kind) = self.is_reuse_item() {
@ -303,8 +301,26 @@ impl<'a> Parser<'a> {
// MODULE ITEM
self.parse_item_mod(attrs)?
} else if self.eat_keyword_case(exp!(Type), case) {
// TYPE ITEM
self.parse_type_alias(def_())?
if let Const::Yes(const_span) = self.parse_constness(case) {
// TYPE CONST (mgca)
self.recover_const_mut(const_span);
self.recover_missing_kw_before_item()?;
let (ident, generics, ty, rhs_kind) = self.parse_const_item(true)?;
// Make sure this is only allowed if the feature gate is enabled.
// #![feature(mgca_type_const_syntax)]
self.psess.gated_spans.gate(sym::mgca_type_const_syntax, lo.to(const_span));
ItemKind::Const(Box::new(ConstItem {
defaultness: def_(),
ident,
generics,
ty,
rhs_kind,
define_opaque: None,
}))
} else {
// TYPE ITEM
self.parse_type_alias(def_())?
}
} else if self.eat_keyword_case(exp!(Enum), case) {
// ENUM ITEM
self.parse_item_enum()?
@ -1113,13 +1129,12 @@ impl<'a> Parser<'a> {
define_opaque,
}) => {
self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span });
let rhs = expr.map(ConstItemRhs::Body);
AssocItemKind::Const(Box::new(ConstItem {
defaultness: Defaultness::Final,
ident,
generics: Generics::default(),
ty,
rhs,
rhs_kind: ConstItemRhsKind::Body { rhs: expr },
define_opaque,
}))
}
@ -1360,7 +1375,7 @@ impl<'a> Parser<'a> {
let kind = match ForeignItemKind::try_from(kind) {
Ok(kind) => kind,
Err(kind) => match kind {
ItemKind::Const(box ConstItem { ident, ty, rhs, .. }) => {
ItemKind::Const(box ConstItem { ident, ty, rhs_kind, .. }) => {
let const_span = Some(span.with_hi(ident.span.lo()))
.filter(|span| span.can_be_used_for_suggestions());
self.dcx().emit_err(errors::ExternItemCannotBeConst {
@ -1371,10 +1386,13 @@ impl<'a> Parser<'a> {
ident,
ty,
mutability: Mutability::Not,
expr: rhs.map(|b| match b {
ConstItemRhs::TypeConst(anon_const) => anon_const.value,
ConstItemRhs::Body(expr) => expr,
}),
expr: match rhs_kind {
ConstItemRhsKind::Body { rhs } => rhs,
ConstItemRhsKind::TypeConst { rhs: Some(anon) } => {
Some(anon.value)
}
ConstItemRhsKind::TypeConst { rhs: None } => None,
},
safety: Safety::Default,
define_opaque: None,
}))
@ -1516,13 +1534,16 @@ impl<'a> Parser<'a> {
/// Parse a constant item with the prefix `"const"` already parsed.
///
/// If `const_arg` is true, any expression assigned to the const will be parsed
/// as a const_arg instead of a body expression.
///
/// ```ebnf
/// Const = "const" ($ident | "_") Generics ":" $ty (= $expr)? WhereClause ";" ;
/// ```
fn parse_const_item(
&mut self,
attrs: &[Attribute],
) -> PResult<'a, (Ident, Generics, Box<Ty>, Option<ast::ConstItemRhs>)> {
const_arg: bool,
) -> PResult<'a, (Ident, Generics, Box<Ty>, ConstItemRhsKind)> {
let ident = self.parse_ident_or_underscore()?;
let mut generics = self.parse_generics()?;
@ -1549,16 +1570,15 @@ impl<'a> Parser<'a> {
let before_where_clause =
if self.may_recover() { self.parse_where_clause()? } else { WhereClause::default() };
let rhs = if self.eat(exp!(Eq)) {
if attr::contains_name(attrs, sym::type_const) {
let ct =
self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?;
Some(ConstItemRhs::TypeConst(ct))
} else {
Some(ConstItemRhs::Body(self.parse_expr()?))
}
} else {
None
let rhs = match (self.eat(exp!(Eq)), const_arg) {
(true, true) => ConstItemRhsKind::TypeConst {
rhs: Some(
self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?,
),
},
(true, false) => ConstItemRhsKind::Body { rhs: Some(self.parse_expr()?) },
(false, true) => ConstItemRhsKind::TypeConst { rhs: None },
(false, false) => ConstItemRhsKind::Body { rhs: None },
};
let after_where_clause = self.parse_where_clause()?;
@ -1567,18 +1587,18 @@ impl<'a> Parser<'a> {
// Users may be tempted to write such code if they are still used to the deprecated
// where-clause location on type aliases and associated types. See also #89122.
if before_where_clause.has_where_token
&& let Some(rhs) = &rhs
&& let Some(rhs_span) = rhs.span()
{
self.dcx().emit_err(errors::WhereClauseBeforeConstBody {
span: before_where_clause.span,
name: ident.span,
body: rhs.span(),
body: rhs_span,
sugg: if !after_where_clause.has_where_token {
self.psess.source_map().span_to_snippet(rhs.span()).ok().map(|body_s| {
self.psess.source_map().span_to_snippet(rhs_span).ok().map(|body_s| {
errors::WhereClauseBeforeConstBodySugg {
left: before_where_clause.span.shrink_to_lo(),
snippet: body_s,
right: before_where_clause.span.shrink_to_hi().to(rhs.span()),
right: before_where_clause.span.shrink_to_hi().to(rhs_span),
}
})
} else {

View file

@ -358,7 +358,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::RustcVarianceOfOpaques
| AttributeKind::ShouldPanic { .. }
| AttributeKind::ThreadLocal
| AttributeKind::TypeConst{..}
| AttributeKind::TypeLengthLimit { .. }
| AttributeKind::UnstableFeatureBound(..)
| AttributeKind::Used { .. }

View file

@ -145,7 +145,7 @@ impl<'tcx> ReachableContext<'tcx> {
_ => false,
},
Node::TraitItem(trait_method) => match trait_method.kind {
hir::TraitItemKind::Const(_, ref default) => default.is_some(),
hir::TraitItemKind::Const(_, ref default, _) => default.is_some(),
hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true,
hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_))
| hir::TraitItemKind::Type(..) => false,
@ -209,7 +209,7 @@ impl<'tcx> ReachableContext<'tcx> {
self.visit_nested_body(body);
}
}
// For #[type_const] we want to evaluate the RHS.
// For `type const` we want to evaluate the RHS.
hir::ItemKind::Const(_, _, _, init @ hir::ConstItemRhs::TypeConst(_)) => {
self.visit_const_item_rhs(init);
}
@ -258,11 +258,11 @@ impl<'tcx> ReachableContext<'tcx> {
}
Node::TraitItem(trait_method) => {
match trait_method.kind {
hir::TraitItemKind::Const(_, None)
hir::TraitItemKind::Const(_, None, _)
| hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_)) => {
// Keep going, nothing to get exported
}
hir::TraitItemKind::Const(_, Some(rhs)) => self.visit_const_item_rhs(rhs),
hir::TraitItemKind::Const(_, Some(rhs), _) => self.visit_const_item_rhs(rhs),
hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)) => {
self.visit_nested_body(body_id);
}

View file

@ -2847,11 +2847,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
ident,
generics,
ty,
rhs,
rhs_kind,
define_opaque,
defaultness: _,
}) => {
let is_type_const = attr::contains_name(&item.attrs, sym::type_const);
self.with_generic_param_rib(
&generics.params,
RibKind::Item(
@ -2871,7 +2870,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
this.with_lifetime_rib(
LifetimeRibKind::Elided(LifetimeRes::Static),
|this| {
if is_type_const
if rhs_kind.is_type_const()
&& !this.r.tcx.features().generic_const_parameter_types()
{
this.with_rib(TypeNS, RibKind::ConstParamTy, |this| {
@ -2888,12 +2887,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
},
);
if let Some(rhs) = rhs {
this.resolve_const_item_rhs(
rhs,
Some((*ident, ConstantItemKind::Const)),
);
}
this.resolve_const_item_rhs(
rhs_kind,
Some((*ident, ConstantItemKind::Const)),
);
},
);
self.resolve_define_opaques(define_opaque);
@ -3242,11 +3239,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
AssocItemKind::Const(box ast::ConstItem {
generics,
ty,
rhs,
rhs_kind,
define_opaque,
..
}) => {
let is_type_const = attr::contains_name(&item.attrs, sym::type_const);
self.with_generic_param_rib(
&generics.params,
RibKind::AssocItem,
@ -3261,7 +3257,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
},
|this| {
this.visit_generics(generics);
if is_type_const
if rhs_kind.is_type_const()
&& !this.r.tcx.features().generic_const_parameter_types()
{
this.with_rib(TypeNS, RibKind::ConstParamTy, |this| {
@ -3278,14 +3274,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
// Only impose the restrictions of `ConstRibKind` for an
// actual constant expression in a provided default.
if let Some(rhs) = rhs {
// We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable.
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
this.resolve_const_item_rhs(rhs, None);
}
//
// We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable.
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
this.resolve_const_item_rhs(rhs_kind, None);
},
)
},
@ -3463,12 +3458,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
ident,
generics,
ty,
rhs,
rhs_kind,
define_opaque,
..
}) => {
debug!("resolve_implementation AssocItemKind::Const");
let is_type_const = attr::contains_name(&item.attrs, sym::type_const);
self.with_generic_param_rib(
&generics.params,
RibKind::AssocItem,
@ -3505,7 +3499,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
);
this.visit_generics(generics);
if is_type_const
if rhs_kind.is_type_const()
&& !this
.r
.tcx
@ -3527,14 +3521,12 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
} else {
this.visit_ty(ty);
}
if let Some(rhs) = rhs {
// We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable.
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
this.resolve_const_item_rhs(rhs, None);
}
// We allow arbitrary const expressions inside of associated consts,
// even if they are potentially not const evaluatable.
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
this.resolve_const_item_rhs(rhs_kind, None);
},
)
},
@ -3756,18 +3748,19 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
fn resolve_const_item_rhs(
&mut self,
rhs: &'ast ConstItemRhs,
rhs_kind: &'ast ConstItemRhsKind,
item: Option<(Ident, ConstantItemKind)>,
) {
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| match rhs {
ConstItemRhs::TypeConst(anon_const) => {
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| match rhs_kind {
ConstItemRhsKind::TypeConst { rhs: Some(anon_const) } => {
this.resolve_anon_const(anon_const, AnonConstKind::ConstArg(IsRepeatExpr::No));
}
ConstItemRhs::Body(expr) => {
ConstItemRhsKind::Body { rhs: Some(expr) } => {
this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| {
this.visit_expr(expr)
});
}
_ => (),
})
}

View file

@ -1453,6 +1453,7 @@ symbols! {
meta,
meta_sized,
metadata_type,
mgca_type_const_syntax,
min_const_fn,
min_const_generics,
min_const_unsafe_fn,
@ -2339,7 +2340,6 @@ symbols! {
type_ascribe,
type_ascription,
type_changing_struct_update,
type_const,
type_id,
type_id_eq,
type_info,

View file

@ -453,7 +453,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
// been emitted earlier in compilation.
//
// That's because we can only end up with an Unevaluated ty::Const for a const item
// if it was marked with `#[type_const]`. Using this attribute without the mgca
// if it was marked with `type const`. Using this attribute without the mgca
// feature gate causes a parse error.
let ct = match tcx.def_kind(uv.def) {
DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) {

View file

@ -1209,14 +1209,14 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
let local_did = trait_item.owner_id.to_def_id();
cx.with_param_env(local_did, |cx| {
let inner = match trait_item.kind {
hir::TraitItemKind::Const(ty, Some(default)) => {
hir::TraitItemKind::Const(ty, Some(default), _) => {
ProvidedAssocConstItem(Box::new(Constant {
generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)),
kind: clean_const_item_rhs(default, local_did),
type_: clean_ty(ty, cx),
}))
}
hir::TraitItemKind::Const(ty, None) => {
hir::TraitItemKind::Const(ty, None, _) => {
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
RequiredAssocConstItem(generics, Box::new(clean_ty(ty, cx)))
}

View file

@ -739,7 +739,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
if let TraitItemKind::Const(_, ct_rhs_opt) = item.kind
if let TraitItemKind::Const(_, ct_rhs_opt, _) = item.kind
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
&& match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) {
IsFreeze::No => true,
@ -931,7 +931,7 @@ fn get_const_hir_value<'tcx>(
{
match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) {
Node::ImplItem(item) if let ImplItemKind::Const(.., ct_rhs) = item.kind => (did, ct_rhs),
Node::TraitItem(item) if let TraitItemKind::Const(.., Some(ct_rhs)) = item.kind => (did, ct_rhs),
Node::TraitItem(item) if let TraitItemKind::Const(_, Some(ct_rhs), _) = item.kind => (did, ct_rhs),
_ => return None,
}
},

View file

@ -514,7 +514,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
};
match item.kind {
TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => {
TraitItemKind::Const(ty, _, _) | TraitItemKind::Type(_, Some(ty)) => {
self.check_ty(cx, ty, context);
},
TraitItemKind::Fn(ref sig, trait_method) => {

View file

@ -355,7 +355,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
ident: li,
generics: lg,
ty: lt,
rhs: lb,
rhs_kind: lb,
define_opaque: _,
}),
Const(box ConstItem {
@ -363,7 +363,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
ident: ri,
generics: rg,
ty: rt,
rhs: rb,
rhs_kind: rb,
define_opaque: _,
}),
) => {
@ -371,7 +371,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
&& eq_id(*li, *ri)
&& eq_generics(lg, rg)
&& eq_ty(lt, rt)
&& both(lb.as_ref(), rb.as_ref(), eq_const_item_rhs)
&& both(Some(lb), Some(rb), eq_const_item_rhs)
},
(
Fn(box ast::Fn {
@ -615,7 +615,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
ident: li,
generics: lg,
ty: lt,
rhs: lb,
rhs_kind: lb,
define_opaque: _,
}),
Const(box ConstItem {
@ -623,7 +623,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
ident: ri,
generics: rg,
ty: rt,
rhs: rb,
rhs_kind: rb,
define_opaque: _,
}),
) => {
@ -631,7 +631,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
&& eq_id(*li, *ri)
&& eq_generics(lg, rg)
&& eq_ty(lt, rt)
&& both(lb.as_ref(), rb.as_ref(), eq_const_item_rhs)
&& both(Some(lb), Some(rb), eq_const_item_rhs)
},
(
Fn(box ast::Fn {
@ -791,12 +791,18 @@ pub fn eq_anon_const(l: &AnonConst, r: &AnonConst) -> bool {
eq_expr(&l.value, &r.value)
}
pub fn eq_const_item_rhs(l: &ConstItemRhs, r: &ConstItemRhs) -> bool {
use ConstItemRhs::*;
pub fn eq_const_item_rhs(l: &ConstItemRhsKind, r: &ConstItemRhsKind) -> bool {
use ConstItemRhsKind::*;
match (l, r) {
(TypeConst(l), TypeConst(r)) => eq_anon_const(l, r),
(Body(l), Body(r)) => eq_expr(l, r),
(TypeConst(..), Body(..)) | (Body(..), TypeConst(..)) => false,
(TypeConst { rhs: Some(l) }, TypeConst { rhs: Some(r) }) => eq_anon_const(l, r),
(TypeConst { rhs: None }, TypeConst { rhs: None }) => true,
(TypeConst { rhs: Some(..) }, TypeConst { rhs: None }) => false,
(TypeConst { rhs: None }, TypeConst { rhs: Some(..) }) => false,
(Body { rhs: Some(l) }, Body { rhs: Some(r) }) => eq_expr(l, r),
(Body { rhs: None }, Body { rhs: None }) => true,
(Body { rhs: None }, Body { rhs: Some(..) }) => false,
(Body { rhs: Some(..) }, Body { rhs: None }) => false,
(TypeConst {..}, Body { .. }) | ( Body { .. }, TypeConst { .. }) => false,
}
}

View file

@ -3,8 +3,8 @@
#![feature(min_generic_const_args)]
trait AssocConstTrait {
#[type_const]
const ASSOC: usize;
type const ASSOC: usize;
}
fn assoc_const_args<T>()
where

View file

@ -3,8 +3,8 @@
#![feature(min_generic_const_args)]
trait AssocConstTrait {
#[type_const]
const ASSOC: usize;
type const ASSOC: usize;
}
fn assoc_const_args<T>()
where

View file

@ -2028,12 +2028,16 @@ impl<'a> StaticParts<'a> {
),
ast::ItemKind::Const(c) => (
Some(c.defaultness),
"const",
if c.rhs_kind.is_type_const() {
"type const"
} else {
"const"
},
ast::Safety::Default,
c.ident,
&c.ty,
ast::Mutability::Not,
c.rhs.as_ref().map(|rhs| rhs.expr()),
c.rhs_kind.expr(),
Some(&c.generics),
),
_ => unreachable!(),
@ -2053,17 +2057,25 @@ impl<'a> StaticParts<'a> {
}
pub(crate) fn from_trait_item(ti: &'a ast::AssocItem, ident: Ident) -> Self {
let (defaultness, ty, expr_opt, generics) = match &ti.kind {
ast::AssocItemKind::Const(c) => (
c.defaultness,
&c.ty,
c.rhs.as_ref().map(|rhs| rhs.expr()),
Some(&c.generics),
),
let (defaultness, ty, expr_opt, generics, prefix) = match &ti.kind {
ast::AssocItemKind::Const(c) => {
let prefix = if c.rhs_kind.is_type_const() {
"type const"
} else {
"const"
};
(
c.defaultness,
&c.ty,
c.rhs_kind.expr(),
Some(&c.generics),
prefix,
)
}
_ => unreachable!(),
};
StaticParts {
prefix: "const",
prefix,
safety: ast::Safety::Default,
vis: &ti.vis,
ident,
@ -2077,17 +2089,25 @@ impl<'a> StaticParts<'a> {
}
pub(crate) fn from_impl_item(ii: &'a ast::AssocItem, ident: Ident) -> Self {
let (defaultness, ty, expr_opt, generics) = match &ii.kind {
ast::AssocItemKind::Const(c) => (
c.defaultness,
&c.ty,
c.rhs.as_ref().map(|rhs| rhs.expr()),
Some(&c.generics),
),
let (defaultness, ty, expr_opt, generics, prefix) = match &ii.kind {
ast::AssocItemKind::Const(c) => {
let prefix = if c.rhs_kind.is_type_const() {
"type const"
} else {
"const"
};
(
c.defaultness,
&c.ty,
c.rhs_kind.expr(),
Some(&c.generics),
prefix,
)
}
_ => unreachable!(),
};
StaticParts {
prefix: "const",
prefix,
safety: ast::Safety::Default,
vis: &ii.vis,
ident,

View file

@ -5,8 +5,7 @@ struct Qux<'a> {
x: &'a (),
}
impl<'a> Qux<'a> {
#[type_const]
const LEN: usize = 4;
type const LEN: usize = 4;
fn foo(_: [u8; Qux::LEN]) {}
}

View file

@ -14,12 +14,10 @@
#![expect(unused_variables, incomplete_features)]
trait Trait {
#[type_const]
const N: usize;
type const N: usize;
}
impl Trait for () {
#[type_const]
const N: usize = 101;
type const N: usize = 101;
}
fn main() {

View file

@ -10,8 +10,7 @@ pub enum ParseMode {
Raw,
}
pub trait Parse {
#[type_const]
const PARSE_MODE: ParseMode;
type const PARSE_MODE: ParseMode;
}
pub trait RenderRaw {}

View file

@ -4,6 +4,5 @@
pub fn accept(_: impl Trait<K = 0>) {}
pub trait Trait {
#[type_const]
const K: i32;
type const K: i32;
}

View file

@ -11,8 +11,7 @@ trait T {
}
trait S {
#[type_const]
const C: i32;
type const C: i32;
}
fn main() {}

View file

@ -4,8 +4,7 @@
#![allow(incomplete_features)]
pub trait Trait {
#[type_const]
const ASSOC: usize;
type const ASSOC: usize;
}
pub fn foo<

View file

@ -8,8 +8,7 @@
struct OnDiskDirEntry<'a>(&'a ());
impl<'a> OnDiskDirEntry<'a> {
#[type_const]
const LFN_FRAGMENT_LEN: i64 = 2;
type const LFN_FRAGMENT_LEN: i64 = 2;
fn lfn_contents() -> [char; Self::LFN_FRAGMENT_LEN] {
//~^ ERROR the constant `2` is not of type `usize`

View file

@ -24,7 +24,7 @@ LL | #![feature(inherent_associated_types)]
= note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information
error: the constant `2` is not of type `usize`
--> $DIR/type-const-in-array-len-wrong-type.rs:14:26
--> $DIR/type-const-in-array-len-wrong-type.rs:13:26
|
LL | fn lfn_contents() -> [char; Self::LFN_FRAGMENT_LEN] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `i64`

View file

@ -8,8 +8,7 @@
// Test case from #138226: generic impl with multiple type parameters
struct Foo<A, B>(A, B);
impl<A, B> Foo<A, B> {
#[type_const]
const LEN: usize = 4;
type const LEN: usize = 4;
fn foo() {
let _ = [5; Self::LEN];
@ -19,8 +18,7 @@ impl<A, B> Foo<A, B> {
// Test case from #138226: generic impl with const parameter
struct Bar<const N: usize>;
impl<const N: usize> Bar<N> {
#[type_const]
const LEN: usize = 4;
type const LEN: usize = 4;
fn bar() {
let _ = [0; Self::LEN];
@ -30,8 +28,7 @@ impl<const N: usize> Bar<N> {
// Test case from #150960: non-generic impl with const block
struct Baz;
impl Baz {
#[type_const]
const LEN: usize = 4;
type const LEN: usize = 4;
fn baz() {
let _ = [0; { Self::LEN }];

View file

@ -50,8 +50,7 @@ fn mismatch_2() -> impl Iterator<Item: Copy, Item: Send> {
trait Trait {
type Gat<T>;
#[type_const]
const ASSOC: i32;
type const ASSOC: i32;
fn foo() -> impl Sized;
}
@ -59,8 +58,7 @@ trait Trait {
impl Trait for () {
type Gat<T> = ();
#[type_const]
const ASSOC: i32 = 3;
type const ASSOC: i32 = 3;
fn foo() {}
}
@ -68,8 +66,7 @@ impl Trait for () {
impl Trait for u32 {
type Gat<T> = ();
#[type_const]
const ASSOC: i32 = 4;
type const ASSOC: i32 = 4;
fn foo() -> u32 {
42
@ -89,8 +86,7 @@ type MustFail = dyn Iterator<Item = i32, Item = u32>;
//~| ERROR conflicting associated type bindings
trait Trait2 {
#[type_const]
const ASSOC: u32;
type const ASSOC: u32;
}
type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;

View file

@ -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:111:17
--> $DIR/duplicate-bound-err.rs:107:17
|
LL | fn foo() -> impl Iterator<Item = i32, Item = u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
@ -109,19 +109,19 @@ LL | [2u32].into_iter()
| ------------------ return type was inferred to be `std::array::IntoIter<u32, 1>` here
error[E0271]: expected `impl Iterator<Item = u32>` to be an iterator that yields `i32`, but it yields `u32`
--> $DIR/duplicate-bound-err.rs:111:17
--> $DIR/duplicate-bound-err.rs:107: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:107:31
--> $DIR/duplicate-bound-err.rs:103:31
|
LL | fn foo() -> impl Iterator<Item = i32, Item = u32>;
| ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}`
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
--> $DIR/duplicate-bound-err.rs:87:42
--> $DIR/duplicate-bound-err.rs:84:42
|
LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
| ---------- ^^^^^^^^^^ re-bound here
@ -129,7 +129,7 @@ LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
| `Item` bound here first
error: conflicting associated type bindings for `Item`
--> $DIR/duplicate-bound-err.rs:87:17
--> $DIR/duplicate-bound-err.rs:84:17
|
LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
| ^^^^^^^^^^^^^----------^^----------^
@ -138,7 +138,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:96:43
--> $DIR/duplicate-bound-err.rs:92:43
|
LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
| ------------ ^^^^^^^^^^^^ re-bound here
@ -146,7 +146,7 @@ LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
| `ASSOC` bound here first
error: conflicting associated constant bindings for `ASSOC`
--> $DIR/duplicate-bound-err.rs:96:18
--> $DIR/duplicate-bound-err.rs:92:18
|
LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
| ^^^^^^^^^^^------------^^------------^
@ -155,7 +155,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:100:43
--> $DIR/duplicate-bound-err.rs:96:43
|
LL | type MustFail3 = dyn Iterator<Item = i32, Item = i32>;
| ---------- ^^^^^^^^^^ re-bound here
@ -163,7 +163,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:103:43
--> $DIR/duplicate-bound-err.rs:99:43
|
LL | type MustFail4 = dyn Trait2<ASSOC = 3u32, ASSOC = 3u32>;
| ------------ ^^^^^^^^^^^^ re-bound here
@ -171,7 +171,7 @@ LL | type MustFail4 = dyn Trait2<ASSOC = 3u32, ASSOC = 3u32>;
| `ASSOC` bound here first
error[E0271]: expected `Empty<u32>` to be an iterator that yields `i32`, but it yields `u32`
--> $DIR/duplicate-bound-err.rs:119:16
--> $DIR/duplicate-bound-err.rs:115:16
|
LL | uncallable(iter::empty::<u32>());
| ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
@ -179,13 +179,13 @@ LL | uncallable(iter::empty::<u32>());
| required by a bound introduced by this call
|
note: required by a bound in `uncallable`
--> $DIR/duplicate-bound-err.rs:79:32
--> $DIR/duplicate-bound-err.rs:76:32
|
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:120:16
--> $DIR/duplicate-bound-err.rs:116:16
|
LL | uncallable(iter::empty::<i32>());
| ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
@ -193,13 +193,13 @@ LL | uncallable(iter::empty::<i32>());
| required by a bound introduced by this call
|
note: required by a bound in `uncallable`
--> $DIR/duplicate-bound-err.rs:79:44
--> $DIR/duplicate-bound-err.rs:76:44
|
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:121:22
--> $DIR/duplicate-bound-err.rs:117:22
|
LL | uncallable_const(());
| ---------------- ^^ expected `4`, found `3`
@ -209,13 +209,13 @@ LL | uncallable_const(());
= note: expected constant `4`
found constant `3`
note: required by a bound in `uncallable_const`
--> $DIR/duplicate-bound-err.rs:81:46
--> $DIR/duplicate-bound-err.rs:78:46
|
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:122:22
--> $DIR/duplicate-bound-err.rs:118:22
|
LL | uncallable_const(4u32);
| ---------------- ^^^^ expected `3`, found `4`
@ -225,13 +225,13 @@ LL | uncallable_const(4u32);
= note: expected constant `3`
found constant `4`
note: required by a bound in `uncallable_const`
--> $DIR/duplicate-bound-err.rs:81:35
--> $DIR/duplicate-bound-err.rs:78:35
|
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:123:20
--> $DIR/duplicate-bound-err.rs:119:20
|
LL | uncallable_rtn(());
| -------------- ^^ expected `4`, found `3`
@ -241,7 +241,7 @@ LL | uncallable_rtn(());
= note: expected constant `4`
found constant `3`
note: required by a bound in `uncallable_rtn`
--> $DIR/duplicate-bound-err.rs:84:61
--> $DIR/duplicate-bound-err.rs:81:61
|
LL | fn uncallable_rtn(
| -------------- required by a bound in this function
@ -249,7 +249,7 @@ 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:124:20
--> $DIR/duplicate-bound-err.rs:120:20
|
LL | uncallable_rtn(17u32);
| -------------- ^^^^^ expected `3`, found `4`
@ -259,7 +259,7 @@ 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:34
--> $DIR/duplicate-bound-err.rs:81:34
|
LL | fn uncallable_rtn(
| -------------- required by a bound in this function

View file

@ -189,8 +189,7 @@ trait Tra3 {
trait Trait {
type Gat<T>;
#[type_const]
const ASSOC: i32;
type const ASSOC: i32;
fn foo() -> impl Sized;
}
@ -198,8 +197,7 @@ trait Trait {
impl Trait for () {
type Gat<T> = ();
#[type_const]
const ASSOC: i32 = 3;
type const ASSOC: i32 = 3;
fn foo() {}
}

View file

@ -1,8 +1,8 @@
struct S<const N: usize>;
impl<const N: usize> S<N> {
#[type_const]
//~^ ERROR: the `#[type_const]` attribute is an experimental feature
const LEN: usize = 1;
type const LEN: usize = 1;
//~^ ERROR: associated `type const` are unstable [E0658]
//~| ERROR: `type const` syntax is experimental [E0658]
fn arr() {
[8; Self::LEN]
//~^ WARN: cannot use constants which depend on generic parameters in types

View file

@ -1,8 +1,18 @@
error[E0658]: the `#[type_const]` attribute is an experimental feature
error[E0658]: `type const` syntax is experimental
--> $DIR/type-const-inherent-impl-normalize.rs:3:5
|
LL | #[type_const]
| ^^^^^^^^^^^^^
LL | type const LEN: usize = 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]: associated `type const` are unstable
--> $DIR/type-const-inherent-impl-normalize.rs:3:5
|
LL | type const LEN: usize = 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
@ -36,7 +46,7 @@ LL | fn arr() {
LL | [8; Self::LEN]
| ^^^^^^^^^^^^^^ expected `()`, found `[{integer}; 1]`
error: aborting due to 2 previous errors; 2 warnings emitted
error: aborting due to 3 previous errors; 2 warnings emitted
Some errors have detailed explanations: E0308, E0658.
For more information about an error, try `rustc --explain E0308`.

View file

@ -145,8 +145,6 @@ struct Test;
#[diagnostic::on_unimplemented = 1]
//~^ WARN malformed
trait Hey {
#[type_const = 1]
//~^ ERROR malformed
const HEY: usize = 5;
}

View file

@ -21,13 +21,13 @@ LL | #[cfg_attr]
= note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
error[E0463]: can't find crate for `wloop`
--> $DIR/malformed-attrs.rs:217:1
--> $DIR/malformed-attrs.rs:215:1
|
LL | extern crate wloop;
| ^^^^^^^^^^^^^^^^^^^ can't find crate
error: malformed `allow` attribute input
--> $DIR/malformed-attrs.rs:183:1
--> $DIR/malformed-attrs.rs:181:1
|
LL | #[allow]
| ^^^^^^^^
@ -43,7 +43,7 @@ LL | #[allow(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++
error: malformed `expect` attribute input
--> $DIR/malformed-attrs.rs:185:1
--> $DIR/malformed-attrs.rs:183:1
|
LL | #[expect]
| ^^^^^^^^^
@ -59,7 +59,7 @@ LL | #[expect(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++
error: malformed `warn` attribute input
--> $DIR/malformed-attrs.rs:187:1
--> $DIR/malformed-attrs.rs:185:1
|
LL | #[warn]
| ^^^^^^^
@ -75,7 +75,7 @@ LL | #[warn(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++
error: malformed `deny` attribute input
--> $DIR/malformed-attrs.rs:189:1
--> $DIR/malformed-attrs.rs:187:1
|
LL | #[deny]
| ^^^^^^^
@ -91,7 +91,7 @@ LL | #[deny(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++
error: malformed `forbid` attribute input
--> $DIR/malformed-attrs.rs:191:1
--> $DIR/malformed-attrs.rs:189:1
|
LL | #[forbid]
| ^^^^^^^^^
@ -125,7 +125,7 @@ LL | #[proc_macro_derive]
| ^^^^^^^^^^^^^^^^^^^^
error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint
--> $DIR/malformed-attrs.rs:222:1
--> $DIR/malformed-attrs.rs:220:1
|
LL | #[allow_internal_unsafe = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -541,7 +541,7 @@ LL | #[cfi_encoding = ""]
| help: must be of the form: `#[cfi_encoding = "encoding"]`
error[E0565]: malformed `marker` attribute input
--> $DIR/malformed-attrs.rs:160:1
--> $DIR/malformed-attrs.rs:158:1
|
LL | #[marker = 3]
| ^^^^^^^^^---^
@ -550,7 +550,7 @@ LL | #[marker = 3]
| help: must be of the form: `#[marker]`
error[E0565]: malformed `fundamental` attribute input
--> $DIR/malformed-attrs.rs:162:1
--> $DIR/malformed-attrs.rs:160:1
|
LL | #[fundamental()]
| ^^^^^^^^^^^^^--^
@ -559,7 +559,7 @@ LL | #[fundamental()]
| help: must be of the form: `#[fundamental]`
error[E0565]: malformed `ffi_pure` attribute input
--> $DIR/malformed-attrs.rs:170:5
--> $DIR/malformed-attrs.rs:168:5
|
LL | #[unsafe(ffi_pure = 1)]
| ^^^^^^^^^^^^^^^^^^---^^
@ -568,7 +568,7 @@ LL | #[unsafe(ffi_pure = 1)]
| help: must be of the form: `#[ffi_pure]`
error[E0539]: malformed `link_ordinal` attribute input
--> $DIR/malformed-attrs.rs:172:5
--> $DIR/malformed-attrs.rs:170:5
|
LL | #[link_ordinal]
| ^^^^^^^^^^^^^^^
@ -579,7 +579,7 @@ LL | #[link_ordinal]
= note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute>
error[E0565]: malformed `ffi_const` attribute input
--> $DIR/malformed-attrs.rs:176:5
--> $DIR/malformed-attrs.rs:174:5
|
LL | #[unsafe(ffi_const = 1)]
| ^^^^^^^^^^^^^^^^^^^---^^
@ -588,13 +588,13 @@ LL | #[unsafe(ffi_const = 1)]
| help: must be of the form: `#[ffi_const]`
error[E0539]: malformed `linkage` attribute input
--> $DIR/malformed-attrs.rs:178:5
--> $DIR/malformed-attrs.rs:176:5
|
LL | #[linkage]
| ^^^^^^^^^^ expected this to be of the form `linkage = "..."`
error[E0539]: malformed `debugger_visualizer` attribute input
--> $DIR/malformed-attrs.rs:193:1
--> $DIR/malformed-attrs.rs:191:1
|
LL | #[debugger_visualizer]
| ^^^^^^^^^^^^^^^^^^^^^^
@ -605,7 +605,7 @@ LL | #[debugger_visualizer]
= note: for more information, visit <https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute>
error[E0565]: malformed `automatically_derived` attribute input
--> $DIR/malformed-attrs.rs:195:1
--> $DIR/malformed-attrs.rs:193:1
|
LL | #[automatically_derived = 18]
| ^^^^^^^^^^^^^^^^^^^^^^^^----^
@ -614,7 +614,7 @@ LL | #[automatically_derived = 18]
| help: must be of the form: `#[automatically_derived]`
error[E0565]: malformed `non_exhaustive` attribute input
--> $DIR/malformed-attrs.rs:203:1
--> $DIR/malformed-attrs.rs:201:1
|
LL | #[non_exhaustive = 1]
| ^^^^^^^^^^^^^^^^^---^
@ -623,7 +623,7 @@ LL | #[non_exhaustive = 1]
| help: must be of the form: `#[non_exhaustive]`
error[E0565]: malformed `thread_local` attribute input
--> $DIR/malformed-attrs.rs:209:1
--> $DIR/malformed-attrs.rs:207:1
|
LL | #[thread_local()]
| ^^^^^^^^^^^^^^--^
@ -632,7 +632,7 @@ LL | #[thread_local()]
| help: must be of the form: `#[thread_local]`
error[E0565]: malformed `no_link` attribute input
--> $DIR/malformed-attrs.rs:213:1
--> $DIR/malformed-attrs.rs:211:1
|
LL | #[no_link()]
| ^^^^^^^^^--^
@ -641,7 +641,7 @@ LL | #[no_link()]
| help: must be of the form: `#[no_link]`
error[E0539]: malformed `macro_use` attribute input
--> $DIR/malformed-attrs.rs:215:1
--> $DIR/malformed-attrs.rs:213:1
|
LL | #[macro_use = 1]
| ^^^^^^^^^^^^---^
@ -659,7 +659,7 @@ LL + #[macro_use]
|
error[E0539]: malformed `macro_export` attribute input
--> $DIR/malformed-attrs.rs:220:1
--> $DIR/malformed-attrs.rs:218:1
|
LL | #[macro_export = 18]
| ^^^^^^^^^^^^^^^----^
@ -676,7 +676,7 @@ LL + #[macro_export]
|
error[E0565]: malformed `allow_internal_unsafe` attribute input
--> $DIR/malformed-attrs.rs:222:1
--> $DIR/malformed-attrs.rs:220:1
|
LL | #[allow_internal_unsafe = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^---^
@ -684,15 +684,6 @@ LL | #[allow_internal_unsafe = 1]
| | didn't expect any arguments here
| help: must be of the form: `#[allow_internal_unsafe]`
error[E0565]: malformed `type_const` attribute input
--> $DIR/malformed-attrs.rs:148:5
|
LL | #[type_const = 1]
| ^^^^^^^^^^^^^---^
| | |
| | didn't expect any arguments here
| help: must be of the form: `#[type_const]`
error: attribute should be applied to `const fn`
--> $DIR/malformed-attrs.rs:32:1
|
@ -820,13 +811,13 @@ LL | #[no_implicit_prelude = 23]
= help: `#[no_implicit_prelude]` can be applied to crates and modules
warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
--> $DIR/malformed-attrs.rs:154:1
--> $DIR/malformed-attrs.rs:152:1
|
LL | #[diagnostic::do_not_recommend()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: `#[automatically_derived]` attribute cannot be used on modules
--> $DIR/malformed-attrs.rs:195:1
--> $DIR/malformed-attrs.rs:193:1
|
LL | #[automatically_derived = 18]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -835,7 +826,7 @@ LL | #[automatically_derived = 18]
= help: `#[automatically_derived]` can only be applied to trait impl blocks
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
--> $DIR/malformed-attrs.rs:229:1
--> $DIR/malformed-attrs.rs:227:1
|
LL | #[ignore = 1]
| ^^^^^^^^^^^^^
@ -854,7 +845,7 @@ LL | #[coroutine = 63] || {}
= note: expected unit type `()`
found coroutine `{coroutine@$DIR/malformed-attrs.rs:116:23: 116:25}`
error: aborting due to 76 previous errors; 8 warnings emitted
error: aborting due to 75 previous errors; 8 warnings emitted
Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805.
For more information about an error, try `rustc --explain E0308`.
@ -882,7 +873,7 @@ LL | #[ignore()]
Future breakage diagnostic:
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
--> $DIR/malformed-attrs.rs:229:1
--> $DIR/malformed-attrs.rs:227:1
|
LL | #[ignore = 1]
| ^^^^^^^^^^^^^

View file

@ -6,8 +6,7 @@
trait Trait0: Parent0<i32> + Parent0<u32> {}
trait Parent0<T> {
#[type_const]
const K: ();
type const K: ();
}
fn take0(_: impl Trait0<K = const { }>) {}
@ -15,12 +14,10 @@ fn take0(_: impl Trait0<K = const { }>) {}
trait Trait1: Parent1 + Parent2 {}
trait Parent1 {
#[type_const]
const C: i32;
type const C: i32;
}
trait Parent2 {
#[type_const]
const C: &'static str;
type const C: &'static str;
}
fn take1(_: impl Trait1<C = "?">) {}

View file

@ -1,8 +1,8 @@
error[E0222]: ambiguous associated constant `K` in bounds of `Trait0`
--> $DIR/ambiguity.rs:13:25
--> $DIR/ambiguity.rs:12:25
|
LL | const K: ();
| -----------
LL | type const K: ();
| ----------------
| |
| ambiguous `K` from `Parent0<u32>`
| ambiguous `K` from `Parent0<i32>`
@ -17,13 +17,13 @@ LL | fn take0(_: impl Trait0<K = const { }>) {}
T: Parent0<i32>::K = const { }
error[E0222]: ambiguous associated constant `C` in bounds of `Trait1`
--> $DIR/ambiguity.rs:26:25
--> $DIR/ambiguity.rs:23:25
|
LL | const C: i32;
| ------------ ambiguous `C` from `Parent1`
LL | type const C: i32;
| ----------------- ambiguous `C` from `Parent1`
...
LL | const C: &'static str;
| --------------------- ambiguous `C` from `Parent2`
LL | type const C: &'static str;
| -------------------------- ambiguous `C` from `Parent2`
...
LL | fn take1(_: impl Trait1<C = "?">) {}
| ^^^^^^^ ambiguous associated constant `C`

View file

@ -3,15 +3,13 @@
#![allow(unused, incomplete_features)]
pub trait Foo {
#[type_const]
const N: usize;
type const N: usize;
}
pub struct Bar;
impl Foo for Bar {
#[type_const]
const N: usize = 3;
type const N: usize = 3;
}
const TEST: usize = 3;

View file

@ -11,8 +11,7 @@
use std::marker::ConstParamTy_;
trait Trait<T: ConstParamTy_> {
#[type_const]
const K: T;
type const K: T;
}
fn take(

View file

@ -1,11 +1,11 @@
error: higher-ranked subtype error
--> $DIR/bound-var-in-ty-not-wf.rs:21:13
--> $DIR/bound-var-in-ty-not-wf.rs:20:13
|
LL | K = const { () }
| ^^^^^^^^^^^^
error: higher-ranked subtype error
--> $DIR/bound-var-in-ty-not-wf.rs:21:13
--> $DIR/bound-var-in-ty-not-wf.rs:20:13
|
LL | K = const { () }
| ^^^^^^^^^^^^

View file

@ -14,8 +14,7 @@
use std::marker::ConstParamTy_;
trait Trait<T: ConstParamTy_> {
#[type_const]
const K: T;
type const K: T;
}
fn take(

View file

@ -12,13 +12,11 @@ trait Trait: SuperTrait {
type N;
type Q;
#[type_const]
const N: usize;
type const N: usize;
}
trait SuperTrait {
#[type_const]
const Q: &'static str;
type const Q: &'static str;
}
fn take0(_: impl Trait<N = 0, N = ()>) {}

View file

@ -2,12 +2,10 @@
#![expect(incomplete_features)]
pub trait IsVoid {
#[type_const]
const IS_VOID: bool;
type const IS_VOID: bool;
}
impl IsVoid for () {
#[type_const]
const IS_VOID: bool = true;
type const IS_VOID: bool = true;
}
pub trait Maybe {}

View file

@ -1,5 +1,5 @@
error[E0119]: conflicting implementations of trait `Maybe` for type `()`
--> $DIR/coherence.rs:15:1
--> $DIR/coherence.rs:13:1
|
LL | impl Maybe for () {}
| ----------------- first implementation here

View file

@ -2,8 +2,7 @@
#![allow(incomplete_features)]
trait TraitWAssocConst {
#[type_const]
const A: usize;
type const A: usize;
}
fn foo<T: TraitWAssocConst<A = 1>>() {}

View file

@ -1,5 +1,5 @@
error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 1`
--> $DIR/const-projection-err.rs:12:11
--> $DIR/const-projection-err.rs:11:11
|
LL | foo::<T>();
| ^ expected `1`, found `0`
@ -7,7 +7,7 @@ LL | foo::<T>();
= note: expected constant `1`
found constant `0`
note: required by a bound in `foo`
--> $DIR/const-projection-err.rs:9:28
--> $DIR/const-projection-err.rs:8:28
|
LL | fn foo<T: TraitWAssocConst<A = 1>>() {}
| ^^^^^ required by this bound in `foo`

View file

@ -8,8 +8,7 @@
#![allow(incomplete_features)]
pub trait TraitA<T> {
#[type_const]
const K: u8 = 0;
type const K: u8 = 0;
}
pub trait TraitB<T> {}

View file

@ -14,14 +14,12 @@ trait Trait {
// NOTE: The `ConstParamTy_` bound is intentionally on the assoc const and not on the trait as
// doing the latter would already render the trait dyn incompatible due to it being
// bounded by `PartialEq<Self>` and supertrait bounds cannot mention `Self` like this.
#[type_const]
const K: Self where Self: std::marker::ConstParamTy_;
type const K: Self where Self: std::marker::ConstParamTy_;
//~^ NOTE it contains associated const `K` whose type references the `Self` type
// This is not a "`Self` projection" in our sense (which would be allowed)
// since the trait is not the principal trait or a supertrait thereof.
#[type_const]
const Q: <Self as SomeOtherTrait>::Output;
type const Q: <Self as SomeOtherTrait>::Output;
//~^ NOTE it contains associated const `Q` whose type references the `Self` type
}

View file

@ -1,21 +1,21 @@
error[E0038]: the trait `Trait` is not dyn compatible
--> $DIR/dyn-compat-assoc-const-ty-mentions-self.rs:38:16
--> $DIR/dyn-compat-assoc-const-ty-mentions-self.rs:36:16
|
LL | let _: dyn Trait;
| ^^^^^ `Trait` is not dyn compatible
|
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $DIR/dyn-compat-assoc-const-ty-mentions-self.rs:18:11
--> $DIR/dyn-compat-assoc-const-ty-mentions-self.rs:17:16
|
LL | trait Trait {
| ----- this trait is not dyn compatible...
...
LL | const K: Self where Self: std::marker::ConstParamTy_;
| ^ ...because it contains associated const `K` whose type references the `Self` type
LL | type const K: Self where Self: std::marker::ConstParamTy_;
| ^ ...because it contains associated const `K` whose type references the `Self` type
...
LL | const Q: <Self as SomeOtherTrait>::Output;
| ^ ...because it contains associated const `Q` whose type references the `Self` type
LL | type const Q: <Self as SomeOtherTrait>::Output;
| ^ ...because it contains associated const `Q` whose type references the `Self` type
= help: consider moving `K` to another trait
= help: consider moving `Q` to another trait

View file

@ -7,25 +7,20 @@
#![expect(incomplete_features)]
trait Trait: SuperTrait<C = 3> {
#[type_const]
const K: usize;
type const K: usize;
}
trait SuperTrait {
#[type_const]
const Q: usize;
#[type_const]
const C: usize;
type const Q: usize;
type const C: usize;
}
trait Bound {
#[type_const]
const N: usize;
type const N: usize;
}
impl Bound for () {
#[type_const]
const N: usize = 10;
type const N: usize = 10;
}
fn main() {

View file

@ -4,13 +4,11 @@
#![expect(incomplete_features)]
trait Trait {
#[type_const]
const N: usize;
type const N: usize;
}
impl Trait for () {
#[type_const]
const N: usize = 1;
type const N: usize = 1;
}
fn main() {

View file

@ -1,5 +1,5 @@
error[E0271]: type mismatch resolving `<() as Trait>::N == 0`
--> $DIR/dyn-compat-const-mismatch.rs:17:32
--> $DIR/dyn-compat-const-mismatch.rs:15:32
|
LL | let _: &dyn Trait<N = 0> = &();
| ^^^ expected `0`, found `1`

View file

@ -7,13 +7,11 @@
trait X<const N: usize = { <Self as Y>::N }> {}
trait Y {
#[type_const]
const N: usize;
type const N: usize;
}
impl<T: ?Sized> Y for T {
#[type_const]
const N: usize = 1;
type const N: usize = 1;
}
fn main() {

View file

@ -1,5 +1,5 @@
error[E0393]: the const parameter `N` must be explicitly specified
--> $DIR/dyn-compat-const-param-default-mentions-self.rs:20:16
--> $DIR/dyn-compat-const-param-default-mentions-self.rs:18:16
|
LL | trait X<const N: usize = { <Self as Y>::N }> {}
| -------------------------------------------- const parameter `N` must be specified for this

View file

@ -9,8 +9,7 @@
#![expect(incomplete_features)]
trait Trait {
#[type_const]
const Y: i32;
type const Y: i32;
}
struct Hold<T: ?Sized>(T);

View file

@ -1,5 +1,5 @@
error: associated constant binding in trait object type mentions `Self`
--> $DIR/dyn-compat-const-projection-behind-trait-alias-mentions-self.rs:21:12
--> $DIR/dyn-compat-const-projection-behind-trait-alias-mentions-self.rs:20:12
|
LL | trait Bound = Trait<Y = { Hold::<Self> }>;
| -------------------- this binding mentions `Self`

View file

@ -5,13 +5,11 @@
#![expect(incomplete_features)]
trait X: Y<K = { Self::Q }> {
#[type_const]
const Q: usize;
type const Q: usize;
}
trait Y {
#[type_const]
const K: usize;
type const K: usize;
}
fn main() {

View file

@ -1,8 +1,8 @@
error[E0191]: the value of the associated constant `K` in `Y` must be specified
--> $DIR/dyn-compat-const-projection-from-supertrait-mentions-self.rs:18:16
--> $DIR/dyn-compat-const-projection-from-supertrait-mentions-self.rs:16:16
|
LL | const K: usize;
| -------------- `K` defined here
LL | type const K: usize;
| ------------------- `K` defined here
...
LL | let _: dyn X<Q = 10>;
| ^^^^^^^^^ help: specify the associated constant: `X<Q = 10, K = /* CONST */>`

View file

@ -7,7 +7,7 @@
trait Trait {
const K: usize;
//~^ NOTE it contains associated const `K` that's not marked `#[type_const]`
//~^ NOTE it contains associated const `K` that's not defined as `type const`
}
fn main() {
@ -16,5 +16,5 @@ fn main() {
// Check that specifying the non-type assoc const doesn't "magically make it work".
let _: dyn Trait<K = 0>;
//~^ ERROR the trait `Trait` is not dyn compatible
//~| ERROR use of trait associated const without `#[type_const]`
//~| ERROR use of trait associated const not defined as `type const`
}

View file

@ -11,16 +11,16 @@ note: for a trait to be dyn compatible it needs to allow building a vtable
LL | trait Trait {
| ----- this trait is not dyn compatible...
LL | const K: usize;
| ^ ...because it contains associated const `K` that's not marked `#[type_const]`
| ^ ...because it contains associated const `K` that's not defined as `type const`
= help: consider moving `K` to another trait
error: use of trait associated const without `#[type_const]`
error: use of trait associated const not defined as `type const`
--> $DIR/dyn-compat-non-type-assoc-const.rs:17:22
|
LL | let _: dyn Trait<K = 0>;
| ^^^^^
|
= note: the declaration in the trait must be marked with `#[type_const]`
= note: the declaration in the trait must begin with `type const` not just `const` alone
error[E0038]: the trait `Trait` is not dyn compatible
--> $DIR/dyn-compat-non-type-assoc-const.rs:17:16
@ -35,7 +35,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable
LL | trait Trait {
| ----- this trait is not dyn compatible...
LL | const K: usize;
| ^ ...because it contains associated const `K` that's not marked `#[type_const]`
| ^ ...because it contains associated const `K` that's not defined as `type const`
= help: consider moving `K` to another trait
error: aborting due to 3 previous errors

View file

@ -6,13 +6,11 @@
#![expect(incomplete_features)]
trait Trait {
#[type_const]
const N: i32 where Self: Bound;
type const N: i32 where Self: Bound;
}
impl Trait for () {
#[type_const]
const N: i32 = 0;
type const N: i32 = 0;
}
trait Bound {}

View file

@ -1,19 +1,19 @@
error[E0277]: the trait bound `(): Bound` is not satisfied
--> $DIR/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.rs:23:32
--> $DIR/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.rs:21:32
|
LL | let _: &dyn Trait<N = 0> = &();
| ^^^ the trait `Bound` is not implemented for `()`
|
help: this trait has no implementations, consider adding one
--> $DIR/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.rs:18:1
--> $DIR/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.rs:16:1
|
LL | trait Bound {}
| ^^^^^^^^^^^
note: required by a bound in `Trait::N`
--> $DIR/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.rs:10:30
--> $DIR/dyn-compat-self-bound-on-assoc-const-allowed-and-enforced.rs:9:35
|
LL | const N: i32 where Self: Bound;
| ^^^^^ required by this bound in `Trait::N`
LL | type const N: i32 where Self: Bound;
| ^^^^^ required by this bound in `Trait::N`
error: aborting due to 1 previous error

View file

@ -14,14 +14,12 @@
trait A {
type Ty: std::marker::ConstParamTy_;
#[type_const]
const CT: Self::Ty;
type const CT: Self::Ty;
}
impl A for () {
type Ty = i32;
#[type_const]
const CT: i32 = 0;
type const CT: i32 = 0;
}
fn main() {

View file

@ -1,23 +1,23 @@
error[E0277]: the trait bound `FreshTy(0): A` is not satisfied
--> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:34:33
--> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:32:33
|
LL | let _: dyn A<Ty = i32, CT = 0>;
| ^ the trait `A` is not implemented for `FreshTy(0)`
|
help: the trait `A` is implemented for `()`
--> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:21:1
--> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:20:1
|
LL | impl A for () {
| ^^^^^^^^^^^^^
error[E0277]: the trait bound `FreshTy(0): A` is not satisfied
--> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:36:34
--> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:34:34
|
LL | let _: &dyn A<Ty = i32, CT = 0> = &();
| ^ the trait `A` is not implemented for `FreshTy(0)`
|
help: the trait `A` is implemented for `()`
--> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:21:1
--> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:20:1
|
LL | impl A for () {
| ^^^^^^^^^^^^^

Some files were not shown because too many files have changed in this diff Show more