rustc_typeck: construct {Closure,Generator}Substs more directly.
This commit is contained in:
parent
7a4fb355c6
commit
5d44d5456f
3 changed files with 118 additions and 82 deletions
|
@ -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};
|
||||
|
|
|
@ -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,
|
||||
|
@ -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]
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
@ -76,22 +76,13 @@ 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| {
|
||||
|
||||
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
|
||||
|
@ -102,34 +93,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
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`)
|
||||
self.infcx.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||
span: expr.span,
|
||||
})
|
||||
}
|
||||
.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());
|
||||
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,
|
||||
},
|
||||
);
|
||||
|
||||
// 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);
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue