@@ -45,7 +45,7 @@ use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
4545use  rustc_middle:: ty:: subst:: SubstsRef ; 
4646use  rustc_middle:: ty:: { self ,  InferConst ,  ToPredicate ,  Ty ,  TyCtxt ,  TypeFoldable } ; 
4747use  rustc_middle:: ty:: { IntType ,  UintType } ; 
48- use  rustc_span:: DUMMY_SP ; 
48+ use  rustc_span:: { Span ,   DUMMY_SP } ; 
4949
5050/// Small-storage-optimized implementation of a map 
5151/// made specifically for caching results. 
@@ -219,11 +219,11 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
219219            } 
220220
221221            ( ty:: ConstKind :: Infer ( InferConst :: Var ( vid) ) ,  _)  => { 
222-                 return  self . unify_const_variable ( a_is_expected ,  vid,  b) ; 
222+                 return  self . unify_const_variable ( relation . param_env ( ) ,  vid,  b,  a_is_expected ) ; 
223223            } 
224224
225225            ( _,  ty:: ConstKind :: Infer ( InferConst :: Var ( vid) ) )  => { 
226-                 return  self . unify_const_variable ( !a_is_expected ,  vid,  a) ; 
226+                 return  self . unify_const_variable ( relation . param_env ( ) ,  vid,  a,  !a_is_expected ) ; 
227227            } 
228228            ( ty:: ConstKind :: Unevaluated ( ..) ,  _)  if  self . tcx . lazy_normalization ( )  => { 
229229                // FIXME(#59490): Need to remove the leak check to accommodate 
@@ -247,17 +247,66 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
247247        ty:: relate:: super_relate_consts ( relation,  a,  b) 
248248    } 
249249
250-     pub  fn  unify_const_variable ( 
250+     /// Unifies the const variable `target_vid` with the given constant. 
251+      /// 
252+      /// This also tests if the given const `ct` contains an inference variable which was previously 
253+      /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct` 
254+      /// would result in an infinite type as we continously replace an inference variable 
255+      /// in `ct` with `ct` itself. 
256+      /// 
257+      /// This is especially important as unevaluated consts use their parents generics. 
258+      /// They therefore often contain unused substs, making these errors far more likely. 
259+      /// 
260+      /// A good example of this is the following: 
261+      /// 
262+      /// ```rust 
263+      /// #![feature(const_generics)] 
264+      /// 
265+      /// fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] { 
266+      ///     todo!() 
267+      /// } 
268+      /// 
269+      /// fn main() { 
270+      ///     let mut arr = Default::default(); 
271+      ///     arr = bind(arr); 
272+      /// } 
273+      /// ``` 
274+      /// 
275+      /// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics 
276+      /// of `fn bind` (meaning that its substs contain `N`). 
277+      /// 
278+      /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`. 
279+      /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`. 
280+      /// 
281+      /// As `3 + 4` contains `N` in its substs, this must not succeed. 
282+      /// 
283+      /// See `src/test/ui/const-generics/occurs-check/` for more examples where this is relevant. 
284+      fn  unify_const_variable ( 
251285        & self , 
286+         param_env :  ty:: ParamEnv < ' tcx > , 
287+         target_vid :  ty:: ConstVid < ' tcx > , 
288+         ct :  & ' tcx  ty:: Const < ' tcx > , 
252289        vid_is_expected :  bool , 
253-         vid :  ty:: ConstVid < ' tcx > , 
254-         value :  & ' tcx  ty:: Const < ' tcx > , 
255290    )  -> RelateResult < ' tcx ,  & ' tcx  ty:: Const < ' tcx > >  { 
291+         let  ( for_universe,  span)  = { 
292+             let  mut  inner = self . inner . borrow_mut ( ) ; 
293+             let  variable_table = & mut  inner. const_unification_table ( ) ; 
294+             let  var_value = variable_table. probe_value ( target_vid) ; 
295+             match  var_value. val  { 
296+                 ConstVariableValue :: Known  {  value }  => { 
297+                     bug ! ( "instantiating {:?} which has a known value {:?}" ,  target_vid,  value) 
298+                 } 
299+                 ConstVariableValue :: Unknown  {  universe }  => ( universe,  var_value. origin . span ) , 
300+             } 
301+         } ; 
302+         let  value = ConstInferUnifier  {  infcx :  self ,  span,  param_env,  for_universe,  target_vid } 
303+             . relate ( ct,  ct) ?; 
304+ 
256305        self . inner 
257306            . borrow_mut ( ) 
258307            . const_unification_table ( ) 
259308            . unify_var_value ( 
260-                 vid , 
309+                 target_vid , 
261310                ConstVarValue  { 
262311                    origin :  ConstVariableOrigin  { 
263312                        kind :  ConstVariableOriginKind :: ConstInference , 
@@ -266,8 +315,8 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
266315                    val :  ConstVariableValue :: Known  {  value } , 
267316                } , 
268317            ) 
269-             . map_err ( |e|  const_unification_error ( vid_is_expected ,  e ) ) ? ; 
270-         Ok ( value ) 
318+             . map ( | ( ) | value ) 
319+              . map_err ( |e|  const_unification_error ( vid_is_expected ,  e ) ) 
271320    } 
272321
273322    fn  unify_integral_variable ( 
@@ -422,7 +471,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
422471
423472        let  for_universe = match  self . infcx . inner . borrow_mut ( ) . type_variables ( ) . probe ( for_vid)  { 
424473            v @ TypeVariableValue :: Known  {  .. }  => { 
425-                 panic ! ( "instantiating {:?} which has a known value {:?}" ,  for_vid,  v, ) 
474+                 bug ! ( "instantiating {:?} which has a known value {:?}" ,  for_vid,  v, ) 
426475            } 
427476            TypeVariableValue :: Unknown  {  universe }  => universe, 
428477        } ; 
@@ -740,7 +789,6 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
740789                    } 
741790                } 
742791            } 
743-             ty:: ConstKind :: Unevaluated ( ..)  if  self . tcx ( ) . lazy_normalization ( )  => Ok ( c) , 
744792            _ => relate:: super_relate_consts ( self ,  c,  c) , 
745793        } 
746794    } 
@@ -790,3 +838,175 @@ fn float_unification_error<'tcx>(
790838    let  ( ty:: FloatVarValue ( a) ,  ty:: FloatVarValue ( b) )  = v; 
791839    TypeError :: FloatMismatch ( ty:: relate:: expected_found_bool ( a_is_expected,  a,  b) ) 
792840} 
841+ 
842+ struct  ConstInferUnifier < ' cx ,  ' tcx >  { 
843+     infcx :  & ' cx  InferCtxt < ' cx ,  ' tcx > , 
844+ 
845+     span :  Span , 
846+ 
847+     param_env :  ty:: ParamEnv < ' tcx > , 
848+ 
849+     for_universe :  ty:: UniverseIndex , 
850+ 
851+     /// The vid of the const variable that is in the process of being 
852+      /// instantiated; if we find this within the const we are folding, 
853+      /// that means we would have created a cyclic const. 
854+      target_vid :  ty:: ConstVid < ' tcx > , 
855+ } 
856+ 
857+ // We use `TypeRelation` here to propagate `RelateResult` upwards. 
858+ // 
859+ // Both inputs are expected to be the same. 
860+ impl  TypeRelation < ' tcx >  for  ConstInferUnifier < ' _ ,  ' tcx >  { 
861+     fn  tcx ( & self )  -> TyCtxt < ' tcx >  { 
862+         self . infcx . tcx 
863+     } 
864+ 
865+     fn  param_env ( & self )  -> ty:: ParamEnv < ' tcx >  { 
866+         self . param_env 
867+     } 
868+ 
869+     fn  tag ( & self )  -> & ' static  str  { 
870+         "ConstInferUnifier" 
871+     } 
872+ 
873+     fn  a_is_expected ( & self )  -> bool  { 
874+         true 
875+     } 
876+ 
877+     fn  relate_with_variance < T :  Relate < ' tcx > > ( 
878+         & mut  self , 
879+         _variance :  ty:: Variance , 
880+         a :  T , 
881+         b :  T , 
882+     )  -> RelateResult < ' tcx ,  T >  { 
883+         // We don't care about variance here. 
884+         self . relate ( a,  b) 
885+     } 
886+ 
887+     fn  binders < T > ( 
888+         & mut  self , 
889+         a :  ty:: Binder < T > , 
890+         b :  ty:: Binder < T > , 
891+     )  -> RelateResult < ' tcx ,  ty:: Binder < T > > 
892+     where 
893+         T :  Relate < ' tcx > , 
894+     { 
895+         Ok ( ty:: Binder :: bind ( self . relate ( a. skip_binder ( ) ,  b. skip_binder ( ) ) ?) ) 
896+     } 
897+ 
898+     fn  tys ( & mut  self ,  t :  Ty < ' tcx > ,  _t :  Ty < ' tcx > )  -> RelateResult < ' tcx ,  Ty < ' tcx > >  { 
899+         debug_assert_eq ! ( t,  _t) ; 
900+         debug ! ( "ConstInferUnifier: t={:?}" ,  t) ; 
901+ 
902+         match  t. kind ( )  { 
903+             & ty:: Infer ( ty:: TyVar ( vid) )  => { 
904+                 let  vid = self . infcx . inner . borrow_mut ( ) . type_variables ( ) . root_var ( vid) ; 
905+                 let  probe = self . infcx . inner . borrow_mut ( ) . type_variables ( ) . probe ( vid) ; 
906+                 match  probe { 
907+                     TypeVariableValue :: Known  {  value :  u }  => { 
908+                         debug ! ( "ConstOccursChecker: known value {:?}" ,  u) ; 
909+                         self . tys ( u,  u) 
910+                     } 
911+                     TypeVariableValue :: Unknown  {  universe }  => { 
912+                         if  self . for_universe . can_name ( universe)  { 
913+                             return  Ok ( t) ; 
914+                         } 
915+ 
916+                         let  origin =
917+                             * self . infcx . inner . borrow_mut ( ) . type_variables ( ) . var_origin ( vid) ; 
918+                         let  new_var_id = self . infcx . inner . borrow_mut ( ) . type_variables ( ) . new_var ( 
919+                             self . for_universe , 
920+                             false , 
921+                             origin, 
922+                         ) ; 
923+                         let  u = self . tcx ( ) . mk_ty_var ( new_var_id) ; 
924+                         debug ! ( 
925+                             "ConstInferUnifier: replacing original vid={:?} with new={:?}" , 
926+                             vid,  u
927+                         ) ; 
928+                         Ok ( u) 
929+                     } 
930+                 } 
931+             } 
932+             _ => relate:: super_relate_tys ( self ,  t,  t) , 
933+         } 
934+     } 
935+ 
936+     fn  regions ( 
937+         & mut  self , 
938+         r :  ty:: Region < ' tcx > , 
939+         _r :  ty:: Region < ' tcx > , 
940+     )  -> RelateResult < ' tcx ,  ty:: Region < ' tcx > >  { 
941+         debug_assert_eq ! ( r,  _r) ; 
942+         debug ! ( "ConstInferUnifier: r={:?}" ,  r) ; 
943+ 
944+         match  r { 
945+             // Never make variables for regions bound within the type itself, 
946+             // nor for erased regions. 
947+             ty:: ReLateBound ( ..)  | ty:: ReErased  => { 
948+                 return  Ok ( r) ; 
949+             } 
950+ 
951+             ty:: RePlaceholder ( ..) 
952+             | ty:: ReVar ( ..) 
953+             | ty:: ReEmpty ( _) 
954+             | ty:: ReStatic 
955+             | ty:: ReEarlyBound ( ..) 
956+             | ty:: ReFree ( ..)  => { 
957+                 // see common code below 
958+             } 
959+         } 
960+ 
961+         let  r_universe = self . infcx . universe_of_region ( r) ; 
962+         if  self . for_universe . can_name ( r_universe)  { 
963+             return  Ok ( r) ; 
964+         }  else  { 
965+             // FIXME: This is non-ideal because we don't give a 
966+             // very descriptive origin for this region variable. 
967+             Ok ( self . infcx . next_region_var_in_universe ( MiscVariable ( self . span ) ,  self . for_universe ) ) 
968+         } 
969+     } 
970+ 
971+     fn  consts ( 
972+         & mut  self , 
973+         c :  & ' tcx  ty:: Const < ' tcx > , 
974+         _c :  & ' tcx  ty:: Const < ' tcx > , 
975+     )  -> RelateResult < ' tcx ,  & ' tcx  ty:: Const < ' tcx > >  { 
976+         debug_assert_eq ! ( c,  _c) ; 
977+         debug ! ( "ConstInferUnifier: c={:?}" ,  c) ; 
978+ 
979+         match  c. val  { 
980+             ty:: ConstKind :: Infer ( InferConst :: Var ( vid) )  => { 
981+                 let  mut  inner = self . infcx . inner . borrow_mut ( ) ; 
982+                 let  variable_table = & mut  inner. const_unification_table ( ) ; 
983+ 
984+                 // Check if the current unification would end up 
985+                 // unifying `target_vid` with a const which contains 
986+                 // an inference variable which is unioned with `target_vid`. 
987+                 // 
988+                 // Not doing so can easily result in stack overflows. 
989+                 if  variable_table. unioned ( self . target_vid ,  vid)  { 
990+                     return  Err ( TypeError :: CyclicConst ( c) ) ; 
991+                 } 
992+ 
993+                 let  var_value = variable_table. probe_value ( vid) ; 
994+                 match  var_value. val  { 
995+                     ConstVariableValue :: Known  {  value :  u }  => self . consts ( u,  u) , 
996+                     ConstVariableValue :: Unknown  {  universe }  => { 
997+                         if  self . for_universe . can_name ( universe)  { 
998+                             Ok ( c) 
999+                         }  else  { 
1000+                             let  new_var_id = variable_table. new_key ( ConstVarValue  { 
1001+                                 origin :  var_value. origin , 
1002+                                 val :  ConstVariableValue :: Unknown  {  universe :  self . for_universe  } , 
1003+                             } ) ; 
1004+                             Ok ( self . tcx ( ) . mk_const_var ( new_var_id,  c. ty ) ) 
1005+                         } 
1006+                     } 
1007+                 } 
1008+             } 
1009+             _ => relate:: super_relate_consts ( self ,  c,  c) , 
1010+         } 
1011+     } 
1012+ } 
0 commit comments