diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 4b2be7b5321ff..68704e595a8ed 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -211,7 +211,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let instance = Instance::resolve_closure( bx.cx().tcx(), def_id, - substs, + substs.as_closure(), ty::ClosureKind::FnOnce, ); OperandValue::Immediate(bx.cx().get_fn_addr(instance)) diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index d628d6783d5b0..c3f324204f77b 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -382,14 +382,14 @@ impl<'tcx> Instance<'tcx> { pub fn resolve_closure( tcx: TyCtxt<'tcx>, def_id: DefId, - substs: ty::SubstsRef<'tcx>, + closure_substs: ty::ClosureSubsts<'tcx>, requested_kind: ty::ClosureKind, ) -> Instance<'tcx> { - let actual_kind = substs.as_closure().kind(); + let actual_kind = closure_substs.kind(); match needs_fn_once_adapter_shim(actual_kind, requested_kind) { - Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, substs), - _ => Instance::new(def_id, substs), + Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, closure_substs), + _ => Instance::new(def_id, tcx.intern_substs(closure_substs.base_substs())), } } @@ -399,12 +399,12 @@ impl<'tcx> Instance<'tcx> { Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap().unwrap() } - pub fn fn_once_adapter_instance( + fn fn_once_adapter_instance( tcx: TyCtxt<'tcx>, closure_did: DefId, - substs: ty::SubstsRef<'tcx>, + closure_substs: ty::ClosureSubsts<'tcx>, ) -> Instance<'tcx> { - debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, substs); + debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, closure_substs); let fn_once = tcx.require_lang_item(FnOnceTraitLangItem, None); let call_once = tcx .associated_items(fn_once) @@ -414,9 +414,9 @@ impl<'tcx> Instance<'tcx> { .def_id; let def = ty::InstanceDef::ClosureOnceShim { call_once }; - let self_ty = tcx.mk_closure(closure_did, substs); + let self_ty = tcx.mk_closure(closure_did, closure_substs.substs); - let sig = substs.as_closure().sig(); + let sig = closure_substs.sig(); let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); assert_eq!(sig.inputs().len(), 1); let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]); diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index bec1200d7aa0f..1251ef0576faa 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -65,6 +65,7 @@ pub use self::sty::{ConstVid, FloatVid, IntVid, RegionVid, TyVid}; pub use self::sty::{ExistentialPredicate, InferConst, InferTy, ParamConst, ParamTy, ProjectionTy}; pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; pub use self::sty::{PolyTraitRef, TraitRef, TyKind}; +pub use self::sty::{SplitClosureSubsts, SplitGeneratorSubsts}; pub use crate::ty::diagnostics::*; pub use self::binding::BindingMode; diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index c7683cefd82f6..7be10b5704b42 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -319,19 +319,42 @@ 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> { - closure_kind_ty: GenericArg<'tcx>, - closure_sig_as_fn_ptr_ty: GenericArg<'tcx>, - tupled_upvars_ty: GenericArg<'tcx>, +/// Struct returned by `split()`. +// FIXME(eddyb) find a better name than `Split...` - perhaps `ClosureSubstsParts`? +pub struct SplitClosureSubsts { + 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 base `Substs` (i.e. of the parent function) + /// and `SplitClosureSubsts` containing the additional closure-specific components. + pub fn new( + tcx: TyCtxt<'tcx>, + base_substs: SubstsRef<'tcx>, + parts: SplitClosureSubsts>, + ) -> ClosureSubsts<'tcx> { + ClosureSubsts { + substs: tcx.mk_substs( + base_substs.iter().chain( + [parts.closure_kind_ty, parts.closure_sig_as_fn_ptr_ty, parts.tupled_upvars_ty] + .iter() + .map(|&ty| ty.into()), + ), + ), + } + } + + /// Returns the non-closure-specific base `Substs` (i.e. of the parent function). + /// The ordering assumed here must match that used by `ClosureSubsts::new` above. + pub fn base_substs(self) -> &'tcx [GenericArg<'tcx>] { + &self.substs[..self.substs.len() - 3] + } + + /// Divides the closure substs into their respective components. + /// The ordering assumed here must match that used by `ClosureSubsts::new` above. + fn split(self) -> SplitClosureSubsts> { match self.substs[..] { [.., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => { SplitClosureSubsts { closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty } @@ -395,16 +418,49 @@ pub struct GeneratorSubsts<'tcx> { pub substs: SubstsRef<'tcx>, } -struct SplitGeneratorSubsts<'tcx> { - resume_ty: GenericArg<'tcx>, - yield_ty: GenericArg<'tcx>, - return_ty: GenericArg<'tcx>, - witness: GenericArg<'tcx>, - tupled_upvars_ty: GenericArg<'tcx>, +// FIXME(eddyb) find a better name than `Split...` - perhaps `GeneratorSubstsParts`? +pub struct SplitGeneratorSubsts { + 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 base `Substs` (i.e. of the parent function) + /// and `SplitGeneratorSubsts` containing the additional generator-specific components. + pub fn new( + tcx: TyCtxt<'tcx>, + base_substs: SubstsRef<'tcx>, + parts: SplitGeneratorSubsts>, + ) -> GeneratorSubsts<'tcx> { + GeneratorSubsts { + substs: tcx.mk_substs( + base_substs.iter().chain( + [ + parts.resume_ty, + parts.yield_ty, + parts.return_ty, + parts.witness, + parts.tupled_upvars_ty, + ] + .iter() + .map(|&ty| ty.into()), + ), + ), + } + } + + /// Returns the non-generator-specific base `Substs` (i.e. of the parent function). + /// The ordering assumed here must match that used by `GeneratorSubsts::new` above. + pub fn base_substs(self) -> &'tcx [GenericArg<'tcx>] { + &self.substs[..self.substs.len() - 5] + } + + /// Divides the generator substs into their respective components. + /// The ordering assumed here must match that used by `GeneratorSubsts::new` above. + fn split(self) -> SplitGeneratorSubsts> { match self.substs[..] { [.., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => { SplitGeneratorSubsts { resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty } diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 60cf21552e9e9..8bf17d1214a21 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -96,7 +96,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let instance = ty::Instance::resolve_closure( *self.tcx, def_id, - substs, + substs.as_closure(), ty::ClosureKind::FnOnce, ); let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index f9b3c319c1f66..de3732db17507 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -581,7 +581,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let instance = Instance::resolve_closure( self.tcx, def_id, - substs, + substs.as_closure(), ty::ClosureKind::FnOnce, ); if should_monomorphize_locally(self.tcx, &instance) { diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs index 9f5ab7f8e4a02..f1f4b7b0039f4 100644 --- a/src/librustc_ty/instance.rs +++ b/src/librustc_ty/instance.rs @@ -190,7 +190,7 @@ fn resolve_associated_item<'tcx>( Some(Instance::resolve_closure( tcx, closure_data.closure_def_id, - closure_data.substs, + closure_data.substs.as_closure(), trait_closure_kind, )) } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index fce2b18b782fb..67ece70e228c1 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; @@ -80,56 +80,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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, + base_substs, + ty::SplitGeneratorSubsts { + 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, + base_substs, + ty::SplitClosureSubsts { + 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); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 15481660a5218..64686f6edcd6b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -224,7 +224,6 @@ impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { if let hir::ExprKind::Closure(..) = expr.kind { let def_id = self.tcx.hir().local_def_id(expr.hir_id); self.tcx.ensure().generics_of(def_id); - self.tcx.ensure().type_of(def_id); } intravisit::walk_expr(self, expr); } @@ -1362,29 +1361,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { } })); - // provide junk type parameter defs - the only place that - // cares about anything but the length is instantiation, - // and we don't do that for closures. - if let Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., gen), .. }) = node { - let dummy_args = if gen.is_some() { - &["", "", "", "", ""][..] - } else { - &["", "", ""][..] - }; - - params.extend(dummy_args.iter().enumerate().map(|(i, &arg)| ty::GenericParamDef { - index: type_start + i as u32, - name: Symbol::intern(arg), - def_id, - pure_wrt_drop: false, - kind: ty::GenericParamDefKind::Type { - has_default: false, - object_lifetime_default: rl::Set1::Empty, - synthetic: None, - }, - })); - } - let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); ty::Generics { diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs index 3dd9c9c5c39db..9d384700b1c8f 100644 --- a/src/librustc_typeck/collect/type_of.rs +++ b/src/librustc_typeck/collect/type_of.rs @@ -177,13 +177,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { Node::Field(field) => icx.to_ty(&field.ty), - Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - if let Some(movability) = gen { - tcx.mk_generator(def_id, substs, movability) - } else { - tcx.mk_closure(def_id, substs) - } + Node::Expr(&Expr { kind: ExprKind::Closure(..), .. }) => { + tcx.typeck_tables_of(def_id.expect_local()).node_type(hir_id) } Node::AnonConst(_) => {