@@ -39,6 +39,7 @@ use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
39
39
use middle:: ty:: { IntType , UintType } ;
40
40
use middle:: ty:: { BuiltinBounds } ;
41
41
use middle:: ty;
42
+ use middle:: ty_fold;
42
43
use middle:: typeck:: infer:: equate:: Equate ;
43
44
use middle:: typeck:: infer:: glb:: Glb ;
44
45
use middle:: typeck:: infer:: lub:: Lub ;
@@ -48,14 +49,15 @@ use middle::typeck::infer::{InferCtxt, cres};
48
49
use middle:: typeck:: infer:: { MiscVariable , TypeTrace } ;
49
50
use middle:: typeck:: infer:: type_variable:: { RelationDir , EqTo ,
50
51
SubtypeOf , SupertypeOf } ;
51
- use middle:: ty_fold:: { RegionFolder , TypeFoldable } ;
52
+ use middle:: ty_fold:: { TypeFoldable } ;
52
53
use util:: ppaux:: Repr ;
53
54
54
55
use std:: result;
55
56
56
57
use syntax:: ast:: { Onceness , FnStyle } ;
57
58
use syntax:: ast;
58
59
use syntax:: abi;
60
+ use syntax:: codemap:: Span ;
59
61
60
62
pub trait Combine < ' tcx > {
61
63
fn infcx < ' a > ( & ' a self ) -> & ' a InferCtxt < ' a , ' tcx > ;
@@ -637,10 +639,14 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
637
639
Some ( t) => t, // ...already instantiated.
638
640
None => { // ...not yet instantiated:
639
641
// Generalize type if necessary.
640
- let generalized_ty = match dir {
641
- EqTo => a_ty,
642
- SupertypeOf | SubtypeOf => self . generalize ( a_ty)
643
- } ;
642
+ let generalized_ty = try!( match dir {
643
+ EqTo => {
644
+ self . generalize ( a_ty, b_vid, false )
645
+ }
646
+ SupertypeOf | SubtypeOf => {
647
+ self . generalize ( a_ty, b_vid, true )
648
+ }
649
+ } ) ;
644
650
debug ! ( "instantiate(a_ty={}, dir={}, \
645
651
b_vid={}, generalized_ty={})",
646
652
a_ty. repr( tcx) , dir, b_vid. repr( tcx) ,
@@ -678,15 +684,85 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
678
684
Ok ( ( ) )
679
685
}
680
686
681
- fn generalize ( & self , t : ty:: t ) -> ty:: t {
682
- // FIXME(#16847): This is non-ideal because we don't give a
683
- // very descriptive origin for this region variable.
687
+ fn generalize ( & self ,
688
+ ty : ty:: t ,
689
+ for_vid : ty:: TyVid ,
690
+ make_region_vars : bool )
691
+ -> cres < ty:: t >
692
+ {
693
+ /*!
694
+ * Attempts to generalize `ty` for the type variable
695
+ * `for_vid`. This checks for cycle -- that is, whether the
696
+ * type `ty` references `for_vid`. If `make_region_vars` is
697
+ * true, it will also replace all regions with fresh
698
+ * variables. Returns `ty_err` in the case of a cycle, `Ok`
699
+ * otherwise.
700
+ */
701
+
702
+ let mut generalize = Generalizer { infcx : self . infcx ,
703
+ span : self . trace . origin . span ( ) ,
704
+ for_vid : for_vid,
705
+ make_region_vars : make_region_vars,
706
+ cycle_detected : false } ;
707
+ let u = ty. fold_with ( & mut generalize) ;
708
+ if generalize. cycle_detected {
709
+ Err ( ty:: terr_cyclic_ty)
710
+ } else {
711
+ Ok ( u)
712
+ }
713
+ }
714
+ }
684
715
685
- let infcx = self . infcx ;
686
- let span = self . trace . origin . span ( ) ;
687
- t. fold_with (
688
- & mut RegionFolder :: regions (
689
- self . infcx . tcx ,
690
- |_| infcx. next_region_var ( MiscVariable ( span) ) ) )
716
+ struct Generalizer < ' cx , ' tcx : ' cx > {
717
+ infcx : & ' cx InferCtxt < ' cx , ' tcx > ,
718
+ span : Span ,
719
+ for_vid : ty:: TyVid ,
720
+ make_region_vars : bool ,
721
+ cycle_detected : bool ,
722
+ }
723
+
724
+ impl < ' cx , ' tcx > ty_fold:: TypeFolder < ' tcx > for Generalizer < ' cx , ' tcx > {
725
+ fn tcx ( & self ) -> & ty:: ctxt < ' tcx > {
726
+ self . infcx . tcx
727
+ }
728
+
729
+ fn fold_ty ( & mut self , t : ty:: t ) -> ty:: t {
730
+ // Check to see whether the type we are genealizing references
731
+ // `vid`. At the same time, also update any type variables to
732
+ // the values that they are bound to. This is needed to truly
733
+ // check for cycles, but also just makes things readable.
734
+ //
735
+ // (In particular, you could have something like `$0 = Box<$1>`
736
+ // where `$1` has already been instantiated with `Box<$0>`)
737
+ match ty:: get ( t) . sty {
738
+ ty:: ty_infer( ty:: TyVar ( vid) ) => {
739
+ if vid == self . for_vid {
740
+ self . cycle_detected = true ;
741
+ ty:: mk_err ( )
742
+ } else {
743
+ match self . infcx . type_variables . borrow ( ) . probe ( vid) {
744
+ Some ( u) => self . fold_ty ( u) ,
745
+ None => t,
746
+ }
747
+ }
748
+ }
749
+ _ => {
750
+ ty_fold:: super_fold_ty ( self , t)
751
+ }
752
+ }
753
+ }
754
+
755
+ fn fold_region ( & mut self , r : ty:: Region ) -> ty:: Region {
756
+ match r {
757
+ ty:: ReLateBound ( ..) | ty:: ReEarlyBound ( ..) => r,
758
+ _ if self . make_region_vars => {
759
+ // FIXME: This is non-ideal because we don't give a
760
+ // very descriptive origin for this region variable.
761
+ self . infcx . next_region_var ( MiscVariable ( self . span ) )
762
+ }
763
+ _ => r,
764
+ }
691
765
}
692
766
}
767
+
768
+
0 commit comments