Skip to content

Commit 4218803

Browse files
committed
Auto merge of #67899 - Marwes:view, r=<try>
perf: Avoid re-interning types in outlives checking In profiling `intern_ty` is a very hot function (9% in the test I used). While there does not seem to be a way to reduce the cost of calling we can avoid the call in some cases. In outlives checking `ParamTy` and `ProjectionTy` are extracted from the `Ty` value that contains them only to later be passed as an argument to `intern_ty` again later. This seems to be happening a lot in my test with `intern_ty` called from outlives is at ~6%. Since all `ParamTy` and `ProjectionTy` are already stored in a `Ty` I had an idea to pass around a `View` type which provides direct access to the specific, inner type without losing the original `Ty` pointer. While the current implementation does so with some unsafe to let the branch be elided on `Deref`, it could be done entirely in safe code as well, either by accepting the (predictable) branch in `Deref` or by storing the inner type in `View` as well as the `Ty`. But considering that the unsafe is trivial to prove and the call sites seem quite hot I opted to show the unsafe approach first. Based on #67840 (since it touches the same file/lines) Commits without #67840 https://github.com/rust-lang/rust/pull/67899/files/77ddc3540e52be4b5bd75cf082c621392acaf81b..b55bab206096c27533120921f6b0c273f115e34a
2 parents 7785834 + b55bab2 commit 4218803

File tree

15 files changed

+472
-219
lines changed

15 files changed

+472
-219
lines changed

Diff for: src/librustc/infer/lexical_region_resolve/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
606606
continue;
607607
}
608608

609-
let verify_kind_ty = verify.kind.to_ty(self.tcx());
609+
let verify_kind_ty = verify.kind.as_ty();
610610
if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
611611
continue;
612612
}

Diff for: src/librustc/infer/outlives/obligations.rs

+31-18
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ use crate::hir;
6363
use crate::infer::outlives::env::RegionBoundPairs;
6464
use crate::infer::outlives::verify::VerifyBoundCx;
6565
use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
66+
use crate::traits;
6667
use crate::traits::ObligationCause;
6768
use crate::ty::outlives::Component;
6869
use crate::ty::subst::GenericArgKind;
@@ -154,6 +155,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
154155

155156
let my_region_obligations = self.take_registered_region_obligations();
156157

158+
let mut elaborator = traits::Elaborator::new(self.tcx);
159+
157160
for (body_id, RegionObligation { sup_type, sub_region, origin }) in my_region_obligations {
158161
debug!(
159162
"process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}",
@@ -169,6 +172,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
169172
&region_bound_pairs,
170173
implicit_region_bound,
171174
param_env,
175+
&mut elaborator,
172176
);
173177
outlives.type_must_outlive(origin, sup_type, sub_region);
174178
} else {
@@ -191,15 +195,16 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
191195
ty: Ty<'tcx>,
192196
region: ty::Region<'tcx>,
193197
) {
194-
let outlives = &mut TypeOutlives::new(
198+
let ty = self.resolve_vars_if_possible(&ty);
199+
TypeOutlives::new(
195200
self,
196201
self.tcx,
197202
region_bound_pairs,
198203
implicit_region_bound,
199204
param_env,
200-
);
201-
let ty = self.resolve_vars_if_possible(&ty);
202-
outlives.type_must_outlive(origin, ty, region);
205+
&mut traits::Elaborator::new(self.tcx),
206+
)
207+
.type_must_outlive(origin, ty, region);
203208
}
204209
}
205210

@@ -209,15 +214,15 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
209214
/// via a "delegate" of type `D` -- this is usually the `infcx`, which
210215
/// accrues them into the `region_obligations` code, but for NLL we
211216
/// use something else.
212-
pub struct TypeOutlives<'cx, 'tcx, D>
217+
pub struct TypeOutlives<'cx, 'tcx, 'e, D>
213218
where
214219
D: TypeOutlivesDelegate<'tcx>,
215220
{
216221
// See the comments on `process_registered_region_obligations` for the meaning
217222
// of these fields.
218223
delegate: D,
219224
tcx: TyCtxt<'tcx>,
220-
verify_bound: VerifyBoundCx<'cx, 'tcx>,
225+
verify_bound: VerifyBoundCx<'cx, 'tcx, 'e>,
221226
}
222227

