Skip to content

Commit 51b891a

Browse files
MarwesMarkus Westerlind
authored and
Markus Westerlind
committed
Reduce Vec allocations in normalization by passing &mut Vec
1 parent 1f8df25 commit 51b891a

File tree

4 files changed

+100
-61
lines changed

4 files changed

+100
-61
lines changed

Diff for: src/librustc/traits/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ pub use self::object_safety::MethodViolationCode;
5050
pub use self::object_safety::ObjectSafetyViolation;
5151
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
5252
pub use self::project::MismatchedProjectionTypes;
53-
pub use self::project::{normalize, normalize_projection_type, poly_project_and_unify_type};
53+
pub use self::project::{
54+
normalize, normalize_projection_type, normalize_to, poly_project_and_unify_type,
55+
};
5456
pub use self::project::{Normalized, ProjectionCache, ProjectionCacheSnapshot};
5557
pub use self::select::{IntercrateAmbiguityCause, SelectionContext};
5658
pub use self::specialize::find_associated_item;

Diff for: src/librustc/traits/project.rs

+59-22
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,22 @@ pub fn normalize<'a, 'b, 'tcx, T>(
216216
where
217217
T: TypeFoldable<'tcx>,
218218
{
219-
normalize_with_depth(selcx, param_env, cause, 0, value)
219+
let mut obligations = Vec::new();
220+
let value = normalize_to(selcx, param_env, cause, value, &mut obligations);
221+
Normalized { value, obligations }
222+
}
223+
224+
pub fn normalize_to<'a, 'b, 'tcx, T>(
225+
selcx: &'a mut SelectionContext<'b, 'tcx>,
226+
param_env: ty::ParamEnv<'tcx>,
227+
cause: ObligationCause<'tcx>,
228+
value: &T,
229+
obligations: &mut Vec<PredicateObligation<'tcx>>,
230+
) -> T
231+
where
232+
T: TypeFoldable<'tcx>,
233+
{
234+
normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations)
220235
}
221236

222237
/// As `normalize`, but with a custom depth.
@@ -227,11 +242,27 @@ pub fn normalize_with_depth<'a, 'b, 'tcx, T>(
227242
depth: usize,
228243
value: &T,
229244
) -> Normalized<'tcx, T>
245+
where
246+
T: TypeFoldable<'tcx>,
247+
{
248+
let mut obligations = Vec::new();
249+
let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations);
250+
Normalized { value, obligations }
251+
}
252+
253+
pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
254+
selcx: &'a mut SelectionContext<'b, 'tcx>,
255+
param_env: ty::ParamEnv<'tcx>,
256+
cause: ObligationCause<'tcx>,
257+
depth: usize,
258+
value: &T,
259+
obligations: &mut Vec<PredicateObligation<'tcx>>,
260+
) -> T
230261
where
231262
T: TypeFoldable<'tcx>,
232263
{
233264
debug!("normalize_with_depth(depth={}, value={:?})", depth, value);
234-
let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth);
265+
let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
235266
let result = normalizer.fold(value);
236267
debug!(
237268
"normalize_with_depth: depth={} result={:?} with {} obligations",
@@ -240,14 +271,14 @@ where
240271
normalizer.obligations.len()
241272
);
242273
debug!("normalize_with_depth: depth={} obligations={:?}", depth, normalizer.obligations);
243-
Normalized { value: result, obligations: normalizer.obligations }
274+
result
244275
}
245276

246277
struct AssocTypeNormalizer<'a, 'b, 'tcx> {
247278
selcx: &'a mut SelectionContext<'b, 'tcx>,
248279
param_env: ty::ParamEnv<'tcx>,
249280
cause: ObligationCause<'tcx>,
250-
obligations: Vec<PredicateObligation<'tcx>>,
281+
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
251282
depth: usize,
252283
}
253284

@@ -257,8 +288,9 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
257288
param_env: ty::ParamEnv<'tcx>,
258289
cause: ObligationCause<'tcx>,
259290
depth: usize,
291+
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
260292
) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
261-
AssocTypeNormalizer { selcx, param_env, cause, obligations: vec![], depth }
293+
AssocTypeNormalizer { selcx, param_env, cause, obligations, depth }
262294
}
263295

264296
fn fold<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
@@ -343,7 +375,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
343375
);
344376
debug!(
345377
"AssocTypeNormalizer: depth={} normalized {:?} to {:?}, \
346-
now with {} obligations",
378+
now with {} obligations",
347379
self.depth,
348380
ty,
349381
normalized_ty,
@@ -441,8 +473,8 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
441473

442474
debug!(
443475
"opt_normalize_projection_type(\
444-
projection_ty={:?}, \
445-
depth={})",
476+
projection_ty={:?}, \
477+
depth={})",
446478
projection_ty, depth
447479
);
448480

