Skip to content

Commit 67e65e6

Browse files
authored
Merge pull request #6 from N1ark/vtables
2 parents 57793da + 23a7895 commit 67e65e6

File tree

2 files changed

+108
-67
lines changed

2 files changed

+108
-67
lines changed

frontend/exporter/src/types/mir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ pub enum Operand {
335335

336336
#[cfg(feature = "rustc")]
337337
impl Operand {
338-
pub(crate) fn ty(&self) -> &Ty {
338+
pub fn ty(&self) -> &Ty {
339339
match self {
340340
Operand::Copy(p) | Operand::Move(p) => &p.ty,
341341
Operand::Constant(c) => &c.ty,

frontend/exporter/src/types/ty.rs

Lines changed: 107 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,15 +1120,8 @@ pub enum TyKind {
11201120
Str,
11211121
RawPtr(Box<Ty>, Mutability),
11221122
Ref(Region, Box<Ty>, Mutability),
1123-
#[custom_arm(FROM_TYPE::Dynamic(preds, region) => make_dyn(s, preds, region),)]
1124-
Dynamic(
1125-
/// Fresh type parameter that we use as the `Self` type in the prediates below.
1126-
ParamTy,
1127-
/// Clauses that define the trait object. These clauses use the fresh type parameter above
1128-
/// as `Self` type.
1129-
GenericPredicates,
1130-
Region,
1131-
),
1123+
#[custom_arm(FROM_TYPE::Dynamic(preds, region) => TyKind::Dynamic(resolve_for_dyn(s, preds, |_| ()), region.sinto(s)),)]
1124+
Dynamic(DynBinder<()>, Region),
11321125
#[custom_arm(FROM_TYPE::Coroutine(def_id, generics) => TO_TYPE::Coroutine(translate_item_ref(s, *def_id, generics)),)]
11331126
Coroutine(ItemRef),
11341127
Never,
@@ -1144,23 +1137,68 @@ pub enum TyKind {
11441137
Todo(String),
11451138
}
11461139

1147-
/// Transform existential predicates into properly resolved predicates.
1140+
/// A representation of `exists<T: Trait1 + Trait2>(value)`: we create a fresh type id and the
1141+
/// appropriate trait clauses. The contained value may refer to the fresh ty and the in-scope trait
1142+
/// clauses. This is used to represent types related to `dyn Trait`.
1143+
#[derive_group(Serializers)]
1144+
#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)]
1145+
pub struct DynBinder<T> {
1146+
/// Fresh type parameter that we use as the `Self` type in the prediates below.
1147+
pub existential_ty: ParamTy,
1148+
/// Clauses that define the trait object. These clauses use the fresh type parameter above
1149+
/// as `Self` type.
1150+
pub predicates: GenericPredicates,
1151+
/// The value inside the binder.
1152+
pub val: T,
1153+
}
1154+
1155+
/// Do trait resolution in the context of the clauses of a `dyn Trait` type.
11481156
#[cfg(feature = "rustc")]
1149-
fn make_dyn<'tcx, S: UnderOwnerState<'tcx>>(
1157+
fn resolve_for_dyn<'tcx, S: UnderOwnerState<'tcx>, R>(
11501158
s: &S,
1159+
// The predicates in the context.
11511160
epreds: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
1152-
region: &ty::Region<'tcx>,
1153-
) -> TyKind {
1154-
let tcx = s.base().tcx;
1155-
let def_id = s.owner_id();
1156-
let span = rustc_span::DUMMY_SP.sinto(s);
1161+
f: impl FnOnce(&mut PredicateSearcher<'tcx>) -> R,
1162+
) -> DynBinder<R> {
1163+
fn searcher_for_traits<'tcx, S: UnderOwnerState<'tcx>>(
1164+
s: &S,
1165+
clauses: &Vec<ty::Clause<'tcx>>,
1166+
) -> PredicateSearcher<'tcx> {
1167+
let tcx = s.base().tcx;
1168+
// Populate a predicate searcher that knows about the `dyn` clauses.
1169+
let mut predicate_searcher = s.with_predicate_searcher(|ps| ps.clone());
1170+
predicate_searcher
1171+
.insert_bound_predicates(clauses.iter().filter_map(|clause| clause.as_trait_clause()));
1172+
predicate_searcher.set_param_env(
1173+
rustc_trait_selection::traits::normalize_param_env_or_error(
1174+
tcx,
1175+
ty::ParamEnv::new(
1176+
tcx.mk_clauses_from_iter(
1177+
s.param_env()
1178+
.caller_bounds()
1179+
.iter()
1180+
.chain(clauses.iter().copied()),
1181+
),
1182+
),
1183+
rustc_trait_selection::traits::ObligationCause::dummy(),
1184+
),
1185+
);
1186+
predicate_searcher
1187+
}
11571188

1158-
// Pretend there's an extra type in the environment.
1159-
let new_param_ty = {
1189+
fn fresh_param_ty<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> ty::ParamTy {
1190+
let tcx = s.base().tcx;
1191+
let def_id = s.owner_id();
11601192
let generics = tcx.generics_of(def_id);
11611193
let param_count = generics.parent_count + generics.own_params.len();
11621194
ty::ParamTy::new(param_count as u32 + 1, rustc_span::Symbol::intern("_dyn"))
1163-
};
1195+
}
1196+
1197+
let tcx = s.base().tcx;
1198+
let span = rustc_span::DUMMY_SP.sinto(s);
1199+
1200+
// Pretend there's an extra type in the environment.
1201+
let new_param_ty = fresh_param_ty(s);
11641202
let new_ty = new_param_ty.to_ty(tcx);
11651203

11661204
// Set the new type as the `Self` parameter of our predicates.
@@ -1170,21 +1208,8 @@ fn make_dyn<'tcx, S: UnderOwnerState<'tcx>>(
11701208
.collect();
11711209

11721210
// Populate a predicate searcher that knows about the `dyn` clauses.
1173-
let mut predicate_searcher = s.with_predicate_searcher(|ps| ps.clone());
1174-
predicate_searcher
1175-
.insert_bound_predicates(clauses.iter().filter_map(|clause| clause.as_trait_clause()));
1176-
predicate_searcher.set_param_env(rustc_trait_selection::traits::normalize_param_env_or_error(
1177-
tcx,
1178-
ty::ParamEnv::new(
1179-
tcx.mk_clauses_from_iter(
1180-
s.param_env()
1181-
.caller_bounds()
1182-
.iter()
1183-
.chain(clauses.iter().copied()),
1184-
),
1185-
),
1186-
rustc_trait_selection::traits::ObligationCause::dummy(),
1187-
));
1211+
let mut predicate_searcher = searcher_for_traits(s, &clauses);
1212+
let val = f(&mut predicate_searcher);
11881213

11891214
// Using the predicate searcher, translate the predicates. Only the projection predicates need
11901215
// to be handled specially.
@@ -1231,9 +1256,11 @@ fn make_dyn<'tcx, S: UnderOwnerState<'tcx>>(
12311256
.collect();
12321257

12331258
let predicates = GenericPredicates { predicates };
1234-
let param_ty = new_param_ty.sinto(s);
1235-
let region = region.sinto(s);
1236-
TyKind::Dynamic(param_ty, predicates, region)
1259+
DynBinder {
1260+
existential_ty: new_param_ty.sinto(s),
1261+
predicates,
1262+
val,
1263+
}
12371264
}
12381265

12391266
/// Reflects [`ty::CanonicalUserTypeAnnotation`]
@@ -1331,8 +1358,13 @@ pub enum PointerCoercion {
13311358
#[derive_group(Serializers)]
13321359
#[derive(Clone, Debug, JsonSchema)]
13331360
pub enum UnsizingMetadata {
1361+
/// Unsize an array to a slice, storing the length as metadata.
13341362
Length(ConstantExpr),
1335-
VTablePtr(ImplExpr),
1363+
/// Unsize a non-dyn type to a dyn type, adding a vtable pointer as metadata.
1364+
DirectVTable(ImplExpr),
1365+
/// Unsize a dyn-type to another dyn-type, (optionally) indexing within the current vtable.
1366+
NestedVTable(DynBinder<ImplExpr>),
1367+
/// Couldn't compute
13361368
Unknown,
13371369
}
13381370

@@ -1355,35 +1387,44 @@ impl PointerCoercion {
13551387
}
13561388
ty::adjustment::PointerCoercion::ArrayToPointer => PointerCoercion::ArrayToPointer,
13571389
ty::adjustment::PointerCoercion::Unsize => {
1358-
// We only support unsizing behind references, pointers and boxes for now.
1359-
let meta = match (src_ty.builtin_deref(true), tgt_ty.builtin_deref(true)) {
1360-
(Some(src_ty), Some(tgt_ty)) => {
1361-
let tcx = s.base().tcx;
1362-
let typing_env = s.typing_env();
1363-
let (src_ty, tgt_ty) =
1364-
tcx.struct_lockstep_tails_raw(src_ty, tgt_ty, |ty| {
1365-
normalize(tcx, typing_env, ty)
1366-
});
1367-
match tgt_ty.kind() {
1368-
ty::Slice(_) | ty::Str => match src_ty.kind() {
1369-
ty::Array(_, len) => {
1370-
let len = len.sinto(s);
1371-
UnsizingMetadata::Length(len)
1372-
}
1373-
_ => UnsizingMetadata::Unknown,
1374-
},
1375-
ty::Dynamic(preds, ..) => {
1376-
let pred = preds[0].with_self_ty(tcx, src_ty);
1377-
let clause = pred.as_trait_clause().expect(
1378-
"the first `ExistentialPredicate` of `TyKind::Dynamic` \
1390+
// TODO: to properly find out what field we want, we should use the query
1391+
// `coerce_unsized_info`, which we call recursively to get the list of fields
1392+
// to go into until we reach a pointer/reference.
1393+
// We should also pass this list of field IDs in the unsizing metadata.
1394+
1395+
let (Some(src_ty), Some(tgt_ty)) =
1396+
(src_ty.builtin_deref(true), tgt_ty.builtin_deref(true))
1397+
else {
1398+
return PointerCoercion::Unsize(UnsizingMetadata::Unknown);
1399+
};
1400+
1401+
let tcx = s.base().tcx;
1402+
let typing_env = s.typing_env();
1403+
let (src_ty, tgt_ty) = tcx
1404+
.struct_lockstep_tails_raw(src_ty, tgt_ty, |ty| normalize(tcx, typing_env, ty));
1405+
1406+
let meta = match (&src_ty.kind(), &tgt_ty.kind()) {
1407+
(ty::Array(_, len), ty::Slice(_)) => {
1408+
let len = len.sinto(s);
1409+
UnsizingMetadata::Length(len)
1410+
}
1411+
(ty::Dynamic(from_preds, _), ty::Dynamic(to_preds, ..)) => {
1412+
let to_pred = to_preds.principal().unwrap().with_self_ty(tcx, src_ty);
1413+
let impl_expr = resolve_for_dyn(s, from_preds, |searcher| {
1414+
searcher.resolve(&to_pred, &|_| {}).s_unwrap(s).sinto(s)
1415+
});
1416+
UnsizingMetadata::NestedVTable(impl_expr)
1417+
}
1418+
(_, ty::Dynamic(preds, ..)) => {
1419+
let pred = preds[0].with_self_ty(tcx, src_ty);
1420+
let clause = pred.as_trait_clause().expect(
1421+
"the first `ExistentialPredicate` of `TyKind::Dynamic` \
13791422
should be a trait clause",
1380-
);
1381-
let tref = clause.rebind(clause.skip_binder().trait_ref);
1382-
let impl_expr = solve_trait(s, tref);
1383-
UnsizingMetadata::VTablePtr(impl_expr)
1384-
}
1385-
_ => UnsizingMetadata::Unknown,
1386-
}
1423+
);
1424+
let tref = clause.rebind(clause.skip_binder().trait_ref);
1425+
let impl_expr = solve_trait(s, tref);
1426+
1427+
UnsizingMetadata::DirectVTable(impl_expr)
13871428
}
13881429
_ => UnsizingMetadata::Unknown,
13891430
};

0 commit comments

Comments
 (0)