29
29
use infer:: { InferCtxt , InferOk , InferResult , RegionVariableOrigin , TypeVariableOrigin } ;
30
30
use rustc_data_structures:: indexed_vec:: Idx ;
31
31
use std:: fmt:: Debug ;
32
+ use std:: ops:: Index ;
32
33
use syntax:: codemap:: Span ;
33
34
use traits:: { Obligation , ObligationCause , PredicateObligation } ;
34
35
use ty:: { self , CanonicalVar , Lift , Region , Slice , Ty , TyCtxt , TypeFlags } ;
@@ -395,28 +396,27 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
395
396
. collect ( ) ,
396
397
} ;
397
398
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
-
406
399
// Unify the original values for the canonical variables in
407
400
// the input with the value found in the query
408
401
// post-substitution. Often, but not always, this is a no-op,
409
402
// 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
+ } ;
410
406
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 ) ?
412
408
. into_obligations ( ) ;
413
409
414
410
obligations. extend ( self . query_region_constraints_into_obligations (
415
411
cause,
416
412
param_env,
417
- query_region_constraints,
413
+ & query_result. value . region_constraints ,
414
+ result_subst,
418
415
) ) ;
419
416
417
+ let user_result: R =
418
+ query_result. substitute_projected ( self . tcx , result_subst, |q_r| & q_r. value ) ;
419
+
420
420
Ok ( InferOk {
421
421
value : user_result,
422
422
obligations,
@@ -426,25 +426,30 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
426
426
/// Converts the region constraints resulting from a query into an
427
427
/// iterator of obligations.
428
428
fn query_region_constraints_into_obligations < ' a > (
429
- & self ,
429
+ & ' a self ,
430
430
cause : & ' a ObligationCause < ' tcx > ,
431
431
param_env : ty:: ParamEnv < ' tcx > ,
432
- query_region_constraints : QueryRegionConstraints < ' tcx > ,
432
+ unsubstituted_region_constraints : & ' a QueryRegionConstraints < ' tcx > ,
433
+ result_subst : & ' a CanonicalVarValues < ' tcx > ,
433
434
) -> impl Iterator < Item = PredicateObligation < ' tcx > > + ' a {
434
435
let QueryRegionConstraints {
435
436
region_outlives,
436
437
ty_outlives,
437
- } = query_region_constraints ;
438
+ } = unsubstituted_region_constraints ;
438
439
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) ;
440
443
Obligation :: new (
441
444
cause. clone ( ) ,
442
445
param_env,
443
446
ty:: Predicate :: RegionOutlives ( ty:: Binder ( ty:: OutlivesPredicate ( r1, r2) ) ) ,
444
447
)
445
448
} ) ;
446
449
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) ;
448
453
Obligation :: new (
449
454
cause. clone ( ) ,
450
455
param_env,
@@ -456,17 +461,19 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
456
461
}
457
462
458
463
/// 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 (
460
466
& self ,
461
467
cause : & ObligationCause < ' tcx > ,
462
468
param_env : ty:: ParamEnv < ' tcx > ,
463
469
variables1 : & CanonicalVarValues < ' tcx > ,
464
- variables2 : & CanonicalVarValues < ' tcx > ,
470
+ variables2 : impl Fn ( CanonicalVar ) -> Kind < ' tcx > ,
465
471
) -> InferResult < ' tcx , ( ) > {
466
- assert_eq ! ( variables1. var_values. len( ) , variables2. var_values. len( ) ) ;
467
472
self . commit_if_ok ( |_| {
468
473
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
+
470
477
match ( value1. unpack ( ) , value2. unpack ( ) ) {
471
478
( UnpackedKind :: Type ( v1) , UnpackedKind :: Type ( v2) ) => {
472
479
obligations
@@ -724,7 +731,9 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
724
731
value : out_value,
725
732
} ,
726
733
) ;
727
- let values = CanonicalVarValues { var_values : IndexVec :: default ( ) } ;
734
+ let values = CanonicalVarValues {
735
+ var_values : IndexVec :: default ( ) ,
736
+ } ;
728
737
return ( canon_value, values) ;
729
738
}
730
739
@@ -810,13 +819,50 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
810
819
impl < ' tcx , V > Canonical < ' tcx , V > {
811
820
/// Instantiate the wrapped value, replacing each canonical value
812
821
/// 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
814
823
where
815
824
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 > ,
816
841
{
817
842
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 } )
820
866
}
821
867
}
822
868
@@ -838,7 +884,13 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'g
838
884
r => bug ! ( "{:?} is a type but value is {:?}" , c, r) ,
839
885
}
840
886
}
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
+ }
842
894
}
843
895
}
844
896
@@ -926,3 +978,11 @@ BraceStructLiftImpl! {
926
978
var_values, region_constraints, certainty, value
927
979
} where R : Lift <' tcx>
928
980
}
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