Move impl constness into impl trait header

This commit is contained in:
Oli Scherer 2024-12-10 10:12:36 +00:00
parent c0e0d8f874
commit 2ffe3b1e70
8 changed files with 35 additions and 33 deletions

View file

@ -4,16 +4,21 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { fn parent_impl_constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
let parent_id = tcx.local_parent(def_id); let parent_id = tcx.local_parent(def_id);
matches!(tcx.def_kind(parent_id), DefKind::Impl { .. }) if matches!(tcx.def_kind(parent_id), DefKind::Impl { .. })
&& tcx.constness(parent_id) == hir::Constness::Const && let Some(header) = tcx.impl_trait_header(parent_id)
{
header.constness
} else {
hir::Constness::NotConst
}
} }
/// Checks whether an item is considered to be `const`. If it is a constructor, anonymous const, /// Checks whether an item is considered to be `const`. If it is a constructor, it is const.
/// const block, const item or associated const, it is const. If it is a trait impl/function, /// If it is an assoc method or function,
/// return if it has a `const` modifier. If it is an intrinsic, report whether said intrinsic /// return if it has a `const` modifier. If it is an intrinsic, report whether said intrinsic
/// has a `rustc_const_{un,}stable` attribute. Otherwise, return `Constness::NotConst`. /// has a `rustc_const_{un,}stable` attribute. Otherwise, panic.
fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
let node = tcx.hir_node_by_def_id(def_id); let node = tcx.hir_node_by_def_id(def_id);
@ -22,7 +27,6 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => { | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => {
hir::Constness::Const hir::Constness::Const
} }
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness,
hir::Node::ForeignItem(_) => { hir::Node::ForeignItem(_) => {
// Foreign items cannot be evaluated at compile-time. // Foreign items cannot be evaluated at compile-time.
hir::Constness::NotConst hir::Constness::NotConst
@ -36,8 +40,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
// If the function itself is not annotated with `const`, it may still be a `const fn` // If the function itself is not annotated with `const`, it may still be a `const fn`
// if it resides in a const trait impl. // if it resides in a const trait impl.
let is_const = is_parent_const_impl_raw(tcx, def_id); parent_impl_constness(tcx, def_id)
if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
} else { } else {
tcx.dcx().span_bug( tcx.dcx().span_bug(
tcx.def_span(def_id), tcx.def_span(def_id),

View file

@ -1611,7 +1611,7 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
impl_.of_trait.as_ref().map(|ast_trait_ref| { impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id).instantiate_identity(); let selfty = tcx.type_of(def_id).instantiate_identity();
check_impl_constness(tcx, tcx.is_const_trait_impl(def_id.to_def_id()), ast_trait_ref); check_impl_constness(tcx, impl_.constness, ast_trait_ref);
let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty); let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty);
@ -1619,22 +1619,23 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
trait_ref: ty::EarlyBinder::bind(trait_ref), trait_ref: ty::EarlyBinder::bind(trait_ref),
safety: impl_.safety, safety: impl_.safety,
polarity: polarity_of_impl(tcx, def_id, impl_, item.span), polarity: polarity_of_impl(tcx, def_id, impl_, item.span),
constness: impl_.constness,
} }
}) })
} }
fn check_impl_constness( fn check_impl_constness(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
is_const: bool, constness: hir::Constness,
hir_trait_ref: &hir::TraitRef<'_>, hir_trait_ref: &hir::TraitRef<'_>,
) -> Option<ErrorGuaranteed> { ) {
if !is_const { if let hir::Constness::NotConst = constness {
return None; return;
} }
let trait_def_id = hir_trait_ref.trait_def_id()?; let Some(trait_def_id) = hir_trait_ref.trait_def_id() else { return };
if tcx.is_const_trait(trait_def_id) { if tcx.is_const_trait(trait_def_id) {
return None; return;
} }
let trait_name = tcx.item_name(trait_def_id).to_string(); let trait_name = tcx.item_name(trait_def_id).to_string();
@ -1650,14 +1651,14 @@ fn check_impl_constness(
), ),
(false, _) | (_, false) => (None, ""), (false, _) | (_, false) => (None, ""),
}; };
Some(tcx.dcx().emit_err(errors::ConstImplForNonConstTrait { tcx.dcx().emit_err(errors::ConstImplForNonConstTrait {
trait_ref_span: hir_trait_ref.path.span, trait_ref_span: hir_trait_ref.path.span,
trait_name, trait_name,
local_trait_span, local_trait_span,
suggestion_pre, suggestion_pre,
marking: (), marking: (),
adding: (), adding: (),
})) });
} }
fn polarity_of_impl( fn polarity_of_impl(

View file

@ -1264,11 +1264,7 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool {
fn should_encode_constness(def_kind: DefKind) -> bool { fn should_encode_constness(def_kind: DefKind) -> bool {
match def_kind { match def_kind {
DefKind::Fn DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Ctor(_, CtorKind::Fn) => true,
| DefKind::AssocFn
| DefKind::Closure
| DefKind::Impl { of_trait: true }
| DefKind::Ctor(_, CtorKind::Fn) => true,
DefKind::Struct DefKind::Struct
| DefKind::Union | DefKind::Union
@ -1280,7 +1276,7 @@ fn should_encode_constness(def_kind: DefKind) -> bool {
| DefKind::Static { .. } | DefKind::Static { .. }
| DefKind::TyAlias | DefKind::TyAlias
| DefKind::OpaqueTy | DefKind::OpaqueTy
| DefKind::Impl { of_trait: false } | DefKind::Impl { .. }
| DefKind::ForeignTy | DefKind::ForeignTy
| DefKind::ConstParam | DefKind::ConstParam
| DefKind::InlineConst | DefKind::InlineConst

View file

@ -746,7 +746,8 @@ rustc_queries! {
desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) } desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) }
} }
/// Returns the constness of functions and impls. /// Returns the constness of function-like things (tuple struct/variant constructors, functions,
/// methods)
/// ///
/// Will ICE if used on things that are always const or never const. /// Will ICE if used on things that are always const or never const.
/// ///

View file

@ -3141,7 +3141,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Whether the trait impl is marked const. This does not consider stability or feature gates. /// Whether the trait impl is marked const. This does not consider stability or feature gates.
pub fn is_const_trait_impl(self, def_id: DefId) -> bool { pub fn is_const_trait_impl(self, def_id: DefId) -> bool {
self.def_kind(def_id) == DefKind::Impl { of_trait: true } self.def_kind(def_id) == DefKind::Impl { of_trait: true }
&& self.constness(def_id) == hir::Constness::Const && self.impl_trait_header(def_id).unwrap().constness == hir::Constness::Const
} }
pub fn intrinsic(self, def_id: impl IntoQueryParam<DefId> + Copy) -> Option<ty::IntrinsicDef> { pub fn intrinsic(self, def_id: impl IntoQueryParam<DefId> + Copy) -> Option<ty::IntrinsicDef> {

View file

@ -253,6 +253,7 @@ pub struct ImplTraitHeader<'tcx> {
pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>, pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>,
pub polarity: ImplPolarity, pub polarity: ImplPolarity,
pub safety: hir::Safety, pub safety: hir::Safety,
pub constness: hir::Constness,
} }
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
@ -2004,11 +2005,9 @@ impl<'tcx> TyCtxt<'tcx> {
let def_id: DefId = def_id.into(); let def_id: DefId = def_id.into();
match self.def_kind(def_id) { match self.def_kind(def_id) {
DefKind::Impl { of_trait: true } => { DefKind::Impl { of_trait: true } => {
self.constness(def_id) == hir::Constness::Const let header = self.impl_trait_header(def_id).unwrap();
&& self.is_const_trait( header.constness == hir::Constness::Const
self.trait_id_of_impl(def_id) && self.is_const_trait(header.trait_ref.skip_binder().def_id)
.expect("expected trait for trait implementation"),
)
} }
DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => { DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => {
self.constness(def_id) == hir::Constness::Const self.constness(def_id) == hir::Constness::Const

View file

@ -389,7 +389,7 @@ impl<'tcx> TyCtxt<'tcx> {
.delay_as_bug(); .delay_as_bug();
} }
dtor_candidate = Some((*item_id, self.constness(impl_did))); dtor_candidate = Some((*item_id, self.impl_trait_header(impl_did).unwrap().constness));
}); });
let (did, constness) = dtor_candidate?; let (did, constness) = dtor_candidate?;

View file

@ -128,7 +128,9 @@ fn evaluate_host_effect_from_selection_candiate<'tcx>(
Err(_) => Err(EvaluationFailure::NoSolution), Err(_) => Err(EvaluationFailure::NoSolution),
Ok(Some(source)) => match source { Ok(Some(source)) => match source {
ImplSource::UserDefined(impl_) => { ImplSource::UserDefined(impl_) => {
if tcx.constness(impl_.impl_def_id) != hir::Constness::Const { if tcx.impl_trait_header(impl_.impl_def_id).unwrap().constness
!= hir::Constness::Const
{
return Err(EvaluationFailure::NoSolution); return Err(EvaluationFailure::NoSolution);
} }