Be better at enforcing that const_conditions is only called on const items

This commit is contained in:
Michael Goulet 2024-10-23 16:53:59 +00:00
parent 25c9253379
commit 0f5a47d088
12 changed files with 126 additions and 120 deletions

View file

@ -89,7 +89,11 @@ impl<'tcx> Bounds<'tcx> {
host: ty::HostPolarity,
span: Span,
) {
self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, host), span));
if tcx.is_const_trait(bound_trait_ref.def_id()) {
self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, host), span));
} else {
tcx.dcx().span_delayed_bug(span, "tried to lower {host:?} bound for non-const trait");
}
}
pub(crate) fn clauses(

View file

@ -206,8 +206,8 @@ fn compare_method_predicate_entailment<'tcx>(
);
// FIXME(effects): This should be replaced with a more dedicated method.
let check_const_if_const = tcx.constness(impl_def_id) == hir::Constness::Const;
if check_const_if_const {
let is_conditionally_const = tcx.is_conditionally_const(impl_def_id);
if is_conditionally_const {
// Augment the hybrid param-env with the const conditions
// of the impl header and the trait method.
hybrid_preds.extend(
@ -255,7 +255,7 @@ fn compare_method_predicate_entailment<'tcx>(
// This registers the `~const` bounds of the impl method, which we will prove
// using the hybrid param-env that we earlier augmented with the const conditions
// from the impl header and trait method declaration.
if check_const_if_const {
if is_conditionally_const {
for (const_condition, span) in
tcx.const_conditions(impl_m.def_id).instantiate_own_identity()
{
@ -1904,9 +1904,8 @@ fn compare_type_predicate_entailment<'tcx>(
let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
let impl_ty_own_bounds = impl_ty_predicates.instantiate_own_identity();
let impl_ty_own_const_conditions =
tcx.const_conditions(impl_ty.def_id).instantiate_own_identity();
if impl_ty_own_bounds.len() == 0 && impl_ty_own_const_conditions.len() == 0 {
// If there are no bounds, then there are no const conditions, so no need to check that here.
if impl_ty_own_bounds.len() == 0 {
// Nothing to check.
return Ok(());
}
@ -1931,8 +1930,8 @@ fn compare_type_predicate_entailment<'tcx>(
let impl_ty_span = tcx.def_span(impl_ty_def_id);
let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id);
let check_const_if_const = tcx.constness(impl_def_id) == hir::Constness::Const;
if check_const_if_const {
let is_conditionally_const = tcx.is_conditionally_const(impl_ty.def_id);
if is_conditionally_const {
// Augment the hybrid param-env with the const conditions
// of the impl header and the trait assoc type.
hybrid_preds.extend(
@ -1968,8 +1967,10 @@ fn compare_type_predicate_entailment<'tcx>(
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
}
if check_const_if_const {
if is_conditionally_const {
// Validate the const conditions of the impl associated type.
let impl_ty_own_const_conditions =
tcx.const_conditions(impl_ty.def_id).instantiate_own_identity();
for (const_condition, span) in impl_ty_own_const_conditions {
let normalize_cause = traits::ObligationCause::misc(span, impl_ty_def_id);
let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
@ -2081,7 +2082,7 @@ pub(super) fn check_type_bounds<'tcx>(
.collect();
// Only in a const implementation do we need to check that the `~const` item bounds hold.
if tcx.constness(container_id) == hir::Constness::Const {
if tcx.is_conditionally_const(impl_ty_def_id) {
obligations.extend(
tcx.implied_const_bounds(trait_ty.def_id)
.iter_instantiated_copied(tcx, rebased_args)

View file

@ -1372,7 +1372,7 @@ fn check_impl<'tcx>(
}
// Ensure that the `~const` where clauses of the trait hold for the impl.
if tcx.constness(item.owner_id.def_id) == hir::Constness::Const {
if tcx.is_conditionally_const(item.owner_id.def_id) {
for (bound, _) in
tcx.const_conditions(trait_ref.def_id).instantiate(tcx, trait_ref.args)
{

View file

@ -888,48 +888,8 @@ pub(super) fn const_conditions<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> ty::ConstConditions<'tcx> {
// This logic is spaghetti, and should be cleaned up. The current methods that are
// defined to deal with constness are very unintuitive.
if tcx.is_const_fn_raw(def_id.to_def_id()) {
// Ok, const fn or method in const trait.
} else {
match tcx.def_kind(def_id) {
DefKind::Trait => {
if !tcx.is_const_trait(def_id.to_def_id()) {
return Default::default();
}
}
DefKind::Impl { .. } => {
// FIXME(effects): Should be using a dedicated function to
// test if this is a const trait impl.
if tcx.constness(def_id) != hir::Constness::Const {
return Default::default();
}
}
DefKind::AssocTy | DefKind::AssocFn => {
let parent_def_id = tcx.local_parent(def_id).to_def_id();
match tcx.associated_item(def_id).container {
ty::AssocItemContainer::TraitContainer => {
if !tcx.is_const_trait(parent_def_id) {
return Default::default();
}
}
ty::AssocItemContainer::ImplContainer => {
// FIXME(effects): Should be using a dedicated function to
// test if this is a const trait impl.
if tcx.constness(parent_def_id) != hir::Constness::Const {
return Default::default();
}
}
}
}
DefKind::Closure | DefKind::OpaqueTy => {
// Closures and RPITs will eventually have const conditions
// for `~const` bounds.
return Default::default();
}
_ => return Default::default(),
}
if !tcx.is_conditionally_const(def_id) {
bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}");
}
let (generics, trait_def_id_and_supertraits, has_parent) = match tcx.hir_node_by_def_id(def_id)
@ -940,7 +900,7 @@ pub(super) fn const_conditions<'tcx>(
hir::ItemKind::Trait(_, _, generics, supertraits, _) => {
(generics, Some((item.owner_id.def_id, supertraits)), false)
}
_ => return Default::default(),
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
},
// While associated types are not really const, we do allow them to have `~const`
// bounds and where clauses. `const_conditions` is responsible for gathering
@ -950,13 +910,21 @@ pub(super) fn const_conditions<'tcx>(
hir::TraitItemKind::Fn(_, _) | hir::TraitItemKind::Type(_, _) => {
(item.generics, None, true)
}
_ => return Default::default(),
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
},
Node::ImplItem(item) => match item.kind {
hir::ImplItemKind::Fn(_, _) | hir::ImplItemKind::Type(_) => (item.generics, None, true),
_ => return Default::default(),
hir::ImplItemKind::Fn(_, _) | hir::ImplItemKind::Type(_) => {
(item.generics, None, tcx.is_conditionally_const(tcx.local_parent(def_id)))
}
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
},
_ => return Default::default(),
Node::ForeignItem(item) => match item.kind {
hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false),
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
},
// N.B. Tuple ctors are unconditionally constant.
Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(),
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
};
let icx = ItemCtxt::new(tcx, def_id);
@ -1017,12 +985,12 @@ pub(super) fn implied_const_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
if !tcx.is_conditionally_const(def_id) {
bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}");
}
let bounds = match tcx.hir_node_by_def_id(def_id) {
Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => {
if !tcx.is_const_trait(def_id.to_def_id()) {
return ty::EarlyBinder::bind(&[]);
}
implied_predicates_with_filter(
tcx,
def_id.to_def_id(),
@ -1030,17 +998,9 @@ pub(super) fn implied_const_bounds<'tcx>(
)
}
Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) => {
if !tcx.is_const_trait(tcx.local_parent(def_id).to_def_id()) {
return ty::EarlyBinder::bind(&[]);
}
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst)
}
Node::OpaqueTy(..) => {
// We should eventually collect the `~const` bounds on opaques.
return ty::EarlyBinder::bind(&[]);
}
_ => return ty::EarlyBinder::bind(&[]),
_ => bug!("implied_const_bounds called on wrong item: {def_id:?}"),
};
bounds.map_bound(|bounds| {