Skip to content

Commit 5533705

Browse files
committed
rustc_typeck: construct {Closure,Generator}Substs more directly.
1 parent 9d09331 commit 5533705

File tree

3 files changed

+123
-71
lines changed

3 files changed

+123
-71
lines changed

src/librustc_middle/ty/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pub use self::sty::{ConstVid, FloatVid, IntVid, RegionVid, TyVid};
6565
pub use self::sty::{ExistentialPredicate, InferConst, InferTy, ParamConst, ParamTy, ProjectionTy};
6666
pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
6767
pub use self::sty::{PolyTraitRef, TraitRef, TyKind};
68+
pub use self::sty::{SplitClosureSubsts, SplitGeneratorSubsts};
6869
pub use crate::ty::diagnostics::*;
6970

7071
pub use self::binding::BindingMode;

src/librustc_middle/ty/sty.rs

+73-17
Original file line numberDiff line numberDiff line change
@@ -319,19 +319,42 @@ pub struct ClosureSubsts<'tcx> {
319319
pub substs: SubstsRef<'tcx>,
320320
}
321321

322-
/// Struct returned by `split()`. Note that these are subslices of the
323-
/// parent slice and not canonical substs themselves.
324-
struct SplitClosureSubsts<'tcx> {
325-
closure_kind_ty: GenericArg<'tcx>,
326-
closure_sig_as_fn_ptr_ty: GenericArg<'tcx>,
327-
tupled_upvars_ty: GenericArg<'tcx>,
322+
/// Struct returned by `split()`.
323+
// FIXME(eddyb) find a better name than `Split...` - perhaps `ClosureSubstsParts`?
324+
pub struct SplitClosureSubsts<T> {
325+
pub closure_kind_ty: T,
326+
pub closure_sig_as_fn_ptr_ty: T,
327+
pub tupled_upvars_ty: T,
328328
}
329329

330330
impl<'tcx> ClosureSubsts<'tcx> {
331-
/// Divides the closure substs into their respective
332-
/// components. Single source of truth with respect to the
333-
/// ordering.
334-
fn split(self) -> SplitClosureSubsts<'tcx> {
331+
/// Construct `ClosureSubsts` from base `Substs` (i.e. of the parent function)
332+
/// and `SplitClosureSubsts` containing the additional closure-specific components.
333+
pub fn new(
334+
tcx: TyCtxt<'tcx>,
335+
base_substs: SubstsRef<'tcx>,
336+
parts: SplitClosureSubsts<Ty<'tcx>>,
337+
) -> ClosureSubsts<'tcx> {
338+
ClosureSubsts {
339+
substs: tcx.mk_substs(
340+
base_substs.iter().chain(
341+
[parts.closure_kind_ty, parts.closure_sig_as_fn_ptr_ty, parts.tupled_upvars_ty]
342+
.iter()
343+
.map(|&ty| ty.into()),
344+
),
345+
),
346+
}
347+
}
348+
349+
/// Returns the non-closure-specific base `Substs` (i.e. of the parent function).
350+
/// The ordering assumed here must match that used by `ClosureSubsts::new` above.
351+
pub fn base_substs(self) -> &'tcx [GenericArg<'tcx>] {
352+
&self.substs[..self.substs.len() - 3]
353+
}
354+
355+
/// Divides the closure substs into their respective components.
356+
/// The ordering assumed here must match that used by `ClosureSubsts::new` above.
357+
fn split(self) -> SplitClosureSubsts<GenericArg<'tcx>> {
335358
match self.substs[..] {
336359
[.., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
337360
SplitClosureSubsts { closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty }
@@ -395,16 +418,49 @@ pub struct GeneratorSubsts<'tcx> {
395418
pub substs: SubstsRef<'tcx>,
396419
}
397420

398-
struct SplitGeneratorSubsts<'tcx> {
399-
resume_ty: GenericArg<'tcx>,
400-
yield_ty: GenericArg<'tcx>,
401-
return_ty: GenericArg<'tcx>,
402-
witness: GenericArg<'tcx>,
403-
tupled_upvars_ty: GenericArg<'tcx>,
421+
// FIXME(eddyb) find a better name than `Split...` - perhaps `GeneratorSubstsParts`?
422+
pub struct SplitGeneratorSubsts<T> {
423+
pub resume_ty: T,
424+
pub yield_ty: T,
425+
pub return_ty: T,
426+
pub witness: T,
427+
pub tupled_upvars_ty: T,
404428
}
405429

406430
impl<'tcx> GeneratorSubsts<'tcx> {
407-
fn split(self) -> SplitGeneratorSubsts<'tcx> {
431+
/// Construct `GeneratorSubsts` from base `Substs` (i.e. of the parent function)
432+
/// and `SplitGeneratorSubsts` containing the additional generator-specific components.
433+
pub fn new(
434+
tcx: TyCtxt<'tcx>,
435+
base_substs: SubstsRef<'tcx>,
436+
parts: SplitGeneratorSubsts<Ty<'tcx>>,
437+
) -> GeneratorSubsts<'tcx> {
438+
GeneratorSubsts {
439+
substs: tcx.mk_substs(
440+
base_substs.iter().chain(
441+
[
442+
parts.resume_ty,
443+
parts.yield_ty,
444+
parts.return_ty,
445+
parts.witness,
446+
parts.tupled_upvars_ty,
447+
]
448+
.iter()
449+
.map(|&ty| ty.into()),
450+
),
451+
),
452+
}
453+
}
454+
455+
/// Returns the non-generator-specific base `Substs` (i.e. of the parent function).
456+
/// The ordering assumed here must match that used by `GeneratorSubsts::new` above.
457+
pub fn base_substs(self) -> &'tcx [GenericArg<'tcx>] {
458+
&self.substs[..self.substs.len() - 5]
459+
}
460+
461+
/// Divides the generator substs into their respective components.
462+
/// The ordering assumed here must match that used by `GeneratorSubsts::new` above.
463+
fn split(self) -> SplitGeneratorSubsts<GenericArg<'tcx>> {
408464
match self.substs[..] {
409465
[.., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
410466
SplitGeneratorSubsts { resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty }

src/librustc_typeck/check/closure.rs

+49-54
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;
@@ -80,56 +80,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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+
base_substs,
103+
ty::SplitGeneratorSubsts {
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+
base_substs,
151+
ty::SplitClosureSubsts {
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)