Skip to content

Commit dc9317f

Browse files
committed
use IfEq to defer equality comparison around where clauses`
1 parent 7f8c42d commit dc9317f

File tree

2 files changed

+59
-49
lines changed

2 files changed

+59
-49
lines changed

src/librustc/infer/outlives/obligations.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -401,12 +401,9 @@ where
401401
// Compute the bounds we can derive from the trait definition.
402402
// These are guaranteed to apply, no matter the inference
403403
// results.
404-
let trait_bounds = self.verify_bound
405-
.projection_declared_bounds_from_trait(projection_ty);
406-
debug!(
407-
"projection_must_outlive: trait_bounds={:?}",
408-
trait_bounds
409-
);
404+
let trait_bounds: Vec<_> = self.verify_bound
405+
.projection_declared_bounds_from_trait(projection_ty)
406+
.collect();
410407

411408
// If declared bounds list is empty, the only applicable rule is
412409
// OutlivesProjectionComponent. If there are inference variables,
@@ -451,7 +448,7 @@ where
451448
if !trait_bounds.is_empty()
452449
&& trait_bounds[1..]
453450
.iter()
454-
.chain(&approx_env_bounds)
451+
.chain(approx_env_bounds.iter().map(|b| &b.1))
455452
.all(|b| *b == trait_bounds[0])
456453
{
457454
let unique_bound = trait_bounds[0];

src/librustc/infer/outlives/verify.rs

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use infer::{GenericKind, VerifyBound};
1414
use traits;
1515
use ty::subst::{Subst, Substs};
1616
use ty::{self, Ty, TyCtxt};
17+
use util::captures::Captures;
1718

1819
/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
1920
/// obligation into a series of `'a: 'b` constraints and "verifys", as
@@ -65,21 +66,15 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
6566

6667
// Start with anything like `T: 'a` we can scrape from the
6768
// environment
68-
let param_bounds =
69-
self.declared_generic_bounds_from_env(GenericKind::Param(param_ty))
70-
.into_iter();
69+
let param_bounds = self.declared_generic_bounds_from_env(GenericKind::Param(param_ty))
70+
.into_iter()
71+
.map(|outlives| outlives.1);
7172

7273
// Add in the default bound of fn body that applies to all in
7374
// scope type parameters:
74-
let param_bounds =
75-
param_bounds
76-
.chain(self.implicit_region_bound);
75+
let param_bounds = param_bounds.chain(self.implicit_region_bound);
7776

78-
VerifyBound::AnyBound(
79-
param_bounds
80-
.map(|r| VerifyBound::OutlivedBy(r))
81-
.collect()
82-
)
77+
VerifyBound::AnyBound(param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect())
8378
}
8479

