@@ -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:: { GenericArg , 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 ;
@@ -2921,6 +2921,16 @@ impl<'tcx> ConstantKind<'tcx> {
29212921 }
29222922 }
29232923
2924+ pub fn try_val ( & self ) -> Option < ConstValue < ' tcx > > {
2925+ match self {
2926+ ConstantKind :: Ty ( c) => match c. val ( ) {
2927+ ty:: ConstKind :: Value ( v) => Some ( v) ,
2928+ _ => None ,
2929+ } ,
2930+ ConstantKind :: Val ( v, _) => Some ( * v) ,
2931+ }
2932+ }
2933+
29242934 #[ inline]
29252935 pub fn try_to_value ( self ) -> Option < interpret:: ConstValue < ' tcx > > {
29262936 match self {
@@ -2949,6 +2959,32 @@ impl<'tcx> ConstantKind<'tcx> {
29492959 self . try_to_scalar_int ( ) ?. try_into ( ) . ok ( )
29502960 }
29512961
2962+ #[ inline]
2963+ pub fn eval ( self , tcx : TyCtxt < ' tcx > , param_env : ty:: ParamEnv < ' tcx > ) -> Self {
2964+ match self {
2965+ Self :: Ty ( c) => {
2966+ // FIXME Need to use a different evaluation function that directly returns a `ConstValue`
2967+ // if evaluation succeeds and does not create a ValTree first
2968+ if let Some ( val) = c. val ( ) . try_eval ( tcx, param_env) {
2969+ match val {
2970+ Ok ( val) => Self :: Val ( val, c. ty ( ) ) ,
2971+ Err ( _) => Self :: Ty ( tcx. const_error ( self . ty ( ) ) ) ,
2972+ }
2973+ } else {
2974+ self
2975+ }
2976+ }
2977+ Self :: Val ( _, _) => self ,
2978+ }
2979+ }
2980+
2981+ /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
2982+ #[ inline]
2983+ pub fn eval_bits ( self , tcx : TyCtxt < ' tcx > , param_env : ty:: ParamEnv < ' tcx > , ty : Ty < ' tcx > ) -> u128 {
2984+ self . try_eval_bits ( tcx, param_env, ty)
2985+ . unwrap_or_else ( || bug ! ( "expected bits of {:#?}, got {:#?}" , ty, self ) )
2986+ }
2987+
29522988 #[ inline]
29532989 pub fn try_eval_bits (
29542990 & self ,
@@ -2983,25 +3019,142 @@ impl<'tcx> ConstantKind<'tcx> {
29833019 }
29843020 }
29853021
3022+ pub fn from_bits (
3023+ tcx : TyCtxt < ' tcx > ,
3024+ bits : u128 ,
3025+ param_env_ty : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
3026+ ) -> Self {
3027+ let size = tcx
3028+ . layout_of ( param_env_ty)
3029+ . unwrap_or_else ( |e| {
3030+ bug ! ( "could not compute layout for {:?}: {:?}" , param_env_ty. value, e)
3031+ } )
3032+ . size ;
3033+ let cv = ConstValue :: Scalar ( Scalar :: from_uint ( bits, size) ) ;
3034+
3035+ Self :: Val ( cv, param_env_ty. value )
3036+ }
3037+
29863038 pub fn from_bool ( tcx : TyCtxt < ' tcx > , v : bool ) -> Self {
29873039 let cv = ConstValue :: from_bool ( v) ;
29883040 Self :: Val ( cv, tcx. types . bool )
29893041 }
29903042
2991- pub fn from_zero_sized ( ty : Ty < ' tcx > ) -> Self {
3043+ pub fn zero_sized ( ty : Ty < ' tcx > ) -> Self {
29923044 let cv = ConstValue :: Scalar ( Scalar :: ZST ) ;
29933045 Self :: Val ( cv, ty)
29943046 }
29953047
29963048 pub fn from_usize ( tcx : TyCtxt < ' tcx > , n : u64 ) -> Self {
29973049 let ty = tcx. types . usize ;
2998- let size = tcx
2999- . layout_of ( ty:: ParamEnv :: empty ( ) . and ( ty) )
3000- . unwrap_or_else ( |e| bug ! ( "could not compute layout for {:?}: {:?}" , ty, e) )
3001- . size ;
3002- let cv = ConstValue :: Scalar ( Scalar :: from_uint ( n as u128 , size) ) ;
3050+ Self :: from_bits ( tcx, n as u128 , ty:: ParamEnv :: empty ( ) . and ( ty) )
3051+ }
30033052
3004- Self :: Val ( cv, ty)
3053+ /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
3054+ /// converted to a constant, everything else becomes `Unevaluated`.
3055+ pub fn from_anon_const (
3056+ tcx : TyCtxt < ' tcx > ,
3057+ def_id : LocalDefId ,
3058+ param_env : ty:: ParamEnv < ' tcx > ,
3059+ ) -> Self {
3060+ Self :: from_opt_const_arg_anon_const ( tcx, ty:: WithOptConstParam :: unknown ( def_id) , param_env)
3061+ }
3062+
3063+ #[ instrument( skip( tcx) , level = "debug" ) ]
3064+ fn from_opt_const_arg_anon_const (
3065+ tcx : TyCtxt < ' tcx > ,
3066+ def : ty:: WithOptConstParam < LocalDefId > ,
3067+ param_env : ty:: ParamEnv < ' tcx > ,
3068+ ) -> Self {
3069+ let body_id = match tcx. hir ( ) . get_by_def_id ( def. did ) {
3070+ hir:: Node :: AnonConst ( ac) => ac. body ,
3071+ _ => span_bug ! (
3072+ tcx. def_span( def. did. to_def_id( ) ) ,
3073+ "from_anon_const can only process anonymous constants"
3074+ ) ,
3075+ } ;
3076+
3077+ let expr = & tcx. hir ( ) . body ( body_id) . value ;
3078+ debug ! ( ?expr) ;
3079+
3080+ // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
3081+ // currently have to be wrapped in curly brackets, so it's necessary to special-case.
3082+ let expr = match & expr. kind {
3083+ hir:: ExprKind :: Block ( block, _) if block. stmts . is_empty ( ) && block. expr . is_some ( ) => {
3084+ block. expr . as_ref ( ) . unwrap ( )
3085+ }
3086+ _ => expr,
3087+ } ;
3088+
3089+ let ty = tcx. type_of ( def. def_id_for_type_of ( ) ) ;
3090+
3091+ // FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
3092+ // does not provide the parents generics to anonymous constants. We still allow generic const
3093+ // parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to
3094+ // ever try to substitute the generic parameters in their bodies.
3095+ //
3096+ // While this doesn't happen as these constants are always used as `ty::ConstKind::Param`, it does
3097+ // cause issues if we were to remove that special-case and try to evaluate the constant instead.
3098+ use hir:: { def:: DefKind :: ConstParam , def:: Res , ExprKind , Path , QPath } ;
3099+ match expr. kind {
3100+ ExprKind :: Path ( QPath :: Resolved ( _, & Path { res : Res :: Def ( ConstParam , def_id) , .. } ) ) => {
3101+ // Find the name and index of the const parameter by indexing the generics of
3102+ // the parent item and construct a `ParamConst`.
3103+ let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id. expect_local ( ) ) ;
3104+ let item_id = tcx. hir ( ) . get_parent_node ( hir_id) ;
3105+ let item_def_id = tcx. hir ( ) . local_def_id ( item_id) ;
3106+ let generics = tcx. generics_of ( item_def_id. to_def_id ( ) ) ;
3107+ let index = generics. param_def_id_to_index [ & def_id] ;
3108+ let name = tcx. hir ( ) . name ( hir_id) ;
3109+ let ty_const = tcx. mk_const ( ty:: ConstS {
3110+ val : ty:: ConstKind :: Param ( ty:: ParamConst :: new ( index, name) ) ,
3111+ ty,
3112+ } ) ;
3113+
3114+ return Self :: Ty ( ty_const) ;
3115+ }
3116+ _ => { }
3117+ }
3118+
3119+ let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def. did ) ;
3120+ let parent_substs = if let Some ( parent_hir_id) = tcx. hir ( ) . find_parent_node ( hir_id) {
3121+ if let Some ( parent_did) = tcx. hir ( ) . opt_local_def_id ( parent_hir_id) {
3122+ InternalSubsts :: identity_for_item ( tcx, parent_did. to_def_id ( ) )
3123+ } else {
3124+ tcx. mk_substs ( Vec :: < GenericArg < ' tcx > > :: new ( ) . into_iter ( ) )
3125+ }
3126+ } else {
3127+ tcx. mk_substs ( Vec :: < GenericArg < ' tcx > > :: new ( ) . into_iter ( ) )
3128+ } ;
3129+ debug ! ( ?parent_substs) ;
3130+
3131+ let did = def. did . to_def_id ( ) ;
3132+ let child_substs = InternalSubsts :: identity_for_item ( tcx, did) ;
3133+ let substs = tcx. mk_substs ( parent_substs. into_iter ( ) . chain ( child_substs. into_iter ( ) ) ) ;
3134+ debug ! ( ?substs) ;
3135+
3136+ let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def. did ) ;
3137+ let span = tcx. hir ( ) . span ( hir_id) ;
3138+ let uneval = ty:: Unevaluated :: new ( def. to_global ( ) , substs) ;
3139+ debug ! ( ?span, ?param_env) ;
3140+
3141+ match tcx. const_eval_resolve ( param_env, uneval, Some ( span) ) {
3142+ Ok ( val) => Self :: Val ( val, ty) ,
3143+ Err ( _) => {
3144+ // Error was handled in `const_eval_resolve`. Here we just create a
3145+ // new unevaluated const and error hard later in codegen
3146+ let ty_const = tcx. mk_const ( ty:: ConstS {
3147+ val : ty:: ConstKind :: Unevaluated ( ty:: Unevaluated {
3148+ def : def. to_global ( ) ,
3149+ substs : InternalSubsts :: identity_for_item ( tcx, def. did . to_def_id ( ) ) ,
3150+ promoted : None ,
3151+ } ) ,
3152+ ty,
3153+ } ) ;
3154+
3155+ Self :: Ty ( ty_const)
3156+ }
3157+ }
30053158 }
30063159}
30073160
0 commit comments