@@ -225,12 +225,14 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
225
225
debug ! ( "project_and_unify_type(obligation={:?})" ,
226
226
obligation) ;
227
227
228
- let Normalized { value : normalized_ty, mut obligations } =
228
+ let mut obligations = vec ! [ ] ;
229
+ let normalized_ty =
229
230
match opt_normalize_projection_type ( selcx,
230
231
obligation. param_env ,
231
232
obligation. predicate . projection_ty ,
232
233
obligation. cause . clone ( ) ,
233
- obligation. recursion_depth ) {
234
+ obligation. recursion_depth ,
235
+ & mut obligations) {
234
236
Some ( n) => n,
235
237
None => return Ok ( None ) ,
236
238
} ;
@@ -386,16 +388,15 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
386
388
// binder). It would be better to normalize in a
387
389
// binding-aware fashion.
388
390
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( ) ) ;
399
400
normalized_ty
400
401
}
401
402
@@ -471,10 +472,12 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
471
472
param_env : ty:: ParamEnv < ' tcx > ,
472
473
projection_ty : ty:: ProjectionTy < ' tcx > ,
473
474
cause : ObligationCause < ' tcx > ,
474
- depth : usize )
475
- -> NormalizedTy < ' tcx >
475
+ depth : usize ,
476
+ obligations : & mut Vec < PredicateObligation < ' tcx > > )
477
+ -> Ty < ' tcx >
476
478
{
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)
478
481
. unwrap_or_else ( move || {
479
482
// if we bottom out in ambiguity, create a type variable
480
483
// and a deferred predicate to resolve this when more type
@@ -490,24 +493,29 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
490
493
} ) ;
491
494
let obligation = Obligation :: with_depth (
492
495
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
497
498
} )
498
499
}
499
500
500
501
/// The guts of `normalize`: normalize a specific projection like `<T
501
502
/// as Trait>::Item`. The result is always a type (and possibly
502
503
/// additional obligations). Returns `None` in the case of ambiguity,
503
504
/// 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.
504
511
fn opt_normalize_projection_type < ' a , ' b , ' gcx , ' tcx > (
505
512
selcx : & ' a mut SelectionContext < ' b , ' gcx , ' tcx > ,
506
513
param_env : ty:: ParamEnv < ' tcx > ,
507
514
projection_ty : ty:: ProjectionTy < ' tcx > ,
508
515
cause : ObligationCause < ' tcx > ,
509
- depth : usize )
510
- -> Option < NormalizedTy < ' tcx > >
516
+ depth : usize ,
517
+ obligations : & mut Vec < PredicateObligation < ' tcx > > )
518
+ -> Option < Ty < ' tcx > >
511
519
{
512
520
let infcx = selcx. infcx ( ) ;
513
521
@@ -579,7 +587,9 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
579
587
projection_ty) ;
580
588
selcx. infcx ( ) . report_overflow_error ( & obligation, false ) ;
581
589
}
582
- Err ( ProjectionCacheEntry :: NormalizedTy ( mut ty) ) => {
590
+ Err ( ProjectionCacheEntry :: NormalizedTy ( ty) ) => {
591
+ // This is the hottest path in this function.
592
+ //
583
593
// If we find the value in the cache, then return it along
584
594
// with the obligations that went along with it. Note
585
595
// that, when using a fulfillment context, these
@@ -597,28 +607,31 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
597
607
// can ignore the `obligations` from that point on.
598
608
if !infcx. any_unresolved_type_vars ( & ty. value ) {
599
609
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 ) ;
601
613
}
602
614
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 ) ;
611
621
}
612
622
Err ( ProjectionCacheEntry :: Error ) => {
613
623
debug ! ( "opt_normalize_projection_type: \
614
624
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 )
616
628
}
617
629
}
618
630
619
631
let obligation = Obligation :: with_depth ( cause. clone ( ) , depth, param_env, projection_ty) ;
620
632
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 } ) ) => {
622
635
// if projection succeeded, then what we get out of this
623
636
// is also non-normalized (consider: it was derived from
624
637
// an impl, where-clause etc) and hence we must
@@ -627,10 +640,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
627
640
debug ! ( "opt_normalize_projection_type: \
628
641
projected_ty={:?} \
629
642
depth={} \
630
- obligations ={:?}",
643
+ projected_obligations ={:?}",
631
644
projected_ty,
632
645
depth,
633
- obligations ) ;
646
+ projected_obligations ) ;
634
647
635
648
let result = if projected_ty. has_projections ( ) {
636
649
let mut normalizer = AssociatedTypeNormalizer :: new ( selcx,
@@ -644,22 +657,22 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
644
657
normalized_ty,
645
658
depth) ;
646
659
647
- obligations . extend ( normalizer. obligations ) ;
660
+ projected_obligations . extend ( normalizer. obligations ) ;
648
661
Normalized {
649
662
value : normalized_ty,
650
- obligations,
663
+ obligations : projected_obligations ,
651
664
}
652
665
} else {
653
666
Normalized {
654
667
value : projected_ty,
655
- obligations,
668
+ obligations : projected_obligations ,
656
669
}
657
670
} ;
658
671
659
672
let cache_value = prune_cache_value_obligations ( infcx, & result) ;
660
673
infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, cache_value) ;
661
-
662
- Some ( result)
674
+ obligations . extend ( result . obligations ) ;
675
+ Some ( result. value )
663
676
}
664
677
Ok ( ProjectedTy :: NoProgress ( projected_ty) ) => {
665
678
debug ! ( "opt_normalize_projection_type: \
@@ -670,7 +683,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
670
683
obligations : vec ! [ ]
671
684
} ;
672
685
infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, result. clone ( ) ) ;
673
- Some ( result)
686
+ // No need to extend `obligations`.
687
+ Some ( result. value )
674
688
}
675
689
Err ( ProjectionTyError :: TooManyCandidates ) => {
676
690
debug ! ( "opt_normalize_projection_type: \
@@ -688,7 +702,9 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
688
702
689
703
infcx. projection_cache . borrow_mut ( )
690
704
. 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 )
692
708
}
693
709
}
694
710
}
@@ -737,7 +753,7 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx,
737
753
/// may or may not be necessary -- in principle, all the obligations
738
754
/// that must be proven to show that `T: Trait` were also returned
739
755
/// 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
741
757
/// the result:
742
758
///
743
759
/// 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,
754
770
/// that may yet turn out to be wrong. This *may* lead to some sort
755
771
/// of trouble, though we don't have a concrete example of how that
756
772
/// 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 >
763
780
{
764
781
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
+ }
770
788
}
771
789
772
790
/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
0 commit comments