@@ -666,6 +666,22 @@ impl<I: Interner, T: TypeFoldable<I>> ty::EarlyBinder<I, T> {
666666 self . value . fold_with ( & mut folder)
667667 }
668668
669+ /// Tries to instantiate the early bound parameters with the given arguments.
670+ /// Returns an error instead of panicking when parameter instantiation fails.
671+ pub fn try_instantiate < A > ( self , cx : I , args : A ) -> Result < T , InstantiationError < I > >
672+ where
673+ A : SliceLike < Item = I :: GenericArg > ,
674+ {
675+ if args. is_empty ( ) {
676+ if self . value . has_param ( ) {
677+ return Err ( InstantiationError :: MissingArgs ) ;
678+ }
679+ return Ok ( self . value ) ;
680+ }
681+ let mut folder = TryArgFolder { cx, args : args. as_slice ( ) , binders_passed : 0 } ;
682+ self . value . try_fold_with ( & mut folder)
683+ }
684+
669685 /// Makes the identity replacement `T0 => T0, ..., TN => TN`.
670686 /// Conceptually, this converts universally bound variables into placeholders
671687 /// when inside of a given item.
@@ -687,6 +703,238 @@ impl<I: Interner, T: TypeFoldable<I>> ty::EarlyBinder<I, T> {
687703///////////////////////////////////////////////////////////////////////////
688704// The actual instantiation engine itself is a type folder.
689705
706+ /// Error type for instantiation failures.
707+ pub enum InstantiationError < I : Interner > {
708+ /// A type parameter was referenced that is not in the provided args.
709+ TypeParamOutOfRange {
710+ param : I :: ParamTy ,
711+ param_index : usize ,
712+ args_len : usize ,
713+ } ,
714+ /// A const parameter was referenced that is not in the provided args.
715+ ConstParamOutOfRange {
716+ param : I :: ParamConst ,
717+ param_index : usize ,
718+ args_len : usize ,
719+ } ,
720+ /// A region parameter was referenced that is not in the provided args.
721+ RegionParamOutOfRange {
722+ param_index : usize ,
723+ args_len : usize ,
724+ } ,
725+ /// Expected a type but found a different kind.
726+ TypeParamExpected {
727+ param : I :: ParamTy ,
728+ found : ty:: GenericArgKind < I > ,
729+ } ,
730+ /// Expected a const but found a different kind.
731+ ConstParamExpected {
732+ param : I :: ParamConst ,
733+ found : ty:: GenericArgKind < I > ,
734+ } ,
735+ /// Expected a region but found a different kind.
736+ RegionParamExpected {
737+ param_index : usize ,
738+ found : ty:: GenericArgKind < I > ,
739+ } ,
740+ /// No args were provided but the value has parameters.
741+ MissingArgs ,
742+ }
743+
744+ impl < I : Interner > std:: fmt:: Debug for InstantiationError < I > {
745+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
746+ match self {
747+ InstantiationError :: TypeParamOutOfRange { param, param_index, args_len } => f
748+ . debug_struct ( "TypeParamOutOfRange" )
749+ . field ( "param" , & format_args ! ( "{:?}" , param) )
750+ . field ( "param_index" , param_index)
751+ . field ( "args_len" , args_len)
752+ . finish ( ) ,
753+ InstantiationError :: ConstParamOutOfRange { param, param_index, args_len } => f
754+ . debug_struct ( "ConstParamOutOfRange" )
755+ . field ( "param" , & format_args ! ( "{:?}" , param) )
756+ . field ( "param_index" , param_index)
757+ . field ( "args_len" , args_len)
758+ . finish ( ) ,
759+ InstantiationError :: RegionParamOutOfRange { param_index, args_len } => f
760+ . debug_struct ( "RegionParamOutOfRange" )
761+ . field ( "param_index" , param_index)
762+ . field ( "args_len" , args_len)
763+ . finish ( ) ,
764+ InstantiationError :: TypeParamExpected { param, found } => f
765+ . debug_struct ( "TypeParamExpected" )
766+ . field ( "param" , & format_args ! ( "{:?}" , param) )
767+ . field ( "found" , & format_args ! ( "{:?}" , found) )
768+ . finish ( ) ,
769+ InstantiationError :: ConstParamExpected { param, found } => f
770+ . debug_struct ( "ConstParamExpected" )
771+ . field ( "param" , & format_args ! ( "{:?}" , param) )
772+ . field ( "found" , & format_args ! ( "{:?}" , found) )
773+ . finish ( ) ,
774+ InstantiationError :: RegionParamExpected { param_index, found } => f
775+ . debug_struct ( "RegionParamExpected" )
776+ . field ( "param_index" , param_index)
777+ . field ( "found" , & format_args ! ( "{:?}" , found) )
778+ . finish ( ) ,
779+ InstantiationError :: MissingArgs => write ! ( f, "MissingArgs" ) ,
780+ }
781+ }
782+ }
783+
784+ struct TryArgFolder < ' a , I : Interner > {
785+ cx : I ,
786+ args : & ' a [ I :: GenericArg ] ,
787+ binders_passed : u32 ,
788+ }
789+
790+ impl < ' a , I : Interner > FallibleTypeFolder < I > for TryArgFolder < ' a , I > {
791+ type Error = InstantiationError < I > ;
792+
793+ #[ inline]
794+ fn cx ( & self ) -> I {
795+ self . cx
796+ }
797+
798+ fn try_fold_binder < T : TypeFoldable < I > > (
799+ & mut self ,
800+ t : ty:: Binder < I , T > ,
801+ ) -> Result < ty:: Binder < I , T > , Self :: Error > {
802+ self . binders_passed += 1 ;
803+ let result = t. try_super_fold_with ( self ) ;
804+ self . binders_passed -= 1 ;
805+ result
806+ }
807+
808+ fn try_fold_region ( & mut self , r : I :: Region ) -> Result < I :: Region , Self :: Error > {
809+ match r. kind ( ) {
810+ ty:: ReEarlyParam ( data) => {
811+ let rk = self . args . get ( data. index ( ) as usize ) . map ( |arg| arg. kind ( ) ) ;
812+ match rk {
813+ Some ( ty:: GenericArgKind :: Lifetime ( lt) ) => {
814+ Ok ( self . shift_region_through_binders ( lt) )
815+ }
816+ Some ( other) => Err ( InstantiationError :: RegionParamExpected {
817+ param_index : data. index ( ) as usize ,
818+ found : other,
819+ } ) ,
820+ None => Err ( InstantiationError :: RegionParamOutOfRange {
821+ param_index : data. index ( ) as usize ,
822+ args_len : self . args . len ( ) ,
823+ } ) ,
824+ }
825+ }
826+ ty:: ReBound ( ..)
827+ | ty:: ReLateParam ( _)
828+ | ty:: ReStatic
829+ | ty:: RePlaceholder ( _)
830+ | ty:: ReErased
831+ | ty:: ReError ( _) => Ok ( r) ,
832+ ty:: ReVar ( _) => panic ! ( "unexpected region: {r:?}" ) ,
833+ }
834+ }
835+
836+ fn try_fold_ty ( & mut self , t : I :: Ty ) -> Result < I :: Ty , Self :: Error > {
837+ if !t. has_param ( ) {
838+ return Ok ( t) ;
839+ }
840+
841+ match t. kind ( ) {
842+ ty:: Param ( p) => self . ty_for_param ( p, t) ,
843+ _ => t. try_super_fold_with ( self ) ,
844+ }
845+ }
846+
847+ fn try_fold_const ( & mut self , c : I :: Const ) -> Result < I :: Const , Self :: Error > {
848+ if let ty:: ConstKind :: Param ( p) = c. kind ( ) {
849+ self . const_for_param ( p, c)
850+ } else {
851+ c. try_super_fold_with ( self )
852+ }
853+ }
854+
855+ fn try_fold_predicate ( & mut self , p : I :: Predicate ) -> Result < I :: Predicate , Self :: Error > {
856+ if p. has_param ( ) {
857+ p. try_super_fold_with ( self )
858+ } else {
859+ Ok ( p)
860+ }
861+ }
862+
863+ fn try_fold_clauses ( & mut self , c : I :: Clauses ) -> Result < I :: Clauses , Self :: Error > {
864+ if c. has_param ( ) {
865+ c. try_super_fold_with ( self )
866+ } else {
867+ Ok ( c)
868+ }
869+ }
870+ }
871+
872+ impl < ' a , I : Interner > TryArgFolder < ' a , I > {
873+ fn ty_for_param ( & self , p : I :: ParamTy , _source_ty : I :: Ty ) -> Result < I :: Ty , InstantiationError < I > > {
874+ let opt_ty = self . args . get ( p. index ( ) as usize ) . map ( |arg| arg. kind ( ) ) ;
875+ let ty = match opt_ty {
876+ Some ( ty:: GenericArgKind :: Type ( ty) ) => ty,
877+ Some ( kind) => {
878+ return Err ( InstantiationError :: TypeParamExpected {
879+ param : p,
880+ found : kind,
881+ } )
882+ }
883+ None => {
884+ return Err ( InstantiationError :: TypeParamOutOfRange {
885+ param : p,
886+ param_index : p. index ( ) as usize ,
887+ args_len : self . args . len ( ) ,
888+ } )
889+ }
890+ } ;
891+
892+ Ok ( self . shift_vars_through_binders ( ty) )
893+ }
894+
895+ fn const_for_param (
896+ & self ,
897+ p : I :: ParamConst ,
898+ _source_ct : I :: Const ,
899+ ) -> Result < I :: Const , InstantiationError < I > > {
900+ let opt_ct = self . args . get ( p. index ( ) as usize ) . map ( |arg| arg. kind ( ) ) ;
901+ let ct = match opt_ct {
902+ Some ( ty:: GenericArgKind :: Const ( ct) ) => ct,
903+ Some ( kind) => {
904+ return Err ( InstantiationError :: ConstParamExpected {
905+ param : p,
906+ found : kind,
907+ } )
908+ }
909+ None => {
910+ return Err ( InstantiationError :: ConstParamOutOfRange {
911+ param : p,
912+ param_index : p. index ( ) as usize ,
913+ args_len : self . args . len ( ) ,
914+ } )
915+ }
916+ } ;
917+
918+ Ok ( self . shift_vars_through_binders ( ct) )
919+ }
920+
921+ fn shift_vars_through_binders < T : TypeFoldable < I > > ( & self , val : T ) -> T {
922+ if self . binders_passed == 0 || !val. has_escaping_bound_vars ( ) {
923+ val
924+ } else {
925+ ty:: shift_vars ( self . cx , val, self . binders_passed )
926+ }
927+ }
928+
929+ fn shift_region_through_binders ( & self , region : I :: Region ) -> I :: Region {
930+ if self . binders_passed == 0 || !region. has_escaping_bound_vars ( ) {
931+ region
932+ } else {
933+ ty:: shift_region ( self . cx , region, self . binders_passed )
934+ }
935+ }
936+ }
937+
690938struct ArgFolder < ' a , I : Interner > {
691939 cx : I ,
692940 args : & ' a [ I :: GenericArg ] ,
0 commit comments