8580
/// Given a projection like `T::Item`, searches the environment
@@ -98,7 +93,7 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
9893
pub fn projection_approx_declared_bounds_from_env(
9994
&self,
10095
projection_ty: ty::ProjectionTy<'tcx>,
101-
) -> Vec<ty::Region<'tcx>> {
96+
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
10297
let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
10398
let erased_projection_ty = self.tcx.erase_regions(&projection_ty);
10499
self.declared_generic_bounds_from_env_with_compare_fn(|ty| {
@@ -117,31 +112,42 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
117112
pub fn projection_declared_bounds_from_trait(
118113
&self,
119114
projection_ty: ty::ProjectionTy<'tcx>,
120-
) -> Vec<ty::Region<'tcx>> {
115+
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'gcx> {
121116
self.declared_projection_bounds_from_trait(projection_ty)
122117
}
123118

124119
pub fn projection_bound(&self, projection_ty: ty::ProjectionTy<'tcx>) -> VerifyBound<'tcx> {
125120
debug!("projection_bound(projection_ty={:?})", projection_ty);
126121

122+
let projection_ty_as_ty =
123+
self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
124+
127125
// Search the env for where clauses like `P: 'a`.
128-
let env_bounds =
129-
self.declared_generic_bounds_from_env(GenericKind::Projection(projection_ty))
130-
.into_iter();
126+
let env_bounds = self.projection_approx_declared_bounds_from_env(projection_ty)
127+
.into_iter()
128+
.map(|ty::OutlivesPredicate(ty, r)| {
129+
let vb = VerifyBound::OutlivedBy(r);
130+
if ty == projection_ty_as_ty {
131+
// Micro-optimize if this is an exact match (this
132+
// occurs often when there are no region variables
133+
// involved).
134+
vb
135+
} else {
136+
VerifyBound::IfEq(ty, Box::new(vb))
137+
}
138+
});
131139

132140
// Extend with bounds that we can find from the trait.
133-
let trait_bounds =
134-
self.projection_declared_bounds_from_trait(projection_ty)
135-
.into_iter();
141+
let trait_bounds = self.projection_declared_bounds_from_trait(projection_ty)
142+
.into_iter()
143+
.map(|r| VerifyBound::OutlivedBy(r));
136144

137145
// see the extensive comment in projection_must_outlive
138146
let ty = self.tcx
139147
.mk_projection(projection_ty.item_def_id, projection_ty.substs);
140148
let recursive_bound = self.recursive_type_bound(ty);
141149

142-
VerifyBound::AnyBound(
143-
env_bounds.chain(trait_bounds).map(|r| VerifyBound::OutlivedBy(r)).collect()
144-
).or(recursive_bound)
150+
VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
145151
}
146152

147153
fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
@@ -151,11 +157,12 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
151157

152158
let mut regions = ty.regions();
153159
regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions
154-
bounds.push(
155-
VerifyBound::AllBounds(
156-
regions.into_iter().map(|r| VerifyBound::OutlivedBy(r)).collect()
157-
)
158-
);
160+
bounds.push(VerifyBound::AllBounds(
161+
regions
162+
.into_iter()
163+
.map(|r| VerifyBound::OutlivedBy(r))
164+
.collect(),
165+
));
159166

160167
// remove bounds that must hold, since they are not interesting
161168
bounds.retain(|b| !b.must_hold());
@@ -176,15 +183,15 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
176183
fn declared_generic_bounds_from_env(
177184
&self,
178185
generic: GenericKind<'tcx>,
179-
) -> Vec<ty::Region<'tcx>> {
186+
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
180187
let generic_ty = generic.to_ty(self.tcx);
181188
self.declared_generic_bounds_from_env_with_compare_fn(|ty| ty == generic_ty)
182189
}
183190

184191
fn declared_generic_bounds_from_env_with_compare_fn(
185192
&self,
186193
compare_ty: impl Fn(Ty<'tcx>) -> bool,
187-
) -> Vec<ty::Region<'tcx>> {
194+
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
188195
let tcx = self.tcx;
189196

190197
// To start, collect bounds from user environment. Note that
@@ -212,14 +219,23 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
212219
"declared_generic_bounds_from_env_with_compare_fn: region_bound_pair = {:?}",
213220
(r, p)
214221
);
215-
if compare_ty(p.to_ty(tcx)) {
216-
Some(r)
222+
let p_ty = p.to_ty(tcx);
223+
if compare_ty(p_ty) {
224+
Some(ty::OutlivesPredicate(p_ty, r))
217225
} else {
218226
None
219227
}
220228
});
221229

222-
param_bounds.chain(from_region_bound_pairs).collect()
230+
param_bounds
231+
.chain(from_region_bound_pairs)
232+
.inspect(|bound| {
233+
debug!(
234+
"declared_generic_bounds_from_env_with_compare_fn: result predicate = {:?}",
235+
bound
236+
)
237+
})
238+
.collect()
223239
}
224240

225241
/// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds
@@ -237,13 +253,11 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
237253
fn declared_projection_bounds_from_trait(
238254
&self,
239255
projection_ty: ty::ProjectionTy<'tcx>,
240-
) -> Vec<ty::Region<'tcx>> {
256+
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'gcx> {
241257
debug!("projection_bounds(projection_ty={:?})", projection_ty);
242-
let mut bounds = self.region_bounds_declared_on_associated_item(projection_ty.item_def_id);
243-
for r in &mut bounds {
244-
*r = r.subst(self.tcx, projection_ty.substs);
245-
}
246-
bounds
258+
let tcx = self.tcx;
259+
self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
260+
.map(move |r| r.subst(tcx, projection_ty.substs))
247261
}
248262

249263
/// Given the def-id of an associated item, returns any region
@@ -279,7 +293,7 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
279293
fn region_bounds_declared_on_associated_item(
280294
&self,
281295
assoc_item_def_id: DefId,
282-
) -> Vec<ty::Region<'tcx>> {
296+
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'gcx> {
283297
let tcx = self.tcx;
284298
let assoc_item = tcx.associated_item(assoc_item_def_id);
285299
let trait_def_id = assoc_item.container.assert_trait();
@@ -289,7 +303,7 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
289303
self.collect_outlives_from_predicate_list(
290304
move |ty| ty == identity_proj,
291305
traits::elaborate_predicates(tcx, trait_predicates.predicates),
292-
).collect()
306+
).map(|b| b.1)
293307
}
294308

295309
/// Searches through a predicate list for a predicate `T: 'a`.
@@ -302,12 +316,11 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
302316
&self,
303317
compare_ty: impl Fn(Ty<'tcx>) -> bool,
304318
predicates: impl IntoIterator<Item = impl AsRef<ty::Predicate<'tcx>>>,
305-
) -> impl Iterator<Item = ty::Region<'tcx>> {
319+
) -> impl Iterator<Item = ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
306320
predicates
307321
.into_iter()
308322
.filter_map(|p| p.as_ref().to_opt_type_outlives())
309323
.filter_map(|p| p.no_late_bound_regions())
310324
.filter(move |p| compare_ty(p.0))
311-
.map(|p| p.1)
312325
}
313326
}

0 commit comments

Comments
 (0)