6161//! we may want to adjust precisely when coercions occur.
6262
6363use check:: { FnCtxt , Needs } ;
64-
64+ use errors :: DiagnosticBuilder ;
6565use rustc:: hir;
6666use rustc:: hir:: def_id:: DefId ;
6767use rustc:: infer:: { Coercion , InferResult , InferOk } ;
@@ -72,14 +72,12 @@ use rustc::ty::{self, TypeAndMut, Ty, ClosureSubsts};
7272use rustc:: ty:: fold:: TypeFoldable ;
7373use rustc:: ty:: error:: TypeError ;
7474use rustc:: ty:: relate:: RelateResult ;
75- use errors:: DiagnosticBuilder ;
75+ use smallvec:: { smallvec, SmallVec } ;
76+ use std:: ops:: Deref ;
7677use syntax:: feature_gate;
7778use syntax:: ptr:: P ;
7879use syntax_pos;
7980
80- use std:: collections:: VecDeque ;
81- use std:: ops:: Deref ;
82-
8381struct 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