Skip to content

Commit

Permalink
Auto merge of #69968 - eddyb:tupled-closure-captures, r=<try>
Browse files Browse the repository at this point in the history
rustc: keep upvars tupled in {Closure,Generator}Substs.

Previously, each closure/generator capture's (aka "upvar") type was tracked as one "synthetic" type parameter in the closure/generator substs, and figuring out where the parent `fn`'s generics end and the synthetics start involved slicing at `tcx.generics_of(def_id).parent_count`.

Needing to query `generics_of` limited @davidtwco (who wants to compute some `TypeFlags` differently for parent generics vs upvars, and `TyCtxt` is not available there), which is how I got started on this, but it's also possible that the `generics_of` queries are slowing down `{Closure,Generator}Substs` methods.

To give an example, for a `foo::<T, U>::{closure#0}` with captures `x: X` and `y: Y`, substs are:
* before this PR: `[T, U, /*kind*/, /*signature*/, X, Y]`
* after this PR: `[T, U, /*kind*/, /*signature*/, (X, Y)]`

You can see that, with this PR, no matter how many captures, the last 3 entries in the substs (or 5 for a generator) are always the "synthetic" ones, with the last one being the tuple of capture types.

r? @nikomatsakis cc @Zoxc
  • Loading branch information
bors committed Mar 13, 2020
2 parents 54b7d21 + da30907 commit 6429062
Show file tree
Hide file tree
Showing 65 changed files with 335 additions and 324 deletions.
4 changes: 2 additions & 2 deletions src/librustc/traits/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,8 @@ 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::Closure(def_id, ref substs) => {
substs.as_closure().upvar_tys(def_id, tcx).all(|t| trivial_dropck_outlives(tcx, t))
ty::Closure(_, ref substs) => {
substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t))
}

