diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 62a62085c6664..dacf242118122 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -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}; diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 05cd1ae456b35..71da5506315af 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -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. diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 255f611cfa357..c7f9e9d63e03c 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -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,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 @@ -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);