Skip to content

Commit f65dfa2

Browse files
committed
perf: Avoid allocating intermediate Vecs
1 parent ebbb2bf commit f65dfa2

File tree

5 files changed

+80
-75
lines changed

5 files changed

+80
-75
lines changed

src/librustc/infer/outlives/obligations.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ where
289289
components: &[Component<'tcx>],
290290
region: ty::Region<'tcx>,
291291
) {
292-
for component in components.iter() {
292+
for component in components {
293293
let origin = origin.clone();
294294
match component {
295295
Component::Region(region1) => {
@@ -367,8 +367,8 @@ where
367367
// Compute the bounds we can derive from the environment. This
368368
// is an "approximate" match -- in some cases, these bounds
369369
// may not apply.
370-
let mut approx_env_bounds =
371-
self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty);
370+
let mut approx_env_bounds: Vec<_> =
371+
self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty).collect();
372372
debug!("projection_must_outlive: approx_env_bounds={:?}", approx_env_bounds);
373373

374374
// Remove outlives bounds that we get from the environment but

src/librustc/infer/outlives/verify.rs

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
5151

5252
// Start with anything like `T: 'a` we can scrape from the
5353
// environment
54-
let param_bounds = self
55-
.declared_generic_bounds_from_env(GenericKind::Param(param_ty))
56-
.into_iter()
57-
.map(|outlives| outlives.1);
54+
let param_bounds =
55+
self.declared_generic_bounds_from_env(param_ty).map(|outlives| outlives.1);
5856

5957
// Add in the default bound of fn body that applies to all in
6058
// scope type parameters:
@@ -79,12 +77,15 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
7977
pub fn projection_approx_declared_bounds_from_env(
8078
&self,
8179
projection_ty: ty::ProjectionTy<'tcx>,
82-
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
83-
let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
84-
let erased_projection_ty = self.tcx.erase_regions(&projection_ty);
85-
self.declared_generic_bounds_from_env_with_compare_fn(|ty| {
80+
) -> impl Iterator<Item = ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> + 'cx + Captures<'tcx>
81+
{
82+
let tcx = self.tcx;
83+
84+
let projection_ty = GenericKind::Projection(projection_ty).to_ty(tcx);
85+
let erased_projection_ty = tcx.erase_regions(&projection_ty);
86+
self.declared_generic_bounds_from_env_with_compare_fn(move |ty| {
8687
if let ty::Projection(..) = ty.kind {
87-
let erased_ty = self.tcx.erase_regions(&ty);
88+
let erased_ty = tcx.erase_regions(&ty);
8889
erased_ty == erased_projection_ty
8990
} else {
9091
false
@@ -95,10 +96,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
9596
/// Searches the where-clauses in scope for regions that
9697
/// `projection_ty` is known to outlive. Currently requires an
9798
/// exact match.
98-
pub fn projection_declared_bounds_from_trait(
99-
&self,
99+
pub fn projection_declared_bounds_from_trait<'a>(
100+
&'a self,
100101
projection_ty: ty::ProjectionTy<'tcx>,
101-
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
102+
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> + 'a
103+
where
104+
'a: 'cx,
105+
{
102106
self.declared_projection_bounds_from_trait(projection_ty)
103107
}
104108

@@ -127,7 +131,6 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
127131
// Extend with bounds that we can find from the trait.
128132
let trait_bounds = self
129133
.projection_declared_bounds_from_trait(projection_ty)
130-
.into_iter()
131134
.map(|r| VerifyBound::OutlivedBy(r));
132135

133136
// see the extensive comment in projection_must_outlive
@@ -138,17 +141,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
138141
}
139142

140143
fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
141-
let mut bounds = ty.walk_shallow().map(|subty| self.type_bound(subty)).collect::<Vec<_>>();
142-
143-
let mut regions = smallvec![];
144-
ty.push_regions(&mut regions);
145-
regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions
146-
bounds.push(VerifyBound::AllBounds(
147-
regions.into_iter().map(|r| VerifyBound::OutlivedBy(r)).collect(),
148-
));
149-
150-
// remove bounds that must hold, since they are not interesting
151-
bounds.retain(|b| !b.must_hold());
144+
let mut bounds = ty
145+
.walk_shallow()
146+
.map(|subty| self.type_bound(subty))
147+
.chain(Some(VerifyBound::AllBounds(
148+
// ignore late-bound regions
149+
ty.regions()
150+
.filter(|r| !r.is_late_bound())
151+
.map(|r| VerifyBound::OutlivedBy(r))
152+
.collect(),
153+
)))
154+
.filter(|b| !b.must_hold())
155+
.collect::<Vec<_>>();
152156

153157
if bounds.len() == 1 { bounds.pop().unwrap() } else { VerifyBound::AllBounds(bounds) }
154158
}
@@ -161,16 +165,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
161165
/// bounds, but all the bounds it returns can be relied upon.
162166
fn declared_generic_bounds_from_env(
163167
&self,
164-
generic: GenericKind<'tcx>,
165-
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
168+
generic: ty::ParamTy,
169+
) -> impl Iterator<Item = ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> + 'cx + Captures<'tcx>
170+
{
166171
let generic_ty = generic.to_ty(self.tcx);
167-
self.declared_generic_bounds_from_env_with_compare_fn(|ty| ty == generic_ty)
172+
self.declared_generic_bounds_from_env_with_compare_fn(move |ty| ty == generic_ty)
168173
}
169174

170175
fn declared_generic_bounds_from_env_with_compare_fn(
171176
&self,
172-
compare_ty: impl Fn(Ty<'tcx>) -> bool,
173-
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
177+
compare_ty: impl Fn(Ty<'tcx>) -> bool + Clone + 'tcx + 'cx,
178+
) -> impl Iterator<Item = ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> + 'cx + Captures<'tcx>
179+
{
174180
let tcx = self.tcx;
175181

176182
// To start, collect bounds from user environment. Note that
@@ -180,7 +186,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
180186
// like `T` and `T::Item`. It may not work as well for things
181187
// like `<T as Foo<'a>>::Item`.
182188
let c_b = self.param_env.caller_bounds;
183-
let param_bounds = self.collect_outlives_from_predicate_list(&compare_ty, c_b);
189+
let param_bounds = self.collect_outlives_from_predicate_list(compare_ty.clone(), c_b);
184190

185191
// Next, collect regions we scraped from the well-formedness
186192
// constraints in the fn signature. To do that, we walk the list
@@ -193,7 +199,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
193199
// The problem is that the type of `x` is `&'a A`. To be
194200
// well-formed, then, A must be lower-generic by `'a`, but we
195201
// don't know that this holds from first principles.
196-
let from_region_bound_pairs = self.region_bound_pairs.iter().filter_map(|&(r, p)| {
202+
let from_region_bound_pairs = self.region_bound_pairs.iter().filter_map(move |&(r, p)| {
197203
debug!(
198204
"declared_generic_bounds_from_env_with_compare_fn: region_bound_pair = {:?}",
199205
(r, p)
@@ -202,15 +208,12 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
202208
compare_ty(p_ty).then_some(ty::OutlivesPredicate(p_ty, r))
203209
});
204210

205-
param_bounds
206-
.chain(from_region_bound_pairs)
207-
.inspect(|bound| {
208-
debug!(
209-
"declared_generic_bounds_from_env_with_compare_fn: result predicate = {:?}",
210-
bound
211-
)
212-
})
213-
.collect()
211+
param_bounds.chain(from_region_bound_pairs).inspect(|bound| {
212+
debug!(
213+
"declared_generic_bounds_from_env_with_compare_fn: result predicate = {:?}",
214+
bound
215+
)
216+
})
214217
}
215218

216219
/// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds
@@ -225,10 +228,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
225228
/// then this function would return `'x`. This is subject to the
226229
/// limitations around higher-ranked bounds described in
227230
/// `region_bounds_declared_on_associated_item`.
228-
fn declared_projection_bounds_from_trait(
229-
&self,
231+
fn declared_projection_bounds_from_trait<'a>(
232+
&'a self,
230233
projection_ty: ty::ProjectionTy<'tcx>,
231-
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
234+
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> + 'a
235+
where
236+
'a: 'cx,
237+
{
232238
debug!("projection_bounds(projection_ty={:?})", projection_ty);
233239
let tcx = self.tcx;
234240
self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
@@ -265,10 +271,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
265271
///
266272
/// This is for simplicity, and because we are not really smart
267273
/// enough to cope with such bounds anywhere.
268-
fn region_bounds_declared_on_associated_item(
269-
&self,
274+
fn region_bounds_declared_on_associated_item<'a>(
275+
&'a self,
270276
assoc_item_def_id: DefId,
271-
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
277+
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> + 'a
278+
where
279+
'a: 'cx,
280+
{
272281
let tcx = self.tcx;
273282
let assoc_item = tcx.associated_item(assoc_item_def_id);
274283
let trait_def_id = assoc_item.container.assert_trait();
@@ -291,7 +300,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
291300
/// otherwise want a precise match.
292301
fn collect_outlives_from_predicate_list(
293302
&self,
294-
compare_ty: impl Fn(Ty<'tcx>) -> bool,
303+
compare_ty: impl Fn(Ty<'tcx>) -> bool + 'tcx,
295304
predicates: impl IntoIterator<Item = impl AsRef<ty::Predicate<'tcx>>>,
296305
) -> impl Iterator<Item = ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
297306
predicates

src/librustc/traits/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub use self::specialize::find_associated_item;
5959
pub use self::specialize::specialization_graph::FutureCompatOverlapError;
6060
pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
6161
pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
62-
pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
62+
pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs, Elaborator};
6363
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
6464
pub use self::util::{
6565
supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,

src/librustc/ty/outlives.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ impl<'tcx> TyCtxt<'tcx> {
157157
// list is maintained explicitly, because bound regions
158158
// themselves can be readily identified.
159159

160-
push_region_constraints(ty, out);
160+
out.extend(region_constraints(ty));
161161
for subty in ty.walk_shallow() {
162162
self.compute_components(subty, out);
163163
}
@@ -167,16 +167,14 @@ impl<'tcx> TyCtxt<'tcx> {
167167

168168
fn capture_components(&self, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
169169
let mut temp = smallvec![];
170-
push_region_constraints(ty, &mut temp);
170+
temp.extend(region_constraints(ty));
171171
for subty in ty.walk_shallow() {
172172
self.compute_components(subty, &mut temp);
173173
}
174-
temp.into_iter().collect()
174+
temp.into_vec()
175175
}
176176
}
177177

178-
fn push_region_constraints<'tcx>(ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
179-
let mut regions = smallvec![];
180-
ty.push_regions(&mut regions);
181-
out.extend(regions.iter().filter(|&r| !r.is_late_bound()).map(|r| Component::Region(r)));
178+
fn region_constraints<'tcx>(ty: Ty<'tcx>) -> impl Iterator<Item = Component<'tcx>> {
179+
ty.regions().filter(|&r| !r.is_late_bound()).map(|r| Component::Region(r))
182180
}

src/librustc/ty/sty.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use rustc_index::vec::Idx;
2222
use rustc_macros::HashStable;
2323
use rustc_span::symbol::{kw, Symbol};
2424
use rustc_target::spec::abi;
25-
use smallvec::SmallVec;
2625
use std::borrow::Cow;
2726
use std::cmp::Ordering;
2827
use std::marker::PhantomData;
@@ -2208,26 +2207,25 @@ impl<'tcx> TyS<'tcx> {
22082207
/// Pushes onto `out` the regions directly referenced from this type (but not
22092208
/// types reachable from this type via `walk_tys`). This ignores late-bound
22102209
/// regions binders.
2211-
pub fn push_regions(&self, out: &mut SmallVec<[ty::Region<'tcx>; 4]>) {
2212-
match self.kind {
2213-
Ref(region, _, _) => {
2214-
out.push(region);
2215-
}
2216-
Dynamic(ref obj, region) => {
2217-
out.push(region);
2218-
if let Some(principal) = obj.principal() {
2219-
out.extend(principal.skip_binder().substs.regions());
2220-
}
2221-
}
2222-
Adt(_, substs) | Opaque(_, substs) => out.extend(substs.regions()),
2223-
Closure(_, ref substs) | Generator(_, ref substs, _) => out.extend(substs.regions()),
2210+
pub fn regions(&self) -> impl Iterator<Item = ty::Region<'tcx>> {
2211+
let (opt_region, opt_subst_regions) = match self.kind {
2212+
Ref(region, _, _) => (Some(region), None),
2213+
Dynamic(ref obj, region) => (
2214+
Some(region),
2215+
obj.principal().map(|principal| principal.skip_binder().substs.regions()),
2216+
),
2217+
Adt(_, substs) | Opaque(_, substs) => (None, Some(substs.regions())),
2218+
Closure(_, ref substs) | Generator(_, ref substs, _) => (None, Some(substs.regions())),
22242219
Projection(ref data) | UnnormalizedProjection(ref data) => {
2225-
out.extend(data.substs.regions())
2220+
(None, Some(data.substs.regions()))
22262221
}
22272222
FnDef(..) | FnPtr(_) | GeneratorWitness(..) | Bool | Char | Int(_) | Uint(_)
22282223
| Float(_) | Str | Array(..) | Slice(_) | RawPtr(_) | Never | Tuple(..)
2229-
| Foreign(..) | Param(_) | Bound(..) | Placeholder(..) | Infer(_) | Error => {}
2230-
}
2224+
| Foreign(..) | Param(_) | Bound(..) | Placeholder(..) | Infer(_) | Error => {
2225+
(None, None)
2226+
}
2227+
};
2228+
opt_region.into_iter().chain(opt_subst_regions.into_iter().flatten())
22312229
}
22322230

22332231
/// When we create a closure, we record its kind (i.e., what trait

0 commit comments

Comments
 (0)