@@ -6,9 +6,10 @@ use rustc_hir::Mutability;
66use rustc_middle:: ty:: { self , TyCtxt } ;
77use rustc_middle:: {
88 mir:: { self , interpret:: ConstAlloc } ,
9- ty:: ScalarInt ,
9+ ty:: { ScalarInt , Ty } ,
1010} ;
1111use rustc_span:: { source_map:: DUMMY_SP , symbol:: Symbol } ;
12+ use rustc_target:: abi:: VariantIdx ;
1213
1314use crate :: interpret:: {
1415 intern_const_alloc_recursive, ConstValue , InternKind , InterpCx , InterpResult , MPlaceTy ,
@@ -55,28 +56,43 @@ pub(crate) fn const_to_valtree<'tcx>(
5556 const_to_valtree_inner ( & ecx, & place)
5657}
5758
59+ #[ instrument( skip( ecx) , level = "debug" ) ]
60+ fn branches < ' tcx > (
61+ ecx : & CompileTimeEvalContext < ' tcx , ' tcx > ,
62+ place : & MPlaceTy < ' tcx > ,
63+ n : usize ,
64+ variant : Option < VariantIdx > ,
65+ ) -> Option < ty:: ValTree < ' tcx > > {
66+ let place = match variant {
67+ Some ( variant) => ecx. mplace_downcast ( & place, variant) . unwrap ( ) ,
68+ None => * place,
69+ } ;
70+ let variant = variant. map ( |variant| Some ( ty:: ValTree :: Leaf ( ScalarInt :: from ( variant. as_u32 ( ) ) ) ) ) ;
71+ debug ! ( ?place, ?variant) ;
72+
73+ let fields = ( 0 ..n) . map ( |i| {
74+ let field = ecx. mplace_field ( & place, i) . unwrap ( ) ;
75+ const_to_valtree_inner ( ecx, & field)
76+ } ) ;
77+ // For enums, we preped their variant index before the variant's fields so we can figure out
78+ // the variant again when just seeing a valtree.
79+ let branches = variant. into_iter ( ) . chain ( fields) ;
80+ Some ( ty:: ValTree :: Branch ( ecx. tcx . arena . alloc_from_iter ( branches. collect :: < Option < Vec < _ > > > ( ) ?) ) )
81+ }
82+
83+ #[ instrument( skip( ecx) , level = "debug" ) ]
5884fn const_to_valtree_inner < ' tcx > (
5985 ecx : & CompileTimeEvalContext < ' tcx , ' tcx > ,
6086 place : & MPlaceTy < ' tcx > ,
6187) -> Option < ty:: ValTree < ' tcx > > {
62- let branches = |n, variant| {
63- let place = match variant {
64- Some ( variant) => ecx. mplace_downcast ( & place, variant) . unwrap ( ) ,
65- None => * place,
66- } ;
67- let variant =
68- variant. map ( |variant| Some ( ty:: ValTree :: Leaf ( ScalarInt :: from ( variant. as_u32 ( ) ) ) ) ) ;
69- let fields = ( 0 ..n) . map ( |i| {
70- let field = ecx. mplace_field ( & place, i) . unwrap ( ) ;
71- const_to_valtree_inner ( ecx, & field)
72- } ) ;
73- // For enums, we preped their variant index before the variant's fields so we can figure out
74- // the variant again when just seeing a valtree.
75- let branches = variant. into_iter ( ) . chain ( fields) ;
76- Some ( ty:: ValTree :: Branch (
77- ecx. tcx . arena . alloc_from_iter ( branches. collect :: < Option < Vec < _ > > > ( ) ?) ,
78- ) )
88+ // We only want to use raw bytes in ValTrees for string slices or &[<integer_ty>]
89+ let use_bytes_for_ref = |ty : Ty < ' tcx > | -> bool {
90+ match ty. kind ( ) {
91+ ty:: Str | ty:: Char | ty:: Uint ( _) | ty:: Int ( _) | ty:: Bool => true ,
92+ _ => false ,
93+ }
7994 } ;
95+
8096 match place. layout . ty . kind ( ) {
8197 ty:: FnDef ( ..) => Some ( ty:: ValTree :: zst ( ) ) ,
8298 ty:: Bool | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) | ty:: Char => {
@@ -90,19 +106,91 @@ fn const_to_valtree_inner<'tcx>(
90106 // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
91107 // agree with runtime equality tests.
92108 ty:: FnPtr ( _) | ty:: RawPtr ( _) => None ,
93- ty:: Ref ( ..) => unimplemented ! ( "need to use deref_const" ) ,
109+
110+ ty:: Ref ( _, ref_ty, _) if place. layout . ty . is_slice ( ) => {
111+ match ecx. try_read_immediate_from_mplace ( & place) {
112+ Ok ( Some ( imm) ) => {
113+ // `imm` is a ScalarPair. We try to get the underlying bytes behind that
114+ // fat pointer for string slices and slices of integer types. For any other
115+ // slice types we use `branches` to recursively construct the Valtree.
116+
117+ if use_bytes_for_ref ( * ref_ty) {
118+ let ( alloc, range) = ecx. get_alloc_from_imm_scalar_pair ( imm) ;
119+ let alloc_bytes = match alloc. get_bytes ( & ecx. tcx , range) {
120+ Ok ( bytes) => bytes,
121+ Err ( _e) => return None ,
122+ } ;
123+ debug ! ( ?alloc_bytes) ;
124+
125+ let bytes = ecx. tcx . arena . alloc_slice ( alloc_bytes) ;
126+ let len = bytes. len ( ) ;
127+ debug ! ( ?bytes, ?len) ;
128+
129+ let slice = ty:: ValSlice { bytes} ;
130+
131+ Some ( ty:: ValTree :: SliceOrStr ( slice) )
132+ } else {
133+ let derefd = ecx. deref_operand ( & imm. into ( ) ) . expect ( & format ! ( "couldnt deref {:?}" , imm) ) ;
134+ debug ! ( "derefd: {:?}" , derefd) ;
135+
136+ let derefd_imm = match ecx. try_read_immediate_from_mplace ( & derefd) {
137+ Ok ( Some ( imm) ) => imm,
138+ _ => return None ,
139+ } ;
140+ debug ! ( ?derefd_imm) ;
141+
142+ let tcx = ecx. tcx . tcx ;
143+ let scalar_len= derefd. meta . unwrap_meta ( ) ;
144+ let len = match scalar_len {
145+ Scalar :: Int ( int) => {
146+ int. try_to_machine_usize ( tcx) . expect ( & format ! ( "Expected a valid ScalarInt in {:?}" , scalar_len) )
147+ }
148+ _ => bug ! ( "expected a ScalarInt in meta data for {:?}" , place) ,
149+ } ;
150+ debug ! ( ?len) ;
151+
152+ let valtree = branches ( ecx, place, len. try_into ( ) . expect ( "BLA" ) , None ) ;
153+ debug ! ( ?valtree) ;
154+
155+ valtree
156+ }
157+ }
158+ _ => {
159+ None
160+ }
161+ }
162+ }
163+
164+ ty:: Ref ( _, inner_ty, _) => {
165+ debug ! ( "Ref with inner_ty: {:?}" , inner_ty) ;
166+ let imm = ecx. try_read_immediate_from_mplace ( & place) . unwrap_or_else ( |e| bug ! ( "couldnt read immediate from {:?}, error: {:?}" , place, e) ) ;
167+ match imm {
168+ Some ( imm) => {
169+ debug ! ( ?imm) ;
170+
171+ let derefd_place = ecx. deref_mplace ( place) . unwrap_or_else ( |e| bug ! ( "couldn't deref {:?}, error: {:?}" , place, e) ) ;
172+ debug ! ( ?derefd_place) ;
173+
174+ const_to_valtree_inner ( ecx, & derefd_place)
175+ }
176+ None => None ,
177+ }
178+ }
179+ ty:: Str => {
180+ bug ! ( "ty::Str should have been handled in ty::Ref branch that uses raw bytes" ) ;
181+ }
182+ ty:: Slice ( _) => {
183+ bug ! ( "should have been handled in the Ref arm" ) ;
184+ }
94185
95186 // Trait objects are not allowed in type level constants, as we have no concept for
96187 // resolving their backing type, even if we can do that at const eval time. We may
97188 // hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
98189 // but it is unclear if this is useful.
99190 ty:: Dynamic ( ..) => None ,
100191
101- ty:: Slice ( _) | ty:: Str => {
102- unimplemented ! ( "need to find the backing data of the slice/str and recurse on that" )
103- }
104- ty:: Tuple ( substs) => branches ( substs. len ( ) , None ) ,
105- ty:: Array ( _, len) => branches ( usize:: try_from ( len. eval_usize ( ecx. tcx . tcx , ecx. param_env ) ) . unwrap ( ) , None ) ,
192+ ty:: Tuple ( substs) => branches ( ecx, place, substs. len ( ) , None ) ,
193+ ty:: Array ( _, len) => branches ( ecx, place, usize:: try_from ( len. eval_usize ( ecx. tcx . tcx , ecx. param_env ) ) . unwrap ( ) , None ) ,
106194
107195 ty:: Adt ( def, _) => {
108196 if def. variants ( ) . is_empty ( ) {
@@ -111,7 +199,7 @@ fn const_to_valtree_inner<'tcx>(
111199
112200 let variant = ecx. read_discriminant ( & place. into ( ) ) . unwrap ( ) . 1 ;
113201
114- branches ( def. variant ( variant) . fields . len ( ) , def. is_enum ( ) . then_some ( variant) )
202+ branches ( ecx , place , def. variant ( variant) . fields . len ( ) , def. is_enum ( ) . then_some ( variant) )
115203 }
116204
117205 ty:: Never
0 commit comments