Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustc_typeck: construct {Closure,Generator}Substs more directly. #74314

Merged
merged 1 commit into from
Aug 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc_middle/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNER
pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
pub use self::sty::{CanonicalPolyFnSig, FnSig, GenSig, PolyFnSig, PolyGenSig};
pub use self::sty::{ClosureSubsts, GeneratorSubsts, TypeAndMut, UpvarSubsts};
pub use self::sty::{ClosureSubstsParts, GeneratorSubstsParts};
pub use self::sty::{ConstVid, FloatVid, IntVid, RegionVid, TyVid};
pub use self::sty::{ExistentialPredicate, InferTy, ParamConst, ParamTy, ProjectionTy};
pub use self::sty::{ExistentialProjection, PolyExistentialProjection};
Expand Down
94 changes: 67 additions & 27 deletions src/librustc_middle/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,24 +325,39 @@ pub struct ClosureSubsts<'tcx> {
pub substs: SubstsRef<'tcx>,
}

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

impl<'tcx> ClosureSubsts<'tcx> {
/// Divides the closure substs into their respective
/// components. Single source of truth with respect to the
/// ordering.
fn split(self) -> SplitClosureSubsts<'tcx> {
/// Construct `ClosureSubsts` from `ClosureSubstsParts`, containing `Substs`
/// for the closure parent, alongside additional closure-specific components.
pub fn new(
tcx: TyCtxt<'tcx>,
parts: ClosureSubstsParts<'tcx, Ty<'tcx>>,
) -> ClosureSubsts<'tcx> {
ClosureSubsts {
substs: tcx.mk_substs(
parts.parent_substs.iter().copied().chain(
[parts.closure_kind_ty, parts.closure_sig_as_fn_ptr_ty, parts.tupled_upvars_ty]
.iter()
.map(|&ty| ty.into()),
),
),
}
}

