Allow provisional mgca syntax of type const <IDENT> = <EXPR> to be reconized.

Revert, but without type const.

Update symbol for feature err, then update suggestion output, and lastly update tests that change because of those.

Update these new tests with the correct syntax, and few existing tests with the new outputs the merge with main added.

Fix for tidyfmt and some errors when manually resolving a merge conflicts.

Update these tests to use update error messages and type const syntax.

Update comments and error message to use new syntax instead of old type_const attribute.

Remove the type_const attribute

update some more tests to use the new syntax.

Update these test cases.

update feature gate test

Change gate logic for `mgca_type_const_syntax` to work also if `min_generic_const_args` is enabled.

Create a new feature gate that checks for the feature before expansion.

Make rustfmt handle the `type const` syntax correctly.

Add a convience method to check if a RhsKind is type const.

Rename `Const` discriminant to `Body` for `ConstItemRhsKind`

Give the `TraitItemKind` flag an enum instead of a simple bool to better describe what the flag is for.

Update formatting for these match statements.

Update clippy test to use type const syntax.

Update test to use type const syntax.

update rustfmt to match ast items.

Update clippy to match ast and hir items.

Few more test cases that used old attribute, instead of 'type const'

Update to match the output from the feature gate checks.

tidyfmt adjustments.

Update the is_type_const, so I can constrain record!(..) in encoder.rs

Update conditional compilation test.

Move the feature gate to after expansion to allow for cfg(...) to work.

Update some more tests to use the new syntax.

Update type const tests in associated-const-bindings to use new syntax.

Don't check based off the attribute, but the item here.

Update some tests outside of the const_generics folder that were using #[type_const]

update the tests in associated consts that use #[type_const] to use type const

Update these mgca tests with the type const syntax.

Add a flag to TraitItemKind for detecting type const for now. Maybe later change ItemConstRhs to have optional consts but that touches a lot more lines of code.

Don't need into for these now that it's a query.

Add is_type_const query to handle foreign def ids.

update this test to use type const syntax.

Fix logic here, we only want to lower if there is expression in this case.

Update built-in macros to use ConstItemRhsKind

Update more instance of the old ConstItemRhs.

Rename ConstItemKind to ConstItemRhsKind, I noticed there is a typed called ConstantItemKind, so add the Rhs to the name to avoid confusion.

Update lower to use ConstItemKind

Add an other helper method to check if the rhs kinda has an expr.

Update item parse to use ConstItemKind enum.

Felt the field name could a be little clear when editing a few other things.

Change the ConstItem struct see know if we have a type const or regular const.

Make sure this syntax is properly feature gated.
This commit is contained in:
Keith-Cancel 2026-02-05 22:01:57 -08:00
parent 4cd4c18438
commit 73a991fb9d
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

@ -297,7 +297,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

@ -1292,9 +1292,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

@ -169,7 +169,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
};
}
@ -1549,7 +1550,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;
@ -1594,7 +1596,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,
_ => {
@ -1624,3 +1626,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

@ -607,14 +607,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

@ -356,7 +356,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