@@ -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 > > ;
@@ -396,6 +398,53 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
396398 normalized_ty
397399 }
398400
401+ ty:: Projection ( data) if !data. trait_ref ( self . tcx ( ) ) . has_escaping_bound_vars ( ) => {
402+ // Okay, so you thought the previous branch was hacky. Well, to
403+ // extend upon this, when the *trait ref* doesn't have escaping
404+ // bound vars, but the associated item *does* (can only occur
405+ // with GATs), then we might still be able to project the type.
406+ // For this, we temporarily replace the bound vars with
407+ // placeholders. Note though, that in the case that we still
408+ // can't project for whatever reason (e.g. self type isn't
409+ // known enough), we *can't* register an obligation and return
410+ // an inference variable (since then that obligation would have
411+ // bound vars and that's a can of worms). Instead, we just
412+ // give up and fall back to pretending like we never tried!
413+
414+ let infcx = self . selcx . infcx ( ) ;
415+ let ( data, mapped_regions, mapped_types, mapped_consts, universe_map) =
416+ BoundVarReplacer :: replace_bound_vars ( infcx, data) ;
417+
418+ let normalized_ty = opt_normalize_projection_type (
419+ self . selcx ,
420+ self . param_env ,
421+ data,
422+ self . cause . clone ( ) ,
423+ self . depth ,
424+ & mut self . obligations ,
425+ )
426+ . ok ( )
427+ . flatten ( )
428+ . unwrap_or_else ( || ty) ;
429+
430+ let normalized_ty = PlaceholderReplacer :: replace_placeholders (
431+ infcx,
432+ mapped_regions,
433+ mapped_types,
434+ mapped_consts,
435+ universe_map,
436+ normalized_ty,
437+ ) ;
438+ debug ! (
439+ ?self . depth,
440+ ?ty,
441+ ?normalized_ty,
442+ obligations. len = ?self . obligations. len( ) ,
443+ "AssocTypeNormalizer: normalized type"
444+ ) ;
445+ normalized_ty
446+ }
447+
399448 _ => ty,
400449 }
401450 }
@@ -410,6 +459,259 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
410459 }
411460}
412461
462+ pub struct BoundVarReplacer < ' me , ' tcx > {
463+ pub infcx : & ' me InferCtxt < ' me , ' tcx > ,
464+ pub mapped_regions : BTreeMap < ty:: PlaceholderRegion , ty:: BoundRegion > ,
465+ pub mapped_types : BTreeMap < ty:: PlaceholderType , ty:: BoundTy > ,
466+ pub mapped_consts : BTreeMap < ty:: PlaceholderConst < ' tcx > , ty:: BoundVar > ,
467+ pub universes : BTreeMap < ty:: DebruijnIndex , ty:: UniverseIndex > ,
468+ pub universes_inverse : BTreeMap < ty:: UniverseIndex , ty:: DebruijnIndex > ,
469+ pub current_index : ty:: DebruijnIndex ,
470+ }
471+
472+ impl < ' me , ' tcx > BoundVarReplacer < ' me , ' tcx > {
473+ pub fn replace_bound_vars < T : TypeFoldable < ' tcx > > (
474+ infcx : & ' me InferCtxt < ' me , ' tcx > ,
475+ value : T ,
476+ ) -> (
477+ T ,
478+ BTreeMap < ty:: PlaceholderRegion , ty:: BoundRegion > ,
479+ BTreeMap < ty:: PlaceholderType , ty:: BoundTy > ,
480+ BTreeMap < ty:: PlaceholderConst < ' tcx > , ty:: BoundVar > ,
481+ BTreeMap < ty:: UniverseIndex , ty:: DebruijnIndex > ,
482+ ) {
483+ let mapped_regions: BTreeMap < ty:: PlaceholderRegion , ty:: BoundRegion > = BTreeMap :: new ( ) ;
484+ let mapped_types: BTreeMap < ty:: PlaceholderType , ty:: BoundTy > = BTreeMap :: new ( ) ;
485+ let mapped_consts: BTreeMap < ty:: PlaceholderConst < ' tcx > , ty:: BoundVar > = BTreeMap :: new ( ) ;
486+
487+ let mut replacer = BoundVarReplacer {
488+ infcx,
489+ mapped_regions,
490+ mapped_types,
491+ mapped_consts,
492+ universes : BTreeMap :: new ( ) ,
493+ universes_inverse : BTreeMap :: new ( ) ,
494+ current_index : ty:: INNERMOST ,
495+ } ;
496+
497+ let value = value. super_fold_with ( & mut replacer) ;
498+
499+ (
500+ value,
501+ replacer. mapped_regions ,
502+ replacer. mapped_types ,
503+ replacer. mapped_consts ,
504+ replacer. universes_inverse ,
505+ )
506+ }
507+ }
508+
509+ impl TypeFolder < ' tcx > for BoundVarReplacer < ' _ , ' tcx > {
510+ fn tcx < ' b > ( & ' b self ) -> TyCtxt < ' tcx > {
511+ self . infcx . tcx
512+ }
513+
514+ fn fold_binder < T : TypeFoldable < ' tcx > > (
515+ & mut self ,
516+ t : ty:: Binder < ' tcx , T > ,
517+ ) -> ty:: Binder < ' tcx , T > {
518+ self . current_index . shift_in ( 1 ) ;
519+ let t = t. super_fold_with ( self ) ;
520+ self . current_index . shift_out ( 1 ) ;
521+ t
522+ }
523+
524+ fn fold_region ( & mut self , r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
525+ match * r {
526+ ty:: ReLateBound ( debruijn, br) => {
527+ let infcx = self . infcx ;
528+ let placeholder_db_index =
529+ ty:: DebruijnIndex :: from_u32 ( self . current_index . as_u32 ( ) - debruijn. as_u32 ( ) ) ;
530+ let universe = * self
531+ . universes
532+ . entry ( placeholder_db_index)
533+ . or_insert_with ( || infcx. create_next_universe ( ) ) ;
534+ self . universes_inverse . insert ( universe, placeholder_db_index) ;
535+ let p = ty:: PlaceholderRegion { universe, name : br. kind } ;
536+ self . mapped_regions . insert ( p. clone ( ) , br) ;
537+ self . infcx . tcx . mk_region ( ty:: RePlaceholder ( p) )
538+ }
539+ _ => r,
540+ }
541+ }
542+
543+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
544+ match * t. kind ( ) {
545+ ty:: Bound ( debruijn, bound_ty) => {
546+ let infcx = self . infcx ;
547+ let placeholder_db_index =
548+ ty:: DebruijnIndex :: from_u32 ( self . current_index . as_u32 ( ) - debruijn. as_u32 ( ) ) ;
549+ let universe = * self
550+ . universes
551+ . entry ( placeholder_db_index)
552+ . or_insert_with ( || infcx. create_next_universe ( ) ) ;
553+ self . universes_inverse . insert ( universe, placeholder_db_index) ;
554+ let p = ty:: PlaceholderType { universe, name : bound_ty. var } ;
555+ self . mapped_types . insert ( p. clone ( ) , bound_ty) ;
556+ self . infcx . tcx . mk_ty ( ty:: Placeholder ( p) )
557+ }
558+ _ if t. has_vars_bound_at_or_above ( self . current_index ) => t. super_fold_with ( self ) ,
559+ _ => t,
560+ }
561+ }
562+
563+ fn fold_const ( & mut self , ct : & ' tcx ty:: Const < ' tcx > ) -> & ' tcx ty:: Const < ' tcx > {
564+ match * ct {
565+ ty:: Const { val : ty:: ConstKind :: Bound ( debruijn, bound_const) , ty } => {
566+ let infcx = self . infcx ;
567+ let placeholder_db_index =
568+ ty:: DebruijnIndex :: from_u32 ( self . current_index . as_u32 ( ) - debruijn. as_u32 ( ) ) ;
569+ let universe = * self
570+ . universes
571+ . entry ( placeholder_db_index)
572+ . or_insert_with ( || infcx. create_next_universe ( ) ) ;
573+ self . universes_inverse . insert ( universe, placeholder_db_index) ;
574+ let p = ty:: PlaceholderConst {
575+ universe,
576+ name : ty:: BoundConst { var : bound_const, ty } ,
577+ } ;
578+ self . mapped_consts . insert ( p. clone ( ) , bound_const) ;
579+ self . infcx . tcx . mk_const ( ty:: Const { val : ty:: ConstKind :: Placeholder ( p) , ty } )
580+ }
581+ _ if ct. has_vars_bound_at_or_above ( self . current_index ) => ct. super_fold_with ( self ) ,
582+ _ => ct,
583+ }
584+ }
585+ }
586+
587+ pub struct PlaceholderReplacer < ' me , ' tcx > {
588+ pub infcx : & ' me InferCtxt < ' me , ' tcx > ,
589+ pub mapped_regions : BTreeMap < ty:: PlaceholderRegion , ty:: BoundRegion > ,
590+ pub mapped_types : BTreeMap < ty:: PlaceholderType , ty:: BoundTy > ,
591+ pub mapped_consts : BTreeMap < ty:: PlaceholderConst < ' tcx > , ty:: BoundVar > ,
592+ pub universes_inverse : BTreeMap < ty:: UniverseIndex , ty:: DebruijnIndex > ,
593+ pub current_index : ty:: DebruijnIndex ,
594+ }
595+
596+ impl < ' me , ' tcx > PlaceholderReplacer < ' me , ' tcx > {
597+ pub fn replace_placeholders < T : TypeFoldable < ' tcx > > (
598+ infcx : & ' me InferCtxt < ' me , ' tcx > ,
599+ mapped_regions : BTreeMap < ty:: PlaceholderRegion , ty:: BoundRegion > ,
600+ mapped_types : BTreeMap < ty:: PlaceholderType , ty:: BoundTy > ,
601+ mapped_consts : BTreeMap < ty:: PlaceholderConst < ' tcx > , ty:: BoundVar > ,
602+ universes_inverse : BTreeMap < ty:: UniverseIndex , ty:: DebruijnIndex > ,
603+ value : T ,
604+ ) -> T {
605+ let mut replacer = PlaceholderReplacer {
606+ infcx,
607+ mapped_regions,
608+ mapped_types,
609+ mapped_consts,
610+ universes_inverse,
611+ current_index : ty:: INNERMOST ,
612+ } ;
613+ value. super_fold_with ( & mut replacer)
614+ }
615+ }
616+
617+ impl TypeFolder < ' tcx > for PlaceholderReplacer < ' _ , ' tcx > {
618+ fn tcx < ' b > ( & ' b self ) -> TyCtxt < ' tcx > {
619+ self . infcx . tcx
620+ }
621+
622+ fn fold_binder < T : TypeFoldable < ' tcx > > (
623+ & mut self ,
624+ t : ty:: Binder < ' tcx , T > ,
625+ ) -> ty:: Binder < ' tcx , T > {
626+ if !t. has_placeholders ( ) && !t. has_infer_regions ( ) {
627+ return t;
628+ }
629+ self . current_index . shift_in ( 1 ) ;
630+ let t = t. super_fold_with ( self ) ;
631+ self . current_index . shift_out ( 1 ) ;
632+ t
633+ }
634+
635+ fn fold_region ( & mut self , r0 : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
636+ let r1 = match r0 {
637+ ty:: ReVar ( _) => self
638+ . infcx
639+ . inner
640+ . borrow_mut ( )
641+ . unwrap_region_constraints ( )
642+ . opportunistic_resolve_region ( self . infcx . tcx , r0) ,
643+ _ => r0,
644+ } ;
645+
646+ let r2 = match * r1 {
647+ ty:: RePlaceholder ( p) => {
648+ let replace_var = self . mapped_regions . get ( & p) ;
649+ match replace_var {
650+ Some ( replace_var) => {
651+ let db = self
652+ . universes_inverse
653+ . get ( & p. universe )
654+ . unwrap_or_else ( || bug ! ( "Unexpected placeholder universe." ) ) ;
655+ let index =
656+ ty:: DebruijnIndex :: from_u32 ( db. as_u32 ( ) + self . current_index . as_u32 ( ) ) ;
657+ self . tcx ( ) . mk_region ( ty:: ReLateBound ( index, * replace_var) )
658+ }
659+ None => r1,
660+ }
661+ }
662+ _ => r1,
663+ } ;
664+
665+ debug ! ( ?r0, ?r1, ?r2, "fold_region" ) ;
666+
667+ r2
668+ }
669+
670+ fn fold_ty ( & mut self , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
671+ match * ty. kind ( ) {
672+ ty:: Placeholder ( p) => {
673+ let replace_var = self . mapped_types . get ( & p) ;
674+ match replace_var {
675+ Some ( replace_var) => {
676+ let db = self
677+ . universes_inverse
678+ . get ( & p. universe )
679+ . unwrap_or_else ( || bug ! ( "Unexpected placeholder universe." ) ) ;
680+ let index =
681+ ty:: DebruijnIndex :: from_u32 ( db. as_u32 ( ) + self . current_index . as_u32 ( ) ) ;
682+ self . tcx ( ) . mk_ty ( ty:: Bound ( index, * replace_var) )
683+ }
684+ None => ty,
685+ }
686+ }
687+
688+ _ if ty. has_placeholders ( ) || ty. has_infer_regions ( ) => ty. super_fold_with ( self ) ,
689+ _ => ty,
690+ }
691+ }
692+
693+ fn fold_const ( & mut self , ct : & ' tcx ty:: Const < ' tcx > ) -> & ' tcx ty:: Const < ' tcx > {
694+ if let ty:: Const { val : ty:: ConstKind :: Placeholder ( p) , ty } = * ct {
695+ let replace_var = self . mapped_consts . get ( & p) ;
696+ match replace_var {
697+ Some ( replace_var) => {
698+ let db = self
699+ . universes_inverse
700+ . get ( & p. universe )
701+ . unwrap_or_else ( || bug ! ( "Unexpected placeholder universe." ) ) ;
702+ let index =
703+ ty:: DebruijnIndex :: from_u32 ( db. as_u32 ( ) + self . current_index . as_u32 ( ) ) ;
704+ self . tcx ( )
705+ . mk_const ( ty:: Const { val : ty:: ConstKind :: Bound ( index, * replace_var) , ty } )
706+ }
707+ None => ct,
708+ }
709+ } else {
710+ ct. super_fold_with ( self )
711+ }
712+ }
713+ }
714+
413715/// The guts of `normalize`: normalize a specific projection like `<T
414716/// as Trait>::Item`. The result is always a type (and possibly
415717/// additional obligations). If ambiguity arises, which implies that
0 commit comments