@@ -7,7 +7,8 @@ use rustc_index::{IndexVec, Idx};
77use rustc_middle:: mir;
88use rustc_middle:: ty:: CoroutineArgsExt ;
99use rustc_const_eval:: interpret:: {
10- self , InterpCx , InterpResult , MPlaceTy , OffsetMode , Projectable ,
10+ self , InterpCx , InterpResult , MemPlaceMeta , MPlaceTy , OffsetMode ,
11+ Projectable ,
1112} ;
1213use rustc_middle:: ty;
1314use rustc_middle:: ty:: { AdtKind , DynKind , TyCtxt , TypeVisitableExt } ;
@@ -244,6 +245,13 @@ pub fn trait_inst_id_str<'tcx>(
244245 }
245246}
246247
248+ pub fn vtable_name < ' tcx > (
249+ mir : & mut MirState < ' _ , ' tcx > ,
250+ trait_ref : ty:: PolyTraitRef < ' tcx > ,
251+ ) -> String {
252+ ext_def_id_str ( mir. tcx , trait_ref. def_id ( ) , "_vtbl" , trait_ref)
253+ }
254+
247255/// Get the mangled name of a monomorphic function. As a side effect, this marks the function as
248256/// "used", so its body will be emitted too.
249257pub fn get_fn_def_name < ' tcx > (
@@ -1464,6 +1472,24 @@ fn make_allocation_body<'tcx>(
14641472) -> serde_json:: Value {
14651473 let tcx = mir. tcx ;
14661474
1475+ fn do_default < ' tcx > (
1476+ mir : & mut MirState < ' _ , ' tcx > ,
1477+ icx : & mut interpret:: InterpCx < ' tcx , RenderConstMachine < ' tcx > > ,
1478+ rty : ty:: Ty < ' tcx > ,
1479+ d : & MPlaceTy < ' tcx > ,
1480+ ) -> serde_json:: Value {
1481+ let rlayout = mir. tcx . layout_of ( ty:: TypingEnv :: fully_monomorphized ( ) . as_query_input ( rty) ) . unwrap ( ) ;
1482+ let mpty: MPlaceTy = d. offset_with_meta ( Size :: ZERO , OffsetMode :: Inbounds , d. meta ( ) , rlayout, icx) . unwrap ( ) ;
1483+ let rendered = try_render_opty ( mir, icx, & mpty. into ( ) ) ;
1484+
1485+ json ! ( {
1486+ "kind" : "constant" ,
1487+ "mutable" : false ,
1488+ "ty" : rty. to_json( mir) ,
1489+ "rendered" : rendered,
1490+ } )
1491+ }
1492+
14671493 if !is_mut {
14681494 /// Common logic for emitting `"kind": "strbody"` constants, shared by the `str` and `CStr`
14691495 /// cases.
@@ -1494,10 +1520,15 @@ fn make_allocation_body<'tcx>(
14941520 }
14951521
14961522 match * rty. kind ( ) {
1497- // Special cases for &str, &CStr, and &[T]
1523+ // Special cases for references to unsized types. Currently, the
1524+ // following are supported:
1525+ //
1526+ // * String slices (&str and &CStr)
1527+ // * Array slices (&[T])
1528+ // * Trait objects (&dyn Trait)
14981529 //
1499- // These and the ones in try_render_ref_opty below should be
1500- // kept in sync.
1530+ // These special cases and the ones in try_render_ref_opty below
1531+ // should be kept in sync.
15011532 ty:: TyKind :: Str => {
15021533 let len = d. len ( icx) . unwrap ( ) ;
15031534 return do_strbody ( mir, icx, d, len) ;
@@ -1531,21 +1562,16 @@ fn make_allocation_body<'tcx>(
15311562 "rendered" : rendered,
15321563 } ) ;
15331564 } ,
1565+ ty:: TyKind :: Dynamic ( ref preds, _, _) => {
1566+ let unpacked_d = unpack_dyn_place ( icx, d, preds) . unwrap ( ) ;
1567+ return do_default ( mir, icx, unpacked_d. layout . ty , & unpacked_d) ;
1568+ } ,
15341569 _ => ( )
15351570 }
15361571 }
15371572
15381573 // Default case
1539- let rlayout = tcx. layout_of ( ty:: TypingEnv :: fully_monomorphized ( ) . as_query_input ( rty) ) . unwrap ( ) ;
1540- let mpty: MPlaceTy = d. offset_with_meta ( Size :: ZERO , OffsetMode :: Inbounds , d. meta ( ) , rlayout, icx) . unwrap ( ) ;
1541- let rendered = try_render_opty ( mir, icx, & mpty. into ( ) ) ;
1542-
1543- return json ! ( {
1544- "kind" : "constant" ,
1545- "mutable" : false ,
1546- "ty" : rty. to_json( mir) ,
1547- "rendered" : rendered,
1548- } ) ;
1574+ return do_default ( mir, icx, rty, d) ;
15491575}
15501576
15511577fn try_render_ref_opty < ' tcx > (
@@ -1602,27 +1628,64 @@ fn try_render_ref_opty<'tcx>(
16021628 return None
16031629 } ;
16041630
1631+ // TODO(#241): Lift this restriction.
16051632 assert ! ( d_offset == Size :: ZERO , "cannot handle nonzero reference offsets" ) ;
16061633
16071634 if !is_mut {
1608- // Special cases for &str, &CStr, and &[T]
1609- //
1610- // These and the ones in make_allocation_body above should be kept in sync.
1611- let do_slice_special_case = match * rty. kind ( ) {
1612- ty:: TyKind :: Str | ty:: TyKind :: Slice ( _) => true ,
1613- ty:: TyKind :: Adt ( adt_def, _) if tcx. is_lang_item ( adt_def. did ( ) , LangItem :: CStr ) => true ,
1614- _ => false ,
1615- } ;
1616- if do_slice_special_case {
1635+ fn do_slice < ' tcx > (
1636+ icx : & mut interpret:: InterpCx < ' tcx , RenderConstMachine < ' tcx > > ,
1637+ d : & MPlaceTy < ' tcx > ,
1638+ def_id_json : serde_json:: Value ,
1639+ ) -> serde_json:: Value {
16171640 // `<MPlaceTy as Projectable>::len` asserts that the input must have `Slice` or
16181641 // `Str` type. However, the implementation it uses works fine on `CStr` too, so we
16191642 // copy-paste the code here.
16201643 let len = d. meta ( ) . unwrap_meta ( ) . to_target_usize ( icx) . unwrap ( ) ;
1621- return Some ( json ! ( {
1644+ json ! ( {
16221645 "kind" : "slice" ,
16231646 "def_id" : def_id_json,
16241647 "len" : len
1625- } ) )
1648+ } )
1649+ }
1650+
1651+ // Special cases for references to unsized types. Currently, the
1652+ // following are supported:
1653+ //
1654+ // * String slices (&str and &CStr)
1655+ // * Array slices (&[T])
1656+ // * Trait objects (&dyn Trait)
1657+ //
1658+ // These special cases and the ones in make_allocation_body above should be kept in sync.
1659+ match * rty. kind ( ) {
1660+ ty:: TyKind :: Str | ty:: TyKind :: Slice ( _) =>
1661+ return Some ( do_slice ( icx, & d, def_id_json) ) ,
1662+ ty:: TyKind :: Adt ( adt_def, _) if tcx. is_lang_item ( adt_def. did ( ) , LangItem :: CStr ) =>
1663+ return Some ( do_slice ( icx, & d, def_id_json) ) ,
1664+ ty:: TyKind :: Dynamic ( ref preds, _, _) => {
1665+ let self_ty = unpack_dyn_ty ( icx, & d, preds) . unwrap ( ) ;
1666+ let vtable_desc = preds. principal ( ) . map ( |pred| pred. with_self_ty ( tcx, self_ty) ) ;
1667+ match vtable_desc {
1668+ Some ( vtable_desc) => {
1669+ mir. used . vtables . insert ( vtable_desc) ;
1670+ let ti = TraitInst :: from_dynamic_predicates ( tcx, preds) ;
1671+ return Some ( json ! ( {
1672+ "kind" : "trait_object" ,
1673+ "def_id" : def_id_json,
1674+ "trait_id" : trait_inst_id_str( tcx, & ti) ,
1675+ "vtable" : vtable_name( mir, vtable_desc) ,
1676+ } ) )
1677+ } ,
1678+ None =>
1679+ // If there is no principal trait bound, then all of
1680+ // the trait bounds are auto traits. We do not
1681+ // currently support computing vtables for these sorts
1682+ // of trait objects (see #239).
1683+ return Some ( json ! ( {
1684+ "kind" : "unsupported" ,
1685+ } ) )
1686+ }
1687+ } ,
1688+ _ => ( ) ,
16261689 }
16271690 }
16281691
@@ -1856,3 +1919,42 @@ pub fn eval_mir_constant<'tcx>(
18561919 . eval ( tcx, ty:: TypingEnv :: fully_monomorphized ( ) , constant. span )
18571920 . unwrap ( )
18581921}
1922+
1923+ // Turn a place with a `dyn Trait` type into the actual dynamic type.
1924+ //
1925+ // This is based on the internals of
1926+ // `rustc_const_eval::interpret::InterpCx::unpack_dyn_trait`.
1927+ fn unpack_dyn_ty < ' tcx > (
1928+ icx : & InterpCx < ' tcx , RenderConstMachine < ' tcx > > ,
1929+ mplace : & MPlaceTy < ' tcx > ,
1930+ expected_trait : & ' tcx ty:: List < ty:: PolyExistentialPredicate < ' tcx > > ,
1931+ ) -> InterpResult < ' tcx , ty:: Ty < ' tcx > > {
1932+ assert ! (
1933+ matches!( mplace. layout. ty. kind( ) , ty:: Dynamic ( _, _, ty:: Dyn ) ) ,
1934+ "`unpack_dyn_ty` only makes sense on `dyn*` types"
1935+ ) ;
1936+ let vtable = mplace. meta ( ) . unwrap_meta ( ) . to_pointer ( icx) ?;
1937+ icx. get_ptr_vtable_ty ( vtable, Some ( expected_trait) )
1938+ }
1939+
1940+ // Turn a place with a `dyn Trait` type into a place with the actual dynamic
1941+ // type.
1942+ //
1943+ // This is based on `rustc_const_eval::interpret::InterpCx::unpack_dyn_trait`.
1944+ fn unpack_dyn_place < ' tcx > (
1945+ icx : & InterpCx < ' tcx , RenderConstMachine < ' tcx > > ,
1946+ mplace : & MPlaceTy < ' tcx > ,
1947+ expected_trait : & ' tcx ty:: List < ty:: PolyExistentialPredicate < ' tcx > > ,
1948+ ) -> InterpResult < ' tcx , MPlaceTy < ' tcx > > {
1949+ let ty = unpack_dyn_ty ( icx, mplace, expected_trait) ?;
1950+ // This is a kind of transmute, from a place with unsized type and metadata to
1951+ // a place with sized type and no metadata.
1952+ let layout = icx. layout_of ( ty) ?;
1953+ mplace. offset_with_meta (
1954+ Size :: ZERO ,
1955+ OffsetMode :: Wrapping ,
1956+ MemPlaceMeta :: None ,
1957+ layout,
1958+ icx,
1959+ )
1960+ }
0 commit comments