@@ -469,7 +501,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
469501
// changes
470502
debug!(
471503
"opt_normalize_projection_type: \
472-
found cache entry: ambiguous"
504+
found cache entry: ambiguous"
473505
);
474506
if !projection_ty.has_closure_types() {
475507
return None;
@@ -498,7 +530,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
498530

499531
debug!(
500532
"opt_normalize_projection_type: \
501-
found cache entry: in-progress"
533+
found cache entry: in-progress"
502534
);
503535

504536
// But for now, let's classify this as an overflow:
@@ -521,7 +553,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
521553
// evaluations can causes ICEs (e.g., #43132).
522554
debug!(
523555
"opt_normalize_projection_type: \
524-
found normalized ty `{:?}`",
556+
found normalized ty `{:?}`",
525557
ty
526558
);
527559

@@ -546,7 +578,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
546578
Err(ProjectionCacheEntry::Error) => {
547579
debug!(
548580
"opt_normalize_projection_type: \
549-
found error"
581+
found error"
550582
);
551583
let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
552584
obligations.extend(result.obligations);
@@ -567,23 +599,28 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
567599

568600
debug!(
569601
"opt_normalize_projection_type: \
570-
projected_ty={:?} \
571-
depth={} \
572-
projected_obligations={:?}",
602+
projected_ty={:?} \
603+
depth={} \
604+
projected_obligations={:?}",
573605
projected_ty, depth, projected_obligations
574606
);
575607

576608
let result = if projected_ty.has_projections() {
577-
let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth + 1);
609+
let mut normalizer = AssocTypeNormalizer::new(
610+
selcx,
611+
param_env,
612+
cause,
613+
depth + 1,
614+
&mut projected_obligations,
615+
);
578616
let normalized_ty = normalizer.fold(&projected_ty);
579617

580618
debug!(
581619
"opt_normalize_projection_type: \
582-
normalized_ty={:?} depth={}",
620+
normalized_ty={:?} depth={}",
583621
normalized_ty, depth
584622
);
585623

586-
projected_obligations.extend(normalizer.obligations);
587624
Normalized { value: normalized_ty, obligations: projected_obligations }
588625
} else {
589626
Normalized { value: projected_ty, obligations: projected_obligations }
@@ -597,7 +634,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
597634
Ok(ProjectedTy::NoProgress(projected_ty)) => {
598635
debug!(
599636
"opt_normalize_projection_type: \
600-
projected_ty={:?} no progress",
637+
projected_ty={:?} no progress",
601638
projected_ty
602639
);
603640
let result = Normalized { value: projected_ty, obligations: vec![] };
@@ -608,7 +645,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
608645
Err(ProjectionTyError::TooManyCandidates) => {
609646
debug!(
610647
"opt_normalize_projection_type: \
611-
too many candidates"
648+
too many candidates"
612649
);
613650
infcx.projection_cache.borrow_mut().ambiguous(cache_key);
614651
None
@@ -930,7 +967,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx, I>(
930967

931968
debug!(
932969
"assemble_candidates_from_predicates: candidate={:?} \
933-
is_match={} same_def_id={}",
970+
is_match={} same_def_id={}",
934971
data, is_match, same_def_id
935972
);
936973

@@ -1192,7 +1229,7 @@ fn confirm_object_candidate<'cx, 'tcx>(
11921229
None => {
11931230
debug!(
11941231
"confirm_object_candidate: no env-predicate \
1195-
found in object type `{:?}`; ill-formed",
1232+
found in object type `{:?}`; ill-formed",
11961233
object_ty
11971234
);
11981235
return Progress::error(selcx.tcx());

Diff for: src/librustc/traits/select.rs

+28-28
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ use self::SelectionCandidate::*;
99

1010
use super::coherence::{self, Conflict};
1111
use super::project;
12-
use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey};
12+
use super::project::{
13+
normalize_with_depth, normalize_with_depth_to, Normalized, ProjectionCacheKey,
14+
};
1315
use super::util;
1416
use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
1517
use super::wf;
@@ -1019,7 +1021,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10191021
if let Some(value) = value {
10201022
debug!(
10211023
"filter_negative_and_reservation_impls: \
1022-
reservation impl ambiguity on {:?}",
1024+
reservation impl ambiguity on {:?}",
10231025
def_id
10241026
);
10251027
intercrate_ambiguity_clauses.push(
@@ -1317,7 +1319,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13171319
if !self.can_cache_candidate(&candidate) {
13181320
debug!(
13191321
"insert_candidate_cache(trait_ref={:?}, candidate={:?} -\
1320-
candidate is not cacheable",
1322+
candidate is not cacheable",
13211323
trait_ref, candidate
13221324
);
13231325
return;
@@ -3484,25 +3486,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
34843486
// that order.
34853487
let predicates = tcx.predicates_of(def_id);
34863488
assert_eq!(predicates.parent, None);
3487-
let mut predicates: Vec<_> = predicates
3488-
.predicates
3489-
.iter()
3490-
.flat_map(|(predicate, _)| {
3491-
let predicate = normalize_with_depth(
3492-
self,
3493-
param_env,
3494-
cause.clone(),
3495-
recursion_depth,
3496-
&predicate.subst(tcx, substs),
3497-
);
3498-
predicate.obligations.into_iter().chain(Some(Obligation {
3499-
cause: cause.clone(),
3500-
recursion_depth,
3501-
param_env,
3502-
predicate: predicate.value,
3503-
}))
3504-
})
3505-
.collect();
3489+
let mut obligations = Vec::new();
3490+
for (predicate, _) in predicates.predicates {
3491+
let predicate = normalize_with_depth_to(
3492+
self,
3493+
param_env,
3494+
cause.clone(),
3495+
recursion_depth,
3496+
&predicate.subst(tcx, substs),
3497+
&mut obligations,
3498+
);
3499+
obligations.push(Obligation {
3500+
cause: cause.clone(),
3501+
recursion_depth,
3502+
param_env,
3503+
predicate,
3504+
});
3505+
}
35063506

35073507
// We are performing deduplication here to avoid exponential blowups
35083508
// (#38528) from happening, but the real cause of the duplication is
@@ -3513,20 +3513,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
35133513
// This code is hot enough that it's worth avoiding the allocation
35143514
// required for the FxHashSet when possible. Special-casing lengths 0,
35153515
// 1 and 2 covers roughly 75-80% of the cases.
3516-
if predicates.len() <= 1 {
3516+
if obligations.len() <= 1 {
35173517
// No possibility of duplicates.
3518-
} else if predicates.len() == 2 {
3518+
} else if obligations.len() == 2 {
35193519
// Only two elements. Drop the second if they are equal.
3520-
if predicates[0] == predicates[1] {
3521-
predicates.truncate(1);
3520+
if obligations[0] == obligations[1] {
3521+
obligations.truncate(1);
35223522
}
35233523
} else {
35243524
// Three or more elements. Use a general deduplication process.
35253525
let mut seen = FxHashSet::default();
3526-
predicates.retain(|i| seen.insert(i.clone()));
3526+
obligations.retain(|i| seen.insert(i.clone()));
35273527
}
35283528

3529-
predicates
3529+
obligations
35303530
}
35313531
}
35323532

Diff for: src/librustc/traits/wf.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use rustc_hir as hir;
88
use rustc_hir::def_id::DefId;
99
use rustc_span::symbol::{kw, Ident};
1010
use rustc_span::Span;
11-
use std::iter::once;
1211

1312
/// Returns the set of obligations needed to make `ty` well-formed.
1413
/// If `ty` contains unresolved inference variables, this may include
@@ -26,6 +25,7 @@ pub fn obligations<'a, 'tcx>(
2625
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
2726
if wf.compute(ty) {
2827
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
28+
2929
let result = wf.normalize();
3030
debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result);
3131
Some(result)
@@ -143,15 +143,15 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
143143
let cause = self.cause(traits::MiscObligation);
144144
let infcx = &mut self.infcx;
145145
let param_env = self.param_env;
146-
self.out
147-
.iter()
148-
.inspect(|pred| assert!(!pred.has_escaping_bound_vars()))
149-
.flat_map(|pred| {
150-
let mut selcx = traits::SelectionContext::new(infcx);
151-
let pred = traits::normalize(&mut selcx, param_env, cause.clone(), pred);
152-
once(pred.value).chain(pred.obligations)
153-
})
154-
.collect()
146+
let mut obligations = Vec::new();
147+
self.out.iter().inspect(|pred| assert!(!pred.has_escaping_bound_vars())).for_each(|pred| {
148+
let mut selcx = traits::SelectionContext::new(infcx);
149+
let i = obligations.len();
150+
let value =
151+
traits::normalize_to(&mut selcx, param_env, cause.clone(), pred, &mut obligations);
152+
obligations.insert(i, value);
153+
});
154+
obligations
155155
}
156156

157157
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.

0 commit comments

Comments
 (0)