61
61
//! we may want to adjust precisely when coercions occur.
62
62
63
63
use check:: { FnCtxt , Needs } ;
64
-
64
+ use errors :: DiagnosticBuilder ;
65
65
use rustc:: hir;
66
66
use rustc:: hir:: def_id:: DefId ;
67
67
use rustc:: infer:: { Coercion , InferResult , InferOk } ;
@@ -72,14 +72,12 @@ use rustc::ty::{self, TypeAndMut, Ty, ClosureSubsts};
72
72
use rustc:: ty:: fold:: TypeFoldable ;
73
73
use rustc:: ty:: error:: TypeError ;
74
74
use rustc:: ty:: relate:: RelateResult ;
75
- use errors:: DiagnosticBuilder ;
75
+ use smallvec:: { smallvec, SmallVec } ;
76
+ use std:: ops:: Deref ;
76
77
use syntax:: feature_gate;
77
78
use syntax:: ptr:: P ;
78
79
use syntax_pos;
79
80
80
- use std:: collections:: VecDeque ;
81
- use std:: ops:: Deref ;
82
-
83
81
struct Coerce < ' a , ' gcx : ' a + ' tcx , ' tcx : ' a > {
84
82
fcx : & ' a FnCtxt < ' a , ' gcx , ' tcx > ,
85
83
cause : ObligationCause < ' tcx > ,
@@ -536,26 +534,32 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
536
534
537
535
let mut selcx = traits:: SelectionContext :: new ( self ) ;
538
536
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
-
543
537
// Create an obligation for `Source: CoerceUnsized<Target>`.
544
538
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( ) ] ) ] ;
551
554
552
555
let mut has_unsized_tuple_coercion = false ;
553
556
554
557
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
555
558
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
556
559
// inference might unify those two inner type variables later.
557
560
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 ) ;
559
563
debug ! ( "coerce_unsized resolve step: {:?}" , obligation) ;
560
564
let trait_ref = match obligation. predicate {
561
565
ty:: Predicate :: Trait ( ref tr) if traits. contains ( & tr. def_id ( ) ) => {
0 commit comments