summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/collect/predicates_of.rs')
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs328
1 files changed, 188 insertions, 140 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index e5b5dae55..129366641 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -1,8 +1,8 @@
-use crate::astconv::{AstConv, OnlySelfBounds};
+use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
use crate::bounds::Bounds;
use crate::collect::ItemCtxt;
use crate::constrained_generic_params as cgp;
-use hir::{HirId, Node};
+use hir::{HirId, Lifetime, Node};
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
@@ -10,9 +10,9 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{GenericPredicates, ToPredicate};
+use rustc_middle::ty::{GenericPredicates, Generics, ImplTraitInTraitData, ToPredicate};
use rustc_span::symbol::{sym, Ident};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{Span, Symbol, DUMMY_SP};
/// Returns a list of all type predicates (explicit and implicit) for the definition with
/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
@@ -62,6 +62,67 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> {
use rustc_hir::*;
+ match tcx.opt_rpitit_info(def_id.to_def_id()) {
+ Some(ImplTraitInTraitData::Trait { opaque_def_id, fn_def_id }) => {
+ let opaque_ty_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id.expect_local());
+ let opaque_ty_node = tcx.hir().get(opaque_ty_id);
+ let Node::Item(&Item { kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping, .. }), .. }) = opaque_ty_node else {
+ bug!("unexpected {opaque_ty_node:?}")
+ };
+
+ let mut predicates = Vec::new();
+
+ // RPITITs should inherit the predicates of their parent. This is
+ // both to ensure that the RPITITs are only instantiated when the
+ // parent predicates would hold, and also so that the param-env
+ // inherits these predicates as assumptions.
+ let identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
+ predicates.extend(
+ tcx.explicit_predicates_of(fn_def_id).instantiate_own(tcx, identity_substs),
+ );
+
+ // We also install bidirectional outlives predicates for the RPITIT
+ // to keep the duplicates lifetimes from opaque lowering in sync.
+ compute_bidirectional_outlives_predicates(
+ tcx,
+ def_id,
+ lifetime_mapping.iter().map(|(lifetime, def_id)| {
+ (*lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span))
+ }),
+ tcx.generics_of(def_id.to_def_id()),
+ &mut predicates,
+ );
+
+ return ty::GenericPredicates {
+ parent: Some(tcx.parent(def_id.to_def_id())),
+ predicates: tcx.arena.alloc_from_iter(predicates),
+ };
+ }
+
+ Some(ImplTraitInTraitData::Impl { fn_def_id }) => {
+ let assoc_item = tcx.associated_item(def_id);
+ let trait_assoc_predicates =
+ tcx.explicit_predicates_of(assoc_item.trait_item_def_id.unwrap());
+
+ let impl_assoc_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
+ let impl_def_id = tcx.parent(fn_def_id);
+ let impl_trait_ref_substs =
+ tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity().substs;
+
+ let impl_assoc_substs =
+ impl_assoc_identity_substs.rebase_onto(tcx, impl_def_id, impl_trait_ref_substs);
+
+ let impl_predicates = trait_assoc_predicates.instantiate_own(tcx, impl_assoc_substs);
+
+ return ty::GenericPredicates {
+ parent: Some(impl_def_id),
+ predicates: tcx.arena.alloc_from_iter(impl_predicates),
+ };
+ }
+
+ None => {}
+ }
+
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let node = tcx.hir().get(hir_id);
@@ -75,7 +136,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// We use an `IndexSet` to preserve order of insertion.
// Preserving the order of insertion is important here so as not to break UI tests.
- let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
+ let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default();
let ast_generics = match node {
Node::TraitItem(item) => item.generics,
@@ -125,8 +186,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
if let Some(self_bounds) = is_trait {
predicates.extend(
icx.astconv()
- .compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false))
- .predicates(),
+ .compute_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All)
+ .clauses(),
);
}
@@ -175,22 +236,24 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
param.span,
);
trace!(?bounds);
- predicates.extend(bounds.predicates());
+ predicates.extend(bounds.clauses());
trace!(?predicates);
}
GenericParamKind::Const { .. } => {
let name = param.name.ident().name;
let param_const = ty::ParamConst::new(index, name);
- let ct_ty = tcx.type_of(param.def_id.to_def_id()).subst_identity();
+ let ct_ty = tcx
+ .type_of(param.def_id.to_def_id())
+ .no_bound_vars()
+ .expect("const parameters cannot be generic");
- let ct = tcx.mk_const(param_const, ct_ty);
+ let ct = ty::Const::new_param(tcx, param_const, ct_ty);
- let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
- ty::Clause::ConstArgHasType(ct, ct_ty),
- ))
- .to_predicate(tcx);
- predicates.insert((predicate, param.span));
+ predicates.insert((
+ ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx),
+ param.span,
+ ));
index += 1;
}
@@ -219,7 +282,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
} else {
let span = bound_pred.bounded_ty.span;
let predicate = ty::Binder::bind_with_vars(
- ty::PredicateKind::WellFormed(ty.into()),
+ ty::ClauseKind::WellFormed(ty.into()),
bound_vars,
);
predicates.insert((predicate.to_predicate(tcx), span));
@@ -234,7 +297,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
bound_vars,
OnlySelfBounds(false),
);
- predicates.extend(bounds.predicates());
+ predicates.extend(bounds.clauses());
}
hir::WherePredicate::RegionPredicate(region_pred) => {
@@ -246,11 +309,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}
_ => bug!(),
};
- let pred = ty::Binder::dummy(ty::PredicateKind::Clause(
- ty::Clause::RegionOutlives(ty::OutlivesPredicate(r1, r2)),
- ))
- .to_predicate(icx.tcx);
-
+ let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
+ .to_predicate(icx.tcx);
(pred, span)
}))
}
@@ -293,39 +353,22 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
bug!("unexpected {opaque_ty_node:?}")
};
debug!(?lifetimes);
- for (arg, duplicate) in std::iter::zip(lifetimes, ast_generics.params) {
- let hir::GenericArg::Lifetime(arg) = arg else { bug!() };
- let orig_region = icx.astconv().ast_region_to_region(&arg, None);
- if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) {
- // Only early-bound regions can point to the original generic parameter.
- continue;
- }
- let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue };
- let dup_def = duplicate.def_id.to_def_id();
-
- let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() };
-
- let dup_region = tcx.mk_re_early_bound(ty::EarlyBoundRegion {
- def_id: dup_def,
- index: dup_index,
- name: duplicate.name.ident().name,
- });
- predicates.push((
- ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives(
- ty::OutlivesPredicate(orig_region, dup_region),
- )))
- .to_predicate(icx.tcx),
- duplicate.span,
- ));
- predicates.push((
- ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives(
- ty::OutlivesPredicate(dup_region, orig_region),
- )))
- .to_predicate(icx.tcx),
- duplicate.span,
- ));
- }
+ let lifetime_mapping = std::iter::zip(lifetimes, ast_generics.params)
+ .map(|(arg, dup)| {
+ let hir::GenericArg::Lifetime(arg) = arg else { bug!() };
+ (**arg, dup)
+ })
+ .filter(|(_, dup)| matches!(dup.kind, hir::GenericParamKind::Lifetime { .. }))
+ .map(|(lifetime, dup)| (lifetime, (dup.def_id, dup.name.ident().name, dup.span)));
+
+ compute_bidirectional_outlives_predicates(
+ tcx,
+ def_id,
+ lifetime_mapping,
+ generics,
+ &mut predicates,
+ );
debug!(?predicates);
}
@@ -335,13 +378,53 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}
}
+/// Opaques have duplicated lifetimes and we need to compute bidirectional outlives predicates to
+/// enforce that these lifetimes stay in sync.
+fn compute_bidirectional_outlives_predicates<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ item_def_id: LocalDefId,
+ lifetime_mapping: impl Iterator<Item = (Lifetime, (LocalDefId, Symbol, Span))>,
+ generics: &Generics,
+ predicates: &mut Vec<(ty::Clause<'tcx>, Span)>,
+) {
+ let icx = ItemCtxt::new(tcx, item_def_id);
+
+ for (arg, (dup_def, name, span)) in lifetime_mapping {
+ let orig_region = icx.astconv().ast_region_to_region(&arg, None);
+ if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) {
+ // There is no late-bound lifetime to actually match up here, since the lifetime doesn't
+ // show up in the opaque's parent's substs.
+ continue;
+ }
+
+ let Some(dup_index) = generics.param_def_id_to_index(icx.tcx, dup_def.to_def_id()) else { bug!() };
+
+ let dup_region = ty::Region::new_early_bound(
+ tcx,
+ ty::EarlyBoundRegion { def_id: dup_def.to_def_id(), index: dup_index, name },
+ );
+
+ predicates.push((
+ ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_region, dup_region))
+ .to_predicate(tcx),
+ span,
+ ));
+
+ predicates.push((
+ ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_region, orig_region))
+ .to_predicate(tcx),
+ span,
+ ));
+ }
+}
+
fn const_evaluatable_predicates_of(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
-) -> FxIndexSet<(ty::Predicate<'_>, Span)> {
+) -> FxIndexSet<(ty::Clause<'_>, Span)> {
struct ConstCollector<'tcx> {
tcx: TyCtxt<'tcx>,
- preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
+ preds: FxIndexSet<(ty::Clause<'tcx>, Span)>,
}
impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
@@ -349,11 +432,8 @@ fn const_evaluatable_predicates_of(
let ct = ty::Const::from_anon_const(self.tcx, c.def_id);
if let ty::ConstKind::Unevaluated(_) = ct.kind() {
let span = self.tcx.def_span(c.def_id);
- self.preds.insert((
- ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
- .to_predicate(self.tcx),
- span,
- ));
+ self.preds
+ .insert((ty::ClauseKind::ConstEvaluatable(ct).to_predicate(self.tcx), span));
}
}
@@ -441,13 +521,9 @@ pub(super) fn explicit_predicates_of<'tcx>(
.iter()
.copied()
.filter(|(pred, _)| match pred.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => !is_assoc_item_ty(tr.self_ty()),
- ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => {
- !is_assoc_item_ty(proj.projection_ty.self_ty())
- }
- ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => {
- !is_assoc_item_ty(outlives.0)
- }
+ ty::ClauseKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
+ ty::ClauseKind::Projection(proj) => !is_assoc_item_ty(proj.projection_ty.self_ty()),
+ ty::ClauseKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
_ => true,
})
.collect();
@@ -460,7 +536,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
}
}
} else {
- if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
+ if matches!(def_kind, DefKind::AnonConst) && tcx.features().generic_const_exprs {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let parent_def_id = tcx.hir().get_parent_item(hir_id);
@@ -488,9 +564,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
.predicates
.into_iter()
.filter(|(pred, _)| {
- if let ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, _)) =
- pred.kind().skip_binder()
- {
+ if let ty::ClauseKind::ConstArgHasType(ct, _) = pred.kind().skip_binder() {
match ct.kind() {
ty::ConstKind::Param(param_const) => {
let defaulted_param_idx = tcx
@@ -544,19 +618,6 @@ pub(super) fn explicit_predicates_of<'tcx>(
}
}
-#[derive(Copy, Clone, Debug)]
-pub enum PredicateFilter {
- /// All predicates may be implied by the trait
- All,
-
- /// Only traits that reference `Self: ..` are implied by the trait
- SelfOnly,
-
- /// Only traits that reference `Self: ..` and define an associated type
- /// with the given ident are implied by the trait
- SelfThatDefines(Ident),
-}
-
/// Ensures that the super-predicates of the trait with a `DefId`
/// of `trait_def_id` are converted and stored. This also ensures that
/// the transitive super-predicates are converted.
@@ -578,11 +639,15 @@ pub(super) fn implied_predicates_of(
tcx: TyCtxt<'_>,
trait_def_id: LocalDefId,
) -> ty::GenericPredicates<'_> {
- if tcx.is_trait_alias(trait_def_id.to_def_id()) {
- implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::All)
- } else {
- tcx.super_predicates_of(trait_def_id)
- }
+ implied_predicates_with_filter(
+ tcx,
+ trait_def_id.to_def_id(),
+ if tcx.is_trait_alias(trait_def_id.to_def_id()) {
+ PredicateFilter::All
+ } else {
+ PredicateFilter::SelfAndAssociatedTypeBounds
+ },
+ )
}
/// Ensures that the super-predicates of the trait with a `DefId`
@@ -615,48 +680,18 @@ pub(super) fn implied_predicates_with_filter(
let icx = ItemCtxt::new(tcx, trait_def_id);
let self_param_ty = tcx.types.self_param;
- let (superbounds, where_bounds_that_match) = match filter {
- PredicateFilter::All => (
- // Convert the bounds that follow the colon (or equal in trait aliases)
- icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false)),
- // Also include all where clause bounds
- icx.type_parameter_bounds_in_generics(
- generics,
- item.owner_id.def_id,
- self_param_ty,
- OnlySelfBounds(false),
- None,
- ),
- ),
- PredicateFilter::SelfOnly => (
- // Convert the bounds that follow the colon (or equal in trait aliases)
- icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(true)),
- // Include where clause bounds for `Self`
- icx.type_parameter_bounds_in_generics(
- generics,
- item.owner_id.def_id,
- self_param_ty,
- OnlySelfBounds(true),
- None,
- ),
- ),
- PredicateFilter::SelfThatDefines(assoc_name) => (
- // Convert the bounds that follow the colon (or equal) that reference the associated name
- icx.astconv().compute_bounds_that_match_assoc_item(self_param_ty, bounds, assoc_name),
- // Include where clause bounds for `Self` that reference the associated name
- icx.type_parameter_bounds_in_generics(
- generics,
- item.owner_id.def_id,
- self_param_ty,
- OnlySelfBounds(true),
- Some(assoc_name),
- ),
- ),
- };
+ let superbounds = icx.astconv().compute_bounds(self_param_ty, bounds, filter);
+
+ let where_bounds_that_match = icx.type_parameter_bounds_in_generics(
+ generics,
+ item.owner_id.def_id,
+ self_param_ty,
+ filter,
+ );
// Combine the two lists to form the complete set of superbounds:
let implied_bounds =
- &*tcx.arena.alloc_from_iter(superbounds.predicates().chain(where_bounds_that_match));
+ &*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match));
debug!(?implied_bounds);
// Now require that immediate supertraits are converted, which will, in
@@ -665,7 +700,7 @@ pub(super) fn implied_predicates_with_filter(
if matches!(filter, PredicateFilter::SelfOnly) {
for &(pred, span) in implied_bounds {
debug!("superbound: {:?}", pred);
- if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder()
+ if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder()
&& bound.polarity == ty::ImplPolarity::Positive
{
tcx.at(span).super_predicates_of(bound.def_id());
@@ -684,6 +719,7 @@ pub(super) fn type_param_predicates(
(item_def_id, def_id, assoc_name): (LocalDefId, LocalDefId, Ident),
) -> ty::GenericPredicates<'_> {
use rustc_hir::*;
+ use rustc_middle::ty::Ty;
// In the AST, bounds can derive from two places. Either
// written inline like `<T: Foo>` or in a where-clause like
@@ -693,7 +729,7 @@ pub(super) fn type_param_predicates(
let param_owner = tcx.hir().ty_param_owner(def_id);
let generics = tcx.generics_of(param_owner);
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
- let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id));
+ let ty = Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id));
// Don't look for bounds where the type parameter isn't in scope.
let parent = if item_def_id == param_owner {
@@ -721,7 +757,7 @@ pub(super) fn type_param_predicates(
ItemKind::Fn(.., generics, _)
| ItemKind::Impl(&hir::Impl { generics, .. })
| ItemKind::TyAlias(_, generics)
- | ItemKind::OpaqueTy(OpaqueTy {
+ | ItemKind::OpaqueTy(&OpaqueTy {
generics,
origin: hir::OpaqueTyOrigin::TyAlias { .. },
..
@@ -757,12 +793,11 @@ pub(super) fn type_param_predicates(
ast_generics,
def_id,
ty,
- OnlySelfBounds(true),
- Some(assoc_name),
+ PredicateFilter::SelfThatDefines(assoc_name),
)
.into_iter()
.filter(|(predicate, _)| match predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(data)) => data.self_ty().is_param(index),
+ ty::ClauseKind::Trait(data) => data.self_ty().is_param(index),
_ => false,
}),
);
@@ -782,9 +817,8 @@ impl<'tcx> ItemCtxt<'tcx> {
ast_generics: &'tcx hir::Generics<'tcx>,
param_def_id: LocalDefId,
ty: Ty<'tcx>,
- only_self_bounds: OnlySelfBounds,
- assoc_name: Option<Ident>,
- ) -> Vec<(ty::Predicate<'tcx>, Span)> {
+ filter: PredicateFilter,
+ ) -> Vec<(ty::Clause<'tcx>, Span)> {
let mut bounds = Bounds::default();
for predicate in ast_generics.predicates {
@@ -792,9 +826,23 @@ impl<'tcx> ItemCtxt<'tcx> {
continue;
};
+ let (only_self_bounds, assoc_name) = match filter {
+ PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
+ (OnlySelfBounds(false), None)
+ }
+ PredicateFilter::SelfOnly => (OnlySelfBounds(true), None),
+ PredicateFilter::SelfThatDefines(assoc_name) => {
+ (OnlySelfBounds(true), Some(assoc_name))
+ }
+ };
+
+ // Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we
+ // want to only consider predicates with `Self: ...`, but we don't want
+ // `OnlySelfBounds(true)` since we want to collect the nested associated
+ // type bound as well.
let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
ty
- } else if !only_self_bounds.0 {
+ } else if matches!(filter, PredicateFilter::All) {
self.to_ty(predicate.bounded_ty)
} else {
continue;
@@ -813,7 +861,7 @@ impl<'tcx> ItemCtxt<'tcx> {
);
}
- bounds.predicates().collect()
+ bounds.clauses().collect()
}
#[instrument(level = "trace", skip(self))]