Implement const effect predicate in new solver
This commit is contained in:
parent
a16d491054
commit
cde29b9ec9
127 changed files with 1702 additions and 1170 deletions
|
@ -81,6 +81,17 @@ impl<'tcx> Bounds<'tcx> {
|
|||
self.clauses.insert(0, (trait_ref.upcast(tcx), span));
|
||||
}
|
||||
|
||||
/// Push a `const` or `~const` bound as a `HostEffect` predicate.
|
||||
pub(crate) fn push_const_bound(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
bound_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
host: ty::HostPolarity,
|
||||
span: Span,
|
||||
) {
|
||||
self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, host), span));
|
||||
}
|
||||
|
||||
pub(crate) fn clauses(
|
||||
&self,
|
||||
// FIXME(effects): remove tcx
|
||||
|
|
|
@ -181,6 +181,7 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
});
|
||||
|
||||
// Create mapping from trait method to impl method.
|
||||
let impl_def_id = impl_m.container_id(tcx);
|
||||
let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto(
|
||||
tcx,
|
||||
impl_m.container_id(tcx),
|
||||
|
@ -204,6 +205,24 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
trait_m_predicates.instantiate_own(tcx, trait_to_impl_args).map(|(predicate, _)| predicate),
|
||||
);
|
||||
|
||||
// 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 {
|
||||
// Augment the hybrid param-env with the const conditions
|
||||
// of the impl header and the trait method.
|
||||
hybrid_preds.extend(
|
||||
tcx.const_conditions(impl_def_id)
|
||||
.instantiate_identity(tcx)
|
||||
.into_iter()
|
||||
.chain(
|
||||
tcx.const_conditions(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args),
|
||||
)
|
||||
.map(|(trait_ref, _)| {
|
||||
trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
|
||||
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
|
||||
|
@ -230,6 +249,34 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
|
||||
}
|
||||
|
||||
// If we're within a const implementation, we need to make sure that the method
|
||||
// does not assume stronger `~const` bounds than the trait definition.
|
||||
//
|
||||
// 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 {
|
||||
for (const_condition, span) in
|
||||
tcx.const_conditions(impl_m.def_id).instantiate_own_identity()
|
||||
{
|
||||
let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);
|
||||
let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
|
||||
|
||||
let cause =
|
||||
ObligationCause::new(span, impl_m_def_id, ObligationCauseCode::CompareImplItem {
|
||||
impl_item_def_id: impl_m_def_id,
|
||||
trait_item_def_id: trait_m.def_id,
|
||||
kind: impl_m.kind,
|
||||
});
|
||||
ocx.register_obligation(traits::Obligation::new(
|
||||
tcx,
|
||||
cause,
|
||||
param_env,
|
||||
const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// We now need to check that the signature of the impl method is
|
||||
// compatible with that of the trait method. We do this by
|
||||
// checking that `impl_fty <: trait_fty`.
|
||||
|
@ -1846,9 +1893,10 @@ fn compare_type_predicate_entailment<'tcx>(
|
|||
trait_ty: ty::AssocItem,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let impl_def_id = impl_ty.container_id(tcx);
|
||||
let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id).rebase_onto(
|
||||
tcx,
|
||||
impl_ty.container_id(tcx),
|
||||
impl_def_id,
|
||||
impl_trait_ref.args,
|
||||
);
|
||||
|
||||
|
@ -1856,7 +1904,9 @@ 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();
|
||||
if impl_ty_own_bounds.len() == 0 {
|
||||
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 {
|
||||
// Nothing to check.
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -1881,6 +1931,23 @@ 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 {
|
||||
// Augment the hybrid param-env with the const conditions
|
||||
// of the impl header and the trait assoc type.
|
||||
hybrid_preds.extend(
|
||||
tcx.const_conditions(impl_ty_predicates.parent.unwrap())
|
||||
.instantiate_identity(tcx)
|
||||
.into_iter()
|
||||
.chain(
|
||||
tcx.const_conditions(trait_ty.def_id).instantiate_own(tcx, trait_to_impl_args),
|
||||
)
|
||||
.map(|(trait_ref, _)| {
|
||||
trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
|
||||
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
|
||||
debug!(caller_bounds=?param_env.caller_bounds());
|
||||
|
@ -1901,6 +1968,27 @@ fn compare_type_predicate_entailment<'tcx>(
|
|||
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
|
||||
}
|
||||
|
||||
if check_const_if_const {
|
||||
// Validate the const conditions of the impl associated type.
|
||||
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);
|
||||
|
||||
let cause =
|
||||
ObligationCause::new(span, impl_ty_def_id, ObligationCauseCode::CompareImplItem {
|
||||
impl_item_def_id: impl_ty_def_id,
|
||||
trait_item_def_id: trait_ty.def_id,
|
||||
kind: impl_ty.kind,
|
||||
});
|
||||
ocx.register_obligation(traits::Obligation::new(
|
||||
tcx,
|
||||
cause,
|
||||
param_env,
|
||||
const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
let errors = ocx.select_all_or_error();
|
||||
|
@ -1983,7 +2071,7 @@ pub(super) fn check_type_bounds<'tcx>(
|
|||
ObligationCause::new(impl_ty_span, impl_ty_def_id, code)
|
||||
};
|
||||
|
||||
let obligations: Vec<_> = tcx
|
||||
let mut obligations: Vec<_> = tcx
|
||||
.explicit_item_bounds(trait_ty.def_id)
|
||||
.iter_instantiated_copied(tcx, rebased_args)
|
||||
.map(|(concrete_ty_bound, span)| {
|
||||
|
@ -1991,6 +2079,22 @@ pub(super) fn check_type_bounds<'tcx>(
|
|||
traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
|
||||
})
|
||||
.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 {
|
||||
obligations.extend(
|
||||
tcx.implied_const_bounds(trait_ty.def_id)
|
||||
.iter_instantiated_copied(tcx, rebased_args)
|
||||
.map(|(c, span)| {
|
||||
traits::Obligation::new(
|
||||
tcx,
|
||||
mk_cause(span),
|
||||
param_env,
|
||||
c.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
|
||||
)
|
||||
}),
|
||||
);
|
||||
}
|
||||
debug!(item_bounds=?obligations);
|
||||
|
||||
// Normalize predicates with the assumption that the GAT may always normalize
|
||||
|
|
|
@ -32,7 +32,8 @@ use rustc_trait_selection::traits::misc::{
|
|||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{
|
||||
self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
|
||||
self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
|
||||
WellFormedLoc,
|
||||
};
|
||||
use rustc_type_ir::TypeFlags;
|
||||
use rustc_type_ir::solve::NoSolution;
|
||||
|
@ -86,7 +87,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
|||
self.body_def_id,
|
||||
ObligationCauseCode::WellFormed(loc),
|
||||
);
|
||||
self.ocx.register_obligation(traits::Obligation::new(
|
||||
self.ocx.register_obligation(Obligation::new(
|
||||
self.tcx(),
|
||||
cause,
|
||||
self.param_env,
|
||||
|
@ -1173,7 +1174,7 @@ fn check_type_defn<'tcx>(
|
|||
wfcx.body_def_id,
|
||||
ObligationCauseCode::Misc,
|
||||
);
|
||||
wfcx.register_obligation(traits::Obligation::new(
|
||||
wfcx.register_obligation(Obligation::new(
|
||||
tcx,
|
||||
cause,
|
||||
wfcx.param_env,
|
||||
|
@ -1369,6 +1370,30 @@ fn check_impl<'tcx>(
|
|||
obligation.cause.span = hir_self_ty.span;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the `~const` where clauses of the trait hold for the impl.
|
||||
if tcx.constness(item.owner_id.def_id) == hir::Constness::Const {
|
||||
for (bound, _) in
|
||||
tcx.const_conditions(trait_ref.def_id).instantiate(tcx, trait_ref.args)
|
||||
{
|
||||
let bound = wfcx.normalize(
|
||||
item.span,
|
||||
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
|
||||
bound,
|
||||
);
|
||||
wfcx.register_obligation(Obligation::new(
|
||||
tcx,
|
||||
ObligationCause::new(
|
||||
hir_self_ty.span,
|
||||
wfcx.body_def_id,
|
||||
ObligationCauseCode::WellFormed(None),
|
||||
),
|
||||
wfcx.param_env,
|
||||
bound.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
debug!(?obligations);
|
||||
wfcx.register_obligations(obligations);
|
||||
}
|
||||
|
@ -1561,7 +1586,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
|||
wfcx.body_def_id,
|
||||
ObligationCauseCode::WhereClause(def_id.to_def_id(), DUMMY_SP),
|
||||
);
|
||||
traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
|
||||
Obligation::new(tcx, cause, wfcx.param_env, pred)
|
||||
});
|
||||
|
||||
let predicates = predicates.instantiate_identity(tcx);
|
||||
|
@ -1852,7 +1877,7 @@ fn receiver_is_implemented<'tcx>(
|
|||
let tcx = wfcx.tcx();
|
||||
let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]);
|
||||
|
||||
let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
|
||||
let obligation = Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
|
||||
|
||||
if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) {
|
||||
true
|
||||
|
@ -2188,7 +2213,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
|||
.unwrap_or(obligation_span);
|
||||
}
|
||||
|
||||
let obligation = traits::Obligation::new(
|
||||
let obligation = Obligation::new(
|
||||
tcx,
|
||||
traits::ObligationCause::new(
|
||||
span,
|
||||
|
|
|
@ -77,6 +77,8 @@ pub fn provide(providers: &mut Providers) {
|
|||
explicit_supertraits_containing_assoc_item:
|
||||
predicates_of::explicit_supertraits_containing_assoc_item,
|
||||
trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
|
||||
const_conditions: predicates_of::const_conditions,
|
||||
implied_const_bounds: predicates_of::implied_const_bounds,
|
||||
type_param_predicates: predicates_of::type_param_predicates,
|
||||
trait_def,
|
||||
adt_def,
|
||||
|
|
|
@ -40,7 +40,16 @@ fn associated_type_bounds<'tcx>(
|
|||
let mut bounds = Bounds::default();
|
||||
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
||||
// Associated types are implicitly sized unless a `?Sized` bound is found
|
||||
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
|
||||
match filter {
|
||||
PredicateFilter::All
|
||||
| PredicateFilter::SelfOnly
|
||||
| PredicateFilter::SelfThatDefines(_)
|
||||
| PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
|
||||
}
|
||||
// `ConstIfConst` is only interested in `~const` bounds.
|
||||
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
|
||||
}
|
||||
|
||||
let trait_def_id = tcx.local_parent(assoc_item_def_id);
|
||||
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
|
||||
|
@ -109,10 +118,19 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>(
|
|||
} else {
|
||||
// Only collect *self* type bounds if the filter is for self.
|
||||
match filter {
|
||||
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
|
||||
PredicateFilter::All => {}
|
||||
PredicateFilter::SelfOnly => {
|
||||
return None;
|
||||
}
|
||||
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {}
|
||||
PredicateFilter::SelfThatDefines(_)
|
||||
| PredicateFilter::SelfConstIfConst
|
||||
| PredicateFilter::SelfAndAssociatedTypeBounds
|
||||
| PredicateFilter::ConstIfConst => {
|
||||
unreachable!(
|
||||
"invalid predicate filter for \
|
||||
`remap_gat_vars_and_recurse_into_nested_projections`"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
clause_ty = alias_ty.self_ty();
|
||||
|
@ -308,7 +326,17 @@ fn opaque_type_bounds<'tcx>(
|
|||
let mut bounds = Bounds::default();
|
||||
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
|
||||
// Opaque types are implicitly sized unless a `?Sized` bound is found
|
||||
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
|
||||
match filter {
|
||||
PredicateFilter::All
|
||||
| PredicateFilter::SelfOnly
|
||||
| PredicateFilter::SelfThatDefines(_)
|
||||
| PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||
// Associated types are implicitly sized unless a `?Sized` bound is found
|
||||
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
|
||||
}
|
||||
//`ConstIfConst` is only interested in `~const` bounds.
|
||||
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
|
||||
}
|
||||
debug!(?bounds);
|
||||
|
||||
tcx.arena.alloc_from_iter(bounds.clauses(tcx))
|
||||
|
|
|
@ -12,6 +12,7 @@ use rustc_span::symbol::Ident;
|
|||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use super::item_bounds::explicit_item_bounds_with_filter;
|
||||
use crate::bounds::Bounds;
|
||||
use crate::collect::ItemCtxt;
|
||||
use crate::constrained_generic_params as cgp;
|
||||
|
@ -685,29 +686,76 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>(
|
|||
assert_eq!(
|
||||
trait_predicate.self_ty(),
|
||||
ty,
|
||||
"expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}"
|
||||
"expected `Self` predicate when computing \
|
||||
`{filter:?}` implied bounds: {clause:?}"
|
||||
);
|
||||
}
|
||||
ty::ClauseKind::Projection(projection_predicate) => {
|
||||
assert_eq!(
|
||||
projection_predicate.self_ty(),
|
||||
ty,
|
||||
"expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}"
|
||||
"expected `Self` predicate when computing \
|
||||
`{filter:?}` implied bounds: {clause:?}"
|
||||
);
|
||||
}
|
||||
ty::ClauseKind::TypeOutlives(outlives_predicate) => {
|
||||
assert_eq!(
|
||||
outlives_predicate.0, ty,
|
||||
"expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}"
|
||||
"expected `Self` predicate when computing \
|
||||
`{filter:?}` implied bounds: {clause:?}"
|
||||
);
|
||||
}
|
||||
|
||||
ty::ClauseKind::RegionOutlives(_)
|
||||
| ty::ClauseKind::ConstArgHasType(_, _)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(_) => {
|
||||
| ty::ClauseKind::ConstEvaluatable(_)
|
||||
| ty::ClauseKind::HostEffect(..) => {
|
||||
bug!(
|
||||
"unexpected non-`Self` predicate when computing `{filter:?}` implied bounds: {clause:?}"
|
||||
"unexpected non-`Self` predicate when computing \
|
||||
`{filter:?}` implied bounds: {clause:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PredicateFilter::ConstIfConst => {
|
||||
for (clause, _) in bounds {
|
||||
match clause.kind().skip_binder() {
|
||||
ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
|
||||
trait_ref: _,
|
||||
host: ty::HostPolarity::Maybe,
|
||||
}) => {}
|
||||
_ => {
|
||||
bug!(
|
||||
"unexpected non-`HostEffect` predicate when computing \
|
||||
`{filter:?}` implied bounds: {clause:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PredicateFilter::SelfConstIfConst => {
|
||||
for (clause, _) in bounds {
|
||||
match clause.kind().skip_binder() {
|
||||
ty::ClauseKind::HostEffect(pred) => {
|
||||
assert_eq!(
|
||||
pred.host,
|
||||
ty::HostPolarity::Maybe,
|
||||
"expected `~const` predicate when computing `{filter:?}` \
|
||||
implied bounds: {clause:?}",
|
||||
);
|
||||
assert_eq!(
|
||||
pred.trait_ref.self_ty(),
|
||||
ty,
|
||||
"expected `Self` predicate when computing `{filter:?}` \
|
||||
implied bounds: {clause:?}"
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
bug!(
|
||||
"unexpected non-`HostEffect` predicate when computing \
|
||||
`{filter:?}` implied bounds: {clause:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -829,3 +877,184 @@ impl<'tcx> ItemCtxt<'tcx> {
|
|||
bounds.clauses(self.tcx).collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the conditions that need to hold for a conditionally-const item to be const.
|
||||
/// That is, compute the set of `~const` where clauses for a given item.
|
||||
///
|
||||
/// This query also computes the `~const` where clauses for associated types, which are
|
||||
/// not "const", but which have item bounds which may be `~const`. These must hold for
|
||||
/// the `~const` item bound to hold.
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
let (generics, trait_def_id_and_supertraits, has_parent) = match tcx.hir_node_by_def_id(def_id)
|
||||
{
|
||||
Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::Impl(impl_) => (impl_.generics, None, false),
|
||||
hir::ItemKind::Fn(_, generics, _) => (generics, None, false),
|
||||
hir::ItemKind::Trait(_, _, generics, supertraits, _) => {
|
||||
(generics, Some((item.owner_id.def_id, supertraits)), false)
|
||||
}
|
||||
_ => return Default::default(),
|
||||
},
|
||||
// While associated types are not really const, we do allow them to have `~const`
|
||||
// bounds and where clauses. `const_conditions` is responsible for gathering
|
||||
// these up so we can check them in `compare_type_predicate_entailment`, and
|
||||
// in `HostEffect` goal computation.
|
||||
Node::TraitItem(item) => match item.kind {
|
||||
hir::TraitItemKind::Fn(_, _) | hir::TraitItemKind::Type(_, _) => {
|
||||
(item.generics, None, true)
|
||||
}
|
||||
_ => return Default::default(),
|
||||
},
|
||||
Node::ImplItem(item) => match item.kind {
|
||||
hir::ImplItemKind::Fn(_, _) | hir::ImplItemKind::Type(_) => (item.generics, None, true),
|
||||
_ => return Default::default(),
|
||||
},
|
||||
_ => return Default::default(),
|
||||
};
|
||||
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
let mut bounds = Bounds::default();
|
||||
|
||||
for pred in generics.predicates {
|
||||
match pred {
|
||||
hir::WherePredicate::BoundPredicate(bound_pred) => {
|
||||
let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty);
|
||||
let bound_vars = tcx.late_bound_vars(bound_pred.hir_id);
|
||||
icx.lowerer().lower_bounds(
|
||||
ty,
|
||||
bound_pred.bounds.iter(),
|
||||
&mut bounds,
|
||||
bound_vars,
|
||||
PredicateFilter::ConstIfConst,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((def_id, supertraits)) = trait_def_id_and_supertraits {
|
||||
bounds.push_const_bound(
|
||||
tcx,
|
||||
ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())),
|
||||
ty::HostPolarity::Maybe,
|
||||
DUMMY_SP,
|
||||
);
|
||||
|
||||
icx.lowerer().lower_bounds(
|
||||
tcx.types.self_param,
|
||||
supertraits.into_iter(),
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
PredicateFilter::ConstIfConst,
|
||||
);
|
||||
}
|
||||
|
||||
ty::ConstConditions {
|
||||
parent: has_parent.then(|| tcx.local_parent(def_id).to_def_id()),
|
||||
predicates: tcx.arena.alloc_from_iter(bounds.clauses(tcx).map(|(clause, span)| {
|
||||
(
|
||||
clause.kind().map_bound(|clause| match clause {
|
||||
ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
|
||||
trait_ref,
|
||||
host: ty::HostPolarity::Maybe,
|
||||
}) => trait_ref,
|
||||
_ => bug!("converted {clause:?}"),
|
||||
}),
|
||||
span,
|
||||
)
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn implied_const_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
|
||||
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(),
|
||||
PredicateFilter::SelfConstIfConst,
|
||||
)
|
||||
}
|
||||
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(&[]),
|
||||
};
|
||||
|
||||
bounds.map_bound(|bounds| {
|
||||
&*tcx.arena.alloc_from_iter(bounds.iter().copied().map(|(clause, span)| {
|
||||
(
|
||||
clause.kind().map_bound(|clause| match clause {
|
||||
ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
|
||||
trait_ref,
|
||||
host: ty::HostPolarity::Maybe,
|
||||
}) => trait_ref,
|
||||
_ => bug!("converted {clause:?}"),
|
||||
}),
|
||||
span,
|
||||
)
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -154,7 +154,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
for hir_bound in hir_bounds {
|
||||
// In order to avoid cycles, when we're lowering `SelfThatDefines`,
|
||||
// we skip over any traits that don't define the given associated type.
|
||||
|
||||
if let PredicateFilter::SelfThatDefines(assoc_name) = predicate_filter {
|
||||
if let Some(trait_ref) = hir_bound.trait_ref()
|
||||
&& let Some(trait_did) = trait_ref.trait_def_id()
|
||||
|
@ -193,6 +192,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
);
|
||||
}
|
||||
hir::GenericBound::Outlives(lifetime) => {
|
||||
// `ConstIfConst` is only interested in `~const` bounds.
|
||||
if matches!(
|
||||
predicate_filter,
|
||||
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound);
|
||||
bounds.push_region_bound(
|
||||
self.tcx(),
|
||||
|
@ -392,21 +399,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
},
|
||||
);
|
||||
|
||||
bounds.push_projection_bound(
|
||||
tcx,
|
||||
projection_term.map_bound(|projection_term| ty::ProjectionPredicate {
|
||||
projection_term,
|
||||
term,
|
||||
}),
|
||||
constraint.span,
|
||||
);
|
||||
match predicate_filter {
|
||||
PredicateFilter::All
|
||||
| PredicateFilter::SelfOnly
|
||||
| PredicateFilter::SelfThatDefines(_)
|
||||
| PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||
bounds.push_projection_bound(
|
||||
tcx,
|
||||
projection_term.map_bound(|projection_term| ty::ProjectionPredicate {
|
||||
projection_term,
|
||||
term,
|
||||
}),
|
||||
constraint.span,
|
||||
);
|
||||
}
|
||||
// `ConstIfConst` is only interested in `~const` bounds.
|
||||
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
|
||||
}
|
||||
}
|
||||
// Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator<Item: Debug>`
|
||||
// to a bound involving a projection: `<T as Iterator>::Item: Debug`.
|
||||
hir::AssocItemConstraintKind::Bound { bounds: hir_bounds } => {
|
||||
match predicate_filter {
|
||||
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {}
|
||||
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||
PredicateFilter::All
|
||||
| PredicateFilter::SelfAndAssociatedTypeBounds
|
||||
| PredicateFilter::ConstIfConst => {
|
||||
let projection_ty = projection_term
|
||||
.map_bound(|projection_term| projection_term.expect_ty(self.tcx()));
|
||||
// Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty`
|
||||
|
@ -421,6 +438,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
predicate_filter,
|
||||
);
|
||||
}
|
||||
PredicateFilter::SelfOnly
|
||||
| PredicateFilter::SelfThatDefines(_)
|
||||
| PredicateFilter::SelfConstIfConst => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
ty::ClauseKind::RegionOutlives(_)
|
||||
| ty::ClauseKind::ConstArgHasType(..)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(_) => {
|
||||
| ty::ClauseKind::ConstEvaluatable(_)
|
||||
| ty::ClauseKind::HostEffect(..) => {
|
||||
span_bug!(span, "did not expect {pred} clause in object bounds");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,6 +81,12 @@ pub enum PredicateFilter {
|
|||
/// For example, given `Self: Tr<A: B>`, this would expand to `Self: Tr`
|
||||
/// and `<Self as Tr>::A: B`.
|
||||
SelfAndAssociatedTypeBounds,
|
||||
|
||||
/// Filter only the `~const` bounds, which are lowered into `HostEffect` clauses.
|
||||
ConstIfConst,
|
||||
|
||||
/// Filter only the `~const` bounds which are *also* in the supertrait position.
|
||||
SelfConstIfConst,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -693,8 +699,49 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
bound_vars,
|
||||
);
|
||||
|
||||
debug!(?poly_trait_ref);
|
||||
bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
|
||||
match predicate_filter {
|
||||
PredicateFilter::All
|
||||
| PredicateFilter::SelfOnly
|
||||
| PredicateFilter::SelfThatDefines(..)
|
||||
| PredicateFilter::SelfAndAssociatedTypeBounds => {
|
||||
debug!(?poly_trait_ref);
|
||||
bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
|
||||
|
||||
match constness {
|
||||
Some(ty::BoundConstness::Const) => {
|
||||
if polarity == ty::PredicatePolarity::Positive {
|
||||
bounds.push_const_bound(
|
||||
tcx,
|
||||
poly_trait_ref,
|
||||
ty::HostPolarity::Const,
|
||||
span,
|
||||
);
|
||||
}
|
||||
}
|
||||
Some(ty::BoundConstness::ConstIfConst) => {
|
||||
// We don't emit a const bound here, since that would mean that we
|
||||
// unconditionally need to prove a `HostEffect` predicate, even when
|
||||
// the predicates are being instantiated in a non-const context. This
|
||||
// is instead handled in the `const_conditions` query.
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
// On the flip side, when filtering `ConstIfConst` bounds, we only need to convert
|
||||
// `~const` bounds. All other predicates are handled in their respective queries.
|
||||
//
|
||||
// Note that like `PredicateFilter::SelfOnly`, we don't need to do any filtering
|
||||
// here because we only call this on self bounds, and deal with the recursive case
|
||||
// in `lower_assoc_item_constraint`.
|
||||
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => match constness {
|
||||
Some(ty::BoundConstness::ConstIfConst) => {
|
||||
if polarity == ty::PredicatePolarity::Positive {
|
||||
bounds.push_const_bound(tcx, poly_trait_ref, ty::HostPolarity::Maybe, span);
|
||||
}
|
||||
}
|
||||
None | Some(ty::BoundConstness::Const) => {}
|
||||
},
|
||||
}
|
||||
|
||||
let mut dup_constraints = FxIndexMap::default();
|
||||
for constraint in trait_segment.args().constraints {
|
||||
|
|
|
@ -530,6 +530,7 @@ fn trait_specialization_kind<'tcx>(
|
|||
| ty::ClauseKind::Projection(_)
|
||||
| ty::ClauseKind::ConstArgHasType(..)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(..) => None,
|
||||
| ty::ClauseKind::ConstEvaluatable(..)
|
||||
| ty::ClauseKind::HostEffect(..) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
|||
| ty::ClauseKind::Projection(_)
|
||||
| ty::ClauseKind::ConstArgHasType(_, _)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(_) => {}
|
||||
| ty::ClauseKind::ConstEvaluatable(_)
|
||||
| ty::ClauseKind::HostEffect(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue