Auto merge of #139558 - camelid:mgca-const-items, r=oli-obk,BoxyUwU
mgca: Add ConstArg representation for const items tracking issue: rust-lang/rust#132980 fixes rust-lang/rust#131046 fixes rust-lang/rust#134641 As part of implementing `min_generic_const_args`, we need to distinguish const items that can be used in the type system, such as in associated const equality projections, from const items containing arbitrary const code, which must be kept out of the type system. Specifically, all "type consts" must be either concrete (no generics) or generic with a trivial expression like `N` or a path to another type const item. To syntactically distinguish these cases, we require, for now at least, that users annotate all type consts with the `#[type_const]` attribute. Then, we validate that the const's right-hand side is indeed eligible to be a type const and represent it differently in the HIR. We accomplish this representation using a new `ConstItemRhs` enum in the HIR, and a similar but simpler enum in the AST. When `#[type_const]` is **not** applied to a const (e.g. on stable), we represent const item right-hand sides (rhs's) as HIR bodies, like before. However, when the attribute is applied, we instead lower to a `hir::ConstArg`. This syntactically distinguishes between trivial const args (paths) and arbitrary expressions, which are represented using `AnonConst`s. Then in `generics_of`, we can take advantage of the existing machinery to bar the `AnonConst` rhs's from using parent generics.
This commit is contained in:
commit
72b21e1a64
117 changed files with 1180 additions and 758 deletions
|
|
@ -3759,10 +3759,29 @@ pub struct ConstItem {
|
|||
pub ident: Ident,
|
||||
pub generics: Generics,
|
||||
pub ty: Box<Ty>,
|
||||
pub expr: Option<Box<Expr>>,
|
||||
pub rhs: Option<ConstItemRhs>,
|
||||
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub enum ConstItemRhs {
|
||||
TypeConst(AnonConst),
|
||||
Body(Box<Expr>),
|
||||
}
|
||||
|
||||
impl ConstItemRhs {
|
||||
pub fn span(&self) -> Span {
|
||||
self.expr().span
|
||||
}
|
||||
|
||||
pub fn expr(&self) -> &Expr {
|
||||
match self {
|
||||
ConstItemRhs::TypeConst(anon_const) => &anon_const.value,
|
||||
ConstItemRhs::Body(expr) => expr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum ItemKind {
|
||||
|
|
|
|||
|
|
@ -423,6 +423,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
Closure,
|
||||
Const,
|
||||
ConstItem,
|
||||
ConstItemRhs,
|
||||
Defaultness,
|
||||
Delegation,
|
||||
DelegationMac,
|
||||
|
|
|
|||
|
|
@ -170,37 +170,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
ItemKind::Static(box ast::StaticItem {
|
||||
ident,
|
||||
ty: t,
|
||||
ty,
|
||||
safety: _,
|
||||
mutability: m,
|
||||
expr: e,
|
||||
define_opaque,
|
||||
}) => {
|
||||
let ident = self.lower_ident(*ident);
|
||||
let (ty, body_id) =
|
||||
self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy);
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
let body_id = self.lower_const_body(span, e.as_deref());
|
||||
self.lower_define_opaque(hir_id, define_opaque);
|
||||
hir::ItemKind::Static(*m, ident, ty, body_id)
|
||||
}
|
||||
ItemKind::Const(box ast::ConstItem {
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
expr,
|
||||
define_opaque,
|
||||
..
|
||||
ident, generics, ty, rhs, define_opaque, ..
|
||||
}) => {
|
||||
let ident = self.lower_ident(*ident);
|
||||
let (generics, (ty, body_id)) = self.lower_generics(
|
||||
let (generics, (ty, rhs)) = self.lower_generics(
|
||||
generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy)
|
||||
let ty = this
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span);
|
||||
(ty, rhs)
|
||||
},
|
||||
);
|
||||
self.lower_define_opaque(hir_id, &define_opaque);
|
||||
hir::ItemKind::Const(ident, generics, ty, body_id)
|
||||
hir::ItemKind::Const(ident, generics, ty, rhs)
|
||||
}
|
||||
ItemKind::Fn(box Fn {
|
||||
sig: FnSig { decl, header, span: fn_sig_span },
|
||||
|
|
@ -462,17 +461,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_const_item(
|
||||
&mut self,
|
||||
ty: &Ty,
|
||||
span: Span,
|
||||
body: Option<&Expr>,
|
||||
impl_trait_position: ImplTraitPosition,
|
||||
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(impl_trait_position));
|
||||
(ty, self.lower_const_body(span, body))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_use_tree(
|
||||
&mut self,
|
||||
|
|
@ -804,12 +792,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let (ident, generics, kind, has_default) = match &i.kind {
|
||||
AssocItemKind::Const(box ConstItem {
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
expr,
|
||||
define_opaque,
|
||||
..
|
||||
ident, generics, ty, rhs, define_opaque, ..
|
||||
}) => {
|
||||
let (generics, kind) = self.lower_generics(
|
||||
generics,
|
||||
|
|
@ -818,14 +801,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|this| {
|
||||
let ty = this
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x)));
|
||||
|
||||
hir::TraitItemKind::Const(ty, body)
|
||||
let rhs = rhs
|
||||
.as_ref()
|
||||
.map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span));
|
||||
hir::TraitItemKind::Const(ty, rhs)
|
||||
},
|
||||
);
|
||||
|
||||
if define_opaque.is_some() {
|
||||
if expr.is_some() {
|
||||
if rhs.is_some() {
|
||||
self.lower_define_opaque(hir_id, &define_opaque);
|
||||
} else {
|
||||
self.dcx().span_err(
|
||||
|
|
@ -835,7 +819,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
(*ident, generics, kind, expr.is_some())
|
||||
(*ident, generics, kind, rhs.is_some())
|
||||
}
|
||||
AssocItemKind::Fn(box Fn {
|
||||
sig, ident, generics, body: None, define_opaque, ..
|
||||
|
|
@ -1022,12 +1006,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let (ident, (generics, kind)) = match &i.kind {
|
||||
AssocItemKind::Const(box ConstItem {
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
expr,
|
||||
define_opaque,
|
||||
..
|
||||
ident, generics, ty, rhs, define_opaque, ..
|
||||
}) => (
|
||||
*ident,
|
||||
self.lower_generics(
|
||||
|
|
@ -1037,9 +1016,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|this| {
|
||||
let ty = this
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let body = this.lower_const_body(i.span, expr.as_deref());
|
||||
this.lower_define_opaque(hir_id, &define_opaque);
|
||||
hir::ImplItemKind::Const(ty, body)
|
||||
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span);
|
||||
hir::ImplItemKind::Const(ty, rhs)
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -2327,6 +2327,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind })
|
||||
}
|
||||
|
||||
fn lower_const_item_rhs(
|
||||
&mut self,
|
||||
attrs: &[hir::Attribute],
|
||||
rhs: Option<&ConstItemRhs>,
|
||||
span: Span,
|
||||
) -> hir::ConstItemRhs<'hir> {
|
||||
match rhs {
|
||||
Some(ConstItemRhs::TypeConst(anon)) => {
|
||||
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg(anon))
|
||||
}
|
||||
None if attr::contains_name(attrs, sym::type_const) => {
|
||||
let const_arg = ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Error(
|
||||
DUMMY_SP,
|
||||
self.dcx().span_delayed_bug(DUMMY_SP, "no block"),
|
||||
),
|
||||
};
|
||||
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)),
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`hir::ConstArg`] for when to use this function vs
|
||||
/// [`Self::lower_anon_const_to_anon_const`].
|
||||
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> {
|
||||
|
|
|
|||
|
|
@ -1239,9 +1239,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
});
|
||||
}
|
||||
ItemKind::Const(box ConstItem { defaultness, expr, .. }) => {
|
||||
ItemKind::Const(box ConstItem { defaultness, rhs, .. }) => {
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
if expr.is_none() {
|
||||
if rhs.is_none() {
|
||||
self.dcx().emit_err(errors::ConstWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
|
|
@ -1581,7 +1581,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
|
||||
if let AssocCtxt::Impl { .. } = ctxt {
|
||||
match &item.kind {
|
||||
AssocItemKind::Const(box ConstItem { expr: None, .. }) => {
|
||||
AssocItemKind::Const(box ConstItem { rhs: None, .. }) => {
|
||||
self.dcx().emit_err(errors::AssocConstWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ impl<'a> State<'a> {
|
|||
ident,
|
||||
generics,
|
||||
ty,
|
||||
expr,
|
||||
rhs,
|
||||
define_opaque,
|
||||
}) => {
|
||||
self.print_item_const(
|
||||
|
|
@ -218,7 +218,7 @@ impl<'a> State<'a> {
|
|||
None,
|
||||
generics,
|
||||
ty,
|
||||
expr.as_deref(),
|
||||
rhs.as_ref().map(|ct| ct.expr()),
|
||||
&item.vis,
|
||||
ast::Safety::Default,
|
||||
*defaultness,
|
||||
|
|
@ -566,7 +566,7 @@ impl<'a> State<'a> {
|
|||
ident,
|
||||
generics,
|
||||
ty,
|
||||
expr,
|
||||
rhs,
|
||||
define_opaque,
|
||||
}) => {
|
||||
self.print_item_const(
|
||||
|
|
@ -574,7 +574,7 @@ impl<'a> State<'a> {
|
|||
None,
|
||||
generics,
|
||||
ty,
|
||||
expr.as_deref(),
|
||||
rhs.as_ref().map(|ct| ct.expr()),
|
||||
vis,
|
||||
ast::Safety::Default,
|
||||
*defaultness,
|
||||
|
|
|
|||
|
|
@ -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 = ecx.expr_block(ecx.block(span, stmts));
|
||||
let const_body = ast::ConstItemRhs::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)))
|
||||
|
|
|
|||
|
|
@ -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 = ecx.expr_block(ecx.block(span, stmts));
|
||||
let const_body = ast::ConstItemRhs::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)))
|
||||
|
|
|
|||
|
|
@ -385,9 +385,9 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> Box<ast::Item> {
|
|||
cx.attr_nested_word(sym::allow, sym::deprecated, span),
|
||||
]);
|
||||
|
||||
let block = cx.expr_block(
|
||||
let block = ast::ConstItemRhs::Body(cx.expr_block(
|
||||
cx.block(span, thin_vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]),
|
||||
);
|
||||
));
|
||||
|
||||
let anon_constant = cx.item_const(
|
||||
span,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
expr: Some(
|
||||
rhs: Some(ast::ConstItemRhs::Body(
|
||||
cx.expr_struct(
|
||||
sp,
|
||||
test_path("TestDescAndFn"),
|
||||
|
|
@ -371,7 +371,7 @@ pub(crate) fn expand_test_or_bench(
|
|||
field("testfn", test_fn), // }
|
||||
],
|
||||
), // }
|
||||
),
|
||||
)),
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
// having basically only two use-cases that act in different ways.
|
||||
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::{LangItem, find_attr};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, AdtDef, Ty};
|
||||
|
|
@ -365,8 +367,14 @@ where
|
|||
// check performed after the promotion. Verify that with an assertion.
|
||||
assert!(promoted.is_none() || Q::ALLOW_PROMOTED);
|
||||
|
||||
// Don't peek inside trait associated constants.
|
||||
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() {
|
||||
// Avoid looking at attrs of anon consts as that will ICE
|
||||
let is_type_const_item =
|
||||
matches!(cx.tcx.def_kind(def), DefKind::Const | DefKind::AssocConst)
|
||||
&& find_attr!(cx.tcx.get_all_attrs(def), AttributeKind::TypeConst(_));
|
||||
|
||||
// Don't peak inside trait associated constants, also `#[type_const] const` items
|
||||
// don't have bodies so there's nothing to look at
|
||||
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !is_type_const_item {
|
||||
let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def);
|
||||
|
||||
if !Q::in_qualifs(&qualifs) {
|
||||
|
|
|
|||
|
|
@ -104,6 +104,10 @@ impl<'a> ExtCtxt<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn anon_const_block(&self, b: Box<ast::Block>) -> Box<ast::AnonConst> {
|
||||
Box::new(self.anon_const(b.span, ast::ExprKind::Block(b, None)))
|
||||
}
|
||||
|
||||
pub fn const_ident(&self, span: Span, ident: Ident) -> ast::AnonConst {
|
||||
self.anon_const(span, ast::ExprKind::Path(None, self.path_ident(span, ident)))
|
||||
}
|
||||
|
|
@ -722,7 +726,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
span: Span,
|
||||
ident: Ident,
|
||||
ty: Box<ast::Ty>,
|
||||
expr: Box<ast::Expr>,
|
||||
rhs: ast::ConstItemRhs,
|
||||
) -> Box<ast::Item> {
|
||||
let defaultness = ast::Defaultness::Final;
|
||||
self.item(
|
||||
|
|
@ -735,7 +739,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
// FIXME(generic_const_items): Pass the generics as a parameter.
|
||||
generics: ast::Generics::default(),
|
||||
ty,
|
||||
expr: Some(expr),
|
||||
rhs: Some(rhs),
|
||||
define_opaque: None,
|
||||
}
|
||||
.into(),
|
||||
|
|
|
|||
|
|
@ -403,6 +403,28 @@ impl<'hir> PathSegment<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
pub enum ConstItemRhs<'hir> {
|
||||
Body(BodyId),
|
||||
TypeConst(&'hir ConstArg<'hir>),
|
||||
}
|
||||
|
||||
impl<'hir> ConstItemRhs<'hir> {
|
||||
pub fn hir_id(&self) -> HirId {
|
||||
match self {
|
||||
ConstItemRhs::Body(body_id) => body_id.hir_id,
|
||||
ConstItemRhs::TypeConst(ct_arg) => ct_arg.hir_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span<'tcx>(&self, tcx: impl crate::intravisit::HirTyCtxt<'tcx>) -> Span {
|
||||
match self {
|
||||
ConstItemRhs::Body(body_id) => tcx.hir_body(*body_id).value.span,
|
||||
ConstItemRhs::TypeConst(ct_arg) => ct_arg.span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A constant that enters the type system, used for arguments to const generics (e.g. array lengths).
|
||||
///
|
||||
/// These are distinct from [`AnonConst`] as anon consts in the type system are not allowed
|
||||
|
|
@ -474,6 +496,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> {
|
|||
match self.kind {
|
||||
ConstArgKind::Path(path) => path.span(),
|
||||
ConstArgKind::Anon(anon) => anon.span,
|
||||
ConstArgKind::Error(span, _) => span,
|
||||
ConstArgKind::Infer(span, _) => span,
|
||||
}
|
||||
}
|
||||
|
|
@ -490,6 +513,8 @@ pub enum ConstArgKind<'hir, Unambig = ()> {
|
|||
/// However, in the future, we'll be using it for all of those.
|
||||
Path(QPath<'hir>),
|
||||
Anon(&'hir AnonConst),
|
||||
/// Error const
|
||||
Error(Span, ErrorGuaranteed),
|
||||
/// This variant is not always used to represent inference consts, sometimes
|
||||
/// [`GenericArg::Infer`] is used instead.
|
||||
Infer(Span, Unambig),
|
||||
|
|
@ -3076,8 +3101,8 @@ impl<'hir> TraitItem<'hir> {
|
|||
}
|
||||
|
||||
expect_methods_self_kind! {
|
||||
expect_const, (&'hir Ty<'hir>, Option<BodyId>),
|
||||
TraitItemKind::Const(ty, body), (ty, *body);
|
||||
expect_const, (&'hir Ty<'hir>, Option<ConstItemRhs<'hir>>),
|
||||
TraitItemKind::Const(ty, rhs), (ty, *rhs);
|
||||
|
||||
expect_fn, (&FnSig<'hir>, &TraitFn<'hir>),
|
||||
TraitItemKind::Fn(ty, trfn), (ty, trfn);
|
||||
|
|
@ -3101,7 +3126,7 @@ pub enum TraitFn<'hir> {
|
|||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum TraitItemKind<'hir> {
|
||||
/// An associated constant with an optional value (otherwise `impl`s must contain a value).
|
||||
Const(&'hir Ty<'hir>, Option<BodyId>),
|
||||
Const(&'hir Ty<'hir>, Option<ConstItemRhs<'hir>>),
|
||||
/// An associated function with an optional body.
|
||||
Fn(FnSig<'hir>, TraitFn<'hir>),
|
||||
/// An associated type with (possibly empty) bounds and optional concrete
|
||||
|
|
@ -3170,9 +3195,9 @@ impl<'hir> ImplItem<'hir> {
|
|||
}
|
||||
|
||||
expect_methods_self_kind! {
|
||||
expect_const, (&'hir Ty<'hir>, BodyId), ImplItemKind::Const(ty, body), (ty, *body);
|
||||
expect_fn, (&FnSig<'hir>, BodyId), ImplItemKind::Fn(ty, body), (ty, *body);
|
||||
expect_type, &'hir Ty<'hir>, ImplItemKind::Type(ty), ty;
|
||||
expect_const, (&'hir Ty<'hir>, ConstItemRhs<'hir>), ImplItemKind::Const(ty, rhs), (ty, *rhs);
|
||||
expect_fn, (&FnSig<'hir>, BodyId), ImplItemKind::Fn(ty, body), (ty, *body);
|
||||
expect_type, &'hir Ty<'hir>, ImplItemKind::Type(ty), ty;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3181,7 +3206,7 @@ impl<'hir> ImplItem<'hir> {
|
|||
pub enum ImplItemKind<'hir> {
|
||||
/// An associated constant of the given type, set to the constant result
|
||||
/// of the expression.
|
||||
Const(&'hir Ty<'hir>, BodyId),
|
||||
Const(&'hir Ty<'hir>, ConstItemRhs<'hir>),
|
||||
/// An associated function implementation with the given signature and body.
|
||||
Fn(FnSig<'hir>, BodyId),
|
||||
/// An associated type.
|
||||
|
|
@ -4110,8 +4135,8 @@ impl<'hir> Item<'hir> {
|
|||
expect_static, (Mutability, Ident, &'hir Ty<'hir>, BodyId),
|
||||
ItemKind::Static(mutbl, ident, ty, body), (*mutbl, *ident, ty, *body);
|
||||
|
||||
expect_const, (Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId),
|
||||
ItemKind::Const(ident, generics, ty, body), (*ident, generics, ty, *body);
|
||||
expect_const, (Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, ConstItemRhs<'hir>),
|
||||
ItemKind::Const(ident, generics, ty, rhs), (*ident, generics, ty, *rhs);
|
||||
|
||||
expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId),
|
||||
ItemKind::Fn { ident, sig, generics, body, .. }, (*ident, sig, generics, *body);
|
||||
|
|
@ -4282,7 +4307,7 @@ pub enum ItemKind<'hir> {
|
|||
/// A `static` item.
|
||||
Static(Mutability, Ident, &'hir Ty<'hir>, BodyId),
|
||||
/// A `const` item.
|
||||
Const(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId),
|
||||
Const(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, ConstItemRhs<'hir>),
|
||||
/// A function declaration.
|
||||
Fn {
|
||||
sig: FnSig<'hir>,
|
||||
|
|
@ -4520,17 +4545,18 @@ impl<'hir> OwnerNode<'hir> {
|
|||
OwnerNode::Item(Item {
|
||||
kind:
|
||||
ItemKind::Static(_, _, _, body)
|
||||
| ItemKind::Const(_, _, _, body)
|
||||
| ItemKind::Const(.., ConstItemRhs::Body(body))
|
||||
| ItemKind::Fn { body, .. },
|
||||
..
|
||||
})
|
||||
| OwnerNode::TraitItem(TraitItem {
|
||||
kind:
|
||||
TraitItemKind::Fn(_, TraitFn::Provided(body)) | TraitItemKind::Const(_, Some(body)),
|
||||
TraitItemKind::Fn(_, TraitFn::Provided(body))
|
||||
| TraitItemKind::Const(_, Some(ConstItemRhs::Body(body))),
|
||||
..
|
||||
})
|
||||
| OwnerNode::ImplItem(ImplItem {
|
||||
kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body),
|
||||
kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, ConstItemRhs::Body(body)),
|
||||
..
|
||||
}) => Some(*body),
|
||||
_ => None,
|
||||
|
|
@ -4781,7 +4807,7 @@ impl<'hir> Node<'hir> {
|
|||
Node::Item(Item {
|
||||
owner_id,
|
||||
kind:
|
||||
ItemKind::Const(_, _, _, body)
|
||||
ItemKind::Const(.., ConstItemRhs::Body(body))
|
||||
| ItemKind::Static(.., body)
|
||||
| ItemKind::Fn { body, .. },
|
||||
..
|
||||
|
|
@ -4789,12 +4815,13 @@ impl<'hir> Node<'hir> {
|
|||
| Node::TraitItem(TraitItem {
|
||||
owner_id,
|
||||
kind:
|
||||
TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)),
|
||||
TraitItemKind::Const(.., Some(ConstItemRhs::Body(body)))
|
||||
| TraitItemKind::Fn(_, TraitFn::Provided(body)),
|
||||
..
|
||||
})
|
||||
| Node::ImplItem(ImplItem {
|
||||
owner_id,
|
||||
kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body),
|
||||
kind: ImplItemKind::Const(.., ConstItemRhs::Body(body)) | ImplItemKind::Fn(_, body),
|
||||
..
|
||||
}) => Some((owner_id.def_id, *body)),
|
||||
|
||||
|
|
|
|||
|
|
@ -369,6 +369,10 @@ pub trait Visitor<'v>: Sized {
|
|||
walk_ty(self, t)
|
||||
}
|
||||
|
||||
fn visit_const_item_rhs(&mut self, c: ConstItemRhs<'v>) -> Self::Result {
|
||||
walk_const_item_rhs(self, c)
|
||||
}
|
||||
|
||||
/// All consts are treated as ambiguous consts for the purposes of hir visiting in
|
||||
/// order to ensure that visitors can handle infer vars without it being too error-prone.
|
||||
///
|
||||
|
|
@ -547,11 +551,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
|
|||
try_visit!(visitor.visit_ty_unambig(typ));
|
||||
try_visit!(visitor.visit_nested_body(body));
|
||||
}
|
||||
ItemKind::Const(ident, ref generics, ref typ, body) => {
|
||||
ItemKind::Const(ident, ref generics, ref typ, rhs) => {
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
try_visit!(visitor.visit_ty_unambig(typ));
|
||||
try_visit!(visitor.visit_nested_body(body));
|
||||
try_visit!(visitor.visit_const_item_rhs(rhs));
|
||||
}
|
||||
ItemKind::Fn { ident, sig, generics, body: body_id, .. } => {
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
|
|
@ -1036,6 +1040,16 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -
|
|||
V::Result::output()
|
||||
}
|
||||
|
||||
pub fn walk_const_item_rhs<'v, V: Visitor<'v>>(
|
||||
visitor: &mut V,
|
||||
ct_rhs: ConstItemRhs<'v>,
|
||||
) -> V::Result {
|
||||
match ct_rhs {
|
||||
ConstItemRhs::Body(body_id) => visitor.visit_nested_body(body_id),
|
||||
ConstItemRhs::TypeConst(const_arg) => visitor.visit_const_arg_unambig(const_arg),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>(
|
||||
visitor: &mut V,
|
||||
const_arg: &'v ConstArg<'v>,
|
||||
|
|
@ -1058,6 +1072,7 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
|
|||
match kind {
|
||||
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()),
|
||||
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
|
||||
ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1220,7 +1235,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(
|
|||
match *kind {
|
||||
TraitItemKind::Const(ref ty, default) => {
|
||||
try_visit!(visitor.visit_ty_unambig(ty));
|
||||
visit_opt!(visitor, visit_nested_body, default);
|
||||
visit_opt!(visitor, visit_const_item_rhs, default);
|
||||
}
|
||||
TraitItemKind::Fn(ref sig, TraitFn::Required(param_idents)) => {
|
||||
try_visit!(visitor.visit_fn_decl(sig.decl));
|
||||
|
|
@ -1273,9 +1288,9 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(
|
|||
}
|
||||
}
|
||||
match *kind {
|
||||
ImplItemKind::Const(ref ty, body) => {
|
||||
ImplItemKind::Const(ref ty, rhs) => {
|
||||
try_visit!(visitor.visit_ty_unambig(ty));
|
||||
visitor.visit_nested_body(body)
|
||||
visitor.visit_const_item_rhs(rhs)
|
||||
}
|
||||
ImplItemKind::Fn(ref sig, body_id) => visitor.visit_fn(
|
||||
FnKind::Method(impl_item.ident, sig),
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
rendered_precise_capturing_args,
|
||||
const_param_default,
|
||||
anon_const_kind,
|
||||
const_of_item,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
|
@ -1562,6 +1563,7 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin
|
|||
let const_arg_id = tcx.parent_hir_id(hir_id);
|
||||
match tcx.hir_node(const_arg_id) {
|
||||
hir::Node::ConstArg(_) => {
|
||||
let parent_hir_node = tcx.hir_node(tcx.parent_hir_id(const_arg_id));
|
||||
if tcx.features().generic_const_exprs() {
|
||||
ty::AnonConstKind::GCE
|
||||
} else if tcx.features().min_generic_const_args() {
|
||||
|
|
@ -1569,7 +1571,7 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin
|
|||
} else if let hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Repeat(_, repeat_count),
|
||||
..
|
||||
}) = tcx.hir_node(tcx.parent_hir_id(const_arg_id))
|
||||
}) = parent_hir_node
|
||||
&& repeat_count.hir_id == const_arg_id
|
||||
{
|
||||
ty::AnonConstKind::RepeatExprCount
|
||||
|
|
@ -1580,3 +1582,38 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin
|
|||
_ => ty::AnonConstKind::NonTypeSystem,
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(tcx), ret)]
|
||||
fn const_of_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::EarlyBinder<'tcx, Const<'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), ..
|
||||
}) => ct.expect("no default value for trait assoc const"),
|
||||
hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(.., ct), .. }) => *ct,
|
||||
_ => {
|
||||
span_bug!(tcx.def_span(def_id), "`const_of_item` expected a const or assoc const item")
|
||||
}
|
||||
};
|
||||
let ct_arg = match ct_rhs {
|
||||
hir::ConstItemRhs::TypeConst(ct_arg) => ct_arg,
|
||||
hir::ConstItemRhs::Body(body_id) => {
|
||||
bug!("cannot call const_of_item on a non-type_const {body_id:?}")
|
||||
}
|
||||
};
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
|
||||
let ct = icx
|
||||
.lowerer()
|
||||
.lower_const_arg(ct_arg, FeedConstTy::Param(def_id.to_def_id(), identity_args));
|
||||
if let Err(e) = icx.check_tainted_by_errors()
|
||||
&& !ct.references_error()
|
||||
{
|
||||
ty::EarlyBinder::bind(Const::new_error(tcx, e))
|
||||
} else {
|
||||
ty::EarlyBinder::bind(ct)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,14 +158,15 @@ 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, body_id) => body_id
|
||||
.and_then(|body_id| {
|
||||
TraitItemKind::Const(ty, rhs) => rhs
|
||||
.and_then(|rhs| {
|
||||
ty.is_suggestable_infer_ty().then(|| {
|
||||
infer_placeholder_type(
|
||||
icx.lowerer(),
|
||||
def_id,
|
||||
body_id,
|
||||
rhs.hir_id(),
|
||||
ty.span,
|
||||
rhs.span(tcx),
|
||||
item.ident,
|
||||
"associated constant",
|
||||
)
|
||||
|
|
@ -183,13 +184,14 @@ 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)
|
||||
}
|
||||
ImplItemKind::Const(ty, body_id) => {
|
||||
ImplItemKind::Const(ty, rhs) => {
|
||||
if ty.is_suggestable_infer_ty() {
|
||||
infer_placeholder_type(
|
||||
icx.lowerer(),
|
||||
def_id,
|
||||
body_id,
|
||||
rhs.hir_id(),
|
||||
ty.span,
|
||||
rhs.span(tcx),
|
||||
item.ident,
|
||||
"associated constant",
|
||||
)
|
||||
|
|
@ -212,8 +214,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
|
|||
infer_placeholder_type(
|
||||
icx.lowerer(),
|
||||
def_id,
|
||||
body_id,
|
||||
body_id.hir_id,
|
||||
ty.span,
|
||||
tcx.hir_body(body_id).value.span,
|
||||
ident,
|
||||
"static variable",
|
||||
)
|
||||
|
|
@ -229,13 +232,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
|
|||
}
|
||||
}
|
||||
}
|
||||
ItemKind::Const(ident, _, ty, body_id) => {
|
||||
ItemKind::Const(ident, _, ty, rhs) => {
|
||||
if ty.is_suggestable_infer_ty() {
|
||||
infer_placeholder_type(
|
||||
icx.lowerer(),
|
||||
def_id,
|
||||
body_id,
|
||||
rhs.hir_id(),
|
||||
ty.span,
|
||||
rhs.span(tcx),
|
||||
ident,
|
||||
"constant",
|
||||
)
|
||||
|
|
@ -425,13 +429,14 @@ pub(super) fn type_of_opaque_hir_typeck(
|
|||
fn infer_placeholder_type<'tcx>(
|
||||
cx: &dyn HirTyLowerer<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
body_id: hir::BodyId,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
ty_span: Span,
|
||||
body_span: Span,
|
||||
item_ident: Ident,
|
||||
kind: &'static str,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = cx.tcx();
|
||||
let ty = tcx.typeck(def_id).node_type(body_id.hir_id);
|
||||
let ty = tcx.typeck(def_id).node_type(hir_id);
|
||||
|
||||
// If this came from a free `const` or `static mut?` item,
|
||||
// then the user may have written e.g. `const A = 42;`.
|
||||
|
|
@ -439,10 +444,10 @@ fn infer_placeholder_type<'tcx>(
|
|||
// us to improve in typeck so we do that now.
|
||||
let guar = cx
|
||||
.dcx()
|
||||
.try_steal_modify_and_emit_err(span, StashKey::ItemNoType, |err| {
|
||||
.try_steal_modify_and_emit_err(ty_span, StashKey::ItemNoType, |err| {
|
||||
if !ty.references_error() {
|
||||
// Only suggest adding `:` if it was missing (and suggested by parsing diagnostic).
|
||||
let colon = if span == item_ident.span.shrink_to_hi() { ":" } else { "" };
|
||||
let colon = if ty_span == item_ident.span.shrink_to_hi() { ":" } else { "" };
|
||||
|
||||
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
|
||||
// We are typeck and have the real type, so remove that and suggest the actual type.
|
||||
|
|
@ -452,14 +457,14 @@ fn infer_placeholder_type<'tcx>(
|
|||
|
||||
if let Some(ty) = ty.make_suggestable(tcx, false, None) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
ty_span,
|
||||
format!("provide a type for the {kind}"),
|
||||
format!("{colon} {ty}"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
with_forced_trimmed_paths!(err.span_note(
|
||||
tcx.hir_body(body_id).value.span,
|
||||
body_span,
|
||||
format!("however, the inferred type `{ty}` cannot be named"),
|
||||
));
|
||||
}
|
||||
|
|
@ -473,7 +478,7 @@ fn infer_placeholder_type<'tcx>(
|
|||
}
|
||||
// If we didn't find any infer tys, then just fallback to `span`.
|
||||
if visitor.spans.is_empty() {
|
||||
visitor.spans.push(span);
|
||||
visitor.spans.push(ty_span);
|
||||
}
|
||||
let mut diag = bad_placeholder(cx, visitor.spans, kind);
|
||||
|
||||
|
|
@ -482,20 +487,20 @@ fn infer_placeholder_type<'tcx>(
|
|||
// same span. If this happens, we will fall through to this arm, so
|
||||
// we need to suppress the suggestion since it's invalid. Ideally we
|
||||
// would suppress the duplicated error too, but that's really hard.
|
||||
if span.is_empty() && span.from_expansion() {
|
||||
if ty_span.is_empty() && ty_span.from_expansion() {
|
||||
// An approximately better primary message + no suggestion...
|
||||
diag.primary_message("missing type for item");
|
||||
} else if !ty.references_error() {
|
||||
if let Some(ty) = ty.make_suggestable(tcx, false, None) {
|
||||
diag.span_suggestion_verbose(
|
||||
span,
|
||||
ty_span,
|
||||
"replace this with a fully-specified type",
|
||||
ty,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
with_forced_trimmed_paths!(diag.span_note(
|
||||
tcx.hir_body(body_id).value.span,
|
||||
body_span,
|
||||
format!("however, the inferred type `{ty}` cannot be named"),
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::struct_span_code_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::PolyTraitRef;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
|
||||
use rustc_hir::{PolyTraitRef, find_attr};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{
|
||||
self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||
|
|
@ -602,7 +603,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
term,
|
||||
})
|
||||
});
|
||||
bounds.push((bound.upcast(tcx), constraint.span));
|
||||
|
||||
if let ty::AssocTag::Const = assoc_tag
|
||||
&& !find_attr!(
|
||||
self.tcx().get_all_attrs(assoc_item.def_id),
|
||||
AttributeKind::TypeConst(_)
|
||||
)
|
||||
{
|
||||
if tcx.features().min_generic_const_args()
|
||||
|| tcx.features().associated_const_equality()
|
||||
{
|
||||
let mut err = self.dcx().struct_span_err(
|
||||
constraint.span,
|
||||
"use of trait associated const without `#[type_const]`",
|
||||
);
|
||||
err.note("the declaration in the trait must be marked with `#[type_const]`");
|
||||
return Err(err.emit());
|
||||
} else {
|
||||
let err = self.dcx().span_delayed_bug(
|
||||
constraint.span,
|
||||
"use of trait associated const without `#[type_const]`",
|
||||
);
|
||||
return Err(err);
|
||||
}
|
||||
} else {
|
||||
bounds.push((bound.upcast(tcx), constraint.span));
|
||||
}
|
||||
}
|
||||
// SelfTraitThatDefines is only interested in trait predicates.
|
||||
PredicateFilter::SelfTraitThatDefines(_) => {}
|
||||
|
|
|
|||
|
|
@ -27,9 +27,10 @@ use rustc_errors::codes::*;
|
|||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err,
|
||||
};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId};
|
||||
use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId, find_attr};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::DynCompatibilityViolation;
|
||||
use rustc_macros::{TypeFoldable, TypeVisitable};
|
||||
|
|
@ -1278,7 +1279,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
LowerTypeRelativePathMode::Const,
|
||||
)? {
|
||||
TypeRelativePath::AssocItem(def_id, args) => {
|
||||
if !tcx.associated_item(def_id).is_type_const_capable(tcx) {
|
||||
if !find_attr!(self.tcx().get_all_attrs(def_id), AttributeKind::TypeConst(_)) {
|
||||
let mut err = self.dcx().struct_span_err(
|
||||
span,
|
||||
"use of trait associated const without `#[type_const]`",
|
||||
|
|
@ -1716,6 +1717,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
ty::AssocTag::Const,
|
||||
) {
|
||||
Ok((item_def_id, item_args)) => {
|
||||
if !find_attr!(self.tcx().get_all_attrs(item_def_id), AttributeKind::TypeConst(_)) {
|
||||
let mut err = self.dcx().struct_span_err(
|
||||
span,
|
||||
"use of `const` in the type system without `#[type_const]`",
|
||||
);
|
||||
err.note("the declaration must be marked with `#[type_const]`");
|
||||
return Const::new_error(self.tcx(), err.emit());
|
||||
}
|
||||
|
||||
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
|
||||
Const::new_unevaluated(self.tcx(), uv)
|
||||
}
|
||||
|
|
@ -2242,6 +2252,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon),
|
||||
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
|
||||
hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,13 +87,16 @@ mod variance;
|
|||
|
||||
pub use errors::NoVariantNamed;
|
||||
use rustc_abi::{CVariadicStatus, ExternAbi};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::lints::DelayedLint;
|
||||
use rustc_hir::{self as hir};
|
||||
use rustc_middle::middle;
|
||||
use rustc_hir::{
|
||||
find_attr, {self as hir},
|
||||
};
|
||||
use rustc_middle::mir::interpret::GlobalId;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{Const, Ty, TyCtxt};
|
||||
use rustc_middle::{middle, ty};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
use rustc_trait_selection::traits;
|
||||
|
|
@ -223,7 +226,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||
tcx.ensure_ok().eval_static_initializer(item_def_id);
|
||||
check::maybe_check_static_with_link_section(tcx, item_def_id);
|
||||
}
|
||||
DefKind::Const if !tcx.generics_of(item_def_id).own_requires_monomorphization() => {
|
||||
DefKind::Const
|
||||
if !tcx.generics_of(item_def_id).own_requires_monomorphization()
|
||||
&& !find_attr!(tcx.get_all_attrs(item_def_id), AttributeKind::TypeConst(_)) =>
|
||||
{
|
||||
// FIXME(generic_const_items): Passing empty instead of identity args is fishy but
|
||||
// seems to be fine for now. Revisit this!
|
||||
let instance = ty::Instance::new_raw(item_def_id.into(), ty::GenericArgs::empty());
|
||||
|
|
|
|||
|
|
@ -523,17 +523,17 @@ impl<'a> State<'a> {
|
|||
ident: Ident,
|
||||
generics: &hir::Generics<'_>,
|
||||
ty: &hir::Ty<'_>,
|
||||
default: Option<hir::BodyId>,
|
||||
default: Option<hir::ConstItemRhs<'_>>,
|
||||
) {
|
||||
self.word_space("const");
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(generics.params);
|
||||
self.word_space(":");
|
||||
self.print_type(ty);
|
||||
if let Some(expr) = default {
|
||||
if let Some(ct_rhs) = default {
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.ann.nested(self, Nested::Body(expr));
|
||||
self.print_const_item_rhs(ct_rhs);
|
||||
}
|
||||
self.print_where_clause(generics);
|
||||
self.word(";")
|
||||
|
|
@ -616,7 +616,7 @@ impl<'a> State<'a> {
|
|||
self.word(";");
|
||||
self.end(cb);
|
||||
}
|
||||
hir::ItemKind::Const(ident, generics, ty, expr) => {
|
||||
hir::ItemKind::Const(ident, generics, ty, rhs) => {
|
||||
let (cb, ib) = self.head("const");
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(generics.params);
|
||||
|
|
@ -626,7 +626,7 @@ impl<'a> State<'a> {
|
|||
self.end(ib);
|
||||
|
||||
self.word_space("=");
|
||||
self.ann.nested(self, Nested::Body(expr));
|
||||
self.print_const_item_rhs(rhs);
|
||||
self.print_where_clause(generics);
|
||||
self.word(";");
|
||||
self.end(cb);
|
||||
|
|
@ -1127,10 +1127,18 @@ impl<'a> State<'a> {
|
|||
self.ann.nested(self, Nested::Body(constant.body))
|
||||
}
|
||||
|
||||
fn print_const_item_rhs(&mut self, ct_rhs: hir::ConstItemRhs<'_>) {
|
||||
match ct_rhs {
|
||||
hir::ConstItemRhs::Body(body_id) => self.ann.nested(self, Nested::Body(body_id)),
|
||||
hir::ConstItemRhs::TypeConst(const_arg) => self.print_const_arg(const_arg),
|
||||
}
|
||||
}
|
||||
|
||||
fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) {
|
||||
match &const_arg.kind {
|
||||
ConstArgKind::Path(qpath) => self.print_qpath(qpath, true),
|
||||
ConstArgKind::Anon(anon) => self.print_anon_const(anon),
|
||||
ConstArgKind::Error(_, _) => self.word("/*ERROR*/"),
|
||||
ConstArgKind::Infer(..) => self.word("_"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1583,13 +1583,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) -> bool {
|
||||
if let Some(def_id) = opt_def_id
|
||||
&& let Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Const(_, _, _, body_id),
|
||||
kind: hir::ItemKind::Const(_, _, _, ct_rhs),
|
||||
..
|
||||
})) = self.tcx.hir_get_if_local(def_id)
|
||||
&& let hir::Node::Expr(expr) = self.tcx.hir_node(body_id.hir_id)
|
||||
&& let hir::Node::Expr(expr) = self.tcx.hir_node(ct_rhs.hir_id())
|
||||
&& hir::is_range_literal(expr)
|
||||
{
|
||||
let span = self.tcx.hir_span(body_id.hir_id);
|
||||
let span = self.tcx.hir_span(ct_rhs.hir_id());
|
||||
if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||
e.span_suggestion_verbose(
|
||||
ident.span,
|
||||
|
|
|
|||
|
|
@ -978,9 +978,9 @@ impl<'tcx> LateContext<'tcx> {
|
|||
..
|
||||
}) => *init,
|
||||
hir::Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
|
||||
Some(self.tcx.hir_body(body_id).value)
|
||||
}
|
||||
// FIXME(mgca): figure out how to handle ConstArgKind::Path (or don't but add warning in docs here)
|
||||
hir::ItemKind::Const(.., hir::ConstItemRhs::Body(body_id))
|
||||
| hir::ItemKind::Static(.., body_id) => Some(self.tcx.hir_body(body_id).value),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
|
|
|
|||
|
|
@ -1032,19 +1032,22 @@ trait UnusedDelimLint {
|
|||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
||||
use ast::ItemKind::*;
|
||||
|
||||
if let Const(box ast::ConstItem { expr: Some(expr), .. })
|
||||
| Static(box ast::StaticItem { expr: Some(expr), .. }) = &item.kind
|
||||
{
|
||||
self.check_unused_delims_expr(
|
||||
cx,
|
||||
expr,
|
||||
UnusedDelimsCtx::AssignedValue,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
}
|
||||
let expr = if let Const(box ast::ConstItem { rhs: Some(rhs), .. }) = &item.kind {
|
||||
rhs.expr()
|
||||
} else if let Static(box ast::StaticItem { expr: Some(expr), .. }) = &item.kind {
|
||||
expr
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
self.check_unused_delims_expr(
|
||||
cx,
|
||||
expr,
|
||||
UnusedDelimsCtx::AssignedValue,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -403,6 +403,7 @@ provide! { tcx, def_id, other, cdata,
|
|||
tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index))
|
||||
}
|
||||
anon_const_kind => { table }
|
||||
const_of_item => { table }
|
||||
}
|
||||
|
||||
pub(in crate::rmeta) fn provide(providers: &mut Providers) {
|
||||
|
|
|
|||
|
|
@ -1350,6 +1350,7 @@ fn should_encode_constness(def_kind: DefKind) -> bool {
|
|||
|
||||
fn should_encode_const(def_kind: DefKind) -> bool {
|
||||
match def_kind {
|
||||
// FIXME(mgca): should we remove Const and AssocConst here?
|
||||
DefKind::Const | DefKind::AssocConst | DefKind::AnonConst | DefKind::InlineConst => true,
|
||||
|
||||
DefKind::Struct
|
||||
|
|
@ -1382,6 +1383,21 @@ fn should_encode_const(def_kind: DefKind) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_encode_const_of_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: DefKind) -> bool {
|
||||
matches!(def_kind, DefKind::Const | DefKind::AssocConst)
|
||||
&& find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_))
|
||||
// AssocConst ==> assoc item has value
|
||||
&& (!matches!(def_kind, DefKind::AssocConst) || assoc_item_has_value(tcx, def_id))
|
||||
}
|
||||
|
||||
fn assoc_item_has_value<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
|
||||
let assoc_item = tcx.associated_item(def_id);
|
||||
match assoc_item.container {
|
||||
ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true,
|
||||
ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
fn encode_attrs(&mut self, def_id: LocalDefId) {
|
||||
let tcx = self.tcx;
|
||||
|
|
@ -1428,7 +1444,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
&& match tcx.hir_node_by_def_id(local_id) {
|
||||
hir::Node::ConstArg(hir::ConstArg { kind, .. }) => match kind {
|
||||
// Skip encoding defs for these as they should not have had a `DefId` created
|
||||
hir::ConstArgKind::Path(..) | hir::ConstArgKind::Infer(..) => true,
|
||||
hir::ConstArgKind::Error(..)
|
||||
| hir::ConstArgKind::Path(..)
|
||||
| hir::ConstArgKind::Infer(..) => true,
|
||||
hir::ConstArgKind::Anon(..) => false,
|
||||
},
|
||||
_ => false,
|
||||
|
|
@ -1601,6 +1619,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
if let DefKind::AnonConst = def_kind {
|
||||
record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id));
|
||||
}
|
||||
if should_encode_const_of_item(self.tcx, def_id, def_kind) {
|
||||
record!(self.tables.const_of_item[def_id] <- self.tcx.const_of_item(def_id));
|
||||
}
|
||||
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
|
||||
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -471,6 +471,7 @@ define_tables! {
|
|||
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
|
||||
opaque_ty_origin: Table<DefIndex, LazyValue<hir::OpaqueTyOrigin<DefId>>>,
|
||||
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>>>>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ macro_rules! arena_types {
|
|||
rustc_middle::traits::query::DropckOutlivesResult<'tcx>
|
||||
>
|
||||
>,
|
||||
[] normalize_canonicalized_projection_ty:
|
||||
[] normalize_canonicalized_projection:
|
||||
rustc_middle::infer::canonical::Canonical<'tcx,
|
||||
rustc_middle::infer::canonical::QueryResponse<'tcx,
|
||||
rustc_middle::traits::query::NormalizationResult<'tcx>
|
||||
|
|
|
|||
|
|
@ -293,6 +293,19 @@ rustc_queries! {
|
|||
separate_provide_extern
|
||||
}
|
||||
|
||||
/// 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]`.
|
||||
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() }
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
/// Returns the *type* of the definition given by `DefId`.
|
||||
///
|
||||
/// For type aliases (whether eager or lazy) and associated types, this returns
|
||||
|
|
@ -2417,7 +2430,7 @@ rustc_queries! {
|
|||
/// Do not call this query directly: Invoke `normalize` instead.
|
||||
///
|
||||
/// </div>
|
||||
query normalize_canonicalized_projection_ty(
|
||||
query normalize_canonicalized_projection(
|
||||
goal: CanonicalAliasGoal<'tcx>
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
|
||||
|
|
@ -2445,7 +2458,7 @@ rustc_queries! {
|
|||
/// Do not call this query directly: Invoke `normalize` instead.
|
||||
///
|
||||
/// </div>
|
||||
query normalize_canonicalized_inherent_projection_ty(
|
||||
query normalize_canonicalized_inherent_projection(
|
||||
goal: CanonicalAliasGoal<'tcx>
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ pub mod type_op {
|
|||
}
|
||||
|
||||
pub type CanonicalAliasGoal<'tcx> =
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>;
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTerm<'tcx>>>;
|
||||
|
||||
pub type CanonicalMethodAutoderefStepsGoal<'tcx> =
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, MethodAutoderefSteps<'tcx>>>;
|
||||
|
|
@ -192,11 +192,11 @@ pub struct MethodAutoderefBadTy<'tcx> {
|
|||
pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
|
||||
}
|
||||
|
||||
/// Result of the `normalize_canonicalized_{{,inherent_}projection,free}_ty` queries.
|
||||
/// Result of the `normalize_canonicalized_{{,inherent_}projection,free}` queries.
|
||||
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct NormalizationResult<'tcx> {
|
||||
/// Result of the normalization.
|
||||
pub normalized_ty: Ty<'tcx>,
|
||||
pub normalized_term: ty::Term<'tcx>,
|
||||
}
|
||||
|
||||
/// Outlives bounds are relationships between generic parameters,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use rustc_data_structures::sorted_map::SortedIndexMultiMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{DefKind, Namespace};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::find_attr;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable};
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Symbol};
|
||||
|
||||
|
|
@ -173,24 +171,6 @@ impl AssocItem {
|
|||
pub fn is_impl_trait_in_trait(&self) -> bool {
|
||||
matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
|
||||
}
|
||||
|
||||
/// Returns true if:
|
||||
/// - This trait associated item has the `#[type_const]` attribute,
|
||||
/// - If it is in a trait impl, the item from the original trait has this attribute, or
|
||||
/// - It is an inherent assoc const.
|
||||
pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
|
||||
if !matches!(self.kind, ty::AssocKind::Const { .. }) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let def_id = match self.container {
|
||||
AssocContainer::Trait => self.def_id,
|
||||
AssocContainer::TraitImpl(Ok(trait_item_did)) => trait_item_did,
|
||||
AssocContainer::TraitImpl(Err(_)) => return false,
|
||||
AssocContainer::InherentImpl => return true,
|
||||
};
|
||||
find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
|
||||
|
|
|
|||
|
|
@ -242,6 +242,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
fn type_of_opaque_hir_typeck(self, def_id: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
|
||||
self.type_of_opaque_hir_typeck(def_id)
|
||||
}
|
||||
fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
|
||||
self.const_of_item(def_id)
|
||||
}
|
||||
|
||||
type AdtDef = ty::AdtDef<'tcx>;
|
||||
fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef {
|
||||
|
|
|
|||
|
|
@ -30,14 +30,12 @@ where
|
|||
);
|
||||
|
||||
let actual = if free_alias.kind(cx).is_type() {
|
||||
cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args)
|
||||
cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args).into()
|
||||
} else {
|
||||
// FIXME(mgca): once const items are actual aliases defined as equal to type system consts
|
||||
// this should instead return that.
|
||||
panic!("normalizing free const aliases in the type system is unsupported");
|
||||
cx.const_of_item(free_alias.def_id).instantiate(cx, free_alias.args).into()
|
||||
};
|
||||
|
||||
self.instantiate_normalizes_to_term(goal, actual.into());
|
||||
self.instantiate_normalizes_to_term(goal, actual);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,7 @@ where
|
|||
let normalized = if inherent.kind(cx).is_type() {
|
||||
cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into()
|
||||
} else {
|
||||
// FIXME(mgca): Properly handle IACs in the type system
|
||||
panic!("normalizing inherent associated consts in the type system is unsupported");
|
||||
cx.const_of_item(inherent.def_id).instantiate(cx, inherent_args).into()
|
||||
};
|
||||
self.instantiate_normalizes_to_term(goal, normalized);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
|
|
|
|||
|
|
@ -366,19 +366,7 @@ where
|
|||
cx.type_of(target_item_def_id).map_bound(|ty| ty.into())
|
||||
}
|
||||
ty::AliasTermKind::ProjectionConst => {
|
||||
// FIXME(mgca): once const items are actual aliases defined as equal to type system consts
|
||||
// this should instead return that.
|
||||
if cx.features().associated_const_equality() {
|
||||
panic!("associated const projection is not supported yet")
|
||||
} else {
|
||||
ty::EarlyBinder::bind(
|
||||
Const::new_error_with_message(
|
||||
cx,
|
||||
"associated const projection is not supported yet",
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
cx.const_of_item(target_item_def_id).map_bound(|ct| ct.into())
|
||||
}
|
||||
kind => panic!("expected projection, found {kind:?}"),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ 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::{self as ast};
|
||||
use rustc_ast::{
|
||||
attr, {self as ast},
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, PResult, StashKey, struct_span_code_err};
|
||||
|
|
@ -255,13 +257,13 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
self.recover_const_mut(const_span);
|
||||
self.recover_missing_kw_before_item()?;
|
||||
let (ident, generics, ty, expr) = self.parse_const_item()?;
|
||||
let (ident, generics, ty, rhs) = self.parse_const_item(attrs)?;
|
||||
ItemKind::Const(Box::new(ConstItem {
|
||||
defaultness: def_(),
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
expr,
|
||||
rhs,
|
||||
define_opaque: None,
|
||||
}))
|
||||
}
|
||||
|
|
@ -1010,12 +1012,13 @@ 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,
|
||||
expr,
|
||||
rhs,
|
||||
define_opaque,
|
||||
}))
|
||||
}
|
||||
|
|
@ -1249,7 +1252,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, expr, .. }) => {
|
||||
ItemKind::Const(box ConstItem { ident, ty, rhs, .. }) => {
|
||||
let const_span = Some(span.with_hi(ident.span.lo()))
|
||||
.filter(|span| span.can_be_used_for_suggestions());
|
||||
self.dcx().emit_err(errors::ExternItemCannotBeConst {
|
||||
|
|
@ -1260,7 +1263,10 @@ impl<'a> Parser<'a> {
|
|||
ident,
|
||||
ty,
|
||||
mutability: Mutability::Not,
|
||||
expr,
|
||||
expr: rhs.map(|b| match b {
|
||||
ConstItemRhs::TypeConst(anon_const) => anon_const.value,
|
||||
ConstItemRhs::Body(expr) => expr,
|
||||
}),
|
||||
safety: Safety::Default,
|
||||
define_opaque: None,
|
||||
}))
|
||||
|
|
@ -1431,7 +1437,8 @@ impl<'a> Parser<'a> {
|
|||
/// ```
|
||||
fn parse_const_item(
|
||||
&mut self,
|
||||
) -> PResult<'a, (Ident, Generics, Box<Ty>, Option<Box<ast::Expr>>)> {
|
||||
attrs: &[Attribute],
|
||||
) -> PResult<'a, (Ident, Generics, Box<Ty>, Option<ast::ConstItemRhs>)> {
|
||||
let ident = self.parse_ident_or_underscore()?;
|
||||
|
||||
let mut generics = self.parse_generics()?;
|
||||
|
|
@ -1458,7 +1465,15 @@ impl<'a> Parser<'a> {
|
|||
let before_where_clause =
|
||||
if self.may_recover() { self.parse_where_clause()? } else { WhereClause::default() };
|
||||
|
||||
let expr = if self.eat(exp!(Eq)) { Some(self.parse_expr()?) } else { None };
|
||||
let rhs = if self.eat(exp!(Eq)) {
|
||||
if attr::contains_name(attrs, sym::type_const) {
|
||||
Some(ConstItemRhs::TypeConst(self.parse_expr_anon_const()?))
|
||||
} else {
|
||||
Some(ConstItemRhs::Body(self.parse_expr()?))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let after_where_clause = self.parse_where_clause()?;
|
||||
|
||||
|
|
@ -1466,18 +1481,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(expr) = &expr
|
||||
&& let Some(rhs) = &rhs
|
||||
{
|
||||
self.dcx().emit_err(errors::WhereClauseBeforeConstBody {
|
||||
span: before_where_clause.span,
|
||||
name: ident.span,
|
||||
body: expr.span,
|
||||
body: rhs.span(),
|
||||
sugg: if !after_where_clause.has_where_token {
|
||||
self.psess.source_map().span_to_snippet(expr.span).ok().map(|body| {
|
||||
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,
|
||||
right: before_where_clause.span.shrink_to_hi().to(expr.span),
|
||||
snippet: body_s,
|
||||
right: before_where_clause.span.shrink_to_hi().to(rhs.span()),
|
||||
}
|
||||
})
|
||||
} else {
|
||||
|
|
@ -1515,7 +1530,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
self.expect_semi()?;
|
||||
|
||||
Ok((ident, generics, ty, expr))
|
||||
Ok((ident, generics, ty, rhs))
|
||||
}
|
||||
|
||||
/// We were supposed to parse `":" $ty` but the `:` or the type was missing.
|
||||
|
|
|
|||
|
|
@ -2115,19 +2115,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_type_const(&self, hir_id: HirId, attr_span: Span, target: Target) {
|
||||
let tcx = self.tcx;
|
||||
if target == Target::AssocConst
|
||||
&& let parent = tcx.parent(hir_id.expect_owner().to_def_id())
|
||||
&& self.tcx.def_kind(parent) == DefKind::Trait
|
||||
{
|
||||
fn check_type_const(&self, _hir_id: HirId, attr_span: Span, target: Target) {
|
||||
if matches!(target, Target::AssocConst | Target::Const) {
|
||||
return;
|
||||
} else {
|
||||
self.dcx()
|
||||
.struct_span_err(
|
||||
attr_span,
|
||||
"`#[type_const]` must only be applied to trait associated constants",
|
||||
)
|
||||
.struct_span_err(attr_span, "`#[type_const]` must only be applied to const items")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ impl<'tcx> ReachableContext<'tcx> {
|
|||
// We can't figure out which value the constant will evaluate to. In
|
||||
// lieu of that, we have to consider everything mentioned in the const
|
||||
// initializer reachable, since it *may* end up in the final value.
|
||||
Err(ErrorHandled::TooGeneric(_)) => self.visit_nested_body(init),
|
||||
Err(ErrorHandled::TooGeneric(_)) => self.visit_const_item_rhs(init),
|
||||
// If there was an error evaluating the const, nothing can be reachable
|
||||
// via it, and anyway compilation will fail.
|
||||
Err(ErrorHandled::Reported(..)) => {}
|
||||
|
|
@ -253,16 +253,16 @@ impl<'tcx> ReachableContext<'tcx> {
|
|||
| hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_)) => {
|
||||
// Keep going, nothing to get exported
|
||||
}
|
||||
hir::TraitItemKind::Const(_, Some(body_id))
|
||||
| hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)) => {
|
||||
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);
|
||||
}
|
||||
hir::TraitItemKind::Type(..) => {}
|
||||
}
|
||||
}
|
||||
Node::ImplItem(impl_item) => match impl_item.kind {
|
||||
hir::ImplItemKind::Const(_, body) => {
|
||||
self.visit_nested_body(body);
|
||||
hir::ImplItemKind::Const(_, rhs) => {
|
||||
self.visit_const_item_rhs(rhs);
|
||||
}
|
||||
hir::ImplItemKind::Fn(_, body) => {
|
||||
if recursively_reachable(self.tcx, impl_item.hir_id().owner.to_def_id()) {
|
||||
|
|
|
|||
|
|
@ -2827,7 +2827,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
if let Some(expr) = expr {
|
||||
// We already forbid generic params because of the above item rib,
|
||||
// so it doesn't matter whether this is a trivial constant.
|
||||
this.resolve_const_body(expr, Some((ident, ConstantItemKind::Static)));
|
||||
this.resolve_static_body(expr, Some((ident, ConstantItemKind::Static)));
|
||||
}
|
||||
});
|
||||
self.resolve_define_opaques(define_opaque);
|
||||
|
|
@ -2837,7 +2837,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
ident,
|
||||
ref generics,
|
||||
ref ty,
|
||||
ref expr,
|
||||
ref rhs,
|
||||
ref define_opaque,
|
||||
..
|
||||
}) => {
|
||||
|
|
@ -2862,8 +2862,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
|this| this.visit_ty(ty),
|
||||
);
|
||||
|
||||
if let Some(expr) = expr {
|
||||
this.resolve_const_body(expr, Some((ident, ConstantItemKind::Const)));
|
||||
if let Some(rhs) = rhs {
|
||||
this.resolve_const_item_rhs(
|
||||
rhs,
|
||||
Some((ident, ConstantItemKind::Const)),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
@ -3181,7 +3184,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
AssocItemKind::Const(box ast::ConstItem {
|
||||
generics,
|
||||
ty,
|
||||
expr,
|
||||
rhs,
|
||||
define_opaque,
|
||||
..
|
||||
}) => {
|
||||
|
|
@ -3203,13 +3206,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(expr) = expr {
|
||||
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_body(expr, None);
|
||||
this.resolve_const_item_rhs(rhs, None);
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
@ -3388,7 +3391,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
ident,
|
||||
generics,
|
||||
ty,
|
||||
expr,
|
||||
rhs,
|
||||
define_opaque,
|
||||
..
|
||||
}) => {
|
||||
|
|
@ -3430,13 +3433,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
|
||||
this.visit_generics(generics);
|
||||
this.visit_ty(ty);
|
||||
if let Some(expr) = expr {
|
||||
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_body(expr, None);
|
||||
this.resolve_const_item_rhs(rhs, None);
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
@ -3647,7 +3650,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
fn resolve_const_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) {
|
||||
fn resolve_static_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) {
|
||||
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
|
||||
this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| {
|
||||
this.visit_expr(expr)
|
||||
|
|
@ -3655,6 +3658,23 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
fn resolve_const_item_rhs(
|
||||
&mut self,
|
||||
rhs: &'ast ConstItemRhs,
|
||||
item: Option<(Ident, ConstantItemKind)>,
|
||||
) {
|
||||
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| match rhs {
|
||||
ConstItemRhs::TypeConst(anon_const) => {
|
||||
this.resolve_anon_const(anon_const, AnonConstKind::ConstArg(IsRepeatExpr::No));
|
||||
}
|
||||
ConstItemRhs::Body(expr) => {
|
||||
this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| {
|
||||
this.visit_expr(expr)
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_delegation(&mut self, delegation: &'ast Delegation) {
|
||||
self.smart_resolve_path(
|
||||
delegation.id,
|
||||
|
|
|
|||
|
|
@ -333,10 +333,11 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
let res = if free.kind(infcx.tcx).is_type() {
|
||||
infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into()
|
||||
} else {
|
||||
// FIXME(mgca): once const items are actual aliases defined as equal to type system consts
|
||||
// this should instead use that rather than evaluating.
|
||||
super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env)
|
||||
.super_fold_with(self)
|
||||
infcx
|
||||
.tcx
|
||||
.const_of_item(free.def_id)
|
||||
.instantiate(infcx.tcx, free.args)
|
||||
.fold_with(self)
|
||||
.into()
|
||||
};
|
||||
self.depth -= 1;
|
||||
|
|
@ -436,51 +437,47 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
|||
return ct;
|
||||
}
|
||||
|
||||
// Doing "proper" normalization of const aliases is inherently cyclic until const items
|
||||
// are real aliases instead of having bodies. We gate proper const alias handling behind
|
||||
// mgca to avoid breaking stable code, though this should become the "main" codepath long
|
||||
// before mgca is stabilized.
|
||||
let uv = match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => uv,
|
||||
_ => return ct.super_fold_with(self),
|
||||
};
|
||||
|
||||
// Note that the AssocConst and Const cases are unreachable on stable,
|
||||
// unless a `min_generic_const_args` feature gate error has already
|
||||
// been emitted earlier in compilation.
|
||||
//
|
||||
// FIXME(BoxyUwU): Enabling this by default is blocked on a refactoring to how const items
|
||||
// are represented.
|
||||
if tcx.features().min_generic_const_args() {
|
||||
let uv = match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => uv,
|
||||
_ => return ct.super_fold_with(self),
|
||||
};
|
||||
|
||||
let ct = match tcx.def_kind(uv.def) {
|
||||
DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) {
|
||||
DefKind::Trait => self.normalize_trait_projection(uv.into()),
|
||||
DefKind::Impl { of_trait: false } => {
|
||||
self.normalize_inherent_projection(uv.into())
|
||||
}
|
||||
kind => unreachable!(
|
||||
"unexpected `DefKind` for const alias' resolution's parent def: {:?}",
|
||||
kind
|
||||
),
|
||||
},
|
||||
DefKind::Const | DefKind::AnonConst => self.normalize_free_alias(uv.into()),
|
||||
kind => {
|
||||
unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind)
|
||||
// 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
|
||||
// feature gate causes a parse error.
|
||||
let ct = match tcx.def_kind(uv.def) {
|
||||
DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) {
|
||||
DefKind::Trait => self.normalize_trait_projection(uv.into()).expect_const(),
|
||||
DefKind::Impl { of_trait: false } => {
|
||||
self.normalize_inherent_projection(uv.into()).expect_const()
|
||||
}
|
||||
};
|
||||
kind => unreachable!(
|
||||
"unexpected `DefKind` for const alias' resolution's parent def: {:?}",
|
||||
kind
|
||||
),
|
||||
},
|
||||
DefKind::Const => self.normalize_free_alias(uv.into()).expect_const(),
|
||||
DefKind::AnonConst => {
|
||||
let ct = ct.super_fold_with(self);
|
||||
super::with_replaced_escaping_bound_vars(
|
||||
self.selcx.infcx,
|
||||
&mut self.universes,
|
||||
ct,
|
||||
|ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env),
|
||||
)
|
||||
}
|
||||
kind => {
|
||||
unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind)
|
||||
}
|
||||
};
|
||||
|
||||
// We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
|
||||
// unnormalized after const evaluation returns.
|
||||
ct.expect_const().super_fold_with(self)
|
||||
} else {
|
||||
let ct = ct.super_fold_with(self);
|
||||
return super::with_replaced_escaping_bound_vars(
|
||||
self.selcx.infcx,
|
||||
&mut self.universes,
|
||||
ct,
|
||||
|ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env),
|
||||
)
|
||||
.super_fold_with(self);
|
||||
// We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
|
||||
// unnormalized after const evaluation returns.
|
||||
}
|
||||
// We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
|
||||
// unnormalized after const evaluation returns.
|
||||
ct.super_fold_with(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -546,7 +546,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
|
|||
let term: Term<'tcx> = if alias_term.kind(tcx).is_type() {
|
||||
tcx.type_of(alias_term.def_id).instantiate(tcx, args).into()
|
||||
} else {
|
||||
get_associated_const_value(selcx, alias_term.to_term(tcx).expect_const(), param_env).into()
|
||||
tcx.const_of_item(alias_term.def_id).instantiate(tcx, args).into()
|
||||
};
|
||||
|
||||
let mut term = selcx.infcx.resolve_vars_if_possible(term);
|
||||
|
|
@ -2034,14 +2034,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
|||
let term = if obligation.predicate.kind(tcx).is_type() {
|
||||
tcx.type_of(assoc_term.item.def_id).map_bound(|ty| ty.into())
|
||||
} else {
|
||||
ty::EarlyBinder::bind(
|
||||
get_associated_const_value(
|
||||
selcx,
|
||||
obligation.predicate.to_term(tcx).expect_const(),
|
||||
param_env,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
tcx.const_of_item(assoc_term.item.def_id).map_bound(|ct| ct.into())
|
||||
};
|
||||
|
||||
let progress = if !tcx.check_args_compatible(assoc_term.item.def_id, args) {
|
||||
|
|
@ -2133,15 +2126,3 @@ impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn get_associated_const_value<'tcx>(
|
||||
selcx: &mut SelectionContext<'_, 'tcx>,
|
||||
alias_ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> ty::Const<'tcx> {
|
||||
// FIXME(mgca): We shouldn't be invoking ctfe here, instead const items should be aliases to type
|
||||
// system consts that we can retrieve with some `query const_arg_of_alias` query. Evaluating the
|
||||
// constant is "close enough" to getting the actual rhs of the const item for now even if it might
|
||||
// lead to some cycles
|
||||
super::evaluate_const(selcx.infcx, alias_ct, param_env)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
//! Code for the 'normalization' query. This consists of a wrapper
|
||||
//! which folds deeply, invoking the underlying
|
||||
//! `normalize_canonicalized_projection_ty` query when it encounters projections.
|
||||
//! `normalize_canonicalized_projection` query when it encounters projections.
|
||||
|
||||
use rustc_data_structures::sso::SsoHashMap;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_infer::traits::PredicateObligations;
|
||||
use rustc_macros::extension;
|
||||
pub use rustc_middle::traits::query::NormalizationResult;
|
||||
|
|
@ -255,76 +256,9 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
ty::Projection | ty::Inherent | ty::Free => {
|
||||
// See note in `rustc_trait_selection::traits::project`
|
||||
|
||||
let infcx = self.infcx;
|
||||
let tcx = infcx.tcx;
|
||||
// Just an optimization: When we don't have escaping bound vars,
|
||||
// we don't need to replace them with placeholders.
|
||||
let (data, maps) = if data.has_escaping_bound_vars() {
|
||||
let (data, mapped_regions, mapped_types, mapped_consts) =
|
||||
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
|
||||
(data, Some((mapped_regions, mapped_types, mapped_consts)))
|
||||
} else {
|
||||
(data, None)
|
||||
};
|
||||
let data = data.try_fold_with(self)?;
|
||||
|
||||
let mut orig_values = OriginalQueryValues::default();
|
||||
let c_data = infcx.canonicalize_query(self.param_env.and(data), &mut orig_values);
|
||||
debug!("QueryNormalizer: c_data = {:#?}", c_data);
|
||||
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
|
||||
let result = match kind {
|
||||
ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data),
|
||||
ty::Free => tcx.normalize_canonicalized_free_alias(c_data),
|
||||
ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data),
|
||||
kind => unreachable!("did not expect {kind:?} due to match arm above"),
|
||||
}?;
|
||||
// We don't expect ambiguity.
|
||||
if !result.value.is_proven() {
|
||||
// Rustdoc normalizes possibly not well-formed types, so only
|
||||
// treat this as a bug if we're not in rustdoc.
|
||||
if !tcx.sess.opts.actually_rustdoc {
|
||||
tcx.dcx()
|
||||
.delayed_bug(format!("unexpected ambiguity: {c_data:?} {result:?}"));
|
||||
}
|
||||
return Err(NoSolution);
|
||||
}
|
||||
let InferOk { value: result, obligations } = infcx
|
||||
.instantiate_query_response_and_region_obligations(
|
||||
self.cause,
|
||||
self.param_env,
|
||||
&orig_values,
|
||||
result,
|
||||
)?;
|
||||
debug!("QueryNormalizer: result = {:#?}", result);
|
||||
debug!("QueryNormalizer: obligations = {:#?}", obligations);
|
||||
self.obligations.extend(obligations);
|
||||
let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps {
|
||||
PlaceholderReplacer::replace_placeholders(
|
||||
infcx,
|
||||
mapped_regions,
|
||||
mapped_types,
|
||||
mapped_consts,
|
||||
&self.universes,
|
||||
result.normalized_ty,
|
||||
)
|
||||
} else {
|
||||
result.normalized_ty
|
||||
};
|
||||
// `tcx.normalize_canonicalized_projection_ty` may normalize to a type that
|
||||
// still has unevaluated consts, so keep normalizing here if that's the case.
|
||||
// Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer
|
||||
// of type and we need to continue folding it to reveal the TAIT behind it.
|
||||
if res != ty
|
||||
&& (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Free)
|
||||
{
|
||||
res.try_fold_with(self)?
|
||||
} else {
|
||||
res
|
||||
}
|
||||
}
|
||||
ty::Projection | ty::Inherent | ty::Free => self
|
||||
.try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), data.def_id, data.args))?
|
||||
.expect_type(),
|
||||
};
|
||||
|
||||
self.cache.insert(ty, res);
|
||||
|
|
@ -339,12 +273,22 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
|
|||
return Ok(constant);
|
||||
}
|
||||
|
||||
let constant = crate::traits::with_replaced_escaping_bound_vars(
|
||||
self.infcx,
|
||||
&mut self.universes,
|
||||
constant,
|
||||
|constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env),
|
||||
);
|
||||
let uv = match constant.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => uv,
|
||||
_ => return constant.try_super_fold_with(self),
|
||||
};
|
||||
|
||||
let constant = match self.cx().def_kind(uv.def) {
|
||||
DefKind::AnonConst => crate::traits::with_replaced_escaping_bound_vars(
|
||||
self.infcx,
|
||||
&mut self.universes,
|
||||
constant,
|
||||
|constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env),
|
||||
),
|
||||
_ => self
|
||||
.try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), uv.def, uv.args))?
|
||||
.expect_const(),
|
||||
};
|
||||
debug!(?constant, ?self.param_env);
|
||||
constant.try_super_fold_with(self)
|
||||
}
|
||||
|
|
@ -361,3 +305,85 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> {
|
||||
fn try_fold_free_or_assoc(
|
||||
&mut self,
|
||||
term: ty::AliasTerm<'tcx>,
|
||||
) -> Result<ty::Term<'tcx>, NoSolution> {
|
||||
let infcx = self.infcx;
|
||||
let tcx = infcx.tcx;
|
||||
// Just an optimization: When we don't have escaping bound vars,
|
||||
// we don't need to replace them with placeholders.
|
||||
let (term, maps) = if term.has_escaping_bound_vars() {
|
||||
let (term, mapped_regions, mapped_types, mapped_consts) =
|
||||
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, term);
|
||||
(term, Some((mapped_regions, mapped_types, mapped_consts)))
|
||||
} else {
|
||||
(term, None)
|
||||
};
|
||||
let term = term.try_fold_with(self)?;
|
||||
|
||||
let mut orig_values = OriginalQueryValues::default();
|
||||
let c_term = infcx.canonicalize_query(self.param_env.and(term), &mut orig_values);
|
||||
debug!("QueryNormalizer: c_term = {:#?}", c_term);
|
||||
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
|
||||
let result = match term.kind(tcx) {
|
||||
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
|
||||
tcx.normalize_canonicalized_projection(c_term)
|
||||
}
|
||||
ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => {
|
||||
tcx.normalize_canonicalized_free_alias(c_term)
|
||||
}
|
||||
ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => {
|
||||
tcx.normalize_canonicalized_inherent_projection(c_term)
|
||||
}
|
||||
kind @ (ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::UnevaluatedConst) => {
|
||||
unreachable!("did not expect {kind:?} due to match arm above")
|
||||
}
|
||||
}?;
|
||||
// We don't expect ambiguity.
|
||||
if !result.value.is_proven() {
|
||||
// Rustdoc normalizes possibly not well-formed types, so only
|
||||
// treat this as a bug if we're not in rustdoc.
|
||||
if !tcx.sess.opts.actually_rustdoc {
|
||||
tcx.dcx().delayed_bug(format!("unexpected ambiguity: {c_term:?} {result:?}"));
|
||||
}
|
||||
return Err(NoSolution);
|
||||
}
|
||||
let InferOk { value: result, obligations } = infcx
|
||||
.instantiate_query_response_and_region_obligations(
|
||||
self.cause,
|
||||
self.param_env,
|
||||
&orig_values,
|
||||
result,
|
||||
)?;
|
||||
debug!("QueryNormalizer: result = {:#?}", result);
|
||||
debug!("QueryNormalizer: obligations = {:#?}", obligations);
|
||||
self.obligations.extend(obligations);
|
||||
let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps {
|
||||
PlaceholderReplacer::replace_placeholders(
|
||||
infcx,
|
||||
mapped_regions,
|
||||
mapped_types,
|
||||
mapped_consts,
|
||||
&self.universes,
|
||||
result.normalized_term,
|
||||
)
|
||||
} else {
|
||||
result.normalized_term
|
||||
};
|
||||
// `tcx.normalize_canonicalized_projection` may normalize to a type that
|
||||
// still has unevaluated consts, so keep normalizing here if that's the case.
|
||||
// Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer
|
||||
// of type and we need to continue folding it to reveal the TAIT behind it.
|
||||
if res != term.to_term(tcx)
|
||||
&& (res.as_type().map_or(false, |t| t.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION))
|
||||
|| term.kind(tcx) == ty::AliasTermKind::FreeTy)
|
||||
{
|
||||
res.try_fold_with(self)
|
||||
} else {
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,18 +12,18 @@ use tracing::debug;
|
|||
|
||||
pub(crate) fn provide(p: &mut Providers) {
|
||||
*p = Providers {
|
||||
normalize_canonicalized_projection_ty,
|
||||
normalize_canonicalized_projection,
|
||||
normalize_canonicalized_free_alias,
|
||||
normalize_canonicalized_inherent_projection_ty,
|
||||
normalize_canonicalized_inherent_projection,
|
||||
..*p
|
||||
};
|
||||
}
|
||||
|
||||
fn normalize_canonicalized_projection_ty<'tcx>(
|
||||
fn normalize_canonicalized_projection<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalAliasGoal<'tcx>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
|
||||
debug!("normalize_canonicalized_projection_ty(goal={:#?})", goal);
|
||||
debug!("normalize_canonicalized_projection(goal={:#?})", goal);
|
||||
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(
|
||||
&goal,
|
||||
|
|
@ -32,7 +32,7 @@ fn normalize_canonicalized_projection_ty<'tcx>(
|
|||
let selcx = &mut SelectionContext::new(ocx.infcx);
|
||||
let cause = ObligationCause::dummy();
|
||||
let mut obligations = PredicateObligations::new();
|
||||
let answer = traits::normalize_projection_term(
|
||||
let normalized_term = traits::normalize_projection_term(
|
||||
selcx,
|
||||
param_env,
|
||||
goal.into(),
|
||||
|
|
@ -61,10 +61,7 @@ fn normalize_canonicalized_projection_ty<'tcx>(
|
|||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// FIXME(associated_const_equality): All users of normalize_canonicalized_projection_ty
|
||||
// expected a type, but there is the possibility it could've been a const now.
|
||||
// Maybe change it to a Term later?
|
||||
Ok(NormalizationResult { normalized_ty: answer.expect_type() })
|
||||
Ok(NormalizationResult { normalized_term })
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -89,17 +86,21 @@ fn normalize_canonicalized_free_alias<'tcx>(
|
|||
},
|
||||
);
|
||||
ocx.register_obligations(obligations);
|
||||
let normalized_ty = tcx.type_of(goal.def_id).instantiate(tcx, goal.args);
|
||||
Ok(NormalizationResult { normalized_ty })
|
||||
let normalized_term = if goal.kind(tcx).is_type() {
|
||||
tcx.type_of(goal.def_id).instantiate(tcx, goal.args).into()
|
||||
} else {
|
||||
tcx.const_of_item(goal.def_id).instantiate(tcx, goal.args).into()
|
||||
};
|
||||
Ok(NormalizationResult { normalized_term })
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn normalize_canonicalized_inherent_projection_ty<'tcx>(
|
||||
fn normalize_canonicalized_inherent_projection<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalAliasGoal<'tcx>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
|
||||
debug!("normalize_canonicalized_inherent_projection_ty(goal={:#?})", goal);
|
||||
debug!("normalize_canonicalized_inherent_projection(goal={:#?})", goal);
|
||||
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(
|
||||
&goal,
|
||||
|
|
@ -107,7 +108,7 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>(
|
|||
let selcx = &mut SelectionContext::new(ocx.infcx);
|
||||
let cause = ObligationCause::dummy();
|
||||
let mut obligations = PredicateObligations::new();
|
||||
let answer = traits::normalize_inherent_projection(
|
||||
let normalized_term = traits::normalize_inherent_projection(
|
||||
selcx,
|
||||
param_env,
|
||||
goal.into(),
|
||||
|
|
@ -117,7 +118,7 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>(
|
|||
);
|
||||
ocx.register_obligations(obligations);
|
||||
|
||||
Ok(NormalizationResult { normalized_ty: answer.expect_type() })
|
||||
Ok(NormalizationResult { normalized_term })
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@ pub trait Interner:
|
|||
fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
|
||||
fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId)
|
||||
-> ty::EarlyBinder<Self, Self::Ty>;
|
||||
fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Const>;
|
||||
|
||||
type AdtDef: AdtDef<Self>;
|
||||
fn adt_def(self, adt_def_id: Self::AdtId) -> Self::AdtDef;
|
||||
|
|
|
|||
|
|
@ -306,16 +306,23 @@ pub(crate) fn clean_precise_capturing_arg(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn clean_const<'tcx>(
|
||||
constant: &hir::ConstArg<'tcx>,
|
||||
_cx: &mut DocContext<'tcx>,
|
||||
pub(crate) fn clean_const_item_rhs<'tcx>(
|
||||
ct_rhs: hir::ConstItemRhs<'tcx>,
|
||||
parent: DefId,
|
||||
) -> ConstantKind {
|
||||
match ct_rhs {
|
||||
hir::ConstItemRhs::Body(body) => ConstantKind::Local { def_id: parent, body },
|
||||
hir::ConstItemRhs::TypeConst(ct) => clean_const(ct),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind {
|
||||
match &constant.kind {
|
||||
hir::ConstArgKind::Path(qpath) => {
|
||||
ConstantKind::Path { path: qpath_to_string(qpath).into() }
|
||||
}
|
||||
hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body },
|
||||
hir::ConstArgKind::Infer(..) => ConstantKind::Infer,
|
||||
hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1194,7 +1201,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
|
|||
hir::TraitItemKind::Const(ty, Some(default)) => {
|
||||
ProvidedAssocConstItem(Box::new(Constant {
|
||||
generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)),
|
||||
kind: ConstantKind::Local { def_id: local_did, body: default },
|
||||
kind: clean_const_item_rhs(default, local_did),
|
||||
type_: clean_ty(ty, cx),
|
||||
}))
|
||||
}
|
||||
|
|
@ -1244,7 +1251,7 @@ pub(crate) fn clean_impl_item<'tcx>(
|
|||
let inner = match impl_.kind {
|
||||
hir::ImplItemKind::Const(ty, expr) => ImplAssocConstItem(Box::new(Constant {
|
||||
generics: clean_generics(impl_.generics, cx),
|
||||
kind: ConstantKind::Local { def_id: local_did, body: expr },
|
||||
kind: clean_const_item_rhs(expr, local_did),
|
||||
type_: clean_ty(ty, cx),
|
||||
})),
|
||||
hir::ImplItemKind::Fn(ref sig, body) => {
|
||||
|
|
@ -1799,7 +1806,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
|||
// results in an ICE while manually constructing the constant and using `eval`
|
||||
// does nothing for `ConstKind::Param`.
|
||||
let length = match const_arg.kind {
|
||||
hir::ConstArgKind::Infer(..) => "_".to_string(),
|
||||
hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => "_".to_string(),
|
||||
hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) => {
|
||||
let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No);
|
||||
let typing_env = ty::TypingEnv::post_analysis(cx.tcx, *def_id);
|
||||
|
|
@ -2516,7 +2523,7 @@ fn clean_generic_args<'tcx>(
|
|||
hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
|
||||
hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty.as_unambig_ty(), cx)),
|
||||
hir::GenericArg::Const(ct) => {
|
||||
GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct(), cx)))
|
||||
GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct())))
|
||||
}
|
||||
hir::GenericArg::Infer(_inf) => GenericArg::Infer,
|
||||
})
|
||||
|
|
@ -2785,10 +2792,10 @@ fn clean_maybe_renamed_item<'tcx>(
|
|||
mutability,
|
||||
expr: Some(body_id),
|
||||
}),
|
||||
ItemKind::Const(_, generics, ty, body_id) => ConstantItem(Box::new(Constant {
|
||||
ItemKind::Const(_, generics, ty, rhs) => ConstantItem(Box::new(Constant {
|
||||
generics: clean_generics(generics, cx),
|
||||
type_: clean_ty(ty, cx),
|
||||
kind: ConstantKind::Local { body: body_id, def_id },
|
||||
kind: clean_const_item_rhs(rhs, def_id),
|
||||
})),
|
||||
ItemKind::TyAlias(_, generics, ty) => {
|
||||
*cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
// definitely contains interior mutability.
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant, const_item_rhs_to_expr};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
use clippy_utils::is_in_const_context;
|
||||
use clippy_utils::macros::macro_backtrace;
|
||||
|
|
@ -28,7 +28,8 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, DefIdSet};
|
||||
use rustc_hir::{
|
||||
Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, StructTailExpr, TraitItem, TraitItemKind, UnOp,
|
||||
ConstArgKind, ConstItemRhs, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, StructTailExpr,
|
||||
TraitItem, TraitItemKind, UnOp,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::mir::{ConstValue, UnevaluatedConst};
|
||||
|
|
@ -272,6 +273,7 @@ impl<'tcx> NonCopyConst<'tcx> {
|
|||
|
||||
/// Checks if a value of the given type is `Freeze`, or may be depending on the value.
|
||||
fn is_ty_freeze(&mut self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, ty: Ty<'tcx>) -> IsFreeze {
|
||||
// FIXME: this should probably be using the trait solver
|
||||
let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
|
||||
match self.freeze_tys.entry(ty) {
|
||||
Entry::Occupied(e) => *e.get(),
|
||||
|
|
@ -695,7 +697,7 @@ impl<'tcx> NonCopyConst<'tcx> {
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
if let ItemKind::Const(ident, .., body_id) = item.kind
|
||||
if let ItemKind::Const(ident, .., ct_rhs) = item.kind
|
||||
&& !ident.is_special()
|
||||
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
|
||||
&& match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) {
|
||||
|
|
@ -703,13 +705,14 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
|
|||
IsFreeze::Yes => false,
|
||||
IsFreeze::Maybe => match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) {
|
||||
Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => !is_freeze,
|
||||
_ => !self.is_init_expr_freeze(
|
||||
// FIXME: we just assume mgca rhs's are freeze
|
||||
_ => const_item_rhs_to_expr(cx.tcx, ct_rhs).map_or(false, |e| !self.is_init_expr_freeze(
|
||||
cx.tcx,
|
||||
cx.typing_env(),
|
||||
cx.tcx.typeck(item.owner_id),
|
||||
GenericArgs::identity_for_item(cx.tcx, item.owner_id),
|
||||
cx.tcx.hir_body(body_id).value,
|
||||
),
|
||||
e
|
||||
)),
|
||||
},
|
||||
}
|
||||
&& !item.span.in_external_macro(cx.sess().source_map())
|
||||
|
|
@ -736,22 +739,25 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
|
|||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
|
||||
if let TraitItemKind::Const(_, body_id_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,
|
||||
IsFreeze::Maybe if let Some(body_id) = body_id_opt => {
|
||||
IsFreeze::Maybe if let Some(ct_rhs) = ct_rhs_opt => {
|
||||
match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) {
|
||||
Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => {
|
||||
!is_freeze
|
||||
},
|
||||
_ => !self.is_init_expr_freeze(
|
||||
cx.tcx,
|
||||
cx.typing_env(),
|
||||
cx.tcx.typeck(item.owner_id),
|
||||
GenericArgs::identity_for_item(cx.tcx, item.owner_id),
|
||||
cx.tcx.hir_body(body_id).value,
|
||||
),
|
||||
// FIXME: we just assume mgca rhs's are freeze
|
||||
_ => const_item_rhs_to_expr(cx.tcx, ct_rhs).map_or(false, |e| {
|
||||
!self.is_init_expr_freeze(
|
||||
cx.tcx,
|
||||
cx.typing_env(),
|
||||
cx.tcx.typeck(item.owner_id),
|
||||
GenericArgs::identity_for_item(cx.tcx, item.owner_id),
|
||||
e,
|
||||
)
|
||||
}),
|
||||
}
|
||||
},
|
||||
IsFreeze::Yes | IsFreeze::Maybe => false,
|
||||
|
|
@ -768,7 +774,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
|
|||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
|
||||
if let ImplItemKind::Const(_, body_id) = item.kind
|
||||
if let ImplItemKind::Const(_, ct_rhs) = 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::Yes => false,
|
||||
|
|
@ -799,13 +805,16 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
|
|||
// interior mutability.
|
||||
IsFreeze::Maybe => match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) {
|
||||
Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => !is_freeze,
|
||||
_ => !self.is_init_expr_freeze(
|
||||
cx.tcx,
|
||||
cx.typing_env(),
|
||||
cx.tcx.typeck(item.owner_id),
|
||||
GenericArgs::identity_for_item(cx.tcx, item.owner_id),
|
||||
cx.tcx.hir_body(body_id).value,
|
||||
),
|
||||
// FIXME: we just assume mgca rhs's are freeze
|
||||
_ => const_item_rhs_to_expr(cx.tcx, ct_rhs).map_or(false, |e| {
|
||||
!self.is_init_expr_freeze(
|
||||
cx.tcx,
|
||||
cx.typing_env(),
|
||||
cx.tcx.typeck(item.owner_id),
|
||||
GenericArgs::identity_for_item(cx.tcx, item.owner_id),
|
||||
e,
|
||||
)
|
||||
}),
|
||||
},
|
||||
}
|
||||
&& !item.span.in_external_macro(cx.sess().source_map())
|
||||
|
|
@ -913,20 +922,26 @@ fn get_const_hir_value<'tcx>(
|
|||
args: GenericArgsRef<'tcx>,
|
||||
) -> Option<(&'tcx TypeckResults<'tcx>, &'tcx Expr<'tcx>)> {
|
||||
let did = did.as_local()?;
|
||||
let (did, body_id) = match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) {
|
||||
Node::Item(item) if let ItemKind::Const(.., body_id) = item.kind => (did, body_id),
|
||||
Node::ImplItem(item) if let ImplItemKind::Const(.., body_id) = item.kind => (did, body_id),
|
||||
let (did, ct_rhs) = match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) {
|
||||
Node::Item(item) if let ItemKind::Const(.., ct_rhs) = item.kind => (did, ct_rhs),
|
||||
Node::ImplItem(item) if let ImplItemKind::Const(.., ct_rhs) = item.kind => (did, ct_rhs),
|
||||
Node::TraitItem(_)
|
||||
if let Ok(Some(inst)) = Instance::try_resolve(tcx, typing_env, did.into(), args)
|
||||
&& let Some(did) = inst.def_id().as_local() =>
|
||||
{
|
||||
match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) {
|
||||
Node::ImplItem(item) if let ImplItemKind::Const(.., body_id) = item.kind => (did, body_id),
|
||||
Node::TraitItem(item) if let TraitItemKind::Const(.., Some(body_id)) = item.kind => (did, body_id),
|
||||
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),
|
||||
_ => return None,
|
||||
}
|
||||
},
|
||||
_ => return None,
|
||||
};
|
||||
Some((tcx.typeck(did), tcx.hir_body(body_id).value))
|
||||
match ct_rhs {
|
||||
ConstItemRhs::Body(body_id) => Some((tcx.typeck(did), tcx.hir_body(body_id).value)),
|
||||
ConstItemRhs::TypeConst(ct_arg) => match ct_arg.kind {
|
||||
ConstArgKind::Anon(anon_const) => Some((tcx.typeck(did), tcx.hir_body(anon_const.body).value)),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::ops::ControlFlow;
|
|||
use std::sync::Arc;
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::const_item_rhs_to_expr;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_lint_allowed;
|
||||
use clippy_utils::source::walk_span_to_context;
|
||||
|
|
@ -184,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &hir::Item<'tcx>) {
|
||||
if item.span.in_external_macro(cx.tcx.sess.source_map()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -214,7 +215,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>, (span, help_span): (Span, Span), is_doc: bool) {
|
||||
fn check_has_safety_comment<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, (span, help_span): (Span, Span), is_doc: bool) {
|
||||
match &item.kind {
|
||||
ItemKind::Impl(Impl {
|
||||
of_trait: Some(of_trait),
|
||||
|
|
@ -234,7 +235,29 @@ fn check_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>, (span, h
|
|||
},
|
||||
ItemKind::Impl(_) => {},
|
||||
// const and static items only need a safety comment if their body is an unsafe block, lint otherwise
|
||||
&ItemKind::Const(.., body) | &ItemKind::Static(.., body) => {
|
||||
&ItemKind::Const(.., ct_rhs) => {
|
||||
if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, ct_rhs.hir_id()) {
|
||||
let expr = const_item_rhs_to_expr(cx.tcx, ct_rhs);
|
||||
if let Some(expr) = expr && !matches!(
|
||||
expr.kind, hir::ExprKind::Block(block, _)
|
||||
if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
|
||||
) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
UNNECESSARY_SAFETY_COMMENT,
|
||||
span,
|
||||
format!(
|
||||
"{} has unnecessary safety comment",
|
||||
cx.tcx.def_descr(item.owner_id.to_def_id()),
|
||||
),
|
||||
|diag| {
|
||||
diag.span_help(help_span, "consider removing the safety comment");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
&ItemKind::Static(.., body) => {
|
||||
if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) {
|
||||
let body = cx.tcx.hir_body(body);
|
||||
if !matches!(
|
||||
|
|
|
|||
|
|
@ -320,6 +320,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
self.body(field!(anon_const.body));
|
||||
},
|
||||
ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"),
|
||||
ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
ident: li,
|
||||
generics: lg,
|
||||
ty: lt,
|
||||
expr: le,
|
||||
rhs: lb,
|
||||
define_opaque: _,
|
||||
}),
|
||||
Const(box ConstItem {
|
||||
|
|
@ -364,7 +364,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
ident: ri,
|
||||
generics: rg,
|
||||
ty: rt,
|
||||
expr: re,
|
||||
rhs: rb,
|
||||
define_opaque: _,
|
||||
}),
|
||||
) => {
|
||||
|
|
@ -372,7 +372,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
&& eq_id(*li, *ri)
|
||||
&& eq_generics(lg, rg)
|
||||
&& eq_ty(lt, rt)
|
||||
&& eq_expr_opt(le.as_deref(), re.as_deref())
|
||||
&& both(lb.as_ref(), rb.as_ref(), |l, r| eq_const_item_rhs(l, r))
|
||||
},
|
||||
(
|
||||
Fn(box ast::Fn {
|
||||
|
|
@ -610,7 +610,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
|
|||
ident: li,
|
||||
generics: lg,
|
||||
ty: lt,
|
||||
expr: le,
|
||||
rhs: lb,
|
||||
define_opaque: _,
|
||||
}),
|
||||
Const(box ConstItem {
|
||||
|
|
@ -618,7 +618,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
|
|||
ident: ri,
|
||||
generics: rg,
|
||||
ty: rt,
|
||||
expr: re,
|
||||
rhs: rb,
|
||||
define_opaque: _,
|
||||
}),
|
||||
) => {
|
||||
|
|
@ -626,7 +626,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
|
|||
&& eq_id(*li, *ri)
|
||||
&& eq_generics(lg, rg)
|
||||
&& eq_ty(lt, rt)
|
||||
&& eq_expr_opt(le.as_deref(), re.as_deref())
|
||||
&& both(lb.as_ref(), rb.as_ref(), |l, r| eq_const_item_rhs(l, r))
|
||||
},
|
||||
(
|
||||
Fn(box ast::Fn {
|
||||
|
|
@ -784,6 +784,15 @@ 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::*;
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
|
||||
use UseTreeKind::*;
|
||||
match (l, r) {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ use rustc_apfloat::Float;
|
|||
use rustc_apfloat::ieee::{Half, Quad};
|
||||
use rustc_ast::ast::{LitFloatType, LitKind};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, PatExpr, PatExprKind, QPath, TyKind, UnOp};
|
||||
use rustc_hir::{
|
||||
BinOpKind, Block, ConstArgKind, ConstBlock, ConstItemRhs, Expr, ExprKind, HirId, PatExpr, PatExprKind, QPath,
|
||||
TyKind, UnOp,
|
||||
};
|
||||
use rustc_lexer::{FrontmatterAllowed, tokenize};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir::ConstValue;
|
||||
|
|
@ -1130,3 +1133,14 @@ pub fn integer_const(cx: &LateContext<'_>, expr: &Expr<'_>, ctxt: SyntaxContext)
|
|||
pub fn is_zero_integer_const(cx: &LateContext<'_>, expr: &Expr<'_>, ctxt: SyntaxContext) -> bool {
|
||||
integer_const(cx, expr, ctxt) == Some(0)
|
||||
}
|
||||
|
||||
pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx>) -> Option<&'tcx Expr<'tcx>> {
|
||||
match ct_rhs {
|
||||
ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value),
|
||||
ConstItemRhs::TypeConst(const_arg) => match const_arg.kind {
|
||||
ConstArgKind::Path(_) => None,
|
||||
ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value),
|
||||
ConstArgKind::Error(..) | ConstArgKind::Infer(..) => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -481,7 +481,9 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
(ConstArgKind::Path(..), ConstArgKind::Anon(..))
|
||||
| (ConstArgKind::Anon(..), ConstArgKind::Path(..))
|
||||
| (ConstArgKind::Infer(..), _)
|
||||
| (_, ConstArgKind::Infer(..)) => false,
|
||||
| (_, ConstArgKind::Infer(..))
|
||||
| (ConstArgKind::Error(..), _)
|
||||
| (_, ConstArgKind::Error(..)) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1330,7 +1332,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
match &const_arg.kind {
|
||||
ConstArgKind::Path(path) => self.hash_qpath(path),
|
||||
ConstArgKind::Anon(anon) => self.hash_body(anon.body),
|
||||
ConstArgKind::Infer(..) => {},
|
||||
ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -192,12 +192,12 @@ fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt]) -> Option<RustcVersi
|
|||
|
||||
let msrv_attr = msrv_attrs.next()?;
|
||||
|
||||
if let Some(duplicate) = msrv_attrs.next_back() {
|
||||
sess.dcx()
|
||||
.struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times")
|
||||
.with_span_note(msrv_attr.span(), "first definition found here")
|
||||
.emit();
|
||||
}
|
||||
if let Some(duplicate) = msrv_attrs.next_back() {
|
||||
sess.dcx()
|
||||
.struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times")
|
||||
.with_span_note(msrv_attr.span(), "first definition found here")
|
||||
.emit();
|
||||
}
|
||||
|
||||
let Some(msrv) = msrv_attr.value_str() else {
|
||||
sess.dcx().span_err(msrv_attr.span(), "bad clippy attribute");
|
||||
|
|
@ -205,8 +205,8 @@ fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt]) -> Option<RustcVersi
|
|||
};
|
||||
|
||||
let Some(version) = parse_version(msrv) else {
|
||||
sess.dcx()
|
||||
.span_err(msrv_attr.span(), format!("`{msrv}` is not a valid Rust version"));
|
||||
sess.dcx()
|
||||
.span_err(msrv_attr.span(), format!("`{msrv}` is not a valid Rust version"));
|
||||
return None;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
/// unimplemented!();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// With an explicit return type it should lint too
|
||||
/// ```edition2015
|
||||
/// fn main() -> () {
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
/// unimplemented!();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// This should, too.
|
||||
/// ```rust
|
||||
/// fn main() {
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
/// unimplemented!();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// This one too.
|
||||
/// ```no_run
|
||||
/// // the fn is not always the first line
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![deny(clippy::trait_duplication_in_bounds)]
|
||||
#![allow(unused)]
|
||||
#![feature(associated_const_equality, const_trait_impl)]
|
||||
#![feature(const_trait_impl)]
|
||||
|
||||
use std::any::Any;
|
||||
|
||||
|
|
@ -194,12 +194,3 @@ where
|
|||
T: Iterator<Item: Clone> + Iterator<Item: Clone>,
|
||||
{
|
||||
}
|
||||
trait AssocConstTrait {
|
||||
const ASSOC: usize;
|
||||
}
|
||||
fn assoc_const_args<T>()
|
||||
where
|
||||
T: AssocConstTrait<ASSOC = 0>,
|
||||
//~^ trait_duplication_in_bounds
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![deny(clippy::trait_duplication_in_bounds)]
|
||||
#![allow(unused)]
|
||||
#![feature(associated_const_equality, const_trait_impl)]
|
||||
#![feature(const_trait_impl)]
|
||||
|
||||
use std::any::Any;
|
||||
|
||||
|
|
@ -194,12 +194,3 @@ where
|
|||
T: Iterator<Item: Clone> + Iterator<Item: Clone>,
|
||||
{
|
||||
}
|
||||
trait AssocConstTrait {
|
||||
const ASSOC: usize;
|
||||
}
|
||||
fn assoc_const_args<T>()
|
||||
where
|
||||
T: AssocConstTrait<ASSOC = 0> + AssocConstTrait<ASSOC = 0>,
|
||||
//~^ trait_duplication_in_bounds
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,11 +70,5 @@ error: these where clauses contain repeated elements
|
|||
LL | T: IntoIterator<Item = U::Owned> + IntoIterator<Item = U::Owned>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `IntoIterator<Item = U::Owned>`
|
||||
|
||||
error: these where clauses contain repeated elements
|
||||
--> tests/ui/trait_duplication_in_bounds.rs:202:8
|
||||
|
|
||||
LL | T: AssocConstTrait<ASSOC = 0> + AssocConstTrait<ASSOC = 0>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `AssocConstTrait<ASSOC = 0>`
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
#![deny(clippy::trait_duplication_in_bounds)]
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
|
||||
trait AssocConstTrait {
|
||||
#[type_const]
|
||||
const ASSOC: usize;
|
||||
}
|
||||
fn assoc_const_args<T>()
|
||||
where
|
||||
T: AssocConstTrait<ASSOC = 0>,
|
||||
//~^ trait_duplication_in_bounds
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#![deny(clippy::trait_duplication_in_bounds)]
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
|
||||
trait AssocConstTrait {
|
||||
#[type_const]
|
||||
const ASSOC: usize;
|
||||
}
|
||||
fn assoc_const_args<T>()
|
||||
where
|
||||
T: AssocConstTrait<ASSOC = 0> + AssocConstTrait<ASSOC = 0>,
|
||||
//~^ trait_duplication_in_bounds
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
error: these where clauses contain repeated elements
|
||||
--> tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs:11:8
|
||||
|
|
||||
LL | T: AssocConstTrait<ASSOC = 0> + AssocConstTrait<ASSOC = 0>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `AssocConstTrait<ASSOC = 0>`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs:1:9
|
||||
|
|
||||
LL | #![deny(clippy::trait_duplication_in_bounds)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -2004,37 +2004,37 @@ pub(crate) struct StaticParts<'a> {
|
|||
generics: Option<&'a ast::Generics>,
|
||||
ty: &'a ast::Ty,
|
||||
mutability: ast::Mutability,
|
||||
expr_opt: Option<&'a Box<ast::Expr>>,
|
||||
expr_opt: Option<&'a ast::Expr>,
|
||||
defaultness: Option<ast::Defaultness>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl<'a> StaticParts<'a> {
|
||||
pub(crate) fn from_item(item: &'a ast::Item) -> Self {
|
||||
let (defaultness, prefix, safety, ident, ty, mutability, expr, generics) = match &item.kind
|
||||
{
|
||||
ast::ItemKind::Static(s) => (
|
||||
None,
|
||||
"static",
|
||||
s.safety,
|
||||
s.ident,
|
||||
&s.ty,
|
||||
s.mutability,
|
||||
&s.expr,
|
||||
None,
|
||||
),
|
||||
ast::ItemKind::Const(c) => (
|
||||
Some(c.defaultness),
|
||||
"const",
|
||||
ast::Safety::Default,
|
||||
c.ident,
|
||||
&c.ty,
|
||||
ast::Mutability::Not,
|
||||
&c.expr,
|
||||
Some(&c.generics),
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let (defaultness, prefix, safety, ident, ty, mutability, expr_opt, generics) =
|
||||
match &item.kind {
|
||||
ast::ItemKind::Static(s) => (
|
||||
None,
|
||||
"static",
|
||||
s.safety,
|
||||
s.ident,
|
||||
&s.ty,
|
||||
s.mutability,
|
||||
s.expr.as_deref(),
|
||||
None,
|
||||
),
|
||||
ast::ItemKind::Const(c) => (
|
||||
Some(c.defaultness),
|
||||
"const",
|
||||
ast::Safety::Default,
|
||||
c.ident,
|
||||
&c.ty,
|
||||
ast::Mutability::Not,
|
||||
c.rhs.as_ref().map(|rhs| rhs.expr()),
|
||||
Some(&c.generics),
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
StaticParts {
|
||||
prefix,
|
||||
safety,
|
||||
|
|
@ -2043,7 +2043,7 @@ impl<'a> StaticParts<'a> {
|
|||
generics,
|
||||
ty,
|
||||
mutability,
|
||||
expr_opt: expr.as_ref(),
|
||||
expr_opt,
|
||||
defaultness,
|
||||
span: item.span,
|
||||
}
|
||||
|
|
@ -2051,7 +2051,12 @@ 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.expr, Some(&c.generics)),
|
||||
ast::AssocItemKind::Const(c) => (
|
||||
c.defaultness,
|
||||
&c.ty,
|
||||
c.rhs.as_ref().map(|rhs| rhs.expr()),
|
||||
Some(&c.generics),
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
StaticParts {
|
||||
|
|
@ -2062,15 +2067,20 @@ impl<'a> StaticParts<'a> {
|
|||
generics,
|
||||
ty,
|
||||
mutability: ast::Mutability::Not,
|
||||
expr_opt: expr_opt.as_ref(),
|
||||
expr_opt,
|
||||
defaultness: Some(defaultness),
|
||||
span: ti.span,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_impl_item(ii: &'a ast::AssocItem, ident: Ident) -> Self {
|
||||
let (defaultness, ty, expr, generics) = match &ii.kind {
|
||||
ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr, Some(&c.generics)),
|
||||
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),
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
StaticParts {
|
||||
|
|
@ -2081,7 +2091,7 @@ impl<'a> StaticParts<'a> {
|
|||
generics,
|
||||
ty,
|
||||
mutability: ast::Mutability::Not,
|
||||
expr_opt: expr.as_ref(),
|
||||
expr_opt,
|
||||
defaultness: Some(defaultness),
|
||||
span: ii.span,
|
||||
}
|
||||
|
|
@ -2144,7 +2154,7 @@ fn rewrite_static(
|
|||
rewrite_assign_rhs_with_comments(
|
||||
context,
|
||||
&lhs,
|
||||
&**expr,
|
||||
expr,
|
||||
Shape::legacy(remaining_width, offset.block_only()),
|
||||
&RhsAssignKind::Expr(&expr.kind, expr.span),
|
||||
RhsTactics::Default,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
//@ known-bug: #119783
|
||||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
|
||||
trait Trait { const F: fn(); }
|
||||
trait Trait {
|
||||
#[type_const]
|
||||
const F: fn();
|
||||
}
|
||||
|
||||
fn take(_: impl Trait<F = { || {} }>) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
//@ known-bug: #131046
|
||||
|
||||
trait Owner {
|
||||
const C<const N: u32>: u32;
|
||||
}
|
||||
|
||||
impl Owner for () {
|
||||
const C<const N: u32>: u32 = N;
|
||||
}
|
||||
|
||||
fn take0<const N: u64>(_: impl Owner<C<N> = { N }>) {}
|
||||
|
||||
fn main() {
|
||||
take0::<128>(());
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
//@ known-bug: #134641
|
||||
#![feature(associated_const_equality)]
|
||||
|
||||
pub trait IsVoid {
|
||||
const IS_VOID: bool;
|
||||
}
|
||||
impl IsVoid for () {
|
||||
const IS_VOID: bool = true;
|
||||
}
|
||||
|
||||
pub trait Maybe {}
|
||||
impl Maybe for () {}
|
||||
impl Maybe for () where (): IsVoid<IS_VOID = true> {}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
struct OnDiskDirEntry<'a> {}
|
||||
|
||||
impl<'a> OnDiskDirEntry<'a> {
|
||||
#[type_const]
|
||||
const LFN_FRAGMENT_LEN: i64 = 2;
|
||||
|
||||
fn lfn_contents() -> [char; Self::LFN_FRAGMENT_LEN] {
|
||||
|
|
|
|||
16
tests/crashes/mgca/ace-with-const-ctor.rs
Normal file
16
tests/crashes/mgca/ace-with-const-ctor.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
//@ known-bug: #132980
|
||||
// Originally a rustdoc test. Should be moved back there with @has checks
|
||||
// readded once fixed.
|
||||
// Previous issue (before mgca): https://github.com/rust-lang/rust/issues/105952
|
||||
#![crate_name = "foo"]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
pub enum ParseMode {
|
||||
Raw,
|
||||
}
|
||||
pub trait Parse {
|
||||
#[type_const]
|
||||
const PARSE_MODE: ParseMode;
|
||||
}
|
||||
pub trait RenderRaw {}
|
||||
|
||||
impl<T: Parse<PARSE_MODE = { ParseMode::Raw }>> RenderRaw for T {}
|
||||
23
tests/crashes/mgca/type_const-only-in-trait.rs
Normal file
23
tests/crashes/mgca/type_const-only-in-trait.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
//@ known-bug: #132980
|
||||
// Move this test to tests/ui/const-generics/mgca/type_const-only-in-trait.rs
|
||||
// once fixed.
|
||||
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
|
||||
trait GoodTr {
|
||||
#[type_const]
|
||||
const NUM: usize;
|
||||
}
|
||||
|
||||
struct BadS;
|
||||
|
||||
impl GoodTr for BadS {
|
||||
const NUM: usize = 42;
|
||||
}
|
||||
|
||||
fn accept_good_tr<const N: usize, T: GoodTr<NUM = { N }>>(_x: &T) {}
|
||||
|
||||
fn main() {
|
||||
accept_good_tr(&BadS);
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
// Regression test for <https://github.com/rust-lang/rust/issues/102467>.
|
||||
// It ensures that the expected error is displayed.
|
||||
|
||||
#![feature(associated_const_equality)]
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
|
||||
trait T {
|
||||
type A: S<C<X = 0i32> = 34>;
|
||||
|
|
@ -10,6 +11,7 @@ trait T {
|
|||
}
|
||||
|
||||
trait S {
|
||||
#[type_const]
|
||||
const C: i32;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0229]: associated item constraints are not allowed here
|
||||
--> $DIR/associated-constant-not-allowed-102467.rs:7:17
|
||||
--> $DIR/associated-constant-not-allowed-102467.rs:8:17
|
||||
|
|
||||
LL | type A: S<C<X = 0i32> = 34>;
|
||||
| ^^^^^^^^ associated item constraint not allowed here
|
||||
|
|
@ -11,7 +11,7 @@ LL + type A: S<C = 34>;
|
|||
|
|
||||
|
||||
error[E0229]: associated item constraints are not allowed here
|
||||
--> $DIR/associated-constant-not-allowed-102467.rs:7:17
|
||||
--> $DIR/associated-constant-not-allowed-102467.rs:8:17
|
||||
|
|
||||
LL | type A: S<C<X = 0i32> = 34>;
|
||||
| ^^^^^^^^ associated item constraint not allowed here
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
#![feature(associated_const_equality)]
|
||||
|
||||
trait T {
|
||||
type A: S<C<X = 0i32> = 34>;
|
||||
//~^ ERROR associated item constraints are not allowed here
|
||||
//~| ERROR associated item constraints are not allowed here
|
||||
}
|
||||
|
||||
trait S {
|
||||
const C: i32;
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
error[E0229]: associated item constraints are not allowed here
|
||||
--> $DIR/invalid_associated_const.rs:4:17
|
||||
|
|
||||
LL | type A: S<C<X = 0i32> = 34>;
|
||||
| ^^^^^^^^ associated item constraint not allowed here
|
||||
|
|
||||
help: consider removing this associated item binding
|
||||
|
|
||||
LL - type A: S<C<X = 0i32> = 34>;
|
||||
LL + type A: S<C = 34>;
|
||||
|
|
||||
|
||||
error[E0229]: associated item constraints are not allowed here
|
||||
--> $DIR/invalid_associated_const.rs:4:17
|
||||
|
|
||||
LL | type A: S<C<X = 0i32> = 34>;
|
||||
| ^^^^^^^^ associated item constraint not allowed here
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
help: consider removing this associated item binding
|
||||
|
|
||||
LL - type A: S<C<X = 0i32> = 34>;
|
||||
LL + type A: S<C = 34>;
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0229`.
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// https://github.com/rust-lang/rust/issues/105952
|
||||
#![crate_name = "foo"]
|
||||
|
||||
#![feature(associated_const_equality)]
|
||||
pub enum ParseMode {
|
||||
Raw,
|
||||
}
|
||||
pub trait Parse {
|
||||
const PARSE_MODE: ParseMode;
|
||||
}
|
||||
pub trait RenderRaw {}
|
||||
|
||||
//@ hasraw foo/trait.RenderRaw.html 'impl'
|
||||
//@ hasraw foo/trait.RenderRaw.html 'ParseMode::Raw'
|
||||
impl<T: Parse<PARSE_MODE = { ParseMode::Raw }>> RenderRaw for T {}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
#![feature(associated_const_equality)]
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
|
||||
pub fn accept(_: impl Trait<K = 0>) {}
|
||||
|
||||
pub trait Trait {
|
||||
#[type_const]
|
||||
const K: i32;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,27 @@
|
|||
// We used to say "ambiguous associated type" on ambiguous associated consts.
|
||||
// Ensure that we now use the correct label.
|
||||
|
||||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait0: Parent0<i32> + Parent0<u32> {}
|
||||
trait Parent0<T> { const K: (); }
|
||||
trait Parent0<T> {
|
||||
#[type_const]
|
||||
const K: ();
|
||||
}
|
||||
|
||||
fn take0(_: impl Trait0<K = { () }>) {}
|
||||
//~^ ERROR ambiguous associated constant `K` in bounds of `Trait0`
|
||||
|
||||
trait Trait1: Parent1 + Parent2 {}
|
||||
trait Parent1 { const C: i32; }
|
||||
trait Parent2 { const C: &'static str; }
|
||||
trait Parent1 {
|
||||
#[type_const]
|
||||
const C: i32;
|
||||
}
|
||||
trait Parent2 {
|
||||
#[type_const]
|
||||
const C: &'static str;
|
||||
}
|
||||
|
||||
fn take1(_: impl Trait1<C = "?">) {}
|
||||
//~^ ERROR ambiguous associated constant `C` in bounds of `Trait1`
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
error[E0222]: ambiguous associated constant `K` in bounds of `Trait0`
|
||||
--> $DIR/assoc-const-eq-ambiguity.rs:9:25
|
||||
--> $DIR/assoc-const-eq-ambiguity.rs:13:25
|
||||
|
|
||||
LL | trait Parent0<T> { const K: (); }
|
||||
| -----------
|
||||
| |
|
||||
| ambiguous `K` from `Parent0<u32>`
|
||||
| ambiguous `K` from `Parent0<i32>`
|
||||
LL |
|
||||
LL | const K: ();
|
||||
| -----------
|
||||
| |
|
||||
| ambiguous `K` from `Parent0<u32>`
|
||||
| ambiguous `K` from `Parent0<i32>`
|
||||
...
|
||||
LL | fn take0(_: impl Trait0<K = { () }>) {}
|
||||
| ^^^^^^^^^^ ambiguous associated constant `K`
|
||||
|
|
||||
|
|
@ -17,13 +17,14 @@ LL | fn take0(_: impl Trait0<K = { () }>) {}
|
|||
T: Parent0<i32>::K = { () }
|
||||
|
||||
error[E0222]: ambiguous associated constant `C` in bounds of `Trait1`
|
||||
--> $DIR/assoc-const-eq-ambiguity.rs:16:25
|
||||
--> $DIR/assoc-const-eq-ambiguity.rs:26:25
|
||||
|
|
||||
LL | trait Parent1 { const C: i32; }
|
||||
| ------------ ambiguous `C` from `Parent1`
|
||||
LL | trait Parent2 { const C: &'static str; }
|
||||
| --------------------- ambiguous `C` from `Parent2`
|
||||
LL |
|
||||
LL | const C: i32;
|
||||
| ------------ ambiguous `C` from `Parent1`
|
||||
...
|
||||
LL | const C: &'static str;
|
||||
| --------------------- ambiguous `C` from `Parent2`
|
||||
...
|
||||
LL | fn take1(_: impl Trait1<C = "?">) {}
|
||||
| ^^^^^^^ ambiguous associated constant `C`
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
// Check that we eventually catch types of assoc const bounds
|
||||
// (containing late-bound vars) that are ill-formed.
|
||||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait<T> {
|
||||
#[type_const]
|
||||
const K: T;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
error: higher-ranked subtype error
|
||||
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:12:13
|
||||
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:14:13
|
||||
|
|
||||
LL | K = { () }
|
||||
| ^^^^^^
|
||||
|
||||
error: higher-ranked subtype error
|
||||
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:12:13
|
||||
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:14:13
|
||||
|
|
||||
LL | K = { () }
|
||||
| ^^^^^^
|
||||
|
|
@ -13,7 +13,7 @@ LL | K = { () }
|
|||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: implementation of `Project` is not general enough
|
||||
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:10:13
|
||||
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:12:13
|
||||
|
|
||||
LL | _: impl Trait<
|
||||
| _____________^
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@
|
|||
//
|
||||
//@ check-pass
|
||||
|
||||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait<T> {
|
||||
#[type_const]
|
||||
const K: T;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,13 @@
|
|||
//
|
||||
// issue: <https://github.com/rust-lang/rust/issues/108220>
|
||||
//@ check-pass
|
||||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
pub trait TraitA<T> { const K: u8 = 0; }
|
||||
pub trait TraitA<T> {
|
||||
#[type_const]
|
||||
const K: u8 = 0;
|
||||
}
|
||||
pub trait TraitB<T> {}
|
||||
|
||||
impl<T> TraitA<T> for () {}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
// Detect and reject escaping late-bound generic params in
|
||||
// the type of assoc consts used in an equality bound.
|
||||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait<'a> {
|
||||
#[type_const]
|
||||
const K: &'a ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: the type of the associated constant `K` cannot capture late-bound generic parameters
|
||||
--> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:9:35
|
||||
--> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:11:35
|
||||
|
|
||||
LL | fn take(_: impl for<'r> Trait<'r, K = { &() }>) {}
|
||||
| -- ^ its type cannot capture the late-bound lifetime parameter `'r`
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
// Regression test for issue #108271.
|
||||
// Detect and reject generic params in the type of assoc consts used in an equality bound.
|
||||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait<'a, T: 'a, const N: usize> {
|
||||
#[type_const]
|
||||
const K: &'a [T; N];
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +23,7 @@ fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
|
|||
//~| NOTE `K` has type `&'r [A; Q]`
|
||||
|
||||
trait Project {
|
||||
#[type_const]
|
||||
const SELF: Self;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:9:61
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:11:61
|
||||
|
|
||||
LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
|
||||
| -- the lifetime parameter `'r` is defined here ^ its type must not depend on the lifetime parameter `'r`
|
||||
|
|
@ -7,7 +7,7 @@ LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }
|
|||
= note: `K` has type `&'r [A; Q]`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:9:61
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:11:61
|
||||
|
|
||||
LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
|
||||
| - the type parameter `A` is defined here ^ its type must not depend on the type parameter `A`
|
||||
|
|
@ -15,7 +15,7 @@ LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }
|
|||
= note: `K` has type `&'r [A; Q]`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:9:61
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:11:61
|
||||
|
|
||||
LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
|
||||
| - ^ its type must not depend on the const parameter `Q`
|
||||
|
|
@ -25,7 +25,7 @@ LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }
|
|||
= note: `K` has type `&'r [A; Q]`
|
||||
|
||||
error: the type of the associated constant `SELF` must not depend on `impl Trait`
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:27:26
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:30:26
|
||||
|
|
||||
LL | fn take1(_: impl Project<SELF = {}>) {}
|
||||
| -------------^^^^------
|
||||
|
|
@ -34,7 +34,7 @@ LL | fn take1(_: impl Project<SELF = {}>) {}
|
|||
| the `impl Trait` is specified here
|
||||
|
||||
error: the type of the associated constant `SELF` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:32:21
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:35:21
|
||||
|
|
||||
LL | fn take2<P: Project<SELF = {}>>(_: P) {}
|
||||
| - ^^^^ its type must not depend on the type parameter `P`
|
||||
|
|
@ -44,7 +44,7 @@ LL | fn take2<P: Project<SELF = {}>>(_: P) {}
|
|||
= note: `SELF` has type `P`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:41:52
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:44:52
|
||||
|
|
||||
LL | trait Iface<'r> {
|
||||
| -- the lifetime parameter `'r` is defined here
|
||||
|
|
@ -55,7 +55,7 @@ LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
|||
= note: `K` has type `&'r [Self; Q]`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on `Self`
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:41:52
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:44:52
|
||||
|
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
||||
| ^ its type must not depend on `Self`
|
||||
|
|
@ -63,7 +63,7 @@ LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
|||
= note: `K` has type `&'r [Self; Q]`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:41:52
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:44:52
|
||||
|
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
||||
| - ^ its type must not depend on the const parameter `Q`
|
||||
|
|
@ -73,7 +73,7 @@ LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
|||
= note: `K` has type `&'r [Self; Q]`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:41:52
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:44:52
|
||||
|
|
||||
LL | trait Iface<'r> {
|
||||
| -- the lifetime parameter `'r` is defined here
|
||||
|
|
@ -85,7 +85,7 @@ LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
|||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on `Self`
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:41:52
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:44:52
|
||||
|
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
||||
| ^ its type must not depend on `Self`
|
||||
|
|
@ -94,7 +94,7 @@ LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
|||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: the type of the associated constant `K` must not depend on generic parameters
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:41:52
|
||||
--> $DIR/assoc-const-eq-param-in-ty.rs:44:52
|
||||
|
|
||||
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
|
||||
| - ^ its type must not depend on the const parameter `Q`
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@
|
|||
|
||||
//@ check-pass
|
||||
|
||||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait: SuperTrait {}
|
||||
trait SuperTrait: SuperSuperTrait<i32> {}
|
||||
trait SuperSuperTrait<T> {
|
||||
#[type_const]
|
||||
const K: T;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,16 +5,19 @@
|
|||
|
||||
//@ check-pass
|
||||
|
||||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait: SuperTrait {
|
||||
type N;
|
||||
type Q;
|
||||
|
||||
#[type_const]
|
||||
const N: usize;
|
||||
}
|
||||
|
||||
trait SuperTrait {
|
||||
#[type_const]
|
||||
const Q: &'static str;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
//@ run-pass
|
||||
#![feature(associated_const_equality)]
|
||||
#![allow(unused)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(unused, incomplete_features)]
|
||||
|
||||
pub trait Foo {
|
||||
#[type_const]
|
||||
const N: usize;
|
||||
}
|
||||
|
||||
pub struct Bar;
|
||||
|
||||
impl Foo for Bar {
|
||||
#[type_const]
|
||||
const N: usize = 3;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +1,32 @@
|
|||
//@ check-pass
|
||||
|
||||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
#![deny(dead_code)]
|
||||
|
||||
trait Tr {
|
||||
#[type_const]
|
||||
const I: i32;
|
||||
}
|
||||
|
||||
impl Tr for () {
|
||||
#[type_const]
|
||||
const I: i32 = 1;
|
||||
}
|
||||
|
||||
fn foo() -> impl Tr<I = 1> {}
|
||||
|
||||
trait Tr2 {
|
||||
#[type_const]
|
||||
const J: i32;
|
||||
#[type_const]
|
||||
const K: i32;
|
||||
}
|
||||
|
||||
impl Tr2 for () {
|
||||
#[type_const]
|
||||
const J: i32 = 1;
|
||||
#[type_const]
|
||||
const K: i32 = 1;
|
||||
}
|
||||
|
||||
|
|
@ -27,10 +34,12 @@ fn foo2() -> impl Tr2<J = 1, K = 1> {}
|
|||
|
||||
mod t {
|
||||
pub trait Tr3 {
|
||||
#[type_const]
|
||||
const L: i32;
|
||||
}
|
||||
|
||||
impl Tr3 for () {
|
||||
#[type_const]
|
||||
const L: i32 = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait T {
|
||||
type A: S<C<X = 0i32> = 34>;
|
||||
|
|
@ -7,6 +8,7 @@ trait T {
|
|||
}
|
||||
|
||||
trait S {
|
||||
#[type_const]
|
||||
const C: i32;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0229]: associated item constraints are not allowed here
|
||||
--> $DIR/issue-102335-const.rs:4:17
|
||||
--> $DIR/issue-102335-const.rs:5:17
|
||||
|
|
||||
LL | type A: S<C<X = 0i32> = 34>;
|
||||
| ^^^^^^^^ associated item constraint not allowed here
|
||||
|
|
@ -11,7 +11,7 @@ LL + type A: S<C = 34>;
|
|||
|
|
||||
|
||||
error[E0229]: associated item constraints are not allowed here
|
||||
--> $DIR/issue-102335-const.rs:4:17
|
||||
--> $DIR/issue-102335-const.rs:5:17
|
||||
|
|
||||
LL | type A: S<C<X = 0i32> = 34>;
|
||||
| ^^^^^^^^ associated item constraint not allowed here
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
//@ check-pass
|
||||
|
||||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
pub trait Trait {
|
||||
#[type_const]
|
||||
const ASSOC: usize;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// Issue 110549
|
||||
|
||||
pub trait TraitWAssocConst {
|
||||
#[type_const]
|
||||
const A: usize;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 32`
|
||||
--> $DIR/projection-unspecified-but-bounded.rs:12:11
|
||||
--> $DIR/projection-unspecified-but-bounded.rs:14:11
|
||||
|
|
||||
LL | foo::<T>();
|
||||
| ^ expected `32`, found `<T as TraitWAssocConst>::A`
|
||||
|
|
@ -7,7 +7,7 @@ LL | foo::<T>();
|
|||
= note: expected constant `32`
|
||||
found constant `<T as TraitWAssocConst>::A`
|
||||
note: required by a bound in `foo`
|
||||
--> $DIR/projection-unspecified-but-bounded.rs:9:28
|
||||
--> $DIR/projection-unspecified-but-bounded.rs:11:28
|
||||
|
|
||||
LL | fn foo<T: TraitWAssocConst<A = 32>>() {}
|
||||
| ^^^^^^ required by this bound in `foo`
|
||||
|
|
|
|||
|
|
@ -1,24 +1,15 @@
|
|||
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/const-projection-err.rs:4:26
|
||||
|
|
||||
LL | #![cfg_attr(gce, feature(generic_const_exprs))]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 1`
|
||||
--> $DIR/const-projection-err.rs:14:11
|
||||
--> $DIR/const-projection-err.rs:16:11
|
||||
|
|
||||
LL | foo::<T>();
|
||||
| ^ expected `0`, found `1`
|
||||
|
|
||||
note: required by a bound in `foo`
|
||||
--> $DIR/const-projection-err.rs:11:28
|
||||
--> $DIR/const-projection-err.rs:13:28
|
||||
|
|
||||
LL | fn foo<T: TraitWAssocConst<A = 1>>() {}
|
||||
| ^^^^^ required by this bound in `foo`
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0271`.
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
//@ revisions: stock gce
|
||||
|
||||
#![feature(associated_const_equality)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
#![cfg_attr(gce, feature(generic_const_exprs))]
|
||||
//[gce]~^ WARN the feature `generic_const_exprs` is incomplete
|
||||
|
||||
trait TraitWAssocConst {
|
||||
#[type_const]
|
||||
const A: usize;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 1`
|
||||
--> $DIR/const-projection-err.rs:14:11
|
||||
--> $DIR/const-projection-err.rs:16:11
|
||||
|
|
||||
LL | foo::<T>();
|
||||
| ^ expected `1`, found `<T as TraitWAssocConst>::A`
|
||||
| ^ expected `1`, found `0`
|
||||
|
|
||||
= note: expected constant `1`
|
||||
found constant `<T as TraitWAssocConst>::A`
|
||||
found constant `0`
|
||||
note: required by a bound in `foo`
|
||||
--> $DIR/const-projection-err.rs:11:28
|
||||
--> $DIR/const-projection-err.rs:13:28
|
||||
|
|
||||
LL | fn foo<T: TraitWAssocConst<A = 1>>() {}
|
||||
| ^^^^^ required by this bound in `foo`
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
//@ edition: 2024
|
||||
|
||||
#![feature(associated_const_equality, type_alias_impl_trait, return_type_notation)]
|
||||
#![feature(
|
||||
associated_const_equality,
|
||||
min_generic_const_args,
|
||||
type_alias_impl_trait,
|
||||
return_type_notation
|
||||
)]
|
||||
#![expect(incomplete_features)]
|
||||
#![allow(refining_impl_trait_internal)]
|
||||
|
||||
use std::iter;
|
||||
|
|
@ -45,6 +51,7 @@ fn mismatch_2() -> impl Iterator<Item: Copy, Item: Send> {
|
|||
trait Trait {
|
||||
type Gat<T>;
|
||||
|
||||
#[type_const]
|
||||
const ASSOC: i32;
|
||||
|
||||
fn foo() -> impl Sized;
|
||||
|
|
@ -53,6 +60,7 @@ trait Trait {
|
|||
impl Trait for () {
|
||||
type Gat<T> = ();
|
||||
|
||||
#[type_const]
|
||||
const ASSOC: i32 = 3;
|
||||
|
||||
fn foo() {}
|
||||
|
|
@ -61,6 +69,7 @@ impl Trait for () {
|
|||
impl Trait for u32 {
|
||||
type Gat<T> = ();
|
||||
|
||||
#[type_const]
|
||||
const ASSOC: i32 = 4;
|
||||
|
||||
fn foo() -> u32 {
|
||||
|
|
@ -79,6 +88,7 @@ type MustFail = dyn Iterator<Item = i32, Item = u32>;
|
|||
//~| ERROR conflicting associated type bounds
|
||||
|
||||
trait Trait2 {
|
||||
#[type_const]
|
||||
const ASSOC: u32;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0282]: type annotations needed
|
||||
--> $DIR/duplicate-bound-err.rs:9:5
|
||||
--> $DIR/duplicate-bound-err.rs:15:5
|
||||
|
|
||||
LL | iter::empty()
|
||||
| ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
|
||||
|
|
@ -10,7 +10,7 @@ LL | iter::empty::<T>()
|
|||
| +++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/duplicate-bound-err.rs:13:5
|
||||
--> $DIR/duplicate-bound-err.rs:19:5
|
||||
|
|
||||
LL | iter::empty()
|
||||
| ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
|
||||
|
|
@ -21,7 +21,7 @@ LL | iter::empty::<T>()
|
|||
| +++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/duplicate-bound-err.rs:17:5
|
||||
--> $DIR/duplicate-bound-err.rs:23:5
|
||||
|
|
||||
LL | iter::empty()
|
||||
| ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
|
||||
|
|
@ -32,7 +32,7 @@ LL | iter::empty::<T>()
|
|||
| +++++
|
||||
|
||||
error: unconstrained opaque type
|
||||
--> $DIR/duplicate-bound-err.rs:21:51
|
||||
--> $DIR/duplicate-bound-err.rs:27:51
|
||||
|
|
||||
LL | type Tait1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
|
||||
| ^^^^^^^^^
|
||||
|
|
@ -40,7 +40,7 @@ LL | type Tait1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
|
|||
= note: `Tait1` must be used in combination with a concrete type within the same crate
|
||||
|
||||
error: unconstrained opaque type
|
||||
--> $DIR/duplicate-bound-err.rs:23:51
|
||||
--> $DIR/duplicate-bound-err.rs:29:51
|
||||
|
|
||||
LL | type Tait2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
|
||||
| ^^^^^^^^^
|
||||
|
|
@ -48,7 +48,7 @@ LL | type Tait2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
|
|||
= note: `Tait2` must be used in combination with a concrete type within the same crate
|
||||
|
||||
error: unconstrained opaque type
|
||||
--> $DIR/duplicate-bound-err.rs:25:57
|
||||
--> $DIR/duplicate-bound-err.rs:31:57
|
||||
|
|
||||
LL | type Tait3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
|
||||
| ^^^^^^^^^
|
||||
|
|
@ -56,7 +56,7 @@ LL | type Tait3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
|
|||
= note: `Tait3` must be used in combination with a concrete type within the same crate
|
||||
|
||||
error: unconstrained opaque type
|
||||
--> $DIR/duplicate-bound-err.rs:28:14
|
||||
--> $DIR/duplicate-bound-err.rs:34:14
|
||||
|
|
||||
LL | type Tait4 = impl Iterator<Item: Copy, Item: Send>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -64,7 +64,7 @@ LL | type Tait4 = impl Iterator<Item: Copy, Item: Send>;
|
|||
= note: `Tait4` must be used in combination with a concrete type within the same crate
|
||||
|
||||
error: unconstrained opaque type
|
||||
--> $DIR/duplicate-bound-err.rs:30:14
|
||||
--> $DIR/duplicate-bound-err.rs:36:14
|
||||
|
|
||||
LL | type Tait5 = impl Iterator<Item: Copy, Item: Copy>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -72,7 +72,7 @@ LL | type Tait5 = impl Iterator<Item: Copy, Item: Copy>;
|
|||
= note: `Tait5` must be used in combination with a concrete type within the same crate
|
||||
|
||||
error: unconstrained opaque type
|
||||
--> $DIR/duplicate-bound-err.rs:32:14
|
||||
--> $DIR/duplicate-bound-err.rs:38:14
|
||||
|
|
||||
LL | type Tait6 = impl Iterator<Item: 'static, Item: 'static>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -80,7 +80,7 @@ LL | type Tait6 = impl Iterator<Item: 'static, Item: 'static>;
|
|||
= note: `Tait6` must be used in combination with a concrete type within the same crate
|
||||
|
||||
error[E0277]: `*const ()` cannot be sent between threads safely
|
||||
--> $DIR/duplicate-bound-err.rs:35:18
|
||||
--> $DIR/duplicate-bound-err.rs:41:18
|
||||
|
|
||||
LL | fn mismatch() -> impl Iterator<Item: Copy, Item: Send> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely
|
||||
|
|
@ -91,7 +91,7 @@ LL | iter::empty::<*const ()>()
|
|||
= help: the trait `Send` is not implemented for `*const ()`
|
||||
|
||||
error[E0277]: the trait bound `String: Copy` is not satisfied
|
||||
--> $DIR/duplicate-bound-err.rs:40:20
|
||||
--> $DIR/duplicate-bound-err.rs:46:20
|
||||
|
|
||||
LL | fn mismatch_2() -> impl Iterator<Item: Copy, Item: Send> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
|
||||
|
|
@ -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:100:17
|
||||
--> $DIR/duplicate-bound-err.rs:110:17
|
||||
|
|
||||
LL | fn foo() -> impl Iterator<Item = i32, Item = u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
|
||||
|
|
@ -109,7 +109,7 @@ LL | [2u32].into_iter()
|
|||
| ------------------ return type was inferred to be `std::array::IntoIter<u32, 1>` here
|
||||
|
||||
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
|
||||
--> $DIR/duplicate-bound-err.rs:77:42
|
||||
--> $DIR/duplicate-bound-err.rs:86:42
|
||||
|
|
||||
LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
|
|
@ -117,7 +117,7 @@ LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
|
|||
| `Item` bound here first
|
||||
|
||||
error: conflicting associated type bounds for `Item`
|
||||
--> $DIR/duplicate-bound-err.rs:77:17
|
||||
--> $DIR/duplicate-bound-err.rs:86:17
|
||||
|
|
||||
LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
|
||||
| ^^^^^^^^^^^^^----------^^----------^
|
||||
|
|
@ -126,7 +126,7 @@ LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
|
|||
| `Item` is specified to be `i32` here
|
||||
|
||||
error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified
|
||||
--> $DIR/duplicate-bound-err.rs:85:43
|
||||
--> $DIR/duplicate-bound-err.rs:95:43
|
||||
|
|
||||
LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
|
||||
| ------------ ^^^^^^^^^^^^ re-bound here
|
||||
|
|
@ -134,7 +134,7 @@ LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
|
|||
| `ASSOC` bound here first
|
||||
|
||||
error: conflicting associated type bounds for `ASSOC`
|
||||
--> $DIR/duplicate-bound-err.rs:85:18
|
||||
--> $DIR/duplicate-bound-err.rs:95:18
|
||||
|
|
||||
LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
|
||||
| ^^^^^^^^^^^------------^^------------^
|
||||
|
|
@ -143,7 +143,7 @@ LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
|
|||
| `ASSOC` is specified to be `3` here
|
||||
|
||||
error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
|
||||
--> $DIR/duplicate-bound-err.rs:89:43
|
||||
--> $DIR/duplicate-bound-err.rs:99:43
|
||||
|
|
||||
LL | type MustFail3 = dyn Iterator<Item = i32, Item = i32>;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
|
|
@ -151,7 +151,7 @@ LL | type MustFail3 = dyn Iterator<Item = i32, Item = i32>;
|
|||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified
|
||||
--> $DIR/duplicate-bound-err.rs:92:43
|
||||
--> $DIR/duplicate-bound-err.rs:102:43
|
||||
|
|
||||
LL | type MustFail4 = dyn Trait2<ASSOC = 3u32, ASSOC = 3u32>;
|
||||
| ------------ ^^^^^^^^^^^^ re-bound here
|
||||
|
|
@ -159,19 +159,19 @@ LL | type MustFail4 = dyn Trait2<ASSOC = 3u32, ASSOC = 3u32>;
|
|||
| `ASSOC` bound here first
|
||||
|
||||
error[E0271]: expected `impl Iterator<Item = u32>` to be an iterator that yields `i32`, but it yields `u32`
|
||||
--> $DIR/duplicate-bound-err.rs:100:17
|
||||
--> $DIR/duplicate-bound-err.rs:110: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:96:31
|
||||
--> $DIR/duplicate-bound-err.rs:106:31
|
||||
|
|
||||
LL | fn foo() -> impl Iterator<Item = i32, Item = u32>;
|
||||
| ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}`
|
||||
|
||||
error[E0271]: expected `Empty<u32>` to be an iterator that yields `i32`, but it yields `u32`
|
||||
--> $DIR/duplicate-bound-err.rs:108:16
|
||||
--> $DIR/duplicate-bound-err.rs:118: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:71:32
|
||||
--> $DIR/duplicate-bound-err.rs:80: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:109:16
|
||||
--> $DIR/duplicate-bound-err.rs:119: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:71:44
|
||||
--> $DIR/duplicate-bound-err.rs:80: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:110:22
|
||||
--> $DIR/duplicate-bound-err.rs:120: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:73:46
|
||||
--> $DIR/duplicate-bound-err.rs:82: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:111:22
|
||||
--> $DIR/duplicate-bound-err.rs:121: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:73:35
|
||||
--> $DIR/duplicate-bound-err.rs:82: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:112:20
|
||||
--> $DIR/duplicate-bound-err.rs:122:20
|
||||
|
|
||||
LL | uncallable_rtn(());
|
||||
| -------------- ^^ expected `4`, found `3`
|
||||
|
|
@ -241,13 +241,13 @@ LL | uncallable_rtn(());
|
|||
= note: expected constant `4`
|
||||
found constant `3`
|
||||
note: required by a bound in `uncallable_rtn`
|
||||
--> $DIR/duplicate-bound-err.rs:75:75
|
||||
--> $DIR/duplicate-bound-err.rs:84:75
|
||||
|
|
||||
LL | fn uncallable_rtn(_: 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:113:20
|
||||
--> $DIR/duplicate-bound-err.rs:123:20
|
||||
|
|
||||
LL | uncallable_rtn(17u32);
|
||||
| -------------- ^^^^^ expected `3`, found `4`
|
||||
|
|
@ -257,7 +257,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:75:48
|
||||
--> $DIR/duplicate-bound-err.rs:84:48
|
||||
|
|
||||
LL | fn uncallable_rtn(_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
|
||||
| ^^^^^^^^^ required by this bound in `uncallable_rtn`
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
//@ edition: 2024
|
||||
//@ run-pass
|
||||
|
||||
#![feature(associated_const_equality, return_type_notation)]
|
||||
#![feature(associated_const_equality, min_generic_const_args, return_type_notation)]
|
||||
#![expect(incomplete_features)]
|
||||
#![allow(dead_code, refining_impl_trait_internal, type_alias_bounds)]
|
||||
|
||||
use std::iter;
|
||||
|
|
@ -188,6 +189,7 @@ trait Tra3 {
|
|||
trait Trait {
|
||||
type Gat<T>;
|
||||
|
||||
#[type_const]
|
||||
const ASSOC: i32;
|
||||
|
||||
fn foo() -> impl Sized;
|
||||
|
|
@ -196,6 +198,7 @@ trait Trait {
|
|||
impl Trait for () {
|
||||
type Gat<T> = ();
|
||||
|
||||
#[type_const]
|
||||
const ASSOC: i32 = 3;
|
||||
|
||||
fn foo() {}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
pub trait IsVoid {
|
||||
#[type_const]
|
||||
const IS_VOID: bool;
|
||||
}
|
||||
impl IsVoid for () {
|
||||
#[type_const]
|
||||
const IS_VOID: bool = true;
|
||||
}
|
||||
|
||||
pub trait Maybe {}
|
||||
impl Maybe for () {}
|
||||
impl Maybe for () where (): IsVoid<IS_VOID = true> {}
|
||||
//~^ ERROR conflicting implementations of trait `Maybe` for type `()`
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
error[E0119]: conflicting implementations of trait `Maybe` for type `()`
|
||||
--> $DIR/coherence.rs:15:1
|
||||
|
|
||||
LL | impl Maybe for () {}
|
||||
| ----------------- first implementation here
|
||||
LL | impl Maybe for () where (): IsVoid<IS_VOID = true> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
||||
|
|
@ -1,14 +1,18 @@
|
|||
#![feature(associated_const_equality, generic_const_items)]
|
||||
//@ check-pass
|
||||
|
||||
#![feature(associated_const_equality, min_generic_const_args, generic_const_items)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
// Regression test for #133066 where we would try to evaluate `<() as Foo>::ASSOC<_>` even
|
||||
// though it contained inference variables, which would cause ICEs.
|
||||
|
||||
trait Foo {
|
||||
#[type_const]
|
||||
const ASSOC<const N: u32>: u32;
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
#[type_const]
|
||||
const ASSOC<const N: u32>: u32 = N;
|
||||
}
|
||||
|
||||
|
|
@ -16,9 +20,4 @@ fn bar<const N: u32, T: Foo<ASSOC<N> = 10>>() {}
|
|||
|
||||
fn main() {
|
||||
bar::<_, ()>();
|
||||
//~^ ERROR: type mismatch resolving `<() as Foo>::ASSOC<_> == 10`
|
||||
|
||||
// FIXME(mgca):
|
||||
// FIXME(associated_const_equality):
|
||||
// This ought to start compiling once const items are aliases rather than bodies
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
error[E0271]: type mismatch resolving `<() as Foo>::ASSOC<_> == 10`
|
||||
--> $DIR/equality_bound_with_infer.rs:18:14
|
||||
|
|
||||
LL | bar::<_, ()>();
|
||||
| ^^ expected `10`, found `<() as Foo>::ASSOC::<_>`
|
||||
|
|
||||
= note: expected constant `10`
|
||||
found constant `<() as Foo>::ASSOC::<_>`
|
||||
note: required by a bound in `bar`
|
||||
--> $DIR/equality_bound_with_infer.rs:15:29
|
||||
|
|
||||
LL | fn bar<const N: u32, T: Foo<ASSOC<N> = 10>>() {}
|
||||
| ^^^^^^^^^^^^^ required by this bound in `bar`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0271`.
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue