11use crate :: middle:: resolve_bound_vars as rbv;
2- use crate :: mir:: interpret:: LitToConstInput ;
3- use crate :: ty:: { self , InternalSubsts , ParamEnv , ParamEnvAnd , Ty , TyCtxt } ;
2+ use crate :: mir:: interpret:: { AllocId , ConstValue , LitToConstInput , Scalar } ;
3+ use crate :: ty:: { self , InternalSubsts , ParamEnv , ParamEnvAnd , Ty , TyCtxt , TypeVisitableExt } ;
44use rustc_data_structures:: intern:: Interned ;
55use rustc_error_messages:: MultiSpan ;
66use rustc_hir as hir;
@@ -14,9 +14,13 @@ mod valtree;
1414
1515pub use int:: * ;
1616pub use kind:: * ;
17+ use rustc_span:: ErrorGuaranteed ;
1718use rustc_span:: DUMMY_SP ;
19+ use rustc_target:: abi:: Size ;
1820pub use valtree:: * ;
1921
22+ use super :: sty:: ConstKind ;
23+
2024/// Use this rather than `ConstData`, whenever possible.
2125#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash , HashStable ) ]
2226#[ rustc_pass_by_value]
@@ -32,6 +36,16 @@ pub struct ConstData<'tcx> {
3236#[ cfg( all( target_arch = "x86_64" , target_pointer_width = "64" ) ) ]
3337static_assert_size ! ( ConstData <' _>, 40 ) ;
3438
39+ enum EvalMode {
40+ Typeck ,
41+ Mir ,
42+ }
43+
44+ enum EvalResult < ' tcx > {
45+ ValTree ( ty:: ValTree < ' tcx > ) ,
46+ ConstVal ( ConstValue < ' tcx > ) ,
47+ }
48+
3549impl < ' tcx > Const < ' tcx > {
3650 #[ inline]
3751 pub fn ty ( self ) -> Ty < ' tcx > {
@@ -40,7 +54,7 @@ impl<'tcx> Const<'tcx> {
4054
4155 #[ inline]
4256 pub fn kind ( self ) -> ConstKind < ' tcx > {
43- self . 0 . kind
57+ self . 0 . kind . clone ( )
4458 }
4559
4660 #[ inline]
@@ -293,12 +307,12 @@ impl<'tcx> Const<'tcx> {
293307 assert_eq ! ( self . ty( ) , ty) ;
294308 let size = tcx. layout_of ( param_env. with_reveal_all_normalized ( tcx) . and ( ty) ) . ok ( ) ?. size ;
295309 // if `ty` does not depend on generic parameters, use an empty param_env
296- self . kind ( ) . eval ( tcx, param_env) . try_to_bits ( size)
310+ self . eval ( tcx, param_env) . try_to_bits ( size)
297311 }
298312
299313 #[ inline]
300314 pub fn try_eval_bool ( self , tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > ) -> Option < bool > {
301- self . kind ( ) . eval ( tcx, param_env) . try_to_bool ( )
315+ self . eval ( tcx, param_env) . try_to_bool ( )
302316 }
303317
304318 #[ inline]
@@ -307,14 +321,14 @@ impl<'tcx> Const<'tcx> {
307321 tcx : TyCtxt < ' tcx > ,
308322 param_env : ParamEnv < ' tcx > ,
309323 ) -> Option < u64 > {
310- self . kind ( ) . eval ( tcx, param_env) . try_to_target_usize ( tcx)
324+ self . eval ( tcx, param_env) . try_to_target_usize ( tcx)
311325 }
312326
313327 #[ inline]
314328 /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
315329 /// unevaluated constant.
316330 pub fn eval ( self , tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > ) -> Const < ' tcx > {
317- if let Some ( val) = self . kind ( ) . try_eval_for_typeck ( tcx, param_env) {
331+ if let Some ( val) = self . try_eval_for_typeck ( tcx, param_env) {
318332 match val {
319333 Ok ( val) => ty:: Const :: new_value ( tcx, val, self . ty ( ) ) ,
320334 Err ( guar) => ty:: Const :: new_error ( tcx, guar, self . ty ( ) ) ,
@@ -339,6 +353,138 @@ impl<'tcx> Const<'tcx> {
339353 . unwrap_or_else ( || bug ! ( "expected usize, got {:#?}" , self ) )
340354 }
341355
356+ #[ inline]
357+ /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
358+ /// return `None`.
359+ // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
360+ pub fn try_eval_for_mir (
361+ self ,
362+ tcx : TyCtxt < ' tcx > ,
363+ param_env : ParamEnv < ' tcx > ,
364+ ) -> Option < Result < ConstValue < ' tcx > , ErrorGuaranteed > > {
365+ match self . try_eval_inner ( tcx, param_env, EvalMode :: Mir ) {
366+ Some ( Ok ( EvalResult :: ValTree ( _) ) ) => unreachable ! ( ) ,
367+ Some ( Ok ( EvalResult :: ConstVal ( v) ) ) => Some ( Ok ( v) ) ,
368+ Some ( Err ( e) ) => Some ( Err ( e) ) ,
369+ None => None ,
370+ }
371+ }
372+
373+ #[ inline]
374+ /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
375+ /// return `None`.
376+ // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
377+ pub fn try_eval_for_typeck (
378+ self ,
379+ tcx : TyCtxt < ' tcx > ,
380+ param_env : ParamEnv < ' tcx > ,
381+ ) -> Option < Result < ty:: ValTree < ' tcx > , ErrorGuaranteed > > {
382+ match self . try_eval_inner ( tcx, param_env, EvalMode :: Typeck ) {
383+ Some ( Ok ( EvalResult :: ValTree ( v) ) ) => Some ( Ok ( v) ) ,
384+ Some ( Ok ( EvalResult :: ConstVal ( _) ) ) => unreachable ! ( ) ,
385+ Some ( Err ( e) ) => Some ( Err ( e) ) ,
386+ None => None ,
387+ }
388+ }
389+
390+ #[ inline]
391+ fn try_eval_inner (
392+ self ,
393+ tcx : TyCtxt < ' tcx > ,
394+ param_env : ParamEnv < ' tcx > ,
395+ eval_mode : EvalMode ,
396+ ) -> Option < Result < EvalResult < ' tcx > , ErrorGuaranteed > > {
397+ assert ! ( !self . has_escaping_bound_vars( ) , "escaping vars in {self:?}" ) ;
398+ if let ConstKind :: Unevaluated ( unevaluated) = self . kind ( ) {
399+ use crate :: mir:: interpret:: ErrorHandled ;
400+
401+ // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
402+ // also does later, but we want to do it before checking for
403+ // inference variables.
404+ // Note that we erase regions *before* calling `with_reveal_all_normalized`,
405+ // so that we don't try to invoke this query with
406+ // any region variables.
407+
408+ // HACK(eddyb) when the query key would contain inference variables,
409+ // attempt using identity substs and `ParamEnv` instead, that will succeed
410+ // when the expression doesn't depend on any parameters.
411+ // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
412+ // we can call `infcx.const_eval_resolve` which handles inference variables.
413+ let param_env_and = if ( param_env, unevaluated) . has_non_region_infer ( ) {
414+ tcx. param_env ( unevaluated. def ) . and ( ty:: UnevaluatedConst {
415+ def : unevaluated. def ,
416+ substs : InternalSubsts :: identity_for_item ( tcx, unevaluated. def ) ,
417+ } )
418+ } else {
419+ tcx. erase_regions ( param_env)
420+ . with_reveal_all_normalized ( tcx)
421+ . and ( tcx. erase_regions ( unevaluated) )
422+ } ;
423+
424+ // FIXME(eddyb) maybe the `const_eval_*` methods should take
425+ // `ty::ParamEnvAnd` instead of having them separate.
426+ let ( param_env, unevaluated) = param_env_and. into_parts ( ) ;
427+ // try to resolve e.g. associated constants to their definition on an impl, and then
428+ // evaluate the const.
429+ match eval_mode {
430+ EvalMode :: Typeck => {
431+ match tcx. const_eval_resolve_for_typeck ( param_env, unevaluated, None ) {
432+ // NOTE(eddyb) `val` contains no lifetimes/types/consts,
433+ // and we use the original type, so nothing from `substs`
434+ // (which may be identity substs, see above),
435+ // can leak through `val` into the const we return.
436+ Ok ( val) => Some ( Ok ( EvalResult :: ValTree ( val?) ) ) ,
437+ Err ( ErrorHandled :: TooGeneric ) => None ,
438+ Err ( ErrorHandled :: Reported ( e) ) => Some ( Err ( e. into ( ) ) ) ,
439+ }
440+ }
441+ EvalMode :: Mir => {
442+ match tcx. const_eval_resolve ( param_env, unevaluated. expand ( ) , None ) {
443+ // NOTE(eddyb) `val` contains no lifetimes/types/consts,
444+ // and we use the original type, so nothing from `substs`
445+ // (which may be identity substs, see above),
446+ // can leak through `val` into the const we return.
447+ Ok ( val) => Some ( Ok ( EvalResult :: ConstVal ( val) ) ) ,
448+ Err ( ErrorHandled :: TooGeneric ) => None ,
449+ Err ( ErrorHandled :: Reported ( e) ) => Some ( Err ( e. into ( ) ) ) ,
450+ }
451+ }
452+ }
453+ } else {
454+ None
455+ }
456+ }
457+
458+ #[ inline]
459+ pub fn try_to_value ( self ) -> Option < ty:: ValTree < ' tcx > > {
460+ if let ConstKind :: Value ( val) = self . kind ( ) { Some ( val) } else { None }
461+ }
462+
463+ #[ inline]
464+ pub fn try_to_scalar ( self ) -> Option < Scalar < AllocId > > {
465+ self . try_to_value ( ) ?. try_to_scalar ( )
466+ }
467+
468+ #[ inline]
469+ pub fn try_to_scalar_int ( self ) -> Option < ScalarInt > {
470+ self . try_to_value ( ) ?. try_to_scalar_int ( )
471+ }
472+
473+ #[ inline]
474+ pub fn try_to_bits ( self , size : Size ) -> Option < u128 > {
475+ self . try_to_scalar_int ( ) ?. to_bits ( size) . ok ( )
476+ }
477+
478+ #[ inline]
479+ pub fn try_to_bool ( self ) -> Option < bool > {
480+ self . try_to_scalar_int ( ) ?. try_into ( ) . ok ( )
481+ }
482+
483+ #[ inline]
484+ pub fn try_to_target_usize ( self , tcx : TyCtxt < ' tcx > ) -> Option < u64 > {
485+ self . try_to_value ( ) ?. try_to_target_usize ( tcx)
486+ }
487+
342488 pub fn is_ct_infer ( self ) -> bool {
343489 matches ! ( self . kind( ) , ty:: ConstKind :: Infer ( _) )
344490 }
0 commit comments