Skip to content

Commit 5d44d54

Browse files
committed
rustc_typeck: construct {Closure,Generator}Substs more directly.
1 parent 7a4fb35 commit 5d44d54

File tree

3 files changed

+118
-82
lines changed

3 files changed

+118
-82
lines changed

src/librustc_middle/ty/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNER
6060
pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
6161
pub use self::sty::{CanonicalPolyFnSig, FnSig, GenSig, PolyFnSig, PolyGenSig};
6262
pub use self::sty::{ClosureSubsts, GeneratorSubsts, TypeAndMut, UpvarSubsts};
63+
pub use self::sty::{ClosureSubstsParts, GeneratorSubstsParts};
6364
pub use self::sty::{ConstVid, FloatVid, IntVid, RegionVid, TyVid};
6465
pub use self::sty::{ExistentialPredicate, InferTy, ParamConst, ParamTy, ProjectionTy};
6566
pub use self::sty::{ExistentialProjection, PolyExistentialProjection};

src/librustc_middle/ty/sty.rs

+67-27
Original file line numberDiff line numberDiff line change
@@ -325,24 +325,39 @@ pub struct ClosureSubsts<'tcx> {
325325
pub substs: SubstsRef<'tcx>,
326326
}
327327

328-
/// Struct returned by `split()`. Note that these are subslices of the
329-
/// parent slice and not canonical substs themselves.
330-
struct SplitClosureSubsts<'tcx> {
331-
parent: &'tcx [GenericArg<'tcx>],
332-
closure_kind_ty: GenericArg<'tcx>,
333-
closure_sig_as_fn_ptr_ty: GenericArg<'tcx>,
334-
tupled_upvars_ty: GenericArg<'tcx>,
328+
/// Struct returned by `split()`.
329+
pub struct ClosureSubstsParts<'tcx, T> {
330+
pub parent_substs: &'tcx [GenericArg<'tcx>],
331+
pub closure_kind_ty: T,
332+
pub closure_sig_as_fn_ptr_ty: T,
333+
pub tupled_upvars_ty: T,
335334
}
336335

