2929use infer:: { InferCtxt , InferOk , InferResult , RegionVariableOrigin , TypeVariableOrigin } ;
3030use rustc_data_structures:: indexed_vec:: Idx ;
3131use std:: fmt:: Debug ;
32+ use std:: ops:: Index ;
3233use syntax:: codemap:: Span ;
3334use traits:: { Obligation , ObligationCause , PredicateObligation } ;
3435use ty:: { self , CanonicalVar , Lift , Region , Slice , Ty , TyCtxt , TypeFlags } ;
@@ -395,28 +396,27 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
395396 . collect ( ) ,
396397 } ;
397398
398- // Apply the result substitution to the query.
399- let QueryResult {
400- var_values : query_values,
401- region_constraints : query_region_constraints,
402- certainty : _,
403- value : user_result,
404- } = query_result. substitute ( self . tcx , result_subst) ;
405-
406399 // Unify the original values for the canonical variables in
407400 // the input with the value found in the query
408401 // post-substitution. Often, but not always, this is a no-op,
409402 // because we already found the mapping in the first step.
403+ let substituted_values = |index : CanonicalVar | -> Kind < ' tcx > {
404+ query_result. substitute_projected ( self . tcx , result_subst, |v| & v. var_values [ index] )
405+ } ;
410406 let mut obligations =
411- self . unify_canonical_vars ( cause, param_env, original_values, & query_values ) ?
407+ self . unify_canonical_vars ( cause, param_env, original_values, substituted_values ) ?
412408 . into_obligations ( ) ;
413409
414410 obligations. extend ( self . query_region_constraints_into_obligations (
415411 cause,
416412 param_env,
417- query_region_constraints,
413+ & query_result. value . region_constraints ,
414+ result_subst,
418415 ) ) ;
419416
417+ let user_result: R =
418+ query_result. substitute_projected ( self . tcx , result_subst, |q_r| & q_r. value ) ;
419+
420420 Ok ( InferOk {
421421 value : user_result,
422422 obligations,
@@ -426,25 +426,30 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
426426 /// Converts the region constraints resulting from a query into an
427427 /// iterator of obligations.
428428 fn query_region_constraints_into_obligations < ' a > (
429- & self ,
429+ & ' a self ,
430430 cause : & ' a ObligationCause < ' tcx > ,
431431 param_env : ty:: ParamEnv < ' tcx > ,
432- query_region_constraints : QueryRegionConstraints < ' tcx > ,
432+ unsubstituted_region_constraints : & ' a QueryRegionConstraints < ' tcx > ,
433+ result_subst : & ' a CanonicalVarValues < ' tcx > ,
433434 ) -> impl Iterator < Item = PredicateObligation < ' tcx > > + ' a {
434435 let QueryRegionConstraints {
435436 region_outlives,
436437 ty_outlives,
437- } = query_region_constraints ;
438+ } = unsubstituted_region_constraints ;
438439
439- let region_obligations = region_outlives. into_iter ( ) . map ( move |( r1, r2) | {
440+ let region_obligations = region_outlives. iter ( ) . map ( move |( r1, r2) | {
441+ let r1 = substitute_value ( self . tcx , result_subst, r1) ;
442+ let r2 = substitute_value ( self . tcx , result_subst, r2) ;
440443 Obligation :: new (
441444 cause. clone ( ) ,
442445 param_env,
443446 ty:: Predicate :: RegionOutlives ( ty:: Binder ( ty:: OutlivesPredicate ( r1, r2) ) ) ,
444447 )
445448 } ) ;
446449
447- let ty_obligations = ty_outlives. into_iter ( ) . map ( move |( t1, r2) | {
450+ let ty_obligations = ty_outlives. iter ( ) . map ( move |( t1, r2) | {
451+ let t1 = substitute_value ( self . tcx , result_subst, t1) ;
452+ let r2 = substitute_value ( self . tcx , result_subst, r2) ;
448453 Obligation :: new (
449454 cause. clone ( ) ,
450455 param_env,
@@ -456,17 +461,19 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
456461 }
457462
458463 /// Given two sets of values for the same set of canonical variables, unify them.
459- pub fn unify_canonical_vars (
464+ /// The second set is produced lazilly by supplying indices from the first set.
465+ fn unify_canonical_vars (
460466 & self ,
461467 cause : & ObligationCause < ' tcx > ,
462468 param_env : ty:: ParamEnv < ' tcx > ,
463469 variables1 : & CanonicalVarValues < ' tcx > ,
464- variables2 : & CanonicalVarValues < ' tcx > ,
470+ variables2 : impl Fn ( CanonicalVar ) -> Kind < ' tcx > ,
465471 ) -> InferResult < ' tcx , ( ) > {
466- assert_eq ! ( variables1. var_values. len( ) , variables2. var_values. len( ) ) ;
467472 self . commit_if_ok ( |_| {
468473 let mut obligations = vec ! [ ] ;
469- for ( value1, value2) in variables1. var_values . iter ( ) . zip ( & variables2. var_values ) {
474+ for ( index, value1) in variables1. var_values . iter_enumerated ( ) {
475+ let value2 = variables2 ( index) ;
476+
470477 match ( value1. unpack ( ) , value2. unpack ( ) ) {
471478 ( UnpackedKind :: Type ( v1) , UnpackedKind :: Type ( v2) ) => {
472479 obligations
@@ -724,7 +731,9 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
724731 value : out_value,
725732 } ,
726733 ) ;
727- let values = CanonicalVarValues { var_values : IndexVec :: default ( ) } ;
734+ let values = CanonicalVarValues {
735+ var_values : IndexVec :: default ( ) ,
736+ } ;
728737 return ( canon_value, values) ;
729738 }
730739
@@ -810,13 +819,50 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
810819impl < ' tcx , V > Canonical < ' tcx , V > {
811820 /// Instantiate the wrapped value, replacing each canonical value
812821 /// with the value given in `var_values`.
813- pub fn substitute ( & self , tcx : TyCtxt < ' _ , ' _ , ' tcx > , var_values : & CanonicalVarValues < ' tcx > ) -> V
822+ fn substitute ( & self , tcx : TyCtxt < ' _ , ' _ , ' tcx > , var_values : & CanonicalVarValues < ' tcx > ) -> V
814823 where
815824 V : TypeFoldable < ' tcx > ,
825+ {
826+ self . substitute_projected ( tcx, var_values, |value| value)
827+ }
828+
829+ /// Invoke `projection_fn` with `self.value` to get a value V that
830+ /// is expressed in terms of the same canonical variables bound in
831+ /// `self`. Apply the substitution `var_values` to this value V,
832+ /// replacing each of the canonical variables.
833+ fn substitute_projected < T > (
834+ & self ,
835+ tcx : TyCtxt < ' _ , ' _ , ' tcx > ,
836+ var_values : & CanonicalVarValues < ' tcx > ,
837+ projection_fn : impl FnOnce ( & V ) -> & T ,
838+ ) -> T
839+ where
840+ T : TypeFoldable < ' tcx > ,
816841 {
817842 assert_eq ! ( self . variables. len( ) , var_values. var_values. len( ) ) ;
818- self . value
819- . fold_with ( & mut CanonicalVarValuesSubst { tcx, var_values } )
843+ let value = projection_fn ( & self . value ) ;
844+ substitute_value ( tcx, var_values, value)
845+ }
846+ }
847+
848+ /// Substitute the values from `var_values` into `value`. `var_values`
849+ /// must be values for the set of cnaonical variables that appear in
850+ /// `value`.
851+ fn substitute_value < ' a , ' tcx , T > (
852+ tcx : TyCtxt < ' _ , ' _ , ' tcx > ,
853+ var_values : & CanonicalVarValues < ' tcx > ,
854+ value : & ' a T ,
855+ ) -> T
856+ where
857+ T : TypeFoldable < ' tcx > ,
858+ {
859+ if var_values. var_values . is_empty ( ) {
860+ debug_assert ! ( !value. has_type_flags( TypeFlags :: HAS_CANONICAL_VARS ) ) ;
861+ value. clone ( )
862+ } else if !value. has_type_flags ( TypeFlags :: HAS_CANONICAL_VARS ) {
863+ value. clone ( )
864+ } else {
865+ value. fold_with ( & mut CanonicalVarValuesSubst { tcx, var_values } )
820866 }
821867}
822868
@@ -838,7 +884,13 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'g
838884 r => bug ! ( "{:?} is a type but value is {:?}" , c, r) ,
839885 }
840886 }
841- _ => t. super_fold_with ( self ) ,
887+ _ => {
888+ if !t. has_type_flags ( TypeFlags :: HAS_CANONICAL_VARS ) {
889+ t
890+ } else {
891+ t. super_fold_with ( self )
892+ }
893+ }
842894 }
843895 }
844896
@@ -926,3 +978,11 @@ BraceStructLiftImpl! {
926978 var_values, region_constraints, certainty, value
927979 } where R : Lift <' tcx>
928980}
981+
982+ impl < ' tcx > Index < CanonicalVar > for CanonicalVarValues < ' tcx > {
983+ type Output = Kind < ' tcx > ;
984+
985+ fn index ( & self , value : CanonicalVar ) -> & Kind < ' tcx > {
986+ & self . var_values [ value]
987+ }
988+ }
0 commit comments