ty::Adt(def, _) => {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ impl<'tcx> Instance<'tcx> {
substs: ty::SubstsRef<'tcx>,
requested_kind: ty::ClosureKind,
) -> Instance<'tcx> {
let actual_kind = substs.as_closure().kind(def_id, tcx);
let actual_kind = substs.as_closure().kind();

match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, substs),
Expand Down Expand Up @@ -360,7 +360,7 @@ impl<'tcx> Instance<'tcx> {

let self_ty = tcx.mk_closure(closure_did, substs);

let sig = substs.as_closure().sig(closure_did, tcx);
let sig = substs.as_closure().sig();
let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
assert_eq!(sig.inputs().len(), 1);
let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);
Expand Down
20 changes: 9 additions & 11 deletions src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {

ty::Generator(def_id, substs, _) => self.generator_layout(ty, def_id, substs)?,

ty::Closure(def_id, ref substs) => {
let tys = substs.as_closure().upvar_tys(def_id, tcx);
ty::Closure(_, ref substs) => {
let tys = substs.as_closure().upvar_tys();
univariant(
&tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(),
Expand Down Expand Up @@ -1408,7 +1408,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// Build a prefix layout, including "promoting" all ineligible
// locals as part of the prefix. We compute the layout of all of
// these fields at once to get optimal packing.
let discr_index = substs.as_generator().prefix_tys(def_id, tcx).count();
let discr_index = substs.as_generator().prefix_tys().count();
// FIXME(eddyb) set the correct vaidity range for the discriminant.
let discr_layout = self.layout_of(substs.as_generator().discr_ty(tcx))?;
let discr = match &discr_layout.abi {
Expand All @@ -1422,7 +1422,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
.map(|ty| self.layout_of(ty));
let prefix_layouts = substs
.as_generator()
.prefix_tys(def_id, tcx)
.prefix_tys()
.map(|ty| self.layout_of(ty))
.chain(iter::once(Ok(discr_layout)))
.chain(promoted_layouts)
Expand Down Expand Up @@ -2094,9 +2094,7 @@ where
ty::Str => tcx.types.u8,

// Tuples, generators and closures.
ty::Closure(def_id, ref substs) => {
substs.as_closure().upvar_tys(def_id, tcx).nth(i).unwrap()
}
ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().nth(i).unwrap(),

ty::Generator(def_id, ref substs, _) => match this.variants {
Variants::Single { index } => substs
Expand All @@ -2110,7 +2108,7 @@ where
if i == discr_index {
return discr_layout(discr);
}
substs.as_generator().prefix_tys(def_id, tcx).nth(i).unwrap()
substs.as_generator().prefix_tys().nth(i).unwrap()
}
},

Expand Down Expand Up @@ -2297,7 +2295,7 @@ impl<'tcx> ty::Instance<'tcx> {
sig
}
ty::Closure(def_id, substs) => {
let sig = substs.as_closure().sig(def_id, tcx);
let sig = substs.as_closure().sig();

let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
sig.map_bound(|sig| tcx.mk_fn_sig(
Expand All @@ -2308,8 +2306,8 @@ impl<'tcx> ty::Instance<'tcx> {
sig.abi
))
}
ty::Generator(def_id, substs, _) => {
let sig = substs.as_generator().poly_sig(def_id, tcx);
ty::Generator(_, substs, _) => {
let sig = substs.as_generator().poly_sig();

let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/ty/outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo
// in the `subtys` iterator (e.g., when encountering a
// projection).
match ty.kind {
ty::Closure(def_id, ref substs) => {
for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) {
ty::Closure(_, ref substs) => {
for upvar_ty in substs.as_closure().upvar_tys() {
compute_components(tcx, upvar_ty, out);
}
}

ty::Generator(def_id, ref substs, _) => {
ty::Generator(_, ref substs, _) => {
// Same as the closure case
for upvar_ty in substs.as_generator().upvar_tys(def_id, tcx) {
for upvar_ty in substs.as_generator().upvar_tys() {
compute_components(tcx, upvar_ty, out);
}

Expand Down
88 changes: 60 additions & 28 deletions src/librustc/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,8 +608,8 @@ pub trait PrettyPrinter<'tcx>:
}
ty::Str => p!(write("str")),
ty::Generator(did, substs, movability) => {
let upvar_tys = substs.as_generator().upvar_tys(did, self.tcx());
let witness = substs.as_generator().witness(did, self.tcx());
let tupled_upvars_ty = substs.as_generator().tupled_upvars_ty();
let witness = substs.as_generator().witness();
match movability {
hir::Movability::Movable => p!(write("[generator")),
hir::Movability::Static => p!(write("[static generator")),
Expand All @@ -618,21 +618,40 @@ pub trait PrettyPrinter<'tcx>:
// FIXME(eddyb) should use `def_span`.
if let Some(hir_id) = self.tcx().hir().as_local_hir_id(did) {
p!(write("@{:?}", self.tcx().hir().span(hir_id)));
let mut sep = " ";
for (&var_id, upvar_ty) in
self.tcx().upvars(did).as_ref().iter().flat_map(|v| v.keys()).zip(upvar_tys)
{
p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty));
sep = ", ";

// Only print upvars if they're known (i.e. not infer var or param).
if let ty::Tuple(upvar_tys) = tupled_upvars_ty.kind {
let mut sep = " ";
for (&var_id, upvar_ty) in self
.tcx()
.upvars(did)
.as_ref()
.iter()
.flat_map(|v| v.keys())
.zip(upvar_tys)
{
p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty));
sep = ", ";
}
}
} else {
// Cross-crate closure types should only be
// visible in codegen bug reports, I imagine.
p!(write("@{:?}", did));
let mut sep = " ";
for (index, upvar_ty) in upvar_tys.enumerate() {
p!(write("{}{}:", sep, index), print(upvar_ty));
sep = ", ";

// Only print upvars if they're known (i.e. not infer var or param).
if let ty::Tuple(upvar_tys) = tupled_upvars_ty.kind {
let mut sep = " ";
for (index, upvar_ty) in upvar_tys.iter().enumerate() {
p!(write("{}{}:", sep, index), print(upvar_ty));
sep = ", ";
}
}
}

if self.tcx().sess.verbose() {
if !matches!(tupled_upvars_ty.kind, ty::Tuple(_)) {
p!(write(" tupled_upvars_ty="), print(tupled_upvars_ty));
}
}

Expand All @@ -642,7 +661,7 @@ pub trait PrettyPrinter<'tcx>:
p!(in_binder(&types));
}
ty::Closure(did, substs) => {
let upvar_tys = substs.as_closure().upvar_tys(did, self.tcx());
let tupled_upvars_ty = substs.as_closure().tupled_upvars_ty();
p!(write("[closure"));

// FIXME(eddyb) should use `def_span`.
Expand All @@ -652,30 +671,43 @@ pub trait PrettyPrinter<'tcx>:
} else {
p!(write("@{:?}", self.tcx().hir().span(hir_id)));
}
let mut sep = " ";
for (&var_id, upvar_ty) in
self.tcx().upvars(did).as_ref().iter().flat_map(|v| v.keys()).zip(upvar_tys)
{
p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty));
sep = ", ";

// Only print upvars if they're known (i.e. not infer var or param).
if let ty::Tuple(upvar_tys) = tupled_upvars_ty.kind {
let mut sep = " ";
for (&var_id, upvar_ty) in self
.tcx()
.upvars(did)
.as_ref()
.iter()
.flat_map(|v| v.keys())
.zip(upvar_tys)
{
p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty));
sep = ", ";
}
}
} else {
// Cross-crate closure types should only be
// visible in codegen bug reports, I imagine.
p!(write("@{:?}", did));
let mut sep = " ";
for (index, upvar_ty) in upvar_tys.enumerate() {
p!(write("{}{}:", sep, index), print(upvar_ty));
sep = ", ";

// Only print upvars if they're known (i.e. not infer var or param).
if let ty::Tuple(upvar_tys) = tupled_upvars_ty.kind {
let mut sep = " ";
for (index, upvar_ty) in upvar_tys.iter().enumerate() {
p!(write("{}{}:", sep, index), print(upvar_ty));
sep = ", ";
}
}
}

if self.tcx().sess.verbose() {
p!(write(
" closure_kind_ty={:?} closure_sig_ty={:?}",
substs.as_closure().kind_ty(did, self.tcx()),
substs.as_closure().sig_ty(did, self.tcx())
));
p!(write(" closure_kind_ty="), print(substs.as_closure().kind_ty()));
p!(write(" closure_sig_ty="), print(substs.as_closure().sig_ty()));
if !matches!(tupled_upvars_ty.kind, ty::Tuple(_)) {
p!(write(" tupled_upvars_ty="), print(tupled_upvars_ty));
}
}

p!(write("]"))
Expand Down
Loading

0 comments on commit 6429062

Please sign in to comment.