@@ -29,6 +29,8 @@ use rustc_middle::ty::subst::Subst;
2929use rustc_middle:: ty:: { self , ToPolyTraitRef , ToPredicate , Ty , TyCtxt , WithConstness } ;
3030use rustc_span:: symbol:: sym;
3131
32+ use std:: collections:: BTreeMap ;
33+
3234pub use rustc_middle:: traits:: Reveal ;
3335
3436pub type PolyProjectionObligation < ' tcx > = Obligation < ' tcx , ty:: PolyProjectionPredicate < ' tcx > > ;
@@ -296,6 +298,7 @@ struct AssocTypeNormalizer<'a, 'b, 'tcx> {
296298 cause : ObligationCause < ' tcx > ,
297299 obligations : & ' a mut Vec < PredicateObligation < ' tcx > > ,
298300 depth : usize ,
301+ universes : Vec < Option < ty:: UniverseIndex > > ,
299302}
300303
301304impl < ' a , ' b , ' tcx > AssocTypeNormalizer < ' a , ' b , ' tcx > {
@@ -306,12 +309,18 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
306309 depth : usize ,
307310 obligations : & ' a mut Vec < PredicateObligation < ' tcx > > ,
308311 ) -> AssocTypeNormalizer < ' a , ' b , ' tcx > {
309- AssocTypeNormalizer { selcx, param_env, cause, obligations, depth }
312+ AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes : vec ! [ ] }
310313 }
311314
312315 fn fold < T : TypeFoldable < ' tcx > > ( & mut self , value : T ) -> T {
313316 let value = self . selcx . infcx ( ) . resolve_vars_if_possible ( value) ;
314317
318+ assert ! (
319+ !value. has_escaping_bound_vars( ) ,
320+ "Normalizing {:?} without wrapping in a `Binder`" ,
321+ value
322+ ) ;
323+
315324 if !value. has_projections ( ) { value } else { value. fold_with ( self ) }
316325 }
317326}
@@ -321,6 +330,16 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
321330 self . selcx . tcx ( )
322331 }
323332
333+ fn fold_binder < T : TypeFoldable < ' tcx > > (
334+ & mut self ,
335+ t : ty:: Binder < ' tcx , T > ,
336+ ) -> ty:: Binder < ' tcx , T > {
337+ self . universes . push ( None ) ;
338+ let t = t. super_fold_with ( self ) ;
339+ self . universes . pop ( ) ;
340+ t
341+ }
342+
324343 fn fold_ty ( & mut self , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
325344 if !ty. has_projections ( ) {
326345 return ty;
@@ -396,6 +415,52 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
396415 normalized_ty
397416 }
398417
418+ ty:: Projection ( data) if !data. trait_ref ( self . tcx ( ) ) . has_escaping_bound_vars ( ) => {
419+ // Okay, so you thought the previous branch was hacky. Well, to
420+ // extend upon this, when the *trait ref* doesn't have escaping
421+ // bound vars, but the associated item *does* (can only occur
422+ // with GATs), then we might still be able to project the type.
423+ // For this, we temporarily replace the bound vars with
424+ // placeholders. Note though, that in the case that we still
425+ // can't project for whatever reason (e.g. self type isn't
426+ // known enough), we *can't* register an obligation and return
427+ // an inference variable (since then that obligation would have
428+ // bound vars and that's a can of worms). Instead, we just
429+ // give up and fall back to pretending like we never tried!
430+
431+ let infcx = self . selcx . infcx ( ) ;
432+ let ( data, mapped_regions, mapped_types, mapped_consts) =
433+ BoundVarReplacer :: replace_bound_vars ( infcx, & mut self . universes , data) ;
434+ let normalized_ty = opt_normalize_projection_type (
435+ self . selcx ,
436+ self . param_env ,
437+ data,
438+ self . cause . clone ( ) ,
439+ self . depth ,
440+ & mut self . obligations ,
441+ )
442+ . ok ( )
443+ . flatten ( )
444+ . unwrap_or_else ( || ty) ;
445+
446+ let normalized_ty = PlaceholderReplacer :: replace_placeholders (
447+ infcx,
448+ mapped_regions,
449+ mapped_types,
450+ mapped_consts,
451+ & self . universes ,
452+ normalized_ty,
453+ ) ;
454+ debug ! (
455+ ?self . depth,
456+ ?ty,
457+ ?normalized_ty,
458+ obligations. len = ?self . obligations. len( ) ,
459+ "AssocTypeNormalizer: normalized type"
460+ ) ;
461+ normalized_ty
462+ }
463+
399464 _ => ty,
400465 }
401466 }
@@ -410,6 +475,279 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
410475 }
411476}
412477
478+ pub struct BoundVarReplacer < ' me , ' tcx > {
479+ infcx : & ' me InferCtxt < ' me , ' tcx > ,
480+ // These three maps track the bound variable that were replaced by placeholders. It might be
481+ // nice to remove these since we already have the `kind` in the placeholder; we really just need
482+ // the `var` (but we *could* bring that into scope if we were to track them as we pass them).
483+ mapped_regions : BTreeMap < ty:: PlaceholderRegion , ty:: BoundRegion > ,
484+ mapped_types : BTreeMap < ty:: PlaceholderType , ty:: BoundTy > ,
485+ mapped_consts : BTreeMap < ty:: PlaceholderConst < ' tcx > , ty:: BoundVar > ,
486+ // The current depth relative to *this* folding, *not* the entire normalization. In other words,
487+ // the depth of binders we've passed here.
488+ current_index : ty:: DebruijnIndex ,
489+ // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy:
490+ // we don't actually create a universe until we see a bound var we have to replace.
491+ universe_indices : & ' me mut Vec < Option < ty:: UniverseIndex > > ,
492+ }
493+
494+ impl < ' me , ' tcx > BoundVarReplacer < ' me , ' tcx > {
495+ /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
496+ /// use a binding level above `universe_indices.len()`, we fail.
497+ pub fn replace_bound_vars < T : TypeFoldable < ' tcx > > (
498+ infcx : & ' me InferCtxt < ' me , ' tcx > ,
499+ universe_indices : & ' me mut Vec < Option < ty:: UniverseIndex > > ,
500+ value : T ,
501+ ) -> (
502+ T ,
503+ BTreeMap < ty:: PlaceholderRegion , ty:: BoundRegion > ,
504+ BTreeMap < ty:: PlaceholderType , ty:: BoundTy > ,
505+ BTreeMap < ty:: PlaceholderConst < ' tcx > , ty:: BoundVar > ,
506+ ) {
507+ let mapped_regions: BTreeMap < ty:: PlaceholderRegion , ty:: BoundRegion > = BTreeMap :: new ( ) ;
508+ let mapped_types: BTreeMap < ty:: PlaceholderType , ty:: BoundTy > = BTreeMap :: new ( ) ;
509+ let mapped_consts: BTreeMap < ty:: PlaceholderConst < ' tcx > , ty:: BoundVar > = BTreeMap :: new ( ) ;
510+
511+ let mut replacer = BoundVarReplacer {
512+ infcx,
513+ mapped_regions,
514+ mapped_types,
515+ mapped_consts,
516+ current_index : ty:: INNERMOST ,
517+ universe_indices,
518+ } ;
519+
520+ let value = value. super_fold_with ( & mut replacer) ;
521+
522+ ( value, replacer. mapped_regions , replacer. mapped_types , replacer. mapped_consts )
523+ }
524+
525+ fn universe_for ( & mut self , debruijn : ty:: DebruijnIndex ) -> ty:: UniverseIndex {
526+ let infcx = self . infcx ;
527+ let index =
528+ self . universe_indices . len ( ) - debruijn. as_usize ( ) + self . current_index . as_usize ( ) - 1 ;
529+ let universe = self . universe_indices [ index] . unwrap_or_else ( || {
530+ for i in self . universe_indices . iter_mut ( ) . take ( index + 1 ) {
531+ * i = i. or_else ( || Some ( infcx. create_next_universe ( ) ) )
532+ }
533+ self . universe_indices [ index] . unwrap ( )
534+ } ) ;
535+ universe
536+ }
537+ }
538+
539+ impl TypeFolder < ' tcx > for BoundVarReplacer < ' _ , ' tcx > {
540+ fn tcx < ' b > ( & ' b self ) -> TyCtxt < ' tcx > {
541+ self . infcx . tcx
542+ }
543+
544+ fn fold_binder < T : TypeFoldable < ' tcx > > (
545+ & mut self ,
546+ t : ty:: Binder < ' tcx , T > ,
547+ ) -> ty:: Binder < ' tcx , T > {
548+ self . current_index . shift_in ( 1 ) ;
549+ let t = t. super_fold_with ( self ) ;
550+ self . current_index . shift_out ( 1 ) ;
551+ t
552+ }
553+
554+ fn fold_region ( & mut self , r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
555+ match * r {
556+ ty:: ReLateBound ( debruijn, _)
557+ if debruijn. as_usize ( ) + 1
558+ > self . current_index . as_usize ( ) + self . universe_indices . len ( ) =>
559+ {
560+ bug ! ( "Bound vars outside of `self.universe_indices`" ) ;
561+ }
562+ ty:: ReLateBound ( debruijn, br) if debruijn >= self . current_index => {
563+ let universe = self . universe_for ( debruijn) ;
564+ let p = ty:: PlaceholderRegion { universe, name : br. kind } ;
565+ self . mapped_regions . insert ( p. clone ( ) , br) ;
566+ self . infcx . tcx . mk_region ( ty:: RePlaceholder ( p) )
567+ }
568+ _ => r,
569+ }
570+ }
571+
572+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
573+ match * t. kind ( ) {
574+ ty:: Bound ( debruijn, _)
575+ if debruijn. as_usize ( ) + 1
576+ > self . current_index . as_usize ( ) + self . universe_indices . len ( ) =>
577+ {
578+ bug ! ( "Bound vars outside of `self.universe_indices`" ) ;
579+ }
580+ ty:: Bound ( debruijn, bound_ty) if debruijn >= self . current_index => {
581+ let universe = self . universe_for ( debruijn) ;
582+ let p = ty:: PlaceholderType { universe, name : bound_ty. var } ;
583+ self . mapped_types . insert ( p. clone ( ) , bound_ty) ;
584+ self . infcx . tcx . mk_ty ( ty:: Placeholder ( p) )
585+ }
586+ _ if t. has_vars_bound_at_or_above ( self . current_index ) => t. super_fold_with ( self ) ,
587+ _ => t,
588+ }
589+ }
590+
591+ fn fold_const ( & mut self , ct : & ' tcx ty:: Const < ' tcx > ) -> & ' tcx ty:: Const < ' tcx > {
592+ match * ct {
593+ ty:: Const { val : ty:: ConstKind :: Bound ( debruijn, _) , ty : _ }
594+ if debruijn. as_usize ( ) + 1
595+ > self . current_index . as_usize ( ) + self . universe_indices . len ( ) =>
596+ {
597+ bug ! ( "Bound vars outside of `self.universe_indices`" ) ;
598+ }
599+ ty:: Const { val : ty:: ConstKind :: Bound ( debruijn, bound_const) , ty }
600+ if debruijn >= self . current_index =>
601+ {
602+ let universe = self . universe_for ( debruijn) ;
603+ let p = ty:: PlaceholderConst {
604+ universe,
605+ name : ty:: BoundConst { var : bound_const, ty } ,
606+ } ;
607+ self . mapped_consts . insert ( p. clone ( ) , bound_const) ;
608+ self . infcx . tcx . mk_const ( ty:: Const { val : ty:: ConstKind :: Placeholder ( p) , ty } )
609+ }
610+ _ if ct. has_vars_bound_at_or_above ( self . current_index ) => ct. super_fold_with ( self ) ,
611+ _ => ct,
612+ }
613+ }
614+ }
615+
616+ // The inverse of `BoundVarReplacer`: replaces placeholders with the bound vars from which they came.
617+ pub struct PlaceholderReplacer < ' me , ' tcx > {
618+ infcx : & ' me InferCtxt < ' me , ' tcx > ,
619+ mapped_regions : BTreeMap < ty:: PlaceholderRegion , ty:: BoundRegion > ,
620+ mapped_types : BTreeMap < ty:: PlaceholderType , ty:: BoundTy > ,
621+ mapped_consts : BTreeMap < ty:: PlaceholderConst < ' tcx > , ty:: BoundVar > ,
622+ universe_indices : & ' me Vec < Option < ty:: UniverseIndex > > ,
623+ current_index : ty:: DebruijnIndex ,
624+ }
625+
626+ impl < ' me , ' tcx > PlaceholderReplacer < ' me , ' tcx > {
627+ pub fn replace_placeholders < T : TypeFoldable < ' tcx > > (
628+ infcx : & ' me InferCtxt < ' me , ' tcx > ,
629+ mapped_regions : BTreeMap < ty:: PlaceholderRegion , ty:: BoundRegion > ,
630+ mapped_types : BTreeMap < ty:: PlaceholderType , ty:: BoundTy > ,
631+ mapped_consts : BTreeMap < ty:: PlaceholderConst < ' tcx > , ty:: BoundVar > ,
632+ universe_indices : & ' me Vec < Option < ty:: UniverseIndex > > ,
633+ value : T ,
634+ ) -> T {
635+ let mut replacer = PlaceholderReplacer {
636+ infcx,
637+ mapped_regions,
638+ mapped_types,
639+ mapped_consts,
640+ universe_indices,
641+ current_index : ty:: INNERMOST ,
642+ } ;
643+ value. super_fold_with ( & mut replacer)
644+ }
645+ }
646+
647+ impl TypeFolder < ' tcx > for PlaceholderReplacer < ' _ , ' tcx > {
648+ fn tcx < ' b > ( & ' b self ) -> TyCtxt < ' tcx > {
649+ self . infcx . tcx
650+ }
651+
652+ fn fold_binder < T : TypeFoldable < ' tcx > > (
653+ & mut self ,
654+ t : ty:: Binder < ' tcx , T > ,
655+ ) -> ty:: Binder < ' tcx , T > {
656+ if !t. has_placeholders ( ) && !t. has_infer_regions ( ) {
657+ return t;
658+ }
659+ self . current_index . shift_in ( 1 ) ;
660+ let t = t. super_fold_with ( self ) ;
661+ self . current_index . shift_out ( 1 ) ;
662+ t
663+ }
664+
665+ fn fold_region ( & mut self , r0 : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
666+ let r1 = match r0 {
667+ ty:: ReVar ( _) => self
668+ . infcx
669+ . inner
670+ . borrow_mut ( )
671+ . unwrap_region_constraints ( )
672+ . opportunistic_resolve_region ( self . infcx . tcx , r0) ,
673+ _ => r0,
674+ } ;
675+
676+ let r2 = match * r1 {
677+ ty:: RePlaceholder ( p) => {
678+ let replace_var = self . mapped_regions . get ( & p) ;
679+ match replace_var {
680+ Some ( replace_var) => {
681+ let index = self
682+ . universe_indices
683+ . iter ( )
684+ . position ( |u| matches ! ( u, Some ( pu) if * pu == p. universe) )
685+ . unwrap_or_else ( || bug ! ( "Unexpected placeholder universe." ) ) ;
686+ let db = ty:: DebruijnIndex :: from_usize (
687+ self . universe_indices . len ( ) - index + self . current_index . as_usize ( ) - 1 ,
688+ ) ;
689+ self . tcx ( ) . mk_region ( ty:: ReLateBound ( db, * replace_var) )
690+ }
691+ None => r1,
692+ }
693+ }
694+ _ => r1,
695+ } ;
696+
697+ debug ! ( ?r0, ?r1, ?r2, "fold_region" ) ;
698+
699+ r2
700+ }
701+
702+ fn fold_ty ( & mut self , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
703+ match * ty. kind ( ) {
704+ ty:: Placeholder ( p) => {
705+ let replace_var = self . mapped_types . get ( & p) ;
706+ match replace_var {
707+ Some ( replace_var) => {
708+ let index = self
709+ . universe_indices
710+ . iter ( )
711+ . position ( |u| matches ! ( u, Some ( pu) if * pu == p. universe) )
712+ . unwrap_or_else ( || bug ! ( "Unexpected placeholder universe." ) ) ;
713+ let db = ty:: DebruijnIndex :: from_usize (
714+ self . universe_indices . len ( ) - index + self . current_index . as_usize ( ) - 1 ,
715+ ) ;
716+ self . tcx ( ) . mk_ty ( ty:: Bound ( db, * replace_var) )
717+ }
718+ None => ty,
719+ }
720+ }
721+
722+ _ if ty. has_placeholders ( ) || ty. has_infer_regions ( ) => ty. super_fold_with ( self ) ,
723+ _ => ty,
724+ }
725+ }
726+
727+ fn fold_const ( & mut self , ct : & ' tcx ty:: Const < ' tcx > ) -> & ' tcx ty:: Const < ' tcx > {
728+ if let ty:: Const { val : ty:: ConstKind :: Placeholder ( p) , ty } = * ct {
729+ let replace_var = self . mapped_consts . get ( & p) ;
730+ match replace_var {
731+ Some ( replace_var) => {
732+ let index = self
733+ . universe_indices
734+ . iter ( )
735+ . position ( |u| matches ! ( u, Some ( pu) if * pu == p. universe) )
736+ . unwrap_or_else ( || bug ! ( "Unexpected placeholder universe." ) ) ;
737+ let db = ty:: DebruijnIndex :: from_usize (
738+ self . universe_indices . len ( ) - index + self . current_index . as_usize ( ) - 1 ,
739+ ) ;
740+ self . tcx ( )
741+ . mk_const ( ty:: Const { val : ty:: ConstKind :: Bound ( db, * replace_var) , ty } )
742+ }
743+ None => ct,
744+ }
745+ } else {
746+ ct. super_fold_with ( self )
747+ }
748+ }
749+ }
750+
413751/// The guts of `normalize`: normalize a specific projection like `<T
414752/// as Trait>::Item`. The result is always a type (and possibly
415753/// additional obligations). If ambiguity arises, which implies that
0 commit comments