Skip to content

Commit 8791f80

Browse files
committed
Better unsizing, distinguish vtable unsizes
Update ty.rs
1 parent 59b12f8 commit 8791f80

File tree

1 file changed

+88
-50
lines changed
  • frontend/exporter/src/types

1 file changed

+88
-50
lines changed

frontend/exporter/src/types/ty.rs

Lines changed: 88 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,39 @@ pub enum TyKind {
11431143
#[todo]
11441144
Todo(String),
11451145
}
1146+
#[cfg(feature = "rustc")]
1147+
fn searcher_for_traits<'tcx, S: UnderOwnerState<'tcx>>(
1148+
s: &S,
1149+
clauses: &Vec<ty::Clause<'tcx>>,
1150+
) -> PredicateSearcher<'tcx> {
1151+
let tcx = s.base().tcx;
1152+
// Populate a predicate searcher that knows about the `dyn` clauses.
1153+
let mut predicate_searcher = s.with_predicate_searcher(|ps| ps.clone());
1154+
predicate_searcher
1155+
.insert_bound_predicates(clauses.iter().filter_map(|clause| clause.as_trait_clause()));
1156+
predicate_searcher.set_param_env(rustc_trait_selection::traits::normalize_param_env_or_error(
1157+
tcx,
1158+
ty::ParamEnv::new(
1159+
tcx.mk_clauses_from_iter(
1160+
s.param_env()
1161+
.caller_bounds()
1162+
.iter()
1163+
.chain(clauses.iter().copied()),
1164+
),
1165+
),
1166+
rustc_trait_selection::traits::ObligationCause::dummy(),
1167+
));
1168+
predicate_searcher
1169+
}
1170+
1171+
#[cfg(feature = "rustc")]
1172+
fn fresh_param_ty<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> ty::ParamTy {
1173+
let tcx = s.base().tcx;
1174+
let def_id = s.owner_id();
1175+
let generics = tcx.generics_of(def_id);
1176+
let param_count = generics.parent_count + generics.own_params.len();
1177+
ty::ParamTy::new(param_count as u32 + 1, rustc_span::Symbol::intern("_dyn"))
1178+
}
11461179

11471180
/// Transform existential predicates into properly resolved predicates.
11481181
#[cfg(feature = "rustc")]
@@ -1152,15 +1185,10 @@ fn make_dyn<'tcx, S: UnderOwnerState<'tcx>>(
11521185
region: &ty::Region<'tcx>,
11531186
) -> TyKind {
11541187
let tcx = s.base().tcx;
1155-
let def_id = s.owner_id();
11561188
let span = rustc_span::DUMMY_SP.sinto(s);
11571189

11581190
// Pretend there's an extra type in the environment.
1159-
let new_param_ty = {
1160-
let generics = tcx.generics_of(def_id);
1161-
let param_count = generics.parent_count + generics.own_params.len();
1162-
ty::ParamTy::new(param_count as u32 + 1, rustc_span::Symbol::intern("_dyn"))
1163-
};
1191+
let new_param_ty = fresh_param_ty(s);
11641192
let new_ty = new_param_ty.to_ty(tcx);
11651193

11661194
// Set the new type as the `Self` parameter of our predicates.
@@ -1170,21 +1198,7 @@ fn make_dyn<'tcx, S: UnderOwnerState<'tcx>>(
11701198
.collect();
11711199

11721200
// 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-
));
1201+
let mut predicate_searcher = searcher_for_traits(s, &clauses);
11881202

11891203
// Using the predicate searcher, translate the predicates. Only the projection predicates need
11901204
// to be handled specially.
@@ -1331,8 +1345,13 @@ pub enum PointerCoercion {
13311345
#[derive_group(Serializers)]
13321346
#[derive(Clone, Debug, JsonSchema)]
13331347
pub enum UnsizingMetadata {
1348+
/// Unsize an array to a slice, storing the length as metadata.
13341349
Length(ConstantExpr),
1335-
VTablePtr(ImplExpr),
1350+
/// Unsize a non-dyn type to a dyn type, adding a vtable pointer as metadata.
1351+
DirectVTable(ImplExpr),
1352+
/// Unsize a dyn-type to another dyn-type, (optionally) indexing within the current vtable.
1353+
NestedVTable(ImplExpr),
1354+
/// Couldn't compute
13361355
Unknown,
13371356
}
13381357

@@ -1355,35 +1374,54 @@ impl PointerCoercion {
13551374
}
13561375
ty::adjustment::PointerCoercion::ArrayToPointer => PointerCoercion::ArrayToPointer,
13571376
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` \
1377+
// TODO: to properly find out what field we want, we should use the query
1378+
// `coerce_unsized_info`, which we call recursively to get the list of fields
1379+
// to go into until we reach a pointer/reference.
1380+
// We should also pass this list of field IDs in the unsizing metadata.
1381+
1382+
let (Some(src_ty), Some(tgt_ty)) =
1383+
(src_ty.builtin_deref(true), tgt_ty.builtin_deref(true))
1384+
else {
1385+
return PointerCoercion::Unsize(UnsizingMetadata::Unknown);
1386+
};
1387+
1388+
let tcx = s.base().tcx;
1389+
let typing_env = s.typing_env();
1390+
let (src_ty, tgt_ty) = tcx
1391+
.struct_lockstep_tails_raw(src_ty, tgt_ty, |ty| normalize(tcx, typing_env, ty));
1392+
1393+
let meta = match (&src_ty.kind(), &tgt_ty.kind()) {
1394+
(ty::Array(_, len), ty::Slice(_)) => {
1395+
let len = len.sinto(s);
1396+
UnsizingMetadata::Length(len)
1397+
}
1398+
(ty::Dynamic(from_preds, _), ty::Dynamic(to_preds, ..)) => {
1399+
let src_ty = fresh_param_ty(s).to_ty(tcx);
1400+
let to_pred = to_preds[0].with_self_ty(tcx, src_ty);
1401+
let from_preds: Vec<ty::Clause<'tcx>> = from_preds
1402+
.iter()
1403+
.map(|p| p.clone().with_self_ty(tcx, src_ty))
1404+
.collect::<Vec<_>>();
1405+
let mut searcher = searcher_for_traits(s, &from_preds);
1406+
let impl_expr = searcher
1407+
.resolve(
1408+
&to_pred.as_trait_clause().unwrap().to_poly_trait_ref(),
1409+
&|_| {},
1410+
)
1411+
.s_unwrap(s)
1412+
.sinto(s);
1413+
UnsizingMetadata::NestedVTable(impl_expr)
1414+
}
1415+
(_, ty::Dynamic(preds, ..)) => {
1416+
let pred = preds[0].with_self_ty(tcx, src_ty);
1417+
let clause = pred.as_trait_clause().expect(
1418+
"the first `ExistentialPredicate` of `TyKind::Dynamic` \
13791419
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-
}
1420+
);
1421+
let tref = clause.rebind(clause.skip_binder().trait_ref);
1422+
let impl_expr = solve_trait(s, tref);
1423+
1424+
UnsizingMetadata::DirectVTable(impl_expr)
13871425
}
13881426
_ => UnsizingMetadata::Unknown,
13891427
};

0 commit comments

Comments
 (0)