@@ -9,13 +9,13 @@ use crate::ty::adjustment::PointerCast;
9
9
use crate :: ty:: codec:: { TyDecoder , TyEncoder } ;
10
10
use crate :: ty:: fold:: { FallibleTypeFolder , TypeFoldable , TypeVisitor } ;
11
11
use crate :: ty:: print:: { FmtPrinter , Printer } ;
12
- use crate :: ty:: subst:: { Subst , SubstsRef } ;
12
+ use crate :: ty:: subst:: { InternalSubsts , Subst , SubstsRef } ;
13
13
use crate :: ty:: { self , List , Ty , TyCtxt } ;
14
14
use crate :: ty:: { AdtDef , InstanceDef , Region , ScalarInt , UserTypeAnnotationIndex } ;
15
15
16
16
use rustc_errors:: ErrorGuaranteed ;
17
17
use 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 } ;
19
19
use rustc_hir:: { self , GeneratorKind } ;
20
20
use rustc_hir:: { self as hir, HirId } ;
21
21
use rustc_session:: Session ;
@@ -2664,6 +2664,16 @@ impl<'tcx> ConstantKind<'tcx> {
2664
2664
}
2665
2665
}
2666
2666
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
+
2667
2677
#[ inline]
2668
2678
pub fn try_to_value ( self ) -> Option < interpret:: ConstValue < ' tcx > > {
2669
2679
match self {
@@ -2692,6 +2702,32 @@ impl<'tcx> ConstantKind<'tcx> {
2692
2702
self . try_to_scalar_int ( ) ?. try_into ( ) . ok ( )
2693
2703
}
2694
2704
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
+
2695
2731
#[ inline]
2696
2732
pub fn try_eval_bits (
2697
2733
& self ,
@@ -2726,25 +2762,181 @@ impl<'tcx> ConstantKind<'tcx> {
2726
2762
}
2727
2763
}
2728
2764
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
+
2729
2781
pub fn from_bool ( tcx : TyCtxt < ' tcx > , v : bool ) -> Self {
2730
2782
let cv = ConstValue :: from_bool ( v) ;
2731
2783
Self :: Val ( cv, tcx. types . bool )
2732
2784
}
2733
2785
2734
- pub fn from_zero_sized ( ty : Ty < ' tcx > ) -> Self {
2786
+ pub fn zero_sized ( ty : Ty < ' tcx > ) -> Self {
2735
2787
let cv = ConstValue :: Scalar ( Scalar :: ZST ) ;
2736
2788
Self :: Val ( cv, ty)
2737
2789
}
2738
2790
2739
2791
pub fn from_usize ( tcx : TyCtxt < ' tcx > , n : u64 ) -> Self {
2740
2792
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
+ }
2746
2795
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
+ }
2748
2940
}
2749
2941
}
2750
2942
0 commit comments