rustc_trait_selection/traits/query/type_op/
implied_outlives_bounds.rs1use std::ops::ControlFlow;
2
3use rustc_infer::infer::TypeOutlivesConstraint;
4use rustc_infer::infer::canonical::CanonicalQueryInput;
5use rustc_infer::traits::query::OutlivesBound;
6use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
7use rustc_middle::infer::canonical::CanonicalQueryResponse;
8use rustc_middle::traits::ObligationCause;
9use rustc_middle::ty::outlives::{Component, push_outlives_components};
10use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitable, TypeVisitor};
11use rustc_span::def_id::CRATE_DEF_ID;
12use rustc_span::{DUMMY_SP, Span, sym};
13use smallvec::{SmallVec, smallvec};
14
15use crate::traits::query::NoSolution;
16use crate::traits::{ObligationCtxt, wf};
17
18impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
19 type QueryResponse = Vec<OutlivesBound<'tcx>>;
20
21 fn try_fast_path(
22 _tcx: TyCtxt<'tcx>,
23 key: &ParamEnvAnd<'tcx, Self>,
24 ) -> Option<Self::QueryResponse> {
25 match key.value.ty.kind() {
27 ty::Tuple(elems) if elems.is_empty() => Some(vec![]),
28 ty::Never | ty::Str | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
29 Some(vec![])
30 }
31 _ => None,
32 }
33 }
34
35 fn perform_query(
36 tcx: TyCtxt<'tcx>,
37 canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>,
38 ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
39 tcx.implied_outlives_bounds((canonicalized, false))
40 }
41
42 fn perform_locally_with_next_solver(
43 ocx: &ObligationCtxt<'_, 'tcx>,
44 key: ParamEnvAnd<'tcx, Self>,
45 span: Span,
46 ) -> Result<Self::QueryResponse, NoSolution> {
47 compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty, span, false)
48 }
49}
50
51pub fn compute_implied_outlives_bounds_inner<'tcx>(
52 ocx: &ObligationCtxt<'_, 'tcx>,
53 param_env: ty::ParamEnv<'tcx>,
54 ty: Ty<'tcx>,
55 span: Span,
56 disable_implied_bounds_hack: bool,
57) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
58 assert!(
60 ocx.infcx.inner.borrow().region_obligations().is_empty(),
61 "compute_implied_outlives_bounds assumes region obligations are empty before starting"
62 );
63
64 let normalize_ty = |ty| -> Result<_, NoSolution> {
65 let ty = ocx
69 .deeply_normalize(&ObligationCause::dummy_with_span(span), param_env, ty)
70 .map_err(|_| NoSolution)?;
71 Ok(ty)
72 };
73
74 let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
80 let mut wf_args = vec![ty.into(), normalize_ty(ty)?.into()];
81
82 let mut outlives_bounds: Vec<OutlivesBound<'tcx>> = vec![];
83
84 while let Some(arg) = wf_args.pop() {
85 if !checked_wf_args.insert(arg) {
86 continue;
87 }
88
89 for obligation in
91 wf::unnormalized_obligations(ocx.infcx, param_env, arg, DUMMY_SP, CRATE_DEF_ID)
92 .into_iter()
93 .flatten()
94 {
95 let pred = ocx
96 .deeply_normalize(
97 &ObligationCause::dummy_with_span(span),
98 param_env,
99 obligation.predicate,
100 )
101 .map_err(|_| NoSolution)?;
102 let Some(pred) = pred.kind().no_bound_vars() else {
103 continue;
104 };
105 match pred {
106 ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
109 | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
110 | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
111 | ty::PredicateKind::Subtype(..)
112 | ty::PredicateKind::Coerce(..)
113 | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
114 | ty::PredicateKind::DynCompatible(..)
115 | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
116 | ty::PredicateKind::ConstEquate(..)
117 | ty::PredicateKind::Ambiguous
118 | ty::PredicateKind::NormalizesTo(..)
119 | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
120 | ty::PredicateKind::AliasRelate(..) => {}
121
122 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
124 wf_args.push(term);
125 }
126
127 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
129 ty::OutlivesPredicate(r_a, r_b),
130 )) => outlives_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a)),
131
132 ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
133 ty_a,
134 r_b,
135 ))) => {
136 let mut components = smallvec![];
137 push_outlives_components(ocx.infcx.tcx, ty_a, &mut components);
138 outlives_bounds.extend(implied_bounds_from_components(r_b, components))
139 }
140 }
141 }
142 }
143
144 if !disable_implied_bounds_hack
148 && !ocx.infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat
149 && ty.visit_with(&mut ContainsBevyParamSet { tcx: ocx.infcx.tcx }).is_break()
150 {
151 for TypeOutlivesConstraint { sup_type, sub_region, .. } in
152 ocx.infcx.clone_registered_region_obligations()
153 {
154 let mut components = smallvec![];
155 push_outlives_components(ocx.infcx.tcx, sup_type, &mut components);
156 outlives_bounds.extend(implied_bounds_from_components(sub_region, components));
157 }
158 }
159
160 Ok(outlives_bounds)
161}
162
163struct ContainsBevyParamSet<'tcx> {
164 tcx: TyCtxt<'tcx>,
165}
166
167impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsBevyParamSet<'tcx> {
168 type Result = ControlFlow<()>;
169
170 fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
171 match t.kind() {
173 ty::Adt(def, _) => {
174 if self.tcx.item_name(def.did()) == sym::ParamSet
175 && self.tcx.crate_name(def.did().krate) == sym::bevy_ecs
176 {
177 return ControlFlow::Break(());
178 }
179 }
180 ty::Ref(_, ty, _) => ty.visit_with(self)?,
181 _ => {}
182 }
183
184 ControlFlow::Continue(())
185 }
186}
187
188fn implied_bounds_from_components<'tcx>(
193 sub_region: ty::Region<'tcx>,
194 sup_components: SmallVec<[Component<TyCtxt<'tcx>>; 4]>,
195) -> Vec<OutlivesBound<'tcx>> {
196 sup_components
197 .into_iter()
198 .filter_map(|component| {
199 match component {
200 Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
201 Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
202 Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)),
203 Component::Placeholder(_p) => {
204 None
207 }
208 Component::EscapingAlias(_) =>
209 {
218 None
219 }
220 Component::UnresolvedInferenceVariable(..) => None,
221 }
222 })
223 .collect()
224}