@@ -39,6 +39,7 @@ use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
3939use middle:: ty:: { IntType , UintType } ;
4040use middle:: ty:: { BuiltinBounds } ;
4141use middle:: ty;
42+ use middle:: ty_fold;
4243use middle:: typeck:: infer:: equate:: Equate ;
4344use middle:: typeck:: infer:: glb:: Glb ;
4445use middle:: typeck:: infer:: lub:: Lub ;
@@ -48,14 +49,15 @@ use middle::typeck::infer::{InferCtxt, cres};
4849use middle:: typeck:: infer:: { MiscVariable , TypeTrace } ;
4950use middle:: typeck:: infer:: type_variable:: { RelationDir , EqTo ,
5051 SubtypeOf , SupertypeOf } ;
51- use middle:: ty_fold:: { RegionFolder , TypeFoldable } ;
52+ use middle:: ty_fold:: { TypeFoldable } ;
5253use util:: ppaux:: Repr ;
5354
5455use std:: result;
5556
5657use syntax:: ast:: { Onceness , FnStyle } ;
5758use syntax:: ast;
5859use syntax:: abi;
60+ use syntax:: codemap:: Span ;
5961
6062pub trait Combine < ' tcx > {
6163 fn infcx < ' a > ( & ' a self ) -> & ' a InferCtxt < ' a , ' tcx > ;
@@ -637,10 +639,14 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
637639 Some ( t) => t, // ...already instantiated.
638640 None => { // ...not yet instantiated:
639641 // 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+ } ) ;
644650 debug ! ( "instantiate(a_ty={}, dir={}, \
645651 b_vid={}, generalized_ty={})",
646652 a_ty. repr( tcx) , dir, b_vid. repr( tcx) ,
@@ -678,15 +684,85 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
678684 Ok ( ( ) )
679685 }
680686
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+ }
684715
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+ }
691765 }
692766}
767+
768+
0 commit comments