@@ -9,13 +9,13 @@ use crate::ty::adjustment::PointerCast;
99use crate :: ty:: codec:: { TyDecoder , TyEncoder } ;
1010use crate :: ty:: fold:: { FallibleTypeFolder , TypeFoldable , TypeVisitor } ;
1111use crate :: ty:: print:: { FmtPrinter , Printer } ;
12- use crate :: ty:: subst:: { Subst , SubstsRef } ;
12+ use crate :: ty:: subst:: { InternalSubsts , Subst , SubstsRef } ;
1313use crate :: ty:: { self , List , Ty , TyCtxt } ;
1414use crate :: ty:: { AdtDef , InstanceDef , Region , ScalarInt , UserTypeAnnotationIndex } ;
1515
1616use rustc_errors:: ErrorGuaranteed ;
1717use rustc_hir:: def:: { CtorKind , Namespace } ;
18- use rustc_hir:: def_id:: { DefId , CRATE_DEF_INDEX } ;
18+ use rustc_hir:: def_id:: { DefId , LocalDefId , CRATE_DEF_INDEX } ;
1919use rustc_hir:: { self , GeneratorKind } ;
2020use rustc_hir:: { self as hir, HirId } ;
2121use rustc_session:: Session ;
@@ -2664,6 +2664,16 @@ impl<'tcx> ConstantKind<'tcx> {
26642664 }
26652665 }
26662666
2667+ pub fn try_val ( & self ) -> Option < ConstValue < ' tcx > > {
2668+ match self {
2669+ ConstantKind :: Ty ( c) => match c. val ( ) {
2670+ ty:: ConstKind :: Value ( v) => Some ( v) ,
2671+ _ => None ,
2672+ } ,
2673+ ConstantKind :: Val ( v, _) => Some ( * v) ,
2674+ }
2675+ }
2676+
26672677 #[ inline]
26682678 pub fn try_to_value ( self ) -> Option < interpret:: ConstValue < ' tcx > > {
26692679 match self {
@@ -2692,6 +2702,32 @@ impl<'tcx> ConstantKind<'tcx> {
26922702 self . try_to_scalar_int ( ) ?. try_into ( ) . ok ( )
26932703 }
26942704
2705+ #[ inline]
2706+ pub fn eval ( self , tcx : TyCtxt < ' tcx > , param_env : ty:: ParamEnv < ' tcx > ) -> Self {
2707+ match self {
2708+ Self :: Ty ( c) => {
2709+ // FIXME Need to use a different evaluation function that directly returns a `ConstValue`
2710+ // if evaluation succeeds and does not create a ValTree first
2711+ if let Some ( val) = c. val ( ) . try_eval ( tcx, param_env) {
2712+ match val {
2713+ Ok ( val) => Self :: Val ( val, c. ty ( ) ) ,
2714+ Err ( ErrorReported ) => Self :: Ty ( tcx. const_error ( self . ty ( ) ) ) ,
2715+ }
2716+ } else {
2717+ self
2718+ }
2719+ }
2720+ Self :: Val ( _, _) => self ,
2721+ }
2722+ }
2723+
2724+ #[ inline]
2725+ /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
2726+ pub fn eval_bits ( self , tcx : TyCtxt < ' tcx > , param_env : ty:: ParamEnv < ' tcx > , ty : Ty < ' tcx > ) -> u128 {
2727+ self . try_eval_bits ( tcx, param_env, ty)
2728+ . unwrap_or_else ( || bug ! ( "expected bits of {:#?}, got {:#?}" , ty, self ) )
2729+ }
2730+
26952731 #[ inline]
26962732 pub fn try_eval_bits (
26972733 & self ,
@@ -2726,25 +2762,181 @@ impl<'tcx> ConstantKind<'tcx> {
27262762 }
27272763 }
27282764
2765+ pub fn from_bits (
2766+ tcx : TyCtxt < ' tcx > ,
2767+ bits : u128 ,
2768+ param_env_ty : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
2769+ ) -> Self {
2770+ let size = tcx
2771+ . layout_of ( param_env_ty)
2772+ . unwrap_or_else ( |e| {
2773+ bug ! ( "could not compute layout for {:?}: {:?}" , param_env_ty. value, e)
2774+ } )
2775+ . size ;
2776+ let cv = ConstValue :: Scalar ( Scalar :: from_uint ( bits, size) ) ;
2777+
2778+ Self :: Val ( cv, param_env_ty. value )
2779+ }
2780+
27292781 pub fn from_bool ( tcx : TyCtxt < ' tcx > , v : bool ) -> Self {
27302782 let cv = ConstValue :: from_bool ( v) ;
27312783 Self :: Val ( cv, tcx. types . bool )
27322784 }
27332785
2734- pub fn from_zero_sized ( ty : Ty < ' tcx > ) -> Self {
2786+ pub fn zero_sized ( ty : Ty < ' tcx > ) -> Self {
27352787 let cv = ConstValue :: Scalar ( Scalar :: ZST ) ;
27362788 Self :: Val ( cv, ty)
27372789 }
27382790
27392791 pub fn from_usize ( tcx : TyCtxt < ' tcx > , n : u64 ) -> Self {
27402792 let ty = tcx. types . usize ;
2741- let size = tcx
2742- . layout_of ( ty:: ParamEnv :: empty ( ) . and ( ty) )
2743- . unwrap_or_else ( |e| bug ! ( "could not compute layout for {:?}: {:?}" , ty, e) )
2744- . size ;
2745- let cv = ConstValue :: Scalar ( Scalar :: from_uint ( n as u128 , size) ) ;
2793+ Self :: from_bits ( tcx, n as u128 , ty:: ParamEnv :: empty ( ) . and ( ty) )
2794+ }
27462795
2747- Self :: Val ( cv, ty)
2796+ #[ instrument( skip( tcx) , level = "debug" ) ]
2797+ pub fn try_eval_lit_or_param (
2798+ tcx : TyCtxt < ' tcx > ,
2799+ ty : Ty < ' tcx > ,
2800+ expr : & ' tcx hir:: Expr < ' tcx > ,
2801+ ) -> Option < Self > {
2802+ // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
2803+ // currently have to be wrapped in curly brackets, so it's necessary to special-case.
2804+ let expr = match & expr. kind {
2805+ hir:: ExprKind :: Block ( block, _) if block. stmts . is_empty ( ) && block. expr . is_some ( ) => {
2806+ block. expr . as_ref ( ) . unwrap ( )
2807+ }
2808+ _ => expr,
2809+ } ;
2810+
2811+ let lit_input = match expr. kind {
2812+ hir:: ExprKind :: Lit ( ref lit) => {
2813+ Some ( interpret:: LitToConstInput { lit : & lit. node , ty, neg : false } )
2814+ }
2815+ hir:: ExprKind :: Unary ( hir:: UnOp :: Neg , ref expr) => match expr. kind {
2816+ hir:: ExprKind :: Lit ( ref lit) => {
2817+ Some ( interpret:: LitToConstInput { lit : & lit. node , ty, neg : true } )
2818+ }
2819+ _ => None ,
2820+ } ,
2821+ _ => None ,
2822+ } ;
2823+
2824+ if let Some ( lit_input) = lit_input {
2825+ // If an error occurred, ignore that it's a literal and leave reporting the error up to
2826+ // mir.
2827+ match tcx. at ( expr. span ) . lit_to_mir_constant ( lit_input) {
2828+ Ok ( c) => return Some ( c) ,
2829+ Err ( e) => {
2830+ tcx. sess . delay_span_bug (
2831+ expr. span ,
2832+ & format ! ( "Const::from_anon_const: couldn't lit_to_const {:?}" , e) ,
2833+ ) ;
2834+ }
2835+ }
2836+ }
2837+ use hir:: { def:: DefKind :: ConstParam , def:: Res , ExprKind , Path , QPath } ;
2838+ match expr. kind {
2839+ ExprKind :: Path ( QPath :: Resolved ( _, & Path { res : Res :: Def ( ConstParam , def_id) , .. } ) ) => {
2840+ // Find the name and index of the const parameter by indexing the generics of
2841+ // the parent item and construct a `ParamConst`.
2842+ let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id. expect_local ( ) ) ;
2843+ let item_id = tcx. hir ( ) . get_parent_node ( hir_id) ;
2844+ let item_def_id = tcx. hir ( ) . local_def_id ( item_id) ;
2845+ let generics = tcx. generics_of ( item_def_id. to_def_id ( ) ) ;
2846+ let index = generics. param_def_id_to_index [ & def_id] ;
2847+ let name = tcx. hir ( ) . name ( hir_id) ;
2848+ let ty_const = tcx. mk_const ( ty:: ConstS {
2849+ val : ty:: ConstKind :: Param ( ty:: ParamConst :: new ( index, name) ) ,
2850+ ty,
2851+ } ) ;
2852+
2853+ Some ( Self :: Ty ( ty_const) )
2854+ }
2855+ _ => None ,
2856+ }
2857+ }
2858+
2859+ #[ instrument( skip( tcx) , level = "debug" ) ]
2860+ pub fn from_inline_const ( tcx : TyCtxt < ' tcx > , def_id : LocalDefId ) -> Self {
2861+ let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ;
2862+
2863+ let body_id = match tcx. hir ( ) . get ( hir_id) {
2864+ hir:: Node :: AnonConst ( ac) => ac. body ,
2865+ _ => span_bug ! (
2866+ tcx. def_span( def_id. to_def_id( ) ) ,
2867+ "from_inline_const can only process anonymous constants"
2868+ ) ,
2869+ } ;
2870+
2871+ let expr = & tcx. hir ( ) . body ( body_id) . value ;
2872+
2873+ let ty = tcx. typeck ( def_id) . node_type ( hir_id) ;
2874+
2875+ let ret = match Self :: try_eval_lit_or_param ( tcx, ty, expr) {
2876+ Some ( v) => v,
2877+ None => {
2878+ let typeck_root_def_id = tcx. typeck_root_def_id ( def_id. to_def_id ( ) ) ;
2879+ let parent_substs =
2880+ tcx. erase_regions ( InternalSubsts :: identity_for_item ( tcx, typeck_root_def_id) ) ;
2881+ let substs = ty:: InlineConstSubsts :: new (
2882+ tcx,
2883+ ty:: InlineConstSubstsParts { parent_substs, ty } ,
2884+ )
2885+ . substs ;
2886+ let ty_const = tcx. mk_const ( ty:: ConstS {
2887+ val : ty:: ConstKind :: Unevaluated ( ty:: Unevaluated {
2888+ def : ty:: WithOptConstParam :: unknown ( def_id) . to_global ( ) ,
2889+ substs,
2890+ promoted : None ,
2891+ } ) ,
2892+ ty,
2893+ } ) ;
2894+
2895+ Self :: Ty ( ty_const)
2896+ }
2897+ } ;
2898+ debug_assert ! ( !ret. has_free_regions( ) ) ;
2899+ ret
2900+ }
2901+
2902+ /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
2903+ /// converted to a constant, everything else becomes `Unevaluated`.
2904+ pub fn from_anon_const ( tcx : TyCtxt < ' tcx > , def_id : LocalDefId ) -> Self {
2905+ Self :: from_opt_const_arg_anon_const ( tcx, ty:: WithOptConstParam :: unknown ( def_id) )
2906+ }
2907+
2908+ #[ instrument( skip( tcx) , level = "debug" ) ]
2909+ fn from_opt_const_arg_anon_const (
2910+ tcx : TyCtxt < ' tcx > ,
2911+ def : ty:: WithOptConstParam < LocalDefId > ,
2912+ ) -> Self {
2913+ let body_id = match tcx. hir ( ) . get_by_def_id ( def. did ) {
2914+ hir:: Node :: AnonConst ( ac) => ac. body ,
2915+ _ => span_bug ! (
2916+ tcx. def_span( def. did. to_def_id( ) ) ,
2917+ "from_anon_const can only process anonymous constants"
2918+ ) ,
2919+ } ;
2920+
2921+ let expr = & tcx. hir ( ) . body ( body_id) . value ;
2922+ debug ! ( ?expr) ;
2923+
2924+ let ty = tcx. type_of ( def. def_id_for_type_of ( ) ) ;
2925+
2926+ match Self :: try_eval_lit_or_param ( tcx, ty, expr) {
2927+ Some ( v) => v,
2928+ None => {
2929+ let ty_const = tcx. mk_const ( ty:: ConstS {
2930+ val : ty:: ConstKind :: Unevaluated ( ty:: Unevaluated {
2931+ def : def. to_global ( ) ,
2932+ substs : InternalSubsts :: identity_for_item ( tcx, def. did . to_def_id ( ) ) ,
2933+ promoted : None ,
2934+ } ) ,
2935+ ty,
2936+ } ) ;
2937+ Self :: Ty ( ty_const)
2938+ }
2939+ }
27482940 }
27492941}
27502942
0 commit comments