@@ -225,12 +225,14 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
225225 debug ! ( "project_and_unify_type(obligation={:?})" ,
226226 obligation) ;
227227
228- let Normalized { value : normalized_ty, mut obligations } =
228+ let mut obligations = vec ! [ ] ;
229+ let normalized_ty =
229230 match opt_normalize_projection_type ( selcx,
230231 obligation. param_env ,
231232 obligation. predicate . projection_ty ,
232233 obligation. cause . clone ( ) ,
233- obligation. recursion_depth ) {
234+ obligation. recursion_depth ,
235+ & mut obligations) {
234236 Some ( n) => n,
235237 None => return Ok ( None ) ,
236238 } ;
@@ -386,16 +388,15 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
386388 // binder). It would be better to normalize in a
387389 // binding-aware fashion.
388390
389- let Normalized { value : normalized_ty, obligations } =
390- normalize_projection_type ( self . selcx ,
391- self . param_env ,
392- data. clone ( ) ,
393- self . cause . clone ( ) ,
394- self . depth ) ;
395- debug ! ( "AssociatedTypeNormalizer: depth={} normalized {:?} to {:?} \
396- with {} add'l obligations",
397- self . depth, ty, normalized_ty, obligations. len( ) ) ;
398- self . obligations . extend ( obligations) ;
391+ let normalized_ty = normalize_projection_type ( self . selcx ,
392+ self . param_env ,
393+ data. clone ( ) ,
394+ self . cause . clone ( ) ,
395+ self . depth ,
396+ & mut self . obligations ) ;
397+ debug ! ( "AssociatedTypeNormalizer: depth={} normalized {:?} to {:?}, \
398+ now with {} obligations",
399+ self . depth, ty, normalized_ty, self . obligations. len( ) ) ;
399400 normalized_ty
400401 }
401402
@@ -471,10 +472,12 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
471472 param_env : ty:: ParamEnv < ' tcx > ,
472473 projection_ty : ty:: ProjectionTy < ' tcx > ,
473474 cause : ObligationCause < ' tcx > ,
474- depth : usize )
475- -> NormalizedTy < ' tcx >
475+ depth : usize ,
476+ obligations : & mut Vec < PredicateObligation < ' tcx > > )
477+ -> Ty < ' tcx >
476478{
477- opt_normalize_projection_type ( selcx, param_env, projection_ty. clone ( ) , cause. clone ( ) , depth)
479+ opt_normalize_projection_type ( selcx, param_env, projection_ty. clone ( ) , cause. clone ( ) , depth,
480+ obligations)
478481 . unwrap_or_else ( move || {
479482 // if we bottom out in ambiguity, create a type variable
480483 // and a deferred predicate to resolve this when more type
@@ -490,24 +493,29 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
490493 } ) ;
491494 let obligation = Obligation :: with_depth (
492495 cause, depth + 1 , param_env, projection. to_predicate ( ) ) ;
493- Normalized {
494- value : ty_var,
495- obligations : vec ! [ obligation]
496- }
496+ obligations. push ( obligation) ;
497+ ty_var
497498 } )
498499}
499500
500501/// The guts of `normalize`: normalize a specific projection like `<T
501502/// as Trait>::Item`. The result is always a type (and possibly
502503/// additional obligations). Returns `None` in the case of ambiguity,
503504/// which indicates that there are unbound type variables.
505+ ///
506+ /// This function used to return `Option<NormalizedTy<'tcx>>`, which contains a
507+ /// `Ty<'tcx>` and an obligations vector. But that obligation vector was very
508+ /// often immediately appended to another obligations vector. So now this
509+ /// function takes an obligations vector and appends to it directly, which is
510+ /// slightly uglier but avoids the need for an extra short-lived allocation.
504511fn opt_normalize_projection_type < ' a , ' b , ' gcx , ' tcx > (
505512 selcx : & ' a mut SelectionContext < ' b , ' gcx , ' tcx > ,
506513 param_env : ty:: ParamEnv < ' tcx > ,
507514 projection_ty : ty:: ProjectionTy < ' tcx > ,
508515 cause : ObligationCause < ' tcx > ,
509- depth : usize )
510- -> Option < NormalizedTy < ' tcx > >
516+ depth : usize ,
517+ obligations : & mut Vec < PredicateObligation < ' tcx > > )
518+ -> Option < Ty < ' tcx > >
511519{
512520 let infcx = selcx. infcx ( ) ;
513521
@@ -579,7 +587,9 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
579587 projection_ty) ;
580588 selcx. infcx ( ) . report_overflow_error ( & obligation, false ) ;
581589 }
582- Err ( ProjectionCacheEntry :: NormalizedTy ( mut ty) ) => {
590+ Err ( ProjectionCacheEntry :: NormalizedTy ( ty) ) => {
591+ // This is the hottest path in this function.
592+ //
583593 // If we find the value in the cache, then return it along
584594 // with the obligations that went along with it. Note
585595 // that, when using a fulfillment context, these
@@ -597,28 +607,31 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
597607 // can ignore the `obligations` from that point on.
598608 if !infcx. any_unresolved_type_vars ( & ty. value ) {
599609 infcx. projection_cache . borrow_mut ( ) . complete_normalized ( cache_key, & ty) ;
600- ty. obligations = vec ! [ ] ;
610+ // No need to extend `obligations`.
611+ } else {
612+ obligations. extend ( ty. obligations ) ;
601613 }
602614
603- push_paranoid_cache_value_obligation ( infcx,
604- param_env,
605- projection_ty,
606- cause,
607- depth,
608- & mut ty) ;
609-
610- return Some ( ty) ;
615+ obligations. push ( get_paranoid_cache_value_obligation ( infcx,
616+ param_env,
617+ projection_ty,
618+ cause,
619+ depth) ) ;
620+ return Some ( ty. value ) ;
611621 }
612622 Err ( ProjectionCacheEntry :: Error ) => {
613623 debug ! ( "opt_normalize_projection_type: \
614624 found error") ;
615- return Some ( normalize_to_error ( selcx, param_env, projection_ty, cause, depth) ) ;
625+ let result = normalize_to_error ( selcx, param_env, projection_ty, cause, depth) ;
626+ obligations. extend ( result. obligations ) ;
627+ return Some ( result. value )
616628 }
617629 }
618630
619631 let obligation = Obligation :: with_depth ( cause. clone ( ) , depth, param_env, projection_ty) ;
620632 match project_type ( selcx, & obligation) {
621- Ok ( ProjectedTy :: Progress ( Progress { ty : projected_ty, mut obligations } ) ) => {
633+ Ok ( ProjectedTy :: Progress ( Progress { ty : projected_ty,
634+ obligations : mut projected_obligations } ) ) => {
622635 // if projection succeeded, then what we get out of this
623636 // is also non-normalized (consider: it was derived from
624637 // an impl, where-clause etc) and hence we must
@@ -627,10 +640,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
627640 debug ! ( "opt_normalize_projection_type: \
628641 projected_ty={:?} \
629642 depth={} \
630- obligations ={:?}",
643+ projected_obligations ={:?}",
631644 projected_ty,
632645 depth,
633- obligations ) ;
646+ projected_obligations ) ;
634647
635648 let result = if projected_ty. has_projections ( ) {
636649 let mut normalizer = AssociatedTypeNormalizer :: new ( selcx,
@@ -644,22 +657,22 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
644657 normalized_ty,
645658 depth) ;
646659
647- obligations . extend ( normalizer. obligations ) ;
660+ projected_obligations . extend ( normalizer. obligations ) ;
648661 Normalized {
649662 value : normalized_ty,
650- obligations,
663+ obligations : projected_obligations ,
651664 }
652665 } else {
653666 Normalized {
654667 value : projected_ty,
655- obligations,
668+ obligations : projected_obligations ,
656669 }
657670 } ;
658671
659672 let cache_value = prune_cache_value_obligations ( infcx, & result) ;
660673 infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, cache_value) ;
661-
662- Some ( result)
674+ obligations . extend ( result . obligations ) ;
675+ Some ( result. value )
663676 }
664677 Ok ( ProjectedTy :: NoProgress ( projected_ty) ) => {
665678 debug ! ( "opt_normalize_projection_type: \
@@ -670,7 +683,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
670683 obligations : vec ! [ ]
671684 } ;
672685 infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, result. clone ( ) ) ;
673- Some ( result)
686+ // No need to extend `obligations`.
687+ Some ( result. value )
674688 }
675689 Err ( ProjectionTyError :: TooManyCandidates ) => {
676690 debug ! ( "opt_normalize_projection_type: \
@@ -688,7 +702,9 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
688702
689703 infcx. projection_cache . borrow_mut ( )
690704 . error ( cache_key) ;
691- Some ( normalize_to_error ( selcx, param_env, projection_ty, cause, depth) )
705+ let result = normalize_to_error ( selcx, param_env, projection_ty, cause, depth) ;
706+ obligations. extend ( result. obligations ) ;
707+ Some ( result. value )
692708 }
693709 }
694710}
@@ -737,7 +753,7 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx,
737753/// may or may not be necessary -- in principle, all the obligations
738754/// that must be proven to show that `T: Trait` were also returned
739755/// when the cache was first populated. But there are some vague concerns,
740- /// and so we take the precatuionary measure of including `T: Trait` in
756+ /// and so we take the precautionary measure of including `T: Trait` in
741757/// the result:
742758///
743759/// Concern #1. The current setup is fragile. Perhaps someone could
@@ -754,19 +770,21 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx,
754770/// that may yet turn out to be wrong. This *may* lead to some sort
755771/// of trouble, though we don't have a concrete example of how that
756772/// can occur yet. But it seems risky at best.
757- fn push_paranoid_cache_value_obligation < ' a , ' gcx , ' tcx > ( infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
758- param_env : ty:: ParamEnv < ' tcx > ,
759- projection_ty : ty:: ProjectionTy < ' tcx > ,
760- cause : ObligationCause < ' tcx > ,
761- depth : usize ,
762- result : & mut NormalizedTy < ' tcx > )
773+ fn get_paranoid_cache_value_obligation < ' a , ' gcx , ' tcx > (
774+ infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
775+ param_env : ty:: ParamEnv < ' tcx > ,
776+ projection_ty : ty:: ProjectionTy < ' tcx > ,
777+ cause : ObligationCause < ' tcx > ,
778+ depth : usize )
779+ -> PredicateObligation < ' tcx >
763780{
764781 let trait_ref = projection_ty. trait_ref ( infcx. tcx ) . to_poly_trait_ref ( ) ;
765- let trait_obligation = Obligation { cause,
766- recursion_depth : depth,
767- param_env,
768- predicate : trait_ref. to_predicate ( ) } ;
769- result. obligations . push ( trait_obligation) ;
782+ Obligation {
783+ cause,
784+ recursion_depth : depth,
785+ param_env,
786+ predicate : trait_ref. to_predicate ( ) ,
787+ }
770788}
771789
772790/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
0 commit comments