33use std:: convert:: TryFrom ;
44
55use rustc_hir:: Mutability ;
6- use rustc_middle:: mir;
76use rustc_middle:: ty:: { self , TyCtxt } ;
7+ use rustc_middle:: {
8+ mir:: { self , interpret:: ConstAlloc } ,
9+ ty:: ScalarInt ,
10+ } ;
811use rustc_span:: { source_map:: DUMMY_SP , symbol:: Symbol } ;
912
1013use crate :: interpret:: {
11- intern_const_alloc_recursive, ConstValue , InternKind , InterpCx , MemPlaceMeta , Scalar ,
14+ intern_const_alloc_recursive, ConstValue , InternKind , InterpCx , MPlaceTy , MemPlaceMeta , Scalar ,
1215} ;
1316
1417mod error;
@@ -35,6 +38,91 @@ pub(crate) fn const_caller_location(
3538 ConstValue :: Scalar ( loc_place. ptr )
3639}
3740
41+ /// Convert an evaluated constant to a type level constant
42+ pub ( crate ) fn const_to_valtree < ' tcx > (
43+ tcx : TyCtxt < ' tcx > ,
44+ param_env : ty:: ParamEnv < ' tcx > ,
45+ raw : ConstAlloc < ' tcx > ,
46+ ) -> Option < ty:: ValTree > {
47+ let ecx = mk_eval_cx ( tcx, DUMMY_SP , param_env, false ) ;
48+ let place = ecx. raw_const_to_mplace ( raw) . unwrap ( ) ;
49+ const_to_valtree_inner ( & ecx, & place)
50+ }
51+
52+ fn const_to_valtree_inner < ' tcx > (
53+ ecx : & CompileTimeEvalContext < ' tcx , ' tcx > ,
54+ place : & MPlaceTy < ' tcx > ,
55+ ) -> Option < ty:: ValTree > {
56+ let branches = |n, variant| {
57+ let place = match variant {
58+ Some ( variant) => ecx. mplace_downcast ( & place, variant) . unwrap ( ) ,
59+ None => * place,
60+ } ;
61+ let variant =
62+ variant. map ( |variant| Some ( ty:: ValTree :: Leaf ( ScalarInt :: from ( variant. as_u32 ( ) ) ) ) ) ;
63+ let fields = ( 0 ..n) . map ( |i| {
64+ let field = ecx. mplace_field ( & place, i) . unwrap ( ) ;
65+ const_to_valtree_inner ( ecx, & field)
66+ } ) ;
67+ Some ( ty:: ValTree :: Branch ( variant. into_iter ( ) . chain ( fields) . collect :: < Option < _ > > ( ) ?) )
68+ } ;
69+ match place. layout . ty . kind ( ) {
70+ ty:: FnDef ( ..) => Some ( ty:: ValTree :: zst ( ) ) ,
71+ ty:: Bool | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) | ty:: Char => {
72+ let val = ecx. read_immediate ( & place. into ( ) ) . unwrap ( ) ;
73+ let val = val. to_scalar ( ) . unwrap ( ) ;
74+ Some ( ty:: ValTree :: Leaf ( val. assert_int ( ) ) )
75+ }
76+
77+ // Raw pointers are not allowed in type level constants, as raw pointers cannot be treated
78+ // like references. If we looked behind the raw pointer, we may be breaking the meaning of
79+ // the raw pointer. Equality on raw pointers is performed on the pointer and not on the pointee,
80+ // and we cannot guarantee any kind of pointer stability in the type system.
81+ // Technically we could allow function pointers, but they are not guaranteed to be the
82+ // same as the function pointers at runtime.
83+ ty:: FnPtr ( _) | ty:: RawPtr ( _) => None ,
84+ ty:: Ref ( ..) => unimplemented ! ( "need to use deref_const" ) ,
85+
86+ ty:: Dynamic ( ..) => unimplemented ! (
87+ "for trait objects we must look at the vtable and figure out the real type"
88+ ) ,
89+
90+ ty:: Slice ( _) | ty:: Str => {
91+ unimplemented ! ( "need to find the backing data of the slice/str and recurse on that" )
92+ }
93+ ty:: Tuple ( substs) => branches ( substs. len ( ) , None ) ,
94+ ty:: Array ( _, len) => branches ( usize:: try_from ( len. eval_usize ( ecx. tcx . tcx , ecx. param_env ) ) . unwrap ( ) , None ) ,
95+
96+ ty:: Adt ( def, _) => {
97+ if def. variants . is_empty ( ) {
98+ // Uninhabited
99+ return None ;
100+ }
101+
102+ let variant = ecx. read_discriminant ( & place. into ( ) ) . unwrap ( ) . 1 ;
103+
104+ branches ( def. variants [ variant] . fields . len ( ) , Some ( variant) )
105+ }
106+
107+ ty:: Never
108+ | ty:: Error ( _)
109+ | ty:: Foreign ( ..)
110+ | ty:: Infer ( ty:: FreshIntTy ( _) )
111+ | ty:: Infer ( ty:: FreshFloatTy ( _) )
112+ | ty:: Projection ( ..)
113+ | ty:: Param ( _)
114+ | ty:: Bound ( ..)
115+ | ty:: Placeholder ( ..)
116+ // FIXME(oli-obk): we could look behind opaque types
117+ | ty:: Opaque ( ..)
118+ | ty:: Infer ( _)
119+ // FIXME(oli-obk): we can probably encode closures just like structs
120+ | ty:: Closure ( ..)
121+ | ty:: Generator ( ..)
122+ | ty:: GeneratorWitness ( ..) => None ,
123+ }
124+ }
125+
38126/// This function uses `unwrap` copiously, because an already validated constant
39127/// must have valid fields and can thus never fail outside of compiler bugs. However, it is
40128/// invoked from the pretty printer, where it can receive enums with no variants and e.g.
0 commit comments