337336
impl<'tcx> ClosureSubsts<'tcx> {
338-
/// Divides the closure substs into their respective
339-
/// components. Single source of truth with respect to the
340-
/// ordering.
341-
fn split(self) -> SplitClosureSubsts<'tcx> {
337+
/// Construct `ClosureSubsts` from `ClosureSubstsParts`, containing `Substs`
338+
/// for the closure parent, alongside additional closure-specific components.
339+
pub fn new(
340+
tcx: TyCtxt<'tcx>,
341+
parts: ClosureSubstsParts<'tcx, Ty<'tcx>>,
342+
) -> ClosureSubsts<'tcx> {
343+
ClosureSubsts {
344+
substs: tcx.mk_substs(
345+
parts.parent_substs.iter().copied().chain(
346+
[parts.closure_kind_ty, parts.closure_sig_as_fn_ptr_ty, parts.tupled_upvars_ty]
347+
.iter()
348+
.map(|&ty| ty.into()),
349+
),
350+
),
351+
}
352+
}
353+
354+
/// Divides the closure substs into their respective components.
355+
/// The ordering assumed here must match that used by `ClosureSubsts::new` above.
356+
fn split(self) -> ClosureSubstsParts<'tcx, GenericArg<'tcx>> {
342357
match self.substs[..] {
343-
[ref parent @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
344-
SplitClosureSubsts {
345-
parent,
358+
[ref parent_substs @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
359+
ClosureSubstsParts {
360+
parent_substs,
346361
closure_kind_ty,
347362
closure_sig_as_fn_ptr_ty,
348363
tupled_upvars_ty,
@@ -363,7 +378,7 @@ impl<'tcx> ClosureSubsts<'tcx> {
363378

364379
/// Returns the substitutions of the closure's parent.
365380
pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
366-
self.split().parent
381+
self.split().parent_substs
367382
}
368383

369384
#[inline]
@@ -418,21 +433,46 @@ pub struct GeneratorSubsts<'tcx> {
418433
pub substs: SubstsRef<'tcx>,
419434
}
420435

421-
struct SplitGeneratorSubsts<'tcx> {
422-
parent: &'tcx [GenericArg<'tcx>],
423-
resume_ty: GenericArg<'tcx>,
424-
yield_ty: GenericArg<'tcx>,
425-
return_ty: GenericArg<'tcx>,
426-
witness: GenericArg<'tcx>,
427-
tupled_upvars_ty: GenericArg<'tcx>,
436+
pub struct GeneratorSubstsParts<'tcx, T> {
437+
pub parent_substs: &'tcx [GenericArg<'tcx>],
438+
pub resume_ty: T,
439+
pub yield_ty: T,
440+
pub return_ty: T,
441+
pub witness: T,
442+
pub tupled_upvars_ty: T,
428443
}
429444

430445
impl<'tcx> GeneratorSubsts<'tcx> {
431-
fn split(self) -> SplitGeneratorSubsts<'tcx> {
446+
/// Construct `GeneratorSubsts` from `GeneratorSubstsParts`, containing `Substs`
447+
/// for the generator parent, alongside additional generator-specific components.
448+
pub fn new(
449+
tcx: TyCtxt<'tcx>,
450+
parts: GeneratorSubstsParts<'tcx, Ty<'tcx>>,
451+
) -> GeneratorSubsts<'tcx> {
452+
GeneratorSubsts {
453+
substs: tcx.mk_substs(
454+
parts.parent_substs.iter().copied().chain(
455+
[
456+
parts.resume_ty,
457+
parts.yield_ty,
458+
parts.return_ty,
459+
parts.witness,
460+
parts.tupled_upvars_ty,
461+
]
462+
.iter()
463+
.map(|&ty| ty.into()),
464+
),
465+
),
466+
}
467+
}
468+
469+
/// Divides the generator substs into their respective components.
470+
/// The ordering assumed here must match that used by `GeneratorSubsts::new` above.
471+
fn split(self) -> GeneratorSubstsParts<'tcx, GenericArg<'tcx>> {
432472
match self.substs[..] {
433-
[ref parent @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
434-
SplitGeneratorSubsts {
435-
parent,
473+
[ref parent_substs @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
474+
GeneratorSubstsParts {
475+
parent_substs,
436476
resume_ty,
437477
yield_ty,
438478
return_ty,
@@ -455,7 +495,7 @@ impl<'tcx> GeneratorSubsts<'tcx> {
455495

456496
/// Returns the substitutions of the generator's parent.
457497
pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
458-
self.split().parent
498+
self.split().parent_substs
459499
}
460500

461501
/// This describes the types that can be contained in a generator.

src/librustc_typeck/check/closure.rs

+50-55
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_infer::infer::LateBoundRegionConversionTime;
1111
use rustc_infer::infer::{InferOk, InferResult};
1212
use rustc_middle::ty::fold::TypeFoldable;
1313
use rustc_middle::ty::subst::InternalSubsts;
14-
use rustc_middle::ty::{self, GenericParamDefKind, Ty};
14+
use rustc_middle::ty::{self, Ty};
1515
use rustc_span::source_map::Span;
1616
use rustc_target::spec::abi::Abi;
1717
use rustc_trait_selection::traits::error_reporting::ArgKind;
@@ -76,60 +76,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7676
let generator_types =
7777
check_fn(self, self.param_env, liberated_sig, decl, expr.hir_id, body, gen).1;
7878

79-
let base_substs = InternalSubsts::identity_for_item(
79+
let parent_substs = InternalSubsts::identity_for_item(
8080
self.tcx,
8181
self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
8282
);
83-
// HACK(eddyb) this hardcodes indices into substs but it should rely on
84-
// `ClosureSubsts` and `GeneratorSubsts` providing constructors, instead.
85-
// That would also remove the need for most of the inference variables,
86-
// as they immediately unified with the actual type below, including
87-
// the `InferCtxt::closure_sig` and `ClosureSubsts::sig_ty` methods.
88-
let tupled_upvars_idx = base_substs.len() + if generator_types.is_some() { 4 } else { 2 };
89-
let substs =
90-
base_substs.extend_to(self.tcx, expr_def_id.to_def_id(), |param, _| match param.kind {
91-
GenericParamDefKind::Lifetime => span_bug!(expr.span, "closure has lifetime param"),
92-
GenericParamDefKind::Type { .. } => if param.index as usize == tupled_upvars_idx {
93-
self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map(
94-
|upvars| {
95-
upvars.iter().map(|(&var_hir_id, _)| {
96-
// Create type variables (for now) to represent the transformed
97-
// types of upvars. These will be unified during the upvar
98-
// inference phase (`upvar.rs`).
99-
self.infcx.next_ty_var(TypeVariableOrigin {
100-
// FIXME(eddyb) distinguish upvar inference variables from the rest.
101-
kind: TypeVariableOriginKind::ClosureSynthetic,
102-
span: self.tcx.hir().span(var_hir_id),
103-
})
104-
})
105-
},
106-
))
107-
} else {
108-
// Create type variables (for now) to represent the various
109-
// pieces of information kept in `{Closure,Generic}Substs`.
110-
// They will either be unified below, or later during the upvar
111-
// inference phase (`upvar.rs`)
83+
84+
let tupled_upvars_ty =
85+
self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map(|upvars| {
86+
upvars.iter().map(|(&var_hir_id, _)| {
87+
// Create type variables (for now) to represent the transformed
88+
// types of upvars. These will be unified during the upvar
89+
// inference phase (`upvar.rs`).
11290
self.infcx.next_ty_var(TypeVariableOrigin {
91+
// FIXME(eddyb) distinguish upvar inference variables from the rest.
11392
kind: TypeVariableOriginKind::ClosureSynthetic,
114-
span: expr.span,
93+
span: self.tcx.hir().span(var_hir_id),
11594
})
116-
}
117-
.into(),
118-
GenericParamDefKind::Const => span_bug!(expr.span, "closure has const param"),
119-
});
95+
})
96+
}));
97+
12098
if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
12199
{
122-
let generator_substs = substs.as_generator();
123-
self.demand_eqtype(expr.span, resume_ty, generator_substs.resume_ty());
124-
self.demand_eqtype(expr.span, yield_ty, generator_substs.yield_ty());
125-
self.demand_eqtype(expr.span, liberated_sig.output(), generator_substs.return_ty());
126-
self.demand_eqtype(expr.span, interior, generator_substs.witness());
127-
128-
// HACK(eddyb) this forces the types equated above into `substs` but
129-
// it should rely on `GeneratorSubsts` providing a constructor, instead.
130-
let substs = self.resolve_vars_if_possible(&substs);
100+
let generator_substs = ty::GeneratorSubsts::new(
101+
self.tcx,
102+
ty::GeneratorSubstsParts {
103+
parent_substs,
104+
resume_ty,
105+
yield_ty,
106+
return_ty: liberated_sig.output(),
107+
witness: interior,
108+
tupled_upvars_ty,
109+
},
110+
);
131111

132-
return self.tcx.mk_generator(expr_def_id.to_def_id(), substs, movability);
112+
return self.tcx.mk_generator(
113+
expr_def_id.to_def_id(),
114+
generator_substs.substs,
115+
movability,
116+
);
133117
}
134118

135119
// Tuple up the arguments and insert the resulting function type into
@@ -149,18 +133,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
149133
expr_def_id, sig, opt_kind
150134
);
151135

152-
let sig_fn_ptr_ty = self.tcx.mk_fn_ptr(sig);
153-
self.demand_eqtype(expr.span, sig_fn_ptr_ty, substs.as_closure().sig_as_fn_ptr_ty());
136+
let closure_kind_ty = match opt_kind {
137+
Some(kind) => kind.to_ty(self.tcx),
154138

155-
if let Some(kind) = opt_kind {
156-
self.demand_eqtype(expr.span, kind.to_ty(self.tcx), substs.as_closure().kind_ty());
157-
}
139+
// Create a type variable (for now) to represent the closure kind.
140+
// It will be unified during the upvar inference phase (`upvar.rs`)
141+
None => self.infcx.next_ty_var(TypeVariableOrigin {
142+
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
143+
kind: TypeVariableOriginKind::ClosureSynthetic,
144+
span: expr.span,
145+
}),
146+
};
158147

159-
// HACK(eddyb) this forces the types equated above into `substs` but
160-
// it should rely on `ClosureSubsts` providing a constructor, instead.
161-
let substs = self.resolve_vars_if_possible(&substs);
148+
let closure_substs = ty::ClosureSubsts::new(
149+
self.tcx,
150+
ty::ClosureSubstsParts {
151+
parent_substs,
152+
closure_kind_ty,
153+
closure_sig_as_fn_ptr_ty: self.tcx.mk_fn_ptr(sig),
154+
tupled_upvars_ty,
155+
},
156+
);
162157

163-
let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), substs);
158+
let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs);
164159

165160
debug!("check_closure: expr.hir_id={:?} closure_type={:?}", expr.hir_id, closure_type);
166161

0 commit comments

Comments
 (0)