Skip to content

Commit 526dc14

Browse files
committed
Use SmallVec for the queue in coerce_unsized.
This reduces the number of allocations done for the `tuple-stress` benchmark by 4%.
1 parent f99911a commit 526dc14

File tree

1 file changed

+20
-16
lines changed

1 file changed

+20
-16
lines changed

src/librustc_typeck/check/coercion.rs

+20-16
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
//! we may want to adjust precisely when coercions occur.
6262
6363
use check::{FnCtxt, Needs};
64-
64+
use errors::DiagnosticBuilder;
6565
use rustc::hir;
6666
use rustc::hir::def_id::DefId;
6767
use rustc::infer::{Coercion, InferResult, InferOk};
@@ -72,14 +72,12 @@ use rustc::ty::{self, TypeAndMut, Ty, ClosureSubsts};
7272
use rustc::ty::fold::TypeFoldable;
7373
use rustc::ty::error::TypeError;
7474
use rustc::ty::relate::RelateResult;
75-
use errors::DiagnosticBuilder;
75+
use smallvec::{smallvec, SmallVec};
76+
use std::ops::Deref;
7677
use syntax::feature_gate;
7778
use syntax::ptr::P;
7879
use syntax_pos;
7980

80-
use std::collections::VecDeque;
81-
use std::ops::Deref;
82-
8381
struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
8482
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
8583
cause: ObligationCause<'tcx>,
@@ -536,26 +534,32 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
536534

537535
let mut selcx = traits::SelectionContext::new(self);
538536

539-
// Use a FIFO queue for this custom fulfillment procedure. (The maximum
540-
// length is almost always 1.)
541-
let mut queue = VecDeque::with_capacity(1);
542-
543537
// Create an obligation for `Source: CoerceUnsized<Target>`.
544538
let cause = ObligationCause::misc(self.cause.span, self.body_id);
545-
queue.push_back(self.tcx.predicate_for_trait_def(self.fcx.param_env,
546-
cause,
547-
coerce_unsized_did,
548-
0,
549-
coerce_source,
550-
&[coerce_target.into()]));
539+
540+
// Use a FIFO queue for this custom fulfillment procedure.
541+
//
542+
// A Vec (or SmallVec) is not a natural choice for a queue. However,
543+
// this code path is hot, and this queue usually has a max length of 1
544+
// and almost never more than 3. By using a SmallVec we avoid an
545+
// allocation, at the (very small) cost of (occasionally) having to
546+
// shift subsequent elements down when removing the front element.
547+
let mut queue: SmallVec<[_; 4]> =
548+
smallvec![self.tcx.predicate_for_trait_def(self.fcx.param_env,
549+
cause,
550+
coerce_unsized_did,
551+
0,
552+
coerce_source,
553+
&[coerce_target.into()])];
551554

552555
let mut has_unsized_tuple_coercion = false;
553556

554557
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
555558
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
556559
// inference might unify those two inner type variables later.
557560
let traits = [coerce_unsized_did, unsize_did];
558-
while let Some(obligation) = queue.pop_front() {
561+
while !queue.is_empty() {
562+
let obligation = queue.remove(0);
559563
debug!("coerce_unsized resolve step: {:?}", obligation);
560564
let trait_ref = match obligation.predicate {
561565
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {

0 commit comments

Comments
 (0)