223228
pub trait TypeOutlivesDelegate<'tcx> {
@@ -237,7 +242,7 @@ pub trait TypeOutlivesDelegate<'tcx> {
237242
);
238243
}
239244

240-
impl<'cx, 'tcx, D> TypeOutlives<'cx, 'tcx, D>
245+
impl<'cx, 'tcx, 'e, D> TypeOutlives<'cx, 'tcx, 'e, D>
241246
where
242247
D: TypeOutlivesDelegate<'tcx>,
243248
{
@@ -247,6 +252,7 @@ where
247252
region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
248253
implicit_region_bound: Option<ty::Region<'tcx>>,
249254
param_env: ty::ParamEnv<'tcx>,
255+
elaborator: &'e mut traits::Elaborator<'tcx>,
250256
) -> Self {
251257
Self {
252258
delegate,
@@ -256,6 +262,7 @@ where
256262
region_bound_pairs,
257263
implicit_region_bound,
258264
param_env,
265+
elaborator,
259266
),
260267
}
261268
}
@@ -273,7 +280,9 @@ where
273280
origin: infer::SubregionOrigin<'tcx>,
274281
ty: Ty<'tcx>,
275282
region: ty::Region<'tcx>,
276-
) {
283+
) where
284+
'tcx: 'e,
285+
{
277286
debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})", ty, region, origin);
278287

279288
assert!(!ty.has_escaping_bound_vars());
@@ -288,8 +297,10 @@ where
288297
origin: infer::SubregionOrigin<'tcx>,
289298
components: &[Component<'tcx>],
290299
region: ty::Region<'tcx>,
291-
) {
292-
for component in components.iter() {
300+
) where
301+
'tcx: 'e,
302+
{
303+
for component in components {
293304
let origin = origin.clone();
294305
match component {
295306
Component::Region(region1) => {
@@ -321,7 +332,7 @@ where
321332
&mut self,
322333
origin: infer::SubregionOrigin<'tcx>,
323334
region: ty::Region<'tcx>,
324-
param_ty: ty::ParamTy,
335+
param_ty: ty::View<'tcx, ty::ParamTy>,
325336
) {
326337
debug!(
327338
"param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})",
@@ -337,8 +348,10 @@ where
337348
&mut self,
338349
origin: infer::SubregionOrigin<'tcx>,
339350
region: ty::Region<'tcx>,
340-
projection_ty: ty::ProjectionTy<'tcx>,
341-
) {
351+
projection_ty: ty::View<'tcx, ty::ProjectionTy<'tcx>>,
352+
) where
353+
'tcx: 'e,
354+
{
342355
debug!(
343356
"projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})",
344357
region, projection_ty, origin
@@ -367,17 +380,17 @@ where
367380
// Compute the bounds we can derive from the environment. This
368381
// is an "approximate" match -- in some cases, these bounds
369382
// may not apply.
370-
let mut approx_env_bounds =
371-
self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty);
383+
let mut approx_env_bounds: Vec<_> =
384+
self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty).collect();
372385
debug!("projection_must_outlive: approx_env_bounds={:?}", approx_env_bounds);
373386

374387
// Remove outlives bounds that we get from the environment but
375388
// which are also deducable from the trait. This arises (cc
376389
// #55756) in cases where you have e.g., `<T as Foo<'a>>::Item:
377390
// 'a` in the environment but `trait Foo<'b> { type Item: 'b
378391
// }` in the trait definition.
379-
approx_env_bounds.retain(|bound| match bound.0.kind {
380-
ty::Projection(projection_ty) => self
392+
approx_env_bounds.retain(|bound| match bound.0.into() {
393+
ty::view::Projection(projection_ty) => self
381394
.verify_bound
382395
.projection_declared_bounds_from_trait(projection_ty)
383396
.all(|r| r != bound.1),
@@ -454,7 +467,7 @@ where
454467
}
455468
}
456469

457-
impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> {
470+
impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'_ InferCtxt<'cx, 'tcx> {
458471
fn push_sub_region_constraint(
459472
&mut self,
460473
origin: SubregionOrigin<'tcx>,

0 commit comments

Comments
 (0)