diff options
Diffstat (limited to 'compiler/rustc_hir_analysis/src/collect/predicates_of.rs')
| -rw-r--r-- | compiler/rustc_hir_analysis/src/collect/predicates_of.rs | 239 |
1 files changed, 234 insertions, 5 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index f9460ed5b47..ec5773d174f 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -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, + ) + })) + }) +} |
