Auto merge of #93505 - lcnr:substsref-vs-ty-list, r=michaelwoerister

safely `transmute<&List<Ty<'tcx>>, &List<GenericArg<'tcx>>>`

This PR has 3 relevant steps which are is split in distinct commits.

The first commit now interns `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>` together, potentially reusing memory while allowing free conversions between these two using `List<Ty<'tcx>>::as_substs()` and `SubstsRef<'tcx>::try_as_type_list()`.

Using this, we then use `&'tcx List<Ty<'tcx>>` instead of a `SubstsRef<'tcx>` for tuple fields, simplifying a bunch of code.

Finally, as tuple fields and other generic arguments now use a different `TypeFoldable<'tcx>` impl, we optimize the impl for `List<Ty<'tcx>>` improving perf by slightly less than 1% in tuple heavy benchmarks.
This commit is contained in:
bors 2022-02-21 16:03:38 +00:00
commit 03a8cc7df1
64 changed files with 289 additions and 210 deletions

View file

@ -834,10 +834,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
let expected = match expected_ty.kind() {
ty::Tuple(ref tys) => tys
.iter()
.map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span)))
.collect(),
ty::Tuple(ref tys) => {
tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
}
_ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())],
};

View file

@ -1301,7 +1301,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
if tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() =>
{
tcx.mk_fn_sig(
inputs.iter().map(|k| k.expect_ty()),
inputs.iter(),
tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))),
false,
hir::Unsafety::Normal,

View file

@ -108,7 +108,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
// (T1..Tn) and closures have same properties as T1..Tn --
// check if *any* of those are trivial.
ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())),
ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)),
ty::Closure(_, ref substs) => {
trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty())
}

View file

@ -1015,9 +1015,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Check that the source tuple with the target's
// last element is equal to the target.
let new_tuple = tcx.mk_tup(
a_mid.iter().map(|k| k.expect_ty()).chain(iter::once(b_last.expect_ty())),
);
let new_tuple = tcx.mk_tup(a_mid.iter().copied().chain(iter::once(b_last)));
let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
@ -1033,8 +1031,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.cause.clone(),
obligation.predicate.def_id(),
obligation.recursion_depth + 1,
a_last.expect_ty(),
&[b_last],
a_last,
&[b_last.into()],
)
}));
}
@ -1097,7 +1095,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
stack.push(ty);
}
ty::Tuple(tys) => {
stack.extend(tys.iter().map(|ty| ty.expect_ty()));
stack.extend(tys.iter());
}
ty::Closure(_, substs) => {
stack.push(substs.as_closure().tupled_upvars_ty());

View file

@ -1852,9 +1852,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None,
ty::Tuple(tys) => Where(
obligation
.predicate
.rebind(tys.last().into_iter().map(|k| k.expect_ty()).collect()),
obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])),
),
ty::Adt(def, substs) => {
@ -1917,7 +1915,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::Tuple(tys) => {
// (*) binder moved here
Where(obligation.predicate.rebind(tys.iter().map(|k| k.expect_ty()).collect()))
Where(obligation.predicate.rebind(tys.iter().collect()))
}
ty::Closure(_, substs) => {
@ -1997,7 +1995,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::Tuple(ref tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
t.rebind(tys.iter().map(|k| k.expect_ty()).collect())
t.rebind(tys.iter().collect())
}
ty::Closure(_, ref substs) => {

View file

@ -529,8 +529,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
ty::Tuple(ref tys) => {
if let Some((_last, rest)) = tys.split_last() {
for elem in rest {
self.require_sized(elem.expect_ty(), traits::TupleElem);
for &elem in rest {
self.require_sized(elem, traits::TupleElem);
}
}
}