1use rustc_hir::def::DefKind;
2use rustc_hir::def_id::LocalDefId;
3use rustc_infer::infer::TyCtxtInferExt;
4use rustc_infer::traits::ObligationCause;
5use rustc_infer::traits::query::MirBorrowckImpliedOutlivesBounds;
6use rustc_middle::infer::canonical::{Canonical, QueryResponse};
7use rustc_middle::ty::{
8self, CanonicalVarValues, GenericArg, Ty, TyCtxt, TypeVisitableExt, TypingEnv, fold_regions,
9};
10use rustc_span::DUMMY_SP;
11use rustc_trait_selection::solve::NoSolution;
12use rustc_trait_selection::traits::ObligationCtxt;
13use rustc_trait_selection::traits::implied_outlives_bounds::{
14 compute_implied_outlives_bounds_inner, consider_implied_bounds_hack_for_ty,
15};
16use smallvec::SmallVec;
17use tracing::instrument;
1819use crate::universal_regions::DefiningTy;
2021/// Computes the implied bounds for `body_def_id`. This is a separate query
22/// as it must not reveal the hidden type of opaques defined by `body_def_id`
23/// for typeck roots.
24///
25/// However, nested bodies are checked in the scope of their parent. This means
26/// we should actually normalize opaques when computing their implied bounds.
27pub(super) fn mir_borrowck_implied_outlives_bounds<'tcx>(
28 tcx: TyCtxt<'tcx>,
29 body_def_id: LocalDefId,
30) -> Result<
31&'tcx Canonical<'tcx, QueryResponse<'tcx, MirBorrowckImpliedOutlivesBounds<'tcx>>>,
32NoSolution,
33> {
34// If we're in a typeck root we don't want to reveal any opaque types. We need to
35 // make sure the caller actually checks that all our implied bounds actually hold.
36 // This is not the case with the hidden types of opaque types if we're a defining-scope
37 // and the caller is not.
38 //
39 // However, for nested bodies, we always check that they are well-formed in their
40 // parent body, so for these we do want to define opaque types. Not doing so can result
41 // in incorrect errors when normalizing implied bounds.
42let typing_env = if tcx.is_typeck_child(body_def_id.to_def_id()) {
43TypingEnv::post_typeck_until_borrowck(tcx, body_def_id)
44 } else {
45TypingEnv::non_body_analysis(tcx, body_def_id)
46 };
4748let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
49let ocx = ObligationCtxt::new(&infcx);
5051let defining_ty = DefiningTy::new(tcx, body_def_id);
5253let inputs_and_output = defining_ty.inputs_and_output(tcx);
54let inputs_and_output =
55tcx.liberate_late_bound_regions(body_def_id.to_def_id(), inputs_and_output);
56let inputs_and_output = replace_erased_regions_with_placeholders(tcx, inputs_and_output);
5758let mut outlives_bounds = ::alloc::vec::Vec::new()vec![];
59// Need to return the normalized signature used to compute implied bounds back to borrowck
60 // to deal with unconstrained regions due to #136547.
61let mut normalized_inputs_and_output = Vec::with_capacity(inputs_and_output.len());
62for &ty in &inputs_and_output {
63let num_registered_region_obligations = infcx.num_registered_region_obligations();
64let normalized_ty = ocx
65 .deeply_normalize(&ObligationCause::dummy(), param_env, ty::Unnormalized::new_wip(ty))
66 .map_err(|_| NoSolution)?;
6768 outlives_bounds.extend(compute_implied_outlives_bounds_inner(
69&ocx,
70 param_env,
71 ty,
72 normalized_ty,
73 DUMMY_SP,
74 )?);
7576 outlives_bounds.extend(consider_implied_bounds_hack_for_ty(&ocx, normalized_ty, || {
77 infcx.registered_region_obligations_since(num_registered_region_obligations)
78 }));
7980 normalized_inputs_and_output.push(normalized_ty);
81 }
8283// Add implied bounds from impl header.
84 //
85 // We don't use `assumed_wf_types` to source the entire set of implied bounds for
86 // a few reasons:
87 // - `DefiningTy` for closure has the `&'env Self` type while `assumed_wf_types` doesn't
88 // - We compute implied bounds from the unnormalized types in the `DefiningTy` but do not
89 // do so for types in impl headers
90 // - We must compute the normalized signature and then compute implied bounds from that
91 // in order to connect any unconstrained region vars created during normalization to
92 // the types of the locals corresponding to the inputs and outputs of the item. #136547
93if #[allow(non_exhaustive_omitted_patterns)] match tcx.def_kind(body_def_id) {
DefKind::AssocFn | DefKind::AssocConst { .. } => true,
_ => false,
}matches!(tcx.def_kind(body_def_id), DefKind::AssocFn | DefKind::AssocConst { .. }) {
94for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(body_def_id)) {
95let normalized_ty = ocx
96 .deeply_normalize(
97&ObligationCause::dummy(),
98 param_env,
99 ty::Unnormalized::new_wip(ty),
100 )
101 .map_err(|_| NoSolution)?;
102103// We don't consider the constraints from normalizing the impl header
104 // for the bevy implied bounds hack.
105let num_registered_region_obligations = infcx.num_registered_region_obligations();
106 outlives_bounds.extend(compute_implied_outlives_bounds_inner(
107&ocx,
108 param_env,
109 normalized_ty,
110 normalized_ty,
111 DUMMY_SP,
112 )?);
113114 outlives_bounds.extend(consider_implied_bounds_hack_for_ty(
115&ocx,
116 normalized_ty,
117 || infcx.registered_region_obligations_since(num_registered_region_obligations),
118 ));
119 }
120 }
121122let var_values = implied_bounds_query_var_values(tcx, &inputs_and_output, |r| match r.kind() {
123 ty::RePlaceholder(_) => true,
124 ty::ReEarlyParam(_)
125 | ty::ReLateParam(_)
126 | ty::ReBound(..)
127 | ty::ReStatic128 | ty::ReError(_) => false,
129 ty::ReVar(..) | ty::ReErased => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
130 });
131let input_values = CanonicalVarValues { var_values: tcx.mk_args(&var_values) };
132133ocx.make_canonicalized_query_response(
134input_values,
135MirBorrowckImpliedOutlivesBounds { outlives_bounds, normalized_inputs_and_output },
136 )
137}
138139/// This computes the `var_values` used by the `mir_borrowck_implied_outlives_bounds` query.
140/// The old solver canonicalization does not replace early and late bound parameters,
141/// so the only `var_values` we need are external regions from the signature of the nested
142/// body as we don't have a shared representation between this query and MIR borrowck.
143///
144/// These are not all external regions of the nested body, only the external regions
145/// which may get accessed by this query. We only need to add things to the `var_values`
146/// which can be referenced by both this query and MIR borrowck. MIR borrowck currently
147/// creates external regions for late-bound regions of parent items as these can be
148/// explicitly mentioned in user types. We do not encounter these in this query, as all
149/// free regions in the signature of nested bodies get replaced with `'erased` at the end
150/// of HIR typeck, so we don't care about them.
151x;#[instrument(level = "debug", skip(tcx, is_external_region), ret)]152pub(crate) fn implied_bounds_query_var_values<'tcx>(
153 tcx: TyCtxt<'tcx>,
154 unnormalized_inputs_and_output: &[Ty<'tcx>],
155mut is_external_region: impl FnMut(ty::Region<'tcx>) -> bool,
156) -> SmallVec<[GenericArg<'tcx>; 8]> {
157let mut values: SmallVec<[GenericArg<'tcx>; 8]> = Default::default();
158159for ty in unnormalized_inputs_and_output {
160 tcx.for_each_free_region(ty, |region| {
161if is_external_region(region) {
162 values.push(region.into());
163 }
164 });
165 }
166167 values
168}
169170/// This replaces all external regions in the signature of the current item with
171/// a unique placeholder to collect its implied bounds. This mirrors the way MIR
172/// borrowck replaces all of them with unique NLL vars.
173fn replace_erased_regions_with_placeholders<'tcx>(
174 tcx: TyCtxt<'tcx>,
175 inputs_and_output: &[Ty<'tcx>],
176) -> Vec<Ty<'tcx>> {
177if true {
if !!inputs_and_output.has_placeholders() {
::core::panicking::panic("assertion failed: !inputs_and_output.has_placeholders()")
};
};debug_assert!(!inputs_and_output.has_placeholders());
178let mut next_placeholder = 0;
179inputs_and_output180 .iter()
181 .map(|&ty| {
182fold_regions(tcx, ty, |r, _| match r.kind() {
183 ty::ReErased => {
184let var = ty::BoundVar::from_usize(next_placeholder);
185next_placeholder += 1;
186 ty::Region::new_placeholder(
187tcx,
188 ty::PlaceholderRegion::new(
189 ty::UniverseIndex::ROOT,
190 ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon },
191 ),
192 )
193 }
194 ty::ReEarlyParam(_)
195 | ty::ReLateParam(_)
196 | ty::ReBound(..)
197 | ty::ReStatic198 | ty::ReError(_) => r,
199 ty::ReVar(..) | ty::RePlaceholder(..) => {
200{ ::core::panicking::panic_fmt(format_args!("unexpected region: {0:?}", r)); }panic!("unexpected region: {r:?}")201 }
202 })
203 })
204 .collect()
205}