33use std:: convert:: TryFrom ;
44
55use rustc_hir:: Mutability ;
6+ use rustc_middle:: ty:: layout:: HasTyCtxt ;
67use rustc_middle:: ty:: { self , TyCtxt } ;
78use rustc_middle:: {
89 mir:: { self , interpret:: ConstAlloc } ,
910 ty:: ScalarInt ,
1011} ;
1112use rustc_span:: { source_map:: DUMMY_SP , symbol:: Symbol } ;
13+ use rustc_target:: abi:: VariantIdx ;
1214
1315use crate :: interpret:: {
1416 intern_const_alloc_recursive, ConstValue , InternKind , InterpCx , InterpResult , MPlaceTy ,
@@ -55,28 +57,48 @@ pub(crate) fn const_to_valtree<'tcx>(
5557 const_to_valtree_inner ( & ecx, & place)
5658}
5759
58- fn const_to_valtree_inner < ' tcx > (
60+ #[ instrument( skip( ecx) , level = "debug" ) ]
61+ fn branches < ' tcx > (
5962 ecx : & CompileTimeEvalContext < ' tcx , ' tcx > ,
6063 place : & MPlaceTy < ' tcx > ,
64+ n : usize ,
65+ variant : Option < VariantIdx > ,
6166) -> 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- ) )
67+ let place = match variant {
68+ Some ( variant) => ecx. mplace_downcast ( & place, variant) . unwrap ( ) ,
69+ None => * place,
7970 } ;
71+ let variant = variant. map ( |variant| Some ( ty:: ValTree :: Leaf ( ScalarInt :: from ( variant. as_u32 ( ) ) ) ) ) ;
72+ debug ! ( ?place, ?variant) ;
73+
74+ let fields = ( 0 ..n) . map ( |i| {
75+ let field = ecx. mplace_field ( & place, i) . unwrap ( ) ;
76+ const_to_valtree_inner ( ecx, & field)
77+ } ) ;
78+ // For enums, we prepend their variant index before the variant's fields so we can figure out
79+ // the variant again when just seeing a valtree.
80+ let branches = variant. into_iter ( ) . chain ( fields) ;
81+ Some ( ty:: ValTree :: Branch ( ecx. tcx . arena . alloc_from_iter ( branches. collect :: < Option < Vec < _ > > > ( ) ?) ) )
82+ }
83+
84+ fn slice_branches < ' tcx > (
85+ ecx : & CompileTimeEvalContext < ' tcx , ' tcx > ,
86+ place : & MPlaceTy < ' tcx > ,
87+ ) -> Option < ty:: ValTree < ' tcx > > {
88+ let n = place. len ( & ecx. tcx ( ) ) . expect ( & format ! ( "expected to use len of place {:?}" , place) ) ;
89+ let branches = ( 0 ..n) . map ( |i| {
90+ let place_elem = ecx. mplace_index ( place, i) . unwrap ( ) ;
91+ const_to_valtree_inner ( ecx, & place_elem)
92+ } ) ;
93+
94+ Some ( ty:: ValTree :: Branch ( ecx. tcx . arena . alloc_from_iter ( branches. collect :: < Option < Vec < _ > > > ( ) ?) ) )
95+ }
96+
97+ #[ instrument( skip( ecx) , level = "debug" ) ]
98+ fn const_to_valtree_inner < ' tcx > (
99+ ecx : & CompileTimeEvalContext < ' tcx , ' tcx > ,
100+ place : & MPlaceTy < ' tcx > ,
101+ ) -> Option < ty:: ValTree < ' tcx > > {
80102 match place. layout . ty . kind ( ) {
81103 ty:: FnDef ( ..) => Some ( ty:: ValTree :: zst ( ) ) ,
82104 ty:: Bool | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) | ty:: Char => {
@@ -90,19 +112,27 @@ fn const_to_valtree_inner<'tcx>(
90112 // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
91113 // agree with runtime equality tests.
92114 ty:: FnPtr ( _) | ty:: RawPtr ( _) => None ,
93- ty:: Ref ( ..) => unimplemented ! ( "need to use deref_const" ) ,
94115
116+ ty:: Ref ( _, _, _) => {
117+ let derefd_place = ecx. deref_operand ( & place. into ( ) ) . unwrap_or_else ( |e| bug ! ( "couldn't deref {:?}, error: {:?}" , place, e) ) ;
118+ debug ! ( ?derefd_place) ;
119+
120+ const_to_valtree_inner ( ecx, & derefd_place)
121+ }
122+
123+ ty:: Str | ty:: Slice ( _) | ty:: Array ( _, _) => {
124+ let valtree = slice_branches ( ecx, place) ;
125+ debug ! ( ?valtree) ;
126+
127+ valtree
128+ }
95129 // Trait objects are not allowed in type level constants, as we have no concept for
96130 // resolving their backing type, even if we can do that at const eval time. We may
97131 // hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
98132 // but it is unclear if this is useful.
99133 ty:: Dynamic ( ..) => None ,
100134
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 ) ,
135+ ty:: Tuple ( substs) => branches ( ecx, place, substs. len ( ) , None ) ,
106136
107137 ty:: Adt ( def, _) => {
108138 if def. variants ( ) . is_empty ( ) {
@@ -111,7 +141,7 @@ fn const_to_valtree_inner<'tcx>(
111141
112142 let variant = ecx. read_discriminant ( & place. into ( ) ) . unwrap ( ) . 1 ;
113143
114- branches ( def. variant ( variant) . fields . len ( ) , def. is_enum ( ) . then_some ( variant) )
144+ branches ( ecx , place , def. variant ( variant) . fields . len ( ) , def. is_enum ( ) . then_some ( variant) )
115145 }
116146
117147 ty:: Never
0 commit comments