/// Divides the closure substs into their respective components.
/// The ordering assumed here must match that used by `ClosureSubsts::new` above.
fn split(self) -> ClosureSubstsParts<'tcx, GenericArg<'tcx>> {
match self.substs[..] {
[ref parent @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
SplitClosureSubsts {
parent,
[ref parent_substs @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
ClosureSubstsParts {
parent_substs,
closure_kind_ty,
closure_sig_as_fn_ptr_ty,
tupled_upvars_ty,
Expand All @@ -363,7 +378,7 @@ impl<'tcx> ClosureSubsts<'tcx> {

/// Returns the substitutions of the closure's parent.
pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
self.split().parent
self.split().parent_substs
}

#[inline]
Expand Down Expand Up @@ -418,21 +433,46 @@ pub struct GeneratorSubsts<'tcx> {
pub substs: SubstsRef<'tcx>,
}

struct SplitGeneratorSubsts<'tcx> {
parent: &'tcx [GenericArg<'tcx>],
resume_ty: GenericArg<'tcx>,
yield_ty: GenericArg<'tcx>,
return_ty: GenericArg<'tcx>,
witness: GenericArg<'tcx>,
tupled_upvars_ty: GenericArg<'tcx>,
pub struct GeneratorSubstsParts<'tcx, T> {
pub parent_substs: &'tcx [GenericArg<'tcx>],
pub resume_ty: T,
pub yield_ty: T,
pub return_ty: T,
pub witness: T,
pub tupled_upvars_ty: T,
}

impl<'tcx> GeneratorSubsts<'tcx> {
fn split(self) -> SplitGeneratorSubsts<'tcx> {
/// Construct `GeneratorSubsts` from `GeneratorSubstsParts`, containing `Substs`
/// for the generator parent, alongside additional generator-specific components.
pub fn new(
tcx: TyCtxt<'tcx>,
parts: GeneratorSubstsParts<'tcx, Ty<'tcx>>,
) -> GeneratorSubsts<'tcx> {
GeneratorSubsts {
substs: tcx.mk_substs(
parts.parent_substs.iter().copied().chain(
[
parts.resume_ty,
parts.yield_ty,
parts.return_ty,
parts.witness,
parts.tupled_upvars_ty,
]
.iter()
.map(|&ty| ty.into()),
),
),
}
}

/// Divides the generator substs into their respective components.
/// The ordering assumed here must match that used by `GeneratorSubsts::new` above.
fn split(self) -> GeneratorSubstsParts<'tcx, GenericArg<'tcx>> {
match self.substs[..] {
[ref parent @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
SplitGeneratorSubsts {
parent,
[ref parent_substs @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
GeneratorSubstsParts {
parent_substs,
resume_ty,
yield_ty,
return_ty,
Expand All @@ -455,7 +495,7 @@ impl<'tcx> GeneratorSubsts<'tcx> {

/// Returns the substitutions of the generator's parent.
pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
self.split().parent
self.split().parent_substs
}

/// This describes the types that can be contained in a generator.
Expand Down
105 changes: 50 additions & 55 deletions src/librustc_typeck/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::infer::{InferOk, InferResult};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, GenericParamDefKind, Ty};
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Span;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::ArgKind;
Expand Down Expand Up @@ -76,60 +76,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let generator_types =
check_fn(self, self.param_env, liberated_sig, decl, expr.hir_id, body, gen).1;

let base_substs = InternalSubsts::identity_for_item(
let parent_substs = InternalSubsts::identity_for_item(
self.tcx,
self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
);
// HACK(eddyb) this hardcodes indices into substs but it should rely on
// `ClosureSubsts` and `GeneratorSubsts` providing constructors, instead.
// That would also remove the need for most of the inference variables,
// as they immediately unified with the actual type below, including
// the `InferCtxt::closure_sig` and `ClosureSubsts::sig_ty` methods.
let tupled_upvars_idx = base_substs.len() + if generator_types.is_some() { 4 } else { 2 };
let substs =
base_substs.extend_to(self.tcx, expr_def_id.to_def_id(), |param, _| match param.kind {
GenericParamDefKind::Lifetime => span_bug!(expr.span, "closure has lifetime param"),
GenericParamDefKind::Type { .. } => if param.index as usize == tupled_upvars_idx {
self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map(
|upvars| {
upvars.iter().map(|(&var_hir_id, _)| {
// Create type variables (for now) to represent the transformed
// types of upvars. These will be unified during the upvar
// inference phase (`upvar.rs`).
self.infcx.next_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish upvar inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
span: self.tcx.hir().span(var_hir_id),
})
})
},
))
} else {
// Create type variables (for now) to represent the various
// pieces of information kept in `{Closure,Generic}Substs`.
// They will either be unified below, or later during the upvar
// inference phase (`upvar.rs`)

let tupled_upvars_ty =
self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map(|upvars| {
upvars.iter().map(|(&var_hir_id, _)| {
// Create type variables (for now) to represent the transformed
// types of upvars. These will be unified during the upvar
// inference phase (`upvar.rs`).
self.infcx.next_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish upvar inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr.span,
span: self.tcx.hir().span(var_hir_id),
})
}
.into(),
GenericParamDefKind::Const => span_bug!(expr.span, "closure has const param"),
});
})
}));

if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
{
let generator_substs = substs.as_generator();
self.demand_eqtype(expr.span, resume_ty, generator_substs.resume_ty());
self.demand_eqtype(expr.span, yield_ty, generator_substs.yield_ty());
self.demand_eqtype(expr.span, liberated_sig.output(), generator_substs.return_ty());
self.demand_eqtype(expr.span, interior, generator_substs.witness());

// HACK(eddyb) this forces the types equated above into `substs` but
// it should rely on `GeneratorSubsts` providing a constructor, instead.
let substs = self.resolve_vars_if_possible(&substs);
let generator_substs = ty::GeneratorSubsts::new(
self.tcx,
ty::GeneratorSubstsParts {
parent_substs,
resume_ty,
yield_ty,
return_ty: liberated_sig.output(),
witness: interior,
tupled_upvars_ty,
},
);

return self.tcx.mk_generator(expr_def_id.to_def_id(), substs, movability);
return self.tcx.mk_generator(
expr_def_id.to_def_id(),
generator_substs.substs,
movability,
);
}

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

let sig_fn_ptr_ty = self.tcx.mk_fn_ptr(sig);
self.demand_eqtype(expr.span, sig_fn_ptr_ty, substs.as_closure().sig_as_fn_ptr_ty());
let closure_kind_ty = match opt_kind {
Some(kind) => kind.to_ty(self.tcx),

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

// HACK(eddyb) this forces the types equated above into `substs` but
// it should rely on `ClosureSubsts` providing a constructor, instead.
let substs = self.resolve_vars_if_possible(&substs);
let closure_substs = ty::ClosureSubsts::new(
self.tcx,
ty::ClosureSubstsParts {
parent_substs,
closure_kind_ty,
closure_sig_as_fn_ptr_ty: self.tcx.mk_fn_ptr(sig),
tupled_upvars_ty,
},
);

let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), substs);
let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs);

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

Expand Down