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 | 328 |
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))] |