From b61efecae3c0dc4360761fa6b8ab70ebc989b3e0 Mon Sep 17 00:00:00 2001 From: khyperia <953151+khyperia@users.noreply.github.com> Date: Fri, 4 Sep 2026 08:01:45 +0200 Subject: [PATCH] type system const items via direct rhs --- compiler/rustc_ast_lowering/src/lib.rs | 48 +++++++++++++----- .../src/const_eval/eval_queries.rs | 11 +++- compiler/rustc_hir/src/hir.rs | 6 +-- compiler/rustc_hir/src/intravisit.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 5 +- .../src/check/compare_impl_item.rs | 13 ++--- .../rustc_hir_analysis/src/check/wfcheck.rs | 21 +++----- compiler/rustc_hir_analysis/src/collect.rs | 31 ++++++------ .../src/collect/clauses_of.rs | 2 +- .../rustc_hir_analysis/src/collect/type_of.rs | 50 ++++++++++++------- .../src/hir_ty_lowering/bounds.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 16 +----- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/queries.rs | 14 ++++-- compiler/rustc_middle/src/query/erase.rs | 1 + compiler/rustc_middle/src/ty/assoc.rs | 13 ++--- compiler/rustc_middle/src/ty/context.rs | 25 +++++++--- .../src/ty/context/impl_interner.rs | 23 +++++++-- .../src/builder/expr/as_constant.rs | 13 ++++- compiler/rustc_mir_build/src/thir/cx/mod.rs | 9 +++- .../src/thir/pattern/const_to_pat.rs | 17 +++++-- compiler/rustc_monomorphize/src/collector.rs | 2 +- .../src/solve/normalizes_to.rs | 9 ++-- .../src/solve/project_goals/free_alias.rs | 6 ++- .../src/solve/project_goals/inherent.rs | 7 ++- compiler/rustc_passes/src/reachable.rs | 2 +- .../src/traits/normalize.rs | 6 +-- .../src/traits/project.rs | 20 +++++++- .../rustc_trait_selection/src/traits/wf.rs | 3 +- .../src/normalize_projection_ty.rs | 5 +- compiler/rustc_ty_utils/src/assoc.rs | 12 ++--- compiler/rustc_type_ir/src/const_kind.rs | 10 +--- compiler/rustc_type_ir/src/interner.rs | 7 ++- src/librustdoc/clean/mod.rs | 2 +- .../clippy/clippy_lints/src/non_copy_const.rs | 2 +- src/tools/clippy/clippy_utils/src/consts.rs | 2 +- ...-on-failed-eval-with-vars-fail.next.stderr | 16 +++--- ...s-on-failed-eval-with-vars-fail.old.stderr | 2 +- ...ambiguous-on-failed-eval-with-vars-fail.rs | 5 +- tests/ui/const-generics/gca/assoc-const.rs | 22 ++++++++ .../gca/non-type-equality-fail.rs | 9 ++-- .../gca/non-type-equality-fail.stderr | 18 +++---- .../gca/non-type-equality-ok.rs | 2 + .../gca/wf-inherentimpl.old.stderr | 2 +- .../ui/const-generics/gca/wf-inherentimpl.rs | 3 +- 48 files changed, 307 insertions(+), 197 deletions(-) create mode 100644 tests/ui/const-generics/gca/assoc-const.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5b76606d101bc..a4c6769e91f83 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2672,19 +2672,41 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ConstItemRhs<'hir> { match (body, kind) { (body, ConstItemKind::Body) => { - hir::ConstItemRhs::Body(self.lower_const_body(span, body.as_deref())) - } - (Some(body), ConstItemKind::TypeConst) => { - hir::ConstItemRhs::TypeConst(self.arena.alloc( - match self.can_lower_expr_to_const_arg_direct( - &body, - DirectConstArgContext::MacrolessMinGenericConstArgs, - ) { - Ok(()) => self.lower_expr_to_const_arg_direct(&body, None), - Err(err) => err.emit(self), - }, - )) + let is_direct = |body| { + if self.tcx.features().macroless_generic_const_args() { + self.can_lower_expr_to_const_arg_direct( + body, + DirectConstArgContext::MacrolessMinGenericConstArgs, + ) + .is_ok() + } else { + // do not check can_lower_expr_to_const_arg_direct, but rather just + // ExprKind::DirectConstArg, because we don't want e.g. + // `impl { const C: u8 = N; }` to be a direct-rhs const + matches!(body, Expr { kind: ExprKind::DirectConstArg(_), .. }) + } + }; + // N.B.: the feature gate for this is generic_const_args, not min_generic_const_args + if self.tcx.features().generic_const_args() + && let Some(body) = body + && is_direct(body) + { + hir::ConstItemRhs::Direct( + self.arena.alloc(self.lower_expr_to_const_arg_direct(&body, None)), + ) + } else { + hir::ConstItemRhs::Body(self.lower_const_body(span, body.as_deref())) + } } + (Some(body), ConstItemKind::TypeConst) => hir::ConstItemRhs::Direct(self.arena.alloc( + match self.can_lower_expr_to_const_arg_direct( + &body, + DirectConstArgContext::MacrolessMinGenericConstArgs, + ) { + Ok(()) => self.lower_expr_to_const_arg_direct(&body, None), + Err(err) => err.emit(self), + }, + )), (None, ConstItemKind::TypeConst) => { let const_arg = ConstArg { hir_id: self.next_id(), @@ -2693,7 +2715,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), span: DUMMY_SP, }; - hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg)) + hir::ConstItemRhs::Direct(self.arena.alloc(const_arg)) } } } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 912be902b46f7..c823da68b65bd 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -440,8 +440,15 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( typing_env: ty::TypingEnv<'tcx>, ) -> Result { let def = cid.instance.def.def_id(); - // `type const` don't have bodys - debug_assert!(!tcx.is_type_const(def), "CTFE tried to evaluate type-const: {:?}", def); + // directly represented consts don't have bodies + if cfg!(debug_assertions) + && matches!(tcx.def_kind(def), DefKind::Const { .. } | DefKind::AssocConst { .. }) + { + debug_assert!( + tcx.const_of_item(def).is_none(), + "CTFE tried to evaluate directly represented const item: {def:?}" + ); + } let is_static = tcx.is_static(def); let mut ecx = InterpCx::new( diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index fb4b61e9f4875..e9b519ae2a558 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -416,21 +416,21 @@ impl<'hir> PathSegment<'hir> { #[derive(Clone, Copy, Debug, StableHash)] pub enum ConstItemRhs<'hir> { Body(BodyId), - TypeConst(&'hir ConstArg<'hir>), + Direct(&'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, + ConstItemRhs::Direct(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, + ConstItemRhs::Direct(ct_arg) => ct_arg.span, } } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 811dccc4a0ad9..db0f685b9d5a6 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1082,7 +1082,7 @@ pub fn walk_const_item_rhs<'v, V: Visitor<'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), + ConstItemRhs::Direct(const_arg) => visitor.visit_const_arg_unambig(const_arg), } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 1895f586df2f0..d5bc834b831c7 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -953,10 +953,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), tcx.require_lang_item(LangItem::Sized, ty_span), ); check_where_clauses(wfcx, def_id); - - if tcx.is_type_const(def_id) { - wfcheck::check_type_const(wfcx, def_id, ty, true)?; - } + wfcheck::check_const_item(wfcx, def_id, ty); Ok(()) })); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index e5d26cf72f9a5..4aebe60182333 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2157,12 +2157,10 @@ fn compare_type_const<'tcx>( impl_const_item: ty::AssocItem, trait_const_item: ty::AssocItem, ) -> Result<(), ErrorGuaranteed> { - let impl_is_type_const = tcx.is_type_const(impl_const_item.def_id); - let trait_type_const_span = tcx.type_const_span(trait_const_item.def_id); + let impl_is_type_const = tcx.is_type_const_syntax(impl_const_item.def_id); + let trait_is_type_const = tcx.is_type_const_syntax(trait_const_item.def_id); - if let Some(trait_type_const_span) = trait_type_const_span - && !impl_is_type_const - { + if trait_is_type_const && !impl_is_type_const { return Err(tcx .dcx() .struct_span_err( @@ -2170,10 +2168,7 @@ fn compare_type_const<'tcx>( "implementation of a `type const` must also be marked as `type const`", ) .with_span_note( - MultiSpan::from_spans(vec![ - tcx.def_span(trait_const_item.def_id), - trait_type_const_span, - ]), + tcx.def_span(trait_const_item.def_id), "trait declaration of const is marked as `type const`", ) .emit()); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4b95f1e82cd9a..f0a5db377f6bc 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -929,13 +929,9 @@ pub(crate) fn check_associated_item( let ty = tcx.type_of(def_id).instantiate_identity(); let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); + check_const_item(wfcx, def_id, ty); - let has_value = item.defaultness(tcx).has_value(); - if tcx.is_type_const(def_id) { - check_type_const(wfcx, def_id, ty, has_value)?; - } - - if has_value { + if item.defaultness(tcx).has_value() { let code = ObligationCauseCode::SizedConstOrStatic; wfcx.register_bound( ObligationCause::new(span, def_id, code), @@ -1264,17 +1260,17 @@ pub(crate) fn check_static_item<'tcx>( }) } +/// Runs checks common to both free consts and associated consts #[instrument(level = "debug", skip(wfcx))] -pub(super) fn check_type_const<'tcx>( +pub(super) fn check_const_item<'tcx>( wfcx: &WfCheckingCtxt<'_, 'tcx>, def_id: LocalDefId, item_ty: Ty<'tcx>, - has_value: bool, -) -> Result<(), ErrorGuaranteed> { +) { let tcx = wfcx.tcx(); let span = tcx.def_span(def_id); - if !tcx.features().const_param_ty_unchecked() { + if tcx.is_direct_const(def_id.into()) && !tcx.features().const_param_ty_unchecked() { wfcx.register_bound( ObligationCause::new(span, def_id, ObligationCauseCode::ConstParam(item_ty)), wfcx.param_env, @@ -1283,8 +1279,8 @@ pub(super) fn check_type_const<'tcx>( ); } - if has_value { - let raw_ct = tcx.const_of_item(def_id).instantiate_identity(); + if let Some(direct_rhs) = tcx.const_of_item(def_id) { + let raw_ct = direct_rhs.instantiate_identity(); let norm_ct = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), raw_ct); wfcx.register_wf_obligation(span, Some(WellFormedLoc::Ty(def_id)), norm_ct.into()); @@ -1295,7 +1291,6 @@ pub(super) fn check_type_const<'tcx>( ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(norm_ct, item_ty)), )); } - Ok(()) } #[instrument(level = "debug", skip(tcx, impl_))] diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 248e7aa583a19..0c2b33917cc98 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1804,25 +1804,24 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin fn const_of_item<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> ty::EarlyBinder<'tcx, Const<'tcx>> { +) -> Option>> { 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") + hir::Node::Item(&hir::Item { kind: hir::ItemKind::Const(.., ct), .. }) => ct, + hir::Node::TraitItem(&hir::TraitItem { + kind: hir::TraitItemKind::Const(_, ct), .. + }) => ct?, + hir::Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(.., ct), .. }) => ct, + node => { + span_bug!( + tcx.def_span(def_id), + "`const_of_item` expected a const or assoc const item, got {node:?}" + ) } }; let ct_arg = match ct_rhs { - hir::ConstItemRhs::TypeConst(ct_arg) => ct_arg, + hir::ConstItemRhs::Direct(ct_arg) => ct_arg, hir::ConstItemRhs::Body(_) => { - let e = tcx.dcx().span_delayed_bug( - tcx.def_span(def_id), - "cannot call const_of_item on a non-type_const", - ); - return ty::EarlyBinder::bind(tcx, Const::new_error(tcx, e)); + return None; } }; let icx = ItemCtxt::new(tcx, def_id); @@ -1834,8 +1833,8 @@ fn const_of_item<'tcx>( if let Err(e) = icx.check_tainted_by_errors() && !ct.references_error() { - ty::EarlyBinder::bind(tcx, Const::new_error(tcx, e)) + Some(ty::EarlyBinder::bind(tcx, Const::new_error(tcx, e))) } else { - ty::EarlyBinder::bind(tcx, ct) + Some(ty::EarlyBinder::bind(tcx, ct)) } } diff --git a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs index 488b9a09e6106..00f3874e4707b 100644 --- a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs @@ -444,7 +444,7 @@ fn const_evaluatable_clauses_of<'tcx>( } // Skip type consts as mGCA doesn't support evaluatable clauses. - if alias_const.kind.is_type_const(self.tcx) { + if alias_const.kind.is_direct_const(self.tcx) { return; } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 45254aa23896d..6ebd38195ffbe 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -87,10 +87,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ TraitItemKind::Const(ty, rhs) => rhs .and_then(|rhs| { ty.is_suggestable_infer_ty().then(|| { + let hir_body_id = match rhs { + ConstItemRhs::Body(body) => Some(body.hir_id), + ConstItemRhs::Direct(_) => None, + }; infer_placeholder_type( icx.lowerer(), def_id, - rhs.hir_id(), + hir_body_id, ty.span, rhs.span(tcx), item.ident, @@ -109,10 +113,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ ImplItemKind::Fn(_, _) => new_bound_fn_def(item.hir_id(), def_id.to_def_id()), ImplItemKind::Const(ty, rhs) => { if ty.is_suggestable_infer_ty() { + let hir_body_id = match rhs { + ConstItemRhs::Body(body) => Some(body.hir_id), + ConstItemRhs::Direct(_) => None, + }; infer_placeholder_type( icx.lowerer(), def_id, - rhs.hir_id(), + hir_body_id, ty.span, rhs.span(tcx), item.ident, @@ -137,7 +145,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ infer_placeholder_type( icx.lowerer(), def_id, - body_id.hir_id, + Some(body_id.hir_id), ty.span, tcx.hir_body(body_id).value.span, ident, @@ -157,10 +165,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } ItemKind::Const(ident, _, ty, rhs) => { if ty.is_suggestable_infer_ty() { + let hir_body_id = match rhs { + ConstItemRhs::Body(body) => Some(body.hir_id), + ConstItemRhs::Direct(_) => None, + }; infer_placeholder_type( icx.lowerer(), def_id, - rhs.hir_id(), + hir_body_id, ty.span, rhs.span(tcx), ident, @@ -431,28 +443,28 @@ fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: S fn infer_placeholder_type<'tcx>( cx: &dyn HirTyLowerer<'tcx>, def_id: LocalDefId, - hir_id: HirId, + hir_body_id: Option, ty_span: Span, body_span: Span, item_ident: Ident, kind: &'static str, ) -> Ty<'tcx> { let tcx = cx.tcx(); - // If the type is omitted on a `type const` we can't run - // type check on since that requires the const have a body - // which `type const`s don't. - let ty = if tcx.is_type_const(def_id.to_def_id()) { - if let Some(trait_item_def_id) = tcx.trait_item_of(def_id.to_def_id()) { - tcx.type_of(trait_item_def_id).instantiate_identity().skip_norm_wip() - } else { - Ty::new_error_with_message( - tcx, - ty_span, - "constant with `type const` requires an explicit type", - ) + // If the type is omitted on const with `ConstItemRhs::Direct`, we can't run type check on it, + // since that requires the const have a body, i.e. `ConstItemRhs::Body`. + let ty = match hir_body_id { + Some(hir_id) => tcx.typeck(def_id).node_type(hir_id), + None => { + if let Some(trait_item_def_id) = tcx.trait_item_of(def_id.to_def_id()) { + tcx.type_of(trait_item_def_id).instantiate_identity().skip_norm_wip() + } else { + Ty::new_error_with_message( + tcx, + ty_span, + "directly represented const requires an explicit type", + ) + } } - } else { - tcx.typeck(def_id).node_type(hir_id) }; // If this came from a free `const` or `static mut?` item, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 9fde34f473205..219637ba4f16f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -557,7 +557,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }); if let ty::AssocTag::Const = assoc_tag - && !self.tcx().is_type_const(assoc_item.def_id) + && !self.tcx().is_direct_const(assoc_item.def_id) && !tcx.features().generic_const_args() { if tcx.features().min_generic_const_args() { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index cfff8d1768f0e..e8bb4807f3835 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -3153,7 +3153,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx(); - if tcx.is_type_const(def_id) || tcx.features().generic_const_args() { + if tcx.is_type_const_syntax(def_id) || tcx.features().generic_const_args() { Ok(()) } else { let mut err = self.dcx().struct_span_err( diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 41f98e2fb40c0..20ef75244bb4e 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -174,7 +174,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { } DefKind::Const { .. } if !tcx.generics_of(item_def_id).own_requires_monomorphization() - && !tcx.is_type_const(item_def_id) => + && tcx.const_of_item(item_def_id).is_none() => { // FIXME(generic_const_items): Passing empty instead of identity args is fishy but // seems to be fine for now. Revisit this! diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index a949f8e505fa7..d56c1481a3c27 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1166,7 +1166,7 @@ impl<'a> State<'a> { 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), + hir::ConstItemRhs::Direct(const_arg) => self.print_const_arg(const_arg), } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 1d9dade66a544..f55783e60da0c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1382,20 +1382,6 @@ 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 { - // AssocConst ==> assoc item has value - tcx.is_type_const(def_id) - && (!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; @@ -1632,7 +1618,7 @@ 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) { + if let DefKind::Const { .. } | DefKind::AssocConst { .. } = 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) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 064d906293ae8..938cd2e956c13 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -480,7 +480,7 @@ define_tables! { assumed_wf_types_for_rpitit: Table, Span)>>, opaque_ty_origin: Table>>, anon_const_kind: Table>, - const_of_item: Table>>>, + const_of_item: Table>>>>, associated_types_for_impl_traits_in_trait_or_impl: Table>>>, live_args_for_alias_from_outlives_bounds: Table>>>>>, args_known_to_outlive_alias_params: Table, Vec>)>>>>, diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 5794a6533bd1d..80b73038481d3 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -279,14 +279,22 @@ rustc_queries! { separate_provide_extern } - /// Returns the const of the RHS of a (free or assoc) const item, if it is a `type const`. + /// Returns the const of the RHS of a (free or assoc) const item, if it is a `type const`, or if + /// it is a directly represented `const` (i.e. a const with a `direct_const_arg!` RHS, or a + /// const that `feature(macroless_generic_const_args)` has decided is direct). /// /// 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>> { + /// Returns `None` if the constant does not have a directly represented RHS. This does not + /// necessarily mean the constant is invalid to use in the type system, as is the case for a + /// `type const` in a trait definition without a RHS. + /// + /// # Panics + /// + /// This query will panic if the given definition isn't a const item (free or associated const). + query const_of_item(def_id: DefId) -> Option>> { desc { "computing the type-level value for `{}`", tcx.def_path_str(def_id) } cache_on_disk separate_provide_extern diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 23c02ffcb09c4..93d4c59e75c00 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -195,6 +195,7 @@ impl_erasable_for_types_with_no_type_params! { Option, Option, Option>>, + Option>>, Option>, Option, Result<&'_ TokenStream, ()>, diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 279a3658109bc..8eee87bdd07ca 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -138,17 +138,12 @@ impl AssocItem { self.kind.as_def_kind() } - pub fn is_type_const(&self) -> bool { - matches!(self.kind, ty::AssocKind::Const { is_type_const: true, .. }) - } - /// Whether this associated item can be constrained with an equality binding. pub fn can_have_equality_constraint(&self, tcx: TyCtxt<'_>) -> bool { match self.kind { ty::AssocKind::Type { .. } => true, - ty::AssocKind::Const { is_type_const: true, .. } => true, - ty::AssocKind::Const { is_type_const: false, .. } => { - tcx.features().generic_const_args() + ty::AssocKind::Const { .. } => { + tcx.features().generic_const_args() || tcx.is_direct_const(self.def_id) } ty::AssocKind::Fn { .. } => false, } @@ -209,9 +204,7 @@ impl AssocKind { pub fn as_def_kind(&self) -> DefKind { match self { - Self::Const { is_type_const, .. } => { - DefKind::AssocConst { is_type_const: *is_type_const } - } + &Self::Const { is_type_const, .. } => DefKind::AssocConst { is_type_const }, Self::Fn { .. } => DefKind::AssocFn, Self::Type { .. } => DefKind::AssocTy, } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5b5656c05f10d..6e4c94f860170 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1029,15 +1029,26 @@ impl<'tcx> TyCtxt<'tcx> { self.is_lang_item(self.parent(def_id), LangItem::AsyncDropInPlace) } - pub fn type_const_span(self, def_id: DefId) -> Option { - if !self.is_type_const(def_id) { - return None; - } - Some(self.def_span(def_id)) + /// Returns true if the const is guaranteed to have a directly represented RHS. This is either + /// because it has a directly represented RHS, or is a trait definition that is marked as + /// requiring its implementation to have a directly represented RHS. + /// + /// Note: Be very careful with using this method - under `generic_const_args`, a trait can + /// declare a regular const, but an `impl` could implement it with a directly represented const + /// (a la refinement). This method would return false in such a case. + pub fn is_direct_const(self, def_id: DefId) -> bool { + debug_assert_matches!( + self.def_kind(def_id), + DefKind::Const { .. } | DefKind::AssocConst { .. } + ); + self.is_type_const_syntax(def_id) || self.const_of_item(def_id).is_some() } - /// Check if the given `def_id` is a `type const` (mgca) - pub fn is_type_const(self, def_id: impl IntoQueryKey) -> bool { + /// Check if the given `def_id` is declared with `type const` syntax (mgca) + /// + /// This is NOT the same as whether the `def_id` can be represented in/used by the type system. + /// For that, you probably want to ask `is_direct_const()` or `const_of_item().is_some()`. + pub fn is_type_const_syntax(self, def_id: impl IntoQueryKey) -> bool { let def_id = def_id.into_query_key(); match self.def_kind(def_id) { DefKind::Const { is_type_const } | DefKind::AssocConst { is_type_const } => { diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 74327278dbca6..fa6ea5f1a70dd 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -186,11 +186,26 @@ 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 is_type_const(self, def_id: DefId) -> bool { - self.is_type_const(def_id) + fn is_direct_const(self, alias: ty::AliasConstKind<'tcx>) -> bool { + match alias { + ty::AliasConstKind::Projection { def_id } + | ty::AliasConstKind::InherentSelf { def_id } + | ty::AliasConstKind::InherentImpl { def_id } + | ty::AliasConstKind::Free { def_id } => self.is_direct_const(def_id), + ty::AliasConstKind::Anon { .. } => false, + } } - fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> { - self.const_of_item(def_id) + fn const_of_item( + self, + alias: ty::AliasConstKind<'tcx>, + ) -> Option>> { + match alias { + ty::AliasConstKind::Projection { def_id } + | ty::AliasConstKind::InherentSelf { def_id } + | ty::AliasConstKind::InherentImpl { def_id } + | ty::AliasConstKind::Free { def_id } => self.const_of_item(def_id), + ty::AliasConstKind::Anon { .. } => None, + } } fn anon_const_kind(self, def_id: DefId) -> ty::AnonConstKind { self.anon_const_kind(def_id) diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index 5996073241e2c..830fdc5d75573 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -3,6 +3,7 @@ use rustc_abi::Size; use rustc_ast as ast; use rustc_hir::attrs::lang_items::LangItem; +use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, Scalar}; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -71,7 +72,17 @@ pub(crate) fn as_constant_inner<'tcx>( } ExprKind::NamedConst { def_id, args, ref user_ty } => { let user_ty = user_ty.as_ref().and_then(push_cuta); - if tcx.is_type_const(def_id) { + // Under generic_const_args, `def_id` might be a regular const declared in a trait, but + // is `impl`d as a directly represented const. We do not know whether it is here, so we + // must use type system normalization for all consts under generic_const_args. + // FIXME(generic_const_args): there's a lot to consider here! `Const::Ty` uses valtrees + // and `Const::Unevaluated` does not, we should revisit this before stabilization. + if tcx.features().generic_const_args() + || matches!( + tcx.def_kind(def_id), + DefKind::Const { .. } | DefKind::AssocConst { .. } + ) && tcx.is_direct_const(def_id) + { let uneval = ty::AliasConst::new( tcx, ty::AliasConstKind::new_from_def_id( diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index aad87a99c0036..31a760cc59829 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -17,7 +17,14 @@ pub(crate) fn thir_body<'tcx>( tcx: TyCtxt<'tcx>, owner_def: LocalDefId, ) -> Result<(&'tcx Steal>, ExprId), ErrorGuaranteed> { - debug_assert!(!tcx.is_type_const(owner_def.to_def_id()), "thir_body queried for type_const"); + if cfg!(debug_assertions) + && matches!(tcx.def_kind(owner_def), DefKind::Const { .. } | DefKind::AssocConst { .. }) + { + debug_assert!( + tcx.const_of_item(owner_def.to_def_id()).is_none(), + "thir_body queried for directly represented const item: {owner_def:?}" + ); + } let body = tcx.hir_body_owned_by(owner_def); let mut cx: ThirBuildCx<'tcx> = ThirBuildCx::new(tcx, owner_def); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 86387f5caf325..7c6885bf8020c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -136,11 +136,18 @@ impl<'tcx> ConstToPat<'tcx> { return self.mk_err(err, ty); }; - // FIXME(gca): This will become insufficient once associated constants can be - // implemented as `type` consts (project-const-generics#76). At that point it'll - // become necessary to just use type system normalization for all const patterns - // but that's not yet possible. - let const_value = if alias_const.kind.is_type_const(self.tcx) { + // Under generic_const_args, `alias_const` might be a regular const declared in a trait, but + // is `impl`d as a directly represented const. We do not know whether it is here, so we must + // use type system normalization for all consts under generic_const_args. + // + // We probably want to always use type system normalization on stable too, but that would be + // a breaking change (in addition to needing significant improvements to diagnostics), so + // right now, we limit this to just generic_const_args. + // + // See: https://github.com/rust-lang/project-const-generics/issues/105 + let const_value = if self.tcx.features().generic_const_args() + || alias_const.kind.is_direct_const(self.tcx) + { let Ok(normalize) = self .tcx .try_normalize_erasing_regions(self.typing_env, Unnormalized::new_wip(self.c)) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b7813992db5bf..4ee1abe4a1ff4 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1663,7 +1663,7 @@ impl<'v> RootCollector<'_, 'v> { let def_id = id.owner_id.to_def_id(); // Type Consts don't have bodies to evaluate // nor do they make sense as a static. - if self.tcx.is_type_const(def_id) { + if self.tcx.const_of_item(def_id).is_some() { // FIXME(mgca): Is this actually what we want? We may want to // normalize to a ValTree then convert to a const allocation and // collect that? diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs index 75f15623a9ba7..cb878f2c54878 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs @@ -435,16 +435,17 @@ where } // Finally we construct the actual value of the associated type. - let term = match goal.predicate.alias.kind { + let term = match target_item_kind { ty::AliasTermKind::ProjectionTy { .. } => { let t = cx.type_of(target_item_def_id).instantiate(cx, target_args); let t = ecx.normalize(GoalSource::Misc, goal.param_env, t)?; t.into() } - ty::AliasTermKind::ProjectionConst { .. } - if cx.is_type_const(target_item_def_id) => + ty::AliasTermKind::ProjectionConst { def_id } + if let Some(c) = + cx.const_of_item(ty::AliasConstKind::Projection { def_id }) => { - let c = cx.const_of_item(target_item_def_id).instantiate(cx, target_args); + let c = c.instantiate(cx, target_args); let c = ecx.normalize(GoalSource::Misc, goal.param_env, c)?; c.into() } diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs index efc630a106ee3..4481e1bc144ac 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/free_alias.rs @@ -37,8 +37,10 @@ where let free = self.normalize(GoalSource::Misc, goal.param_env, free)?; free.into() } - ty::AliasTermKind::FreeConst { def_id } if cx.is_type_const(def_id.into()) => { - let free = cx.const_of_item(def_id.into()).instantiate(cx, free_alias.args); + ty::AliasTermKind::FreeConst { def_id } + if let Some(free) = cx.const_of_item(ty::AliasConstKind::Free { def_id }) => + { + let free = free.instantiate(cx, free_alias.args); let free = self.normalize(GoalSource::Misc, goal.param_env, free)?; free.into() diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs index 20c0564b0eeba..d519d1e538f1a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/inherent.rs @@ -48,8 +48,11 @@ where let inherent = self.normalize(GoalSource::Misc, goal.param_env, inherent)?; inherent.into() } - ty::AliasTermKind::InherentConstImpl { def_id } if cx.is_type_const(def_id.into()) => { - let inherent = cx.const_of_item(def_id.into()).instantiate(cx, inherent_args); + ty::AliasTermKind::InherentConstImpl { def_id } + if let Some(inherent) = + cx.const_of_item(ty::AliasConstKind::InherentImpl { def_id }) => + { + let inherent = inherent.instantiate(cx, inherent_args); let normalized_ct = self.normalize(GoalSource::Misc, goal.param_env, inherent)?; let normalized = normalized_ct.into(); let term = ty::AliasTerm::new_from_args(cx, inherent_kind, inherent_args); diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index e5f5b67912c75..de0d0a4f8a4f2 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -209,7 +209,7 @@ impl<'tcx> ReachableContext<'tcx> { } } // For `type const` we want to evaluate the RHS. - hir::ItemKind::Const(_, _, _, init @ hir::ConstItemRhs::TypeConst(_)) => { + hir::ItemKind::Const(_, _, _, init @ hir::ConstItemRhs::Direct(_)) => { self.visit_const_item_rhs(init); } hir::ItemKind::Const(_, _, _, init) => { diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 0d22ca4973511..56df5d917e108 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -349,9 +349,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { .fold_with(self) .into() } else { - infcx - .tcx - .const_of_item(def_id) + project::const_of_item_or_delayed_bug(infcx.tcx, def_id) .instantiate(infcx.tcx, free.args) .skip_norm_wip() .fold_with(self) @@ -469,7 +467,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx if tcx.features().generic_const_exprs() // Normalize type_const items even with feature `generic_const_exprs`. - && !matches!(ct.kind(), ty::ConstKind::Alias(_, alias_const) if alias_const.kind.is_type_const(tcx)) + && !matches!(ct.kind(), ty::ConstKind::Alias(_, alias_const) if alias_const.kind.is_direct_const(tcx)) || !needs_normalization(self.selcx.infcx, &ct) { return ct; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 9d0daa3a8672b..f3504e96965e8 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -505,6 +505,22 @@ fn push_const_arg_has_type_obligation<'tcx>( } } +/// The old solver does not support references to non-type-consts. +/// Emit a delayed bug if there is a type system reference to a non type const, as this should have +/// already errored elsewhere. +pub fn const_of_item_or_delayed_bug<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> ty::EarlyBinder<'tcx, ty::Const<'tcx>> { + tcx.const_of_item(def_id).unwrap_or_else(|| { + let e = tcx.dcx().span_delayed_bug( + tcx.def_span(def_id), + "encountered regular consts in the old solver's const normalization", + ); + ty::EarlyBinder::bind(tcx, ty::Const::new_error(tcx, e)) + }) +} + /// Confirm and normalize the given inherent projection. // FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] @@ -565,7 +581,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( let term = if alias_term.kind.is_type() { tcx.type_of(def_id).instantiate(tcx, args).map(Into::into) } else { - tcx.const_of_item(def_id).instantiate(tcx, args).map(Into::into) + const_of_item_or_delayed_bug(tcx, def_id).instantiate(tcx, args).map(Into::into) }; let term = selcx.infcx.resolve_vars_if_possible(term); @@ -2115,7 +2131,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let term = if obligation.predicate.kind.is_type() { tcx.type_of(assoc_term.item.def_id).map_bound(|ty| ty.into()) } else { - tcx.const_of_item(assoc_term.item.def_id).map_bound(|ct| ct.into()) + const_of_item_or_delayed_bug(tcx, assoc_term.item.def_id).map_bound(|ct| ct.into()) }; assoc_term_own_obligations(selcx, obligation, &mut nested); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fc16b6d44c310..5fc9e57795b72 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1088,7 +1088,8 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty::ConstKind::Alias(_, alias_const) => { if !c.has_escaping_bound_vars() { // Skip type consts as mGCA doesn't support evaluatable clauses - if !alias_const.kind.is_type_const(tcx) && !tcx.features().generic_const_args() + if !alias_const.kind.is_direct_const(tcx) + && !tcx.features().generic_const_args() { let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::ConstEvaluatable(c), diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 03dff745210d6..c3fe949d29d64 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -108,7 +108,10 @@ fn normalize_canonicalized_free_alias<'tcx>( let normalized_term: ty::Term<'tcx> = if goal.kind.is_type() { tcx.type_of(def_id).instantiate(tcx, goal.args).skip_norm_wip().into() } else { - tcx.const_of_item(def_id).instantiate(tcx, goal.args).skip_norm_wip().into() + traits::project::const_of_item_or_delayed_bug(tcx, def_id) + .instantiate(tcx, goal.args) + .skip_norm_wip() + .into() }; ocx.register_obligations(const_arg_has_type_obligation( tcx, diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index de94087498c75..ea58041a12b77 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -2,7 +2,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorState}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, ConstItemRhs, ImplItemImplKind, ItemKind}; +use rustc_hir::{self as hir, ImplItemImplKind, ItemKind}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -89,7 +89,7 @@ fn associated_item_from_trait_item( let name = trait_item.ident.name; let kind = match trait_item.kind { hir::TraitItemKind::Const(_, _) => { - ty::AssocKind::Const { name, is_type_const: tcx.is_type_const(owner_id.def_id) } + ty::AssocKind::Const { name, is_type_const: tcx.is_type_const_syntax(owner_id.def_id) } } hir::TraitItemKind::Fn { .. } => { ty::AssocKind::Fn { name, has_self: fn_has_self_parameter(tcx, owner_id) } @@ -106,13 +106,13 @@ fn associated_item_from_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_> let owner_id = impl_item.owner_id; let name = impl_item.ident.name; let kind = match impl_item.kind { - hir::ImplItemKind::Const(_, rhs) => { - ty::AssocKind::Const { name, is_type_const: matches!(rhs, ConstItemRhs::TypeConst(_)) } + hir::ImplItemKind::Const(..) => { + ty::AssocKind::Const { name, is_type_const: tcx.is_type_const_syntax(owner_id.def_id) } } - hir::ImplItemKind::Fn { .. } => { + hir::ImplItemKind::Fn(..) => { ty::AssocKind::Fn { name, has_self: fn_has_self_parameter(tcx, owner_id) } } - hir::ImplItemKind::Type { .. } => { + hir::ImplItemKind::Type(..) => { ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) } } }; diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 26a4edccd0134..36cef1c13eb29 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -160,14 +160,8 @@ impl AliasConstKind { interner.alias_const_kind_from_def_id(def_id, inherent_args) } - pub fn is_type_const(self, interner: I) -> bool { - match self { - AliasConstKind::Projection { def_id } => interner.is_type_const(def_id.into()), - AliasConstKind::InherentSelf { def_id } => interner.is_type_const(def_id.into()), - AliasConstKind::InherentImpl { def_id } => interner.is_type_const(def_id.into()), - AliasConstKind::Free { def_id } => interner.is_type_const(def_id.into()), - AliasConstKind::Anon { def_id } => interner.is_type_const(def_id.into()), - } + pub fn is_direct_const(self, interner: I) -> bool { + interner.is_direct_const(self) } pub fn def_span(self, interner: I) -> I::Span { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 1dfb34d94c0fc..282ec24246d16 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -266,8 +266,11 @@ pub trait Interner: self, def_id: Self::LocalOpaqueTyId, ) -> ty::EarlyBinder; - fn is_type_const(self, def_id: Self::DefId) -> bool; - fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder; + fn is_direct_const(self, alias: ty::AliasConstKind) -> bool; + fn const_of_item( + self, + alias: ty::AliasConstKind, + ) -> Option>; fn anon_const_kind(self, def_id: Self::DefId) -> ty::AnonConstKind; fn def_span(self, def_id: Self::DefId) -> Self::Span; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 784a80ef02cd2..94f2e2a04a14b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -354,7 +354,7 @@ pub(crate) fn clean_const_item_rhs<'tcx>( ) -> ConstantKind { match ct_rhs { hir::ConstItemRhs::Body(body) => ConstantKind::Local { def_id: parent, body }, - hir::ConstItemRhs::TypeConst(ct) => clean_const(ct), + hir::ConstItemRhs::Direct(ct) => clean_const(ct), } } diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 6230349651026..919b9b8ba8368 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -965,7 +965,7 @@ fn get_const_hir_value<'tcx>( }; 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 { + ConstItemRhs::Direct(ct_arg) => match ct_arg.kind { ConstArgKind::Anon(anon_const) => Some((tcx.typeck(did), tcx.hir_body(anon_const.body).value)), _ => None, }, diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index bcdc7754da6fa..8ca6d08e325f7 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1187,7 +1187,7 @@ pub fn is_zero_integer_const(cx: &LateContext<'_>, expr: &Expr<'_>, ctxt: Syntax 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 { + ConstItemRhs::Direct(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), ConstArgKind::Struct(..) | ConstArgKind::Tup(..) diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr index 366711e6d43c7..3b53adb07a2b9 100644 --- a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr @@ -1,13 +1,13 @@ error[E0284]: type annotations needed for `([(); _], [(); 10])` - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:32:9 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:31:9 | LL | let (mut arr, mut arr_with_weird_len) = free(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ type must be known at this point | note: required by a const generic parameter in `free` - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:27:9 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:26:9 | -LL | fn free() -> ([(); N], [(); FREE::]) { +LL | fn free() -> ([(); N], [(); core::direct_const_arg!(FREE::)]) { | ^^^^^^^^^^^^^^ required by this const generic parameter in `free` help: consider giving this pattern a type, where the value of const parameter `N` is specified | @@ -15,7 +15,7 @@ LL | let (mut arr, mut arr_with_weird_len): ([_; N], _) = free(); | +++++++++++++ error[E0271]: type mismatch resolving `FREE<10> == 2` - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:38:45 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:37:45 | LL | let (mut arr, mut arr_with_weird_len) = free(); | ^^^^^^ expected `2`, found `10` @@ -24,16 +24,16 @@ LL | let (mut arr, mut arr_with_weird_len) = free(); found constant `10` error[E0284]: type annotations needed for `([(); _], [(); 10])` - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:49:9 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:48:9 | LL | let (mut arr, mut arr_with_weird_len) = proj(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ type must be known at this point | = note: cannot satisfy `::PROJ<_> == 10` note: required by a const generic parameter in `proj` - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:44:9 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:43:9 | -LL | fn proj() -> ([(); N], [(); ::PROJ::]) { +LL | fn proj() -> ([(); N], [(); core::direct_const_arg!(::PROJ::)]) { | ^^^^^^^^^^^^^^ required by this const generic parameter in `proj` help: consider giving this pattern a type, where the value of const parameter `N` is specified | @@ -41,7 +41,7 @@ LL | let (mut arr, mut arr_with_weird_len): ([_; N], _) = proj(); | +++++++++++++ error[E0271]: type mismatch resolving `::PROJ<10> == 2` - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:55:45 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:54:45 | LL | let (mut arr, mut arr_with_weird_len) = proj(); | ^^^^^^ expected `2`, found `10` diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr index 11274b947b8f6..4306110c8433d 100644 --- a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr @@ -1,5 +1,5 @@ error: `generic_const_args` requires -Znext-solver=globally to be enabled - --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:10:5 + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:9:5 | LL | generic_const_args, | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs index ef6d047309b13..8ee278af6ef56 100644 --- a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs @@ -6,7 +6,6 @@ #![feature( min_generic_const_args, - macroless_generic_const_args, generic_const_args, //[old]~^ ERROR next-solver generic_const_items @@ -24,7 +23,7 @@ impl Trait for S { const PROJ: usize = 10; } -fn free() -> ([(); N], [(); FREE::]) { +fn free() -> ([(); N], [(); core::direct_const_arg!(FREE::)]) { loop {} } @@ -41,7 +40,7 @@ fn test_free_mismatch() { arr = [(); 10]; } -fn proj() -> ([(); N], [(); ::PROJ::]) { +fn proj() -> ([(); N], [(); core::direct_const_arg!(::PROJ::)]) { loop {} } diff --git a/tests/ui/const-generics/gca/assoc-const.rs b/tests/ui/const-generics/gca/assoc-const.rs new file mode 100644 index 0000000000000..8a8d1b52e7e5a --- /dev/null +++ b/tests/ui/const-generics/gca/assoc-const.rs @@ -0,0 +1,22 @@ +//@ check-pass +//@ compile-flags: -Znext-solver +#![feature(min_generic_const_args, generic_const_args)] + +trait Trait { + const ASSOC: usize; +} + +impl Trait for T { + const ASSOC: usize = core::direct_const_arg!(T::RIGID); +} + +trait Other { + const RIGID: usize; +} + +fn foo() { + let a: [(); core::direct_const_arg!(::ASSOC)] = + [(); core::direct_const_arg!(T::RIGID)]; +} + +fn main() {} diff --git a/tests/ui/const-generics/gca/non-type-equality-fail.rs b/tests/ui/const-generics/gca/non-type-equality-fail.rs index 6e71125a4cffb..e058648e3da54 100644 --- a/tests/ui/const-generics/gca/non-type-equality-fail.rs +++ b/tests/ui/const-generics/gca/non-type-equality-fail.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Znext-solver -#![feature(min_generic_const_args, macroless_generic_const_args, generic_const_args)] +#![feature(min_generic_const_args, generic_const_args)] #![expect(incomplete_features)] trait Trait { @@ -27,13 +27,14 @@ const FREE_B: usize = 1; struct Struct; fn f() { - let _: Struct<{ as Trait>::PROJECTED_A }> = - Struct::<{ as Trait>::PROJECTED_B }>; + let _: Struct<{ core::direct_const_arg!( as Trait>::PROJECTED_A) }> = + Struct::<{ core::direct_const_arg!( as Trait>::PROJECTED_B) }>; //~^ ERROR mismatched types } fn g() { - let _: Struct<{ T::PROJECTED_A }> = Struct::<{ T::PROJECTED_B }>; + let _: Struct<{ core::direct_const_arg!(T::PROJECTED_A) }> = + Struct::<{ core::direct_const_arg!(T::PROJECTED_B) }>; //~^ ERROR mismatched types } diff --git a/tests/ui/const-generics/gca/non-type-equality-fail.stderr b/tests/ui/const-generics/gca/non-type-equality-fail.stderr index 5a9c1bb6d4faa..28557d76d84e5 100644 --- a/tests/ui/const-generics/gca/non-type-equality-fail.stderr +++ b/tests/ui/const-generics/gca/non-type-equality-fail.stderr @@ -1,21 +1,21 @@ error[E0308]: mismatched types --> $DIR/non-type-equality-fail.rs:31:9 | -LL | let _: Struct<{ as Trait>::PROJECTED_A }> = - | -------------------------------------------------------- expected due to this -LL | Struct::<{ as Trait>::PROJECTED_B }>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected ` as Trait>::PROJECTED_A`, found ` as Trait>::PROJECTED_B` +LL | let _: Struct<{ core::direct_const_arg!( as Trait>::PROJECTED_A) }> = + | --------------------------------------------------------------------------------- expected due to this +LL | Struct::<{ core::direct_const_arg!( as Trait>::PROJECTED_B) }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected ` as Trait>::PROJECTED_A`, found ` as Trait>::PROJECTED_B` | = note: expected struct `Struct< as Trait>::PROJECTED_A>` found struct `Struct< as Trait>::PROJECTED_B>` error[E0308]: mismatched types - --> $DIR/non-type-equality-fail.rs:36:41 + --> $DIR/non-type-equality-fail.rs:37:9 | -LL | let _: Struct<{ T::PROJECTED_A }> = Struct::<{ T::PROJECTED_B }>; - | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `::PROJECTED_A`, found `::PROJECTED_B` - | | - | expected due to this +LL | let _: Struct<{ core::direct_const_arg!(T::PROJECTED_A) }> = + | --------------------------------------------------- expected due to this +LL | Struct::<{ core::direct_const_arg!(T::PROJECTED_B) }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `::PROJECTED_A`, found `::PROJECTED_B` | = note: expected struct `Struct<::PROJECTED_A>` found struct `Struct<::PROJECTED_B>` diff --git a/tests/ui/const-generics/gca/non-type-equality-ok.rs b/tests/ui/const-generics/gca/non-type-equality-ok.rs index e476b5d8124ca..45dcef1f2dc00 100644 --- a/tests/ui/const-generics/gca/non-type-equality-ok.rs +++ b/tests/ui/const-generics/gca/non-type-equality-ok.rs @@ -35,6 +35,8 @@ struct Struct; fn f() { let _: Struct<{ as Trait>::PROJECTED_A }> = Struct::<{ as Trait>::PROJECTED_A }>; + let _: Struct<{ as Trait>::PROJECTED_A }> = + Struct::<{ as Trait>::PROJECTED_B }>; } fn g() { diff --git a/tests/ui/const-generics/gca/wf-inherentimpl.old.stderr b/tests/ui/const-generics/gca/wf-inherentimpl.old.stderr index 0766847a93b18..5a9dd515868b9 100644 --- a/tests/ui/const-generics/gca/wf-inherentimpl.old.stderr +++ b/tests/ui/const-generics/gca/wf-inherentimpl.old.stderr @@ -1,5 +1,5 @@ error: `generic_const_args` requires -Znext-solver=globally to be enabled - --> $DIR/wf-inherentimpl.rs:7:12 + --> $DIR/wf-inherentimpl.rs:6:12 | LL | #![feature(generic_const_args, min_generic_const_args)] | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/gca/wf-inherentimpl.rs b/tests/ui/const-generics/gca/wf-inherentimpl.rs index cb3df20daa2dc..c0a7e7f930877 100644 --- a/tests/ui/const-generics/gca/wf-inherentimpl.rs +++ b/tests/ui/const-generics/gca/wf-inherentimpl.rs @@ -3,13 +3,12 @@ //@[next] compile-flags: -Znext-solver //@ ignore-compare-mode-next-solver (explicit revisions) #![feature(inherent_associated_types)] -#![feature(macroless_generic_const_args)] #![feature(generic_const_args, min_generic_const_args)] //[old]~^ ERROR `generic_const_args` requires -Znext-solver=globally to be enabled struct Foo; impl Foo { const SIZE: usize = { todo!() }; - fn to_bytes() -> [u8; Self::SIZE] { + fn to_bytes() -> [u8; core::direct_const_arg!(Self::SIZE)] { todo!() } }