diff options
| author | bors <bors@rust-lang.org> | 2024-06-01 19:07:03 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-06-01 19:07:03 +0000 |
| commit | 0038c021031ce9f1ec2329469c8d85d0e681ef8f (patch) | |
| tree | 853b54354c4fef97dcbf8c5d0a3c44644836ead0 /compiler/rustc_middle/src | |
| parent | a94483a5f2bae907bc898fc7a8d9cc87db47b693 (diff) | |
| parent | 333458c2cbafbea22480075decc4a827f913a020 (diff) | |
| download | rust-0038c021031ce9f1ec2329469c8d85d0e681ef8f.tar.gz rust-0038c021031ce9f1ec2329469c8d85d0e681ef8f.zip | |
Auto merge of #125775 - compiler-errors:uplift-closure-args, r=lcnr
Uplift `{Closure,Coroutine,CoroutineClosure}Args` and friends to `rustc_type_ir`
Part of converting the new solver's `structural_traits.rs` to be interner-agnostic.
I decided against aliasing `ClosureArgs<TyCtxt<'tcx>>` to `ClosureArgs<'tcx>` because it seemed so rare. I could do so if desired, though.
r? lcnr
Diffstat (limited to 'compiler/rustc_middle/src')
| -rw-r--r-- | compiler/rustc_middle/src/mir/query.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/context.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/generic_args.rs | 69 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/layout.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/mod.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/print/pretty.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/relate.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/structural_impls.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/sty.rs | 731 |
9 files changed, 126 insertions, 730 deletions
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 9d70231be3b..46b38e4a6a6 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,7 +1,7 @@ //! Values computed by queries that use MIR. use crate::mir; -use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; +use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c2219fba023..47f66c64406 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -90,7 +90,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type AdtDef = ty::AdtDef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>; - type OwnItemArgs = &'tcx [ty::GenericArg<'tcx>]; + type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>]; type GenericArg = ty::GenericArg<'tcx>; type Term = ty::Term<'tcx>; @@ -113,7 +113,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ErrorGuaranteed = ErrorGuaranteed; type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>; - type PolyFnSig = PolyFnSig<'tcx>; type AllocId = crate::mir::interpret::AllocId; type Pat = Pattern<'tcx>; @@ -191,7 +190,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self, def_id: Self::DefId, args: Self::GenericArgs, - ) -> (rustc_type_ir::TraitRef<Self>, Self::OwnItemArgs) { + ) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) { assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); let trait_def_id = self.parent(def_id); assert_matches!(self.def_kind(trait_def_id), DefKind::Trait); diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 7a516b9f2c8..c3ab755175d 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -2,9 +2,10 @@ use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; -use crate::ty::sty::{ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs}; use crate::ty::visit::{TypeVisitable, TypeVisitor}; -use crate::ty::{self, Lift, List, Ty, TyCtxt}; +use crate::ty::{ + self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs, Lift, List, Ty, TyCtxt, +}; use rustc_ast_ir::visit::VisitorResult; use rustc_ast_ir::walk_visitable_list; @@ -56,6 +57,64 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArg ) -> ty::GenericArgsRef<'tcx> { ty::GenericArgs::extend_with_error(tcx, def_id, original_args) } + + fn split_closure_args(self) -> ty::ClosureArgsParts<TyCtxt<'tcx>> { + match self[..] { + [ref parent_args @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => { + ty::ClosureArgsParts { + parent_args, + closure_kind_ty: closure_kind_ty.expect_ty(), + closure_sig_as_fn_ptr_ty: closure_sig_as_fn_ptr_ty.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + } + } + _ => bug!("closure args missing synthetics"), + } + } + + fn split_coroutine_closure_args(self) -> ty::CoroutineClosureArgsParts<TyCtxt<'tcx>> { + match self[..] { + [ + ref parent_args @ .., + closure_kind_ty, + signature_parts_ty, + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + coroutine_witness_ty, + ] => ty::CoroutineClosureArgsParts { + parent_args, + closure_kind_ty: closure_kind_ty.expect_ty(), + signature_parts_ty: signature_parts_ty.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(), + coroutine_witness_ty: coroutine_witness_ty.expect_ty(), + }, + _ => bug!("closure args missing synthetics"), + } + } + + fn split_coroutine_args(self) -> ty::CoroutineArgsParts<TyCtxt<'tcx>> { + match self[..] { + [ + ref parent_args @ .., + kind_ty, + resume_ty, + yield_ty, + return_ty, + witness, + tupled_upvars_ty, + ] => ty::CoroutineArgsParts { + parent_args, + kind_ty: kind_ty.expect_ty(), + resume_ty: resume_ty.expect_ty(), + yield_ty: yield_ty.expect_ty(), + return_ty: return_ty.expect_ty(), + witness: witness.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + }, + _ => bug!("coroutine args missing synthetics"), + } + } } impl<'tcx> rustc_type_ir::inherent::IntoKind for GenericArg<'tcx> { @@ -295,7 +354,7 @@ impl<'tcx> GenericArgs<'tcx> { /// Closure args have a particular structure controlled by the /// compiler that encodes information like the signature and closure kind; /// see `ty::ClosureArgs` struct for more comments. - pub fn as_closure(&'tcx self) -> ClosureArgs<'tcx> { + pub fn as_closure(&'tcx self) -> ClosureArgs<TyCtxt<'tcx>> { ClosureArgs { args: self } } @@ -303,7 +362,7 @@ impl<'tcx> GenericArgs<'tcx> { /// Coroutine-closure args have a particular structure controlled by the /// compiler that encodes information like the signature and closure kind; /// see `ty::CoroutineClosureArgs` struct for more comments. - pub fn as_coroutine_closure(&'tcx self) -> CoroutineClosureArgs<'tcx> { + pub fn as_coroutine_closure(&'tcx self) -> CoroutineClosureArgs<TyCtxt<'tcx>> { CoroutineClosureArgs { args: self } } @@ -311,7 +370,7 @@ impl<'tcx> GenericArgs<'tcx> { /// Coroutine args have a particular structure controlled by the /// compiler that encodes information like the signature and coroutine kind; /// see `ty::CoroutineArgs` struct for more comments. - pub fn as_coroutine(&'tcx self) -> CoroutineArgs<'tcx> { + pub fn as_coroutine(&'tcx self) -> CoroutineArgs<TyCtxt<'tcx>> { CoroutineArgs { args: self } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 71030febf76..a2df90b2c0f 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2,7 +2,7 @@ use crate::error::UnsupportedFnAbi; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::query::TyCtxtAt; use crate::ty::normalize_erasing_regions::NormalizationError; -use crate::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use crate::ty::{self, CoroutineArgsExt, Ty, TyCtxt, TypeVisitableExt}; use rustc_error_messages::DiagMessage; use rustc_errors::{ Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 90c154233da..2643ce976de 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -113,10 +113,8 @@ pub use self::region::{ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, - ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs, - CoroutineClosureArgsParts, CoroutineClosureSignature, EarlyBinder, FnSig, GenSig, - InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, - UpvarArgs, VarianceDiagInfo, + CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst, + ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 83790db9926..126da2f5a7c 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1938,7 +1938,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Ok(()) } - fn pretty_closure_as_impl(&mut self, closure: ty::ClosureArgs<'tcx>) -> Result<(), PrintError> { + fn pretty_closure_as_impl( + &mut self, + closure: ty::ClosureArgs<TyCtxt<'tcx>>, + ) -> Result<(), PrintError> { let sig = closure.sig(); let kind = closure.kind_ty().to_opt_closure_kind().unwrap_or(ty::ClosureKind::Fn); @@ -2973,7 +2976,7 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> { #[derive(Debug, Copy, Clone, Lift)] pub struct PrintClosureAsImpl<'tcx> { - pub closure: ty::ClosureArgs<'tcx>, + pub closure: ty::ClosureArgs<TyCtxt<'tcx>>, } macro_rules! forward_display_to_print { diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index f02b4849f83..b4179858890 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -756,28 +756,6 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { } } -impl<'tcx> Relate<'tcx> for ty::ClosureArgs<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::ClosureArgs<'tcx>, - b: ty::ClosureArgs<'tcx>, - ) -> RelateResult<'tcx, ty::ClosureArgs<'tcx>> { - let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::ClosureArgs { args }) - } -} - -impl<'tcx> Relate<'tcx> for ty::CoroutineArgs<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::CoroutineArgs<'tcx>, - b: ty::CoroutineArgs<'tcx>, - ) -> RelateResult<'tcx, ty::CoroutineArgs<'tcx>> { - let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::CoroutineArgs { args }) - } -} - impl<'tcx> Relate<'tcx> for GenericArgsRef<'tcx> { fn relate<R: TypeRelation<'tcx>>( relation: &mut R, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index af3aa3b56f7..90791bdd20d 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -259,18 +259,6 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> { } } -impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty::Binder<'tcx, T> { - fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( - this: WithInfcx<'_, Infcx, &Self>, - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { - f.debug_tuple("Binder") - .field(&this.map(|data| data.as_ref().skip_binder())) - .field(&this.data.bound_vars()) - .finish() - } -} - /////////////////////////////////////////////////////////////////////////// // Atomic structs // diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 5f7385fccc9..879396b0678 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -16,7 +16,7 @@ use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; -use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable}; +use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; @@ -30,7 +30,6 @@ use ty::util::{AsyncDropGlueMorphology, IntTypeExt}; use rustc_type_ir::TyKind::*; use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind}; -use super::fold::FnMutDelegate; use super::GenericParamDefKind; // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here @@ -60,670 +59,14 @@ impl<'tcx> Article for TyKind<'tcx> { } } -/// A closure can be modeled as a struct that looks like: -/// ```ignore (illustrative) -/// struct Closure<'l0...'li, T0...Tj, CK, CS, U>(...U); -/// ``` -/// where: -/// -/// - 'l0...'li and T0...Tj are the generic parameters -/// in scope on the function that defined the closure, -/// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This -/// is rather hackily encoded via a scalar type. See -/// `Ty::to_opt_closure_kind` for details. -/// - CS represents the *closure signature*, representing as a `fn()` -/// type. For example, `fn(u32, u32) -> u32` would mean that the closure -/// implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait -/// specified above. -/// - U is a type parameter representing the types of its upvars, tupled up -/// (borrowed, if appropriate; that is, if a U field represents a by-ref upvar, -/// and the up-var has the type `Foo`, then that field of U will be `&Foo`). -/// -/// So, for example, given this function: -/// ```ignore (illustrative) -/// fn foo<'a, T>(data: &'a mut T) { -/// do(|| data.count += 1) -/// } -/// ``` -/// the type of the closure would be something like: -/// ```ignore (illustrative) -/// struct Closure<'a, T, U>(...U); -/// ``` -/// Note that the type of the upvar is not specified in the struct. -/// You may wonder how the impl would then be able to use the upvar, -/// if it doesn't know it's type? The answer is that the impl is -/// (conceptually) not fully generic over Closure but rather tied to -/// instances with the expected upvar types: -/// ```ignore (illustrative) -/// impl<'b, 'a, T> FnMut() for Closure<'a, T, (&'b mut &'a mut T,)> { -/// ... -/// } -/// ``` -/// You can see that the *impl* fully specified the type of the upvar -/// and thus knows full well that `data` has type `&'b mut &'a mut T`. -/// (Here, I am assuming that `data` is mut-borrowed.) -/// -/// Now, the last question you may ask is: Why include the upvar types -/// in an extra type parameter? The reason for this design is that the -/// upvar types can reference lifetimes that are internal to the -/// creating function. In my example above, for example, the lifetime -/// `'b` represents the scope of the closure itself; this is some -/// subset of `foo`, probably just the scope of the call to the to -/// `do()`. If we just had the lifetime/type parameters from the -/// enclosing function, we couldn't name this lifetime `'b`. Note that -/// there can also be lifetimes in the types of the upvars themselves, -/// if one of them happens to be a reference to something that the -/// creating fn owns. -/// -/// OK, you say, so why not create a more minimal set of parameters -/// that just includes the extra lifetime parameters? The answer is -/// primarily that it would be hard --- we don't know at the time when -/// we create the closure type what the full types of the upvars are, -/// nor do we know which are borrowed and which are not. In this -/// design, we can just supply a fresh type parameter and figure that -/// out later. -/// -/// All right, you say, but why include the type parameters from the -/// original function then? The answer is that codegen may need them -/// when monomorphizing, and they may not appear in the upvars. A -/// closure could capture no variables but still make use of some -/// in-scope type parameter with a bound (e.g., if our example above -/// had an extra `U: Default`, and the closure called `U::default()`). -/// -/// There is another reason. This design (implicitly) prohibits -/// closures from capturing themselves (except via a trait -/// object). This simplifies closure inference considerably, since it -/// means that when we infer the kind of a closure or its upvars, we -/// don't have to handle cycles where the decisions we make for -/// closure C wind up influencing the decisions we ought to make for -/// closure C (which would then require fixed point iteration to -/// handle). Plus it fixes an ICE. :P -/// -/// ## Coroutines -/// -/// Coroutines are handled similarly in `CoroutineArgs`. The set of -/// type parameters is similar, but `CK` and `CS` are replaced by the -/// following type parameters: -/// -/// * `GS`: The coroutine's "resume type", which is the type of the -/// argument passed to `resume`, and the type of `yield` expressions -/// inside the coroutine. -/// * `GY`: The "yield type", which is the type of values passed to -/// `yield` inside the coroutine. -/// * `GR`: The "return type", which is the type of value returned upon -/// completion of the coroutine. -/// * `GW`: The "coroutine witness". -#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)] -pub struct ClosureArgs<'tcx> { - /// Lifetime and type parameters from the enclosing function, - /// concatenated with a tuple containing the types of the upvars. - /// - /// These are separated out because codegen wants to pass them around - /// when monomorphizing. - pub args: GenericArgsRef<'tcx>, -} - -/// Struct returned by `split()`. -pub struct ClosureArgsParts<'tcx> { - /// This is the args of the typeck root. - pub parent_args: &'tcx [GenericArg<'tcx>], - /// Represents the maximum calling capability of the closure. - pub closure_kind_ty: Ty<'tcx>, - /// Captures the closure's signature. This closure signature is "tupled", and - /// thus has a peculiar signature of `extern "rust-call" fn((Args, ...)) -> Ty`. - pub closure_sig_as_fn_ptr_ty: Ty<'tcx>, - /// The upvars captured by the closure. Remains an inference variable - /// until the upvar analysis, which happens late in HIR typeck. - pub tupled_upvars_ty: Ty<'tcx>, -} - -impl<'tcx> ClosureArgs<'tcx> { - /// Construct `ClosureArgs` from `ClosureArgsParts`, containing `Args` - /// for the closure parent, alongside additional closure-specific components. - pub fn new(tcx: TyCtxt<'tcx>, parts: ClosureArgsParts<'tcx>) -> ClosureArgs<'tcx> { - ClosureArgs { - args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ - parts.closure_kind_ty.into(), - parts.closure_sig_as_fn_ptr_ty.into(), - parts.tupled_upvars_ty.into(), - ])), - } - } - - /// Divides the closure args into their respective components. - /// The ordering assumed here must match that used by `ClosureArgs::new` above. - fn split(self) -> ClosureArgsParts<'tcx> { - match self.args[..] { - [ref parent_args @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => { - ClosureArgsParts { - parent_args, - closure_kind_ty: closure_kind_ty.expect_ty(), - closure_sig_as_fn_ptr_ty: closure_sig_as_fn_ptr_ty.expect_ty(), - tupled_upvars_ty: tupled_upvars_ty.expect_ty(), - } - } - _ => bug!("closure args missing synthetics"), - } - } - - /// Returns the generic parameters of the closure's parent. - pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { - self.split().parent_args - } - - /// Returns an iterator over the list of types of captured paths by the closure. - /// In case there was a type error in figuring out the types of the captured path, an - /// empty iterator is returned. - #[inline] - pub fn upvar_tys(self) -> &'tcx List<Ty<'tcx>> { - match *self.tupled_upvars_ty().kind() { - TyKind::Error(_) => ty::List::empty(), - TyKind::Tuple(tys) => tys, - TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"), - ty => bug!("Unexpected representation of upvar types tuple {:?}", ty), - } - } - - /// Returns the tuple type representing the upvars for this closure. - #[inline] - pub fn tupled_upvars_ty(self) -> Ty<'tcx> { - self.split().tupled_upvars_ty - } - - /// Returns the closure kind for this closure; may return a type - /// variable during inference. To get the closure kind during - /// inference, use `infcx.closure_kind(args)`. - pub fn kind_ty(self) -> Ty<'tcx> { - self.split().closure_kind_ty - } - - /// Returns the `fn` pointer type representing the closure signature for this - /// closure. - // FIXME(eddyb) this should be unnecessary, as the shallowly resolved - // type is known at the time of the creation of `ClosureArgs`, - // see `rustc_hir_analysis::check::closure`. - pub fn sig_as_fn_ptr_ty(self) -> Ty<'tcx> { - self.split().closure_sig_as_fn_ptr_ty - } - - /// Returns the closure kind for this closure; only usable outside - /// of an inference context, because in that context we know that - /// there are no type variables. - /// - /// If you have an inference context, use `infcx.closure_kind()`. - pub fn kind(self) -> ty::ClosureKind { - self.kind_ty().to_opt_closure_kind().unwrap() - } - - /// Extracts the signature from the closure. - pub fn sig(self) -> ty::PolyFnSig<'tcx> { - match *self.sig_as_fn_ptr_ty().kind() { - ty::FnPtr(sig) => sig, - ty => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {ty:?}"), - } - } - - pub fn print_as_impl_trait(self) -> ty::print::PrintClosureAsImpl<'tcx> { - ty::print::PrintClosureAsImpl { closure: self } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)] -pub struct CoroutineClosureArgs<'tcx> { - pub args: GenericArgsRef<'tcx>, -} - -/// See docs for explanation of how each argument is used. -/// -/// See [`CoroutineClosureSignature`] for how these arguments are put together -/// to make a callable [`FnSig`] suitable for typeck and borrowck. -pub struct CoroutineClosureArgsParts<'tcx> { - /// This is the args of the typeck root. - pub parent_args: &'tcx [GenericArg<'tcx>], - /// Represents the maximum calling capability of the closure. - pub closure_kind_ty: Ty<'tcx>, - /// Represents all of the relevant parts of the coroutine returned by this - /// coroutine-closure. This signature parts type will have the general - /// shape of `fn(tupled_inputs, resume_ty) -> (return_ty, yield_ty)`, where - /// `resume_ty`, `return_ty`, and `yield_ty` are the respective types for the - /// coroutine returned by the coroutine-closure. - /// - /// Use `coroutine_closure_sig` to break up this type rather than using it - /// yourself. - pub signature_parts_ty: Ty<'tcx>, - /// The upvars captured by the closure. Remains an inference variable - /// until the upvar analysis, which happens late in HIR typeck. - pub tupled_upvars_ty: Ty<'tcx>, - /// a function pointer that has the shape `for<'env> fn() -> (&'env T, ...)`. - /// This allows us to represent the binder of the self-captures of the closure. - /// - /// For example, if the coroutine returned by the closure borrows `String` - /// from the closure's upvars, this will be `for<'env> fn() -> (&'env String,)`, - /// while the `tupled_upvars_ty`, representing the by-move version of the same - /// captures, will be `(String,)`. - pub coroutine_captures_by_ref_ty: Ty<'tcx>, - /// Witness type returned by the generator produced by this coroutine-closure. - pub coroutine_witness_ty: Ty<'tcx>, -} - -impl<'tcx> CoroutineClosureArgs<'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - parts: CoroutineClosureArgsParts<'tcx>, - ) -> CoroutineClosureArgs<'tcx> { - CoroutineClosureArgs { - args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ - parts.closure_kind_ty.into(), - parts.signature_parts_ty.into(), - parts.tupled_upvars_ty.into(), - parts.coroutine_captures_by_ref_ty.into(), - parts.coroutine_witness_ty.into(), - ])), - } - } - - fn split(self) -> CoroutineClosureArgsParts<'tcx> { - match self.args[..] { - [ - ref parent_args @ .., - closure_kind_ty, - signature_parts_ty, - tupled_upvars_ty, - coroutine_captures_by_ref_ty, - coroutine_witness_ty, - ] => CoroutineClosureArgsParts { - parent_args, - closure_kind_ty: closure_kind_ty.expect_ty(), - signature_parts_ty: signature_parts_ty.expect_ty(), - tupled_upvars_ty: tupled_upvars_ty.expect_ty(), - coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(), - coroutine_witness_ty: coroutine_witness_ty.expect_ty(), - }, - _ => bug!("closure args missing synthetics"), - } - } - - pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { - self.split().parent_args - } - - #[inline] - pub fn upvar_tys(self) -> &'tcx List<Ty<'tcx>> { - match self.tupled_upvars_ty().kind() { - TyKind::Error(_) => ty::List::empty(), - TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(), - TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"), - ty => bug!("Unexpected representation of upvar types tuple {:?}", ty), - } - } - - #[inline] - pub fn tupled_upvars_ty(self) -> Ty<'tcx> { - self.split().tupled_upvars_ty - } - - pub fn kind_ty(self) -> Ty<'tcx> { - self.split().closure_kind_ty - } - - pub fn kind(self) -> ty::ClosureKind { - self.kind_ty().to_opt_closure_kind().unwrap() - } - - pub fn signature_parts_ty(self) -> Ty<'tcx> { - self.split().signature_parts_ty - } - - pub fn coroutine_closure_sig(self) -> Binder<'tcx, CoroutineClosureSignature<'tcx>> { - let interior = self.coroutine_witness_ty(); - let ty::FnPtr(sig) = self.signature_parts_ty().kind() else { bug!() }; - sig.map_bound(|sig| { - let [resume_ty, tupled_inputs_ty] = *sig.inputs() else { - bug!(); - }; - let [yield_ty, return_ty] = **sig.output().tuple_fields() else { bug!() }; - CoroutineClosureSignature { - interior, - tupled_inputs_ty, - resume_ty, - yield_ty, - return_ty, - c_variadic: sig.c_variadic, - safety: sig.safety, - abi: sig.abi, - } - }) - } - - pub fn coroutine_captures_by_ref_ty(self) -> Ty<'tcx> { - self.split().coroutine_captures_by_ref_ty - } - - pub fn coroutine_witness_ty(self) -> Ty<'tcx> { - self.split().coroutine_witness_ty - } - - pub fn has_self_borrows(&self) -> bool { - match self.coroutine_captures_by_ref_ty().kind() { - ty::FnPtr(sig) => sig - .skip_binder() - .visit_with(&mut HasRegionsBoundAt { binder: ty::INNERMOST }) - .is_break(), - ty::Error(_) => true, - _ => bug!(), - } - } -} -/// Unlike `has_escaping_bound_vars` or `outermost_exclusive_binder`, this will -/// detect only regions bound *at* the debruijn index. -struct HasRegionsBoundAt { - binder: ty::DebruijnIndex, -} -// FIXME: Could be optimized to not walk into components with no escaping bound vars. -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasRegionsBoundAt { - type Result = ControlFlow<()>; - fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( - &mut self, - t: &ty::Binder<'tcx, T>, - ) -> Self::Result { - self.binder.shift_in(1); - t.super_visit_with(self)?; - self.binder.shift_out(1); - ControlFlow::Continue(()) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result { - if let ty::ReBound(binder, _) = *r - && self.binder == binder - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] -pub struct CoroutineClosureSignature<'tcx> { - pub interior: Ty<'tcx>, - pub tupled_inputs_ty: Ty<'tcx>, - pub resume_ty: Ty<'tcx>, - pub yield_ty: Ty<'tcx>, - pub return_ty: Ty<'tcx>, - - // Like the `fn_sig_as_fn_ptr_ty` of a regular closure, these types - // never actually differ. But we save them rather than recreating them - // from scratch just for good measure. - /// Always false - pub c_variadic: bool, - /// Always [`hir::Safety::Safe`] - pub safety: hir::Safety, - /// Always [`abi::Abi::RustCall`] - pub abi: abi::Abi, -} - -impl<'tcx> CoroutineClosureSignature<'tcx> { - /// Construct a coroutine from the closure signature. Since a coroutine signature - /// is agnostic to the type of generator that is returned (by-ref/by-move), - /// the caller must specify what "flavor" of generator that they'd like to - /// create. Additionally, they must manually compute the upvars of the closure. - /// - /// This helper is not really meant to be used directly except for early on - /// during typeck, when we want to put inference vars into the kind and upvars tys. - /// When the kind and upvars are known, use the other helper functions. - pub fn to_coroutine( - self, - tcx: TyCtxt<'tcx>, - parent_args: &'tcx [GenericArg<'tcx>], - coroutine_kind_ty: Ty<'tcx>, - coroutine_def_id: DefId, - tupled_upvars_ty: Ty<'tcx>, - ) -> Ty<'tcx> { - let coroutine_args = ty::CoroutineArgs::new( - tcx, - ty::CoroutineArgsParts { - parent_args, - kind_ty: coroutine_kind_ty, - resume_ty: self.resume_ty, - yield_ty: self.yield_ty, - return_ty: self.return_ty, - witness: self.interior, - tupled_upvars_ty, - }, - ); - - Ty::new_coroutine(tcx, coroutine_def_id, coroutine_args.args) - } - - /// Given known upvars and a [`ClosureKind`](ty::ClosureKind), compute the coroutine - /// returned by that corresponding async fn trait. - /// - /// This function expects the upvars to have been computed already, and doesn't check - /// that the `ClosureKind` is actually supported by the coroutine-closure. - pub fn to_coroutine_given_kind_and_upvars( - self, - tcx: TyCtxt<'tcx>, - parent_args: &'tcx [GenericArg<'tcx>], - coroutine_def_id: DefId, - goal_kind: ty::ClosureKind, - env_region: ty::Region<'tcx>, - closure_tupled_upvars_ty: Ty<'tcx>, - coroutine_captures_by_ref_ty: Ty<'tcx>, - ) -> Ty<'tcx> { - let tupled_upvars_ty = Self::tupled_upvars_by_closure_kind( - tcx, - goal_kind, - self.tupled_inputs_ty, - closure_tupled_upvars_ty, - coroutine_captures_by_ref_ty, - env_region, - ); - - self.to_coroutine( - tcx, - parent_args, - Ty::from_coroutine_closure_kind(tcx, goal_kind), - coroutine_def_id, - tupled_upvars_ty, - ) - } - - /// Compute the tupled upvars that a coroutine-closure's output coroutine - /// would return for the given `ClosureKind`. - /// - /// When `ClosureKind` is `FnMut`/`Fn`, then this will use the "captures by ref" - /// to return a set of upvars which are borrowed with the given `env_region`. - /// - /// This ensures that the `AsyncFn::call` will return a coroutine whose upvars' - /// lifetimes are related to the lifetime of the borrow on the closure made for - /// the call. This allows borrowck to enforce the self-borrows correctly. - pub fn tupled_upvars_by_closure_kind( - tcx: TyCtxt<'tcx>, - kind: ty::ClosureKind, - tupled_inputs_ty: Ty<'tcx>, - closure_tupled_upvars_ty: Ty<'tcx>, - coroutine_captures_by_ref_ty: Ty<'tcx>, - env_region: ty::Region<'tcx>, - ) -> Ty<'tcx> { - match kind { - ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { - let ty::FnPtr(sig) = *coroutine_captures_by_ref_ty.kind() else { - bug!(); - }; - let coroutine_captures_by_ref_ty = tcx.replace_escaping_bound_vars_uncached( - sig.output().skip_binder(), - FnMutDelegate { - consts: &mut |c, t| ty::Const::new_bound(tcx, ty::INNERMOST, c, t), - types: &mut |t| Ty::new_bound(tcx, ty::INNERMOST, t), - regions: &mut |_| env_region, - }, - ); - Ty::new_tup_from_iter( - tcx, - tupled_inputs_ty - .tuple_fields() - .iter() - .chain(coroutine_captures_by_ref_ty.tuple_fields()), - ) - } - ty::ClosureKind::FnOnce => Ty::new_tup_from_iter( - tcx, - tupled_inputs_ty - .tuple_fields() - .iter() - .chain(closure_tupled_upvars_ty.tuple_fields()), - ), - } - } -} -/// Similar to `ClosureArgs`; see the above documentation for more. -#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] -pub struct CoroutineArgs<'tcx> { - pub args: GenericArgsRef<'tcx>, -} - -pub struct CoroutineArgsParts<'tcx> { - /// This is the args of the typeck root. - pub parent_args: &'tcx [GenericArg<'tcx>], - - /// The coroutines returned by a coroutine-closure's `AsyncFnOnce`/`AsyncFnMut` - /// implementations must be distinguished since the former takes the closure's - /// upvars by move, and the latter takes the closure's upvars by ref. - /// - /// This field distinguishes these fields so that codegen can select the right - /// body for the coroutine. This has the same type representation as the closure - /// kind: `i8`/`i16`/`i32`. - /// - /// For regular coroutines, this field will always just be `()`. - pub kind_ty: Ty<'tcx>, - - pub resume_ty: Ty<'tcx>, - pub yield_ty: Ty<'tcx>, - pub return_ty: Ty<'tcx>, - - /// The interior type of the coroutine. - /// Represents all types that are stored in locals - /// in the coroutine's body. - pub witness: Ty<'tcx>, - - /// The upvars captured by the closure. Remains an inference variable - /// until the upvar analysis, which happens late in HIR typeck. - pub tupled_upvars_ty: Ty<'tcx>, -} - -impl<'tcx> CoroutineArgs<'tcx> { - /// Construct `CoroutineArgs` from `CoroutineArgsParts`, containing `Args` - /// for the coroutine parent, alongside additional coroutine-specific components. - pub fn new(tcx: TyCtxt<'tcx>, parts: CoroutineArgsParts<'tcx>) -> CoroutineArgs<'tcx> { - CoroutineArgs { - args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ - parts.kind_ty.into(), - parts.resume_ty.into(), - parts.yield_ty.into(), - parts.return_ty.into(), - parts.witness.into(), - parts.tupled_upvars_ty.into(), - ])), - } - } - - /// Divides the coroutine args into their respective components. - /// The ordering assumed here must match that used by `CoroutineArgs::new` above. - fn split(self) -> CoroutineArgsParts<'tcx> { - match self.args[..] { - [ - ref parent_args @ .., - kind_ty, - resume_ty, - yield_ty, - return_ty, - witness, - tupled_upvars_ty, - ] => CoroutineArgsParts { - parent_args, - kind_ty: kind_ty.expect_ty(), - resume_ty: resume_ty.expect_ty(), - yield_ty: yield_ty.expect_ty(), - return_ty: return_ty.expect_ty(), - witness: witness.expect_ty(), - tupled_upvars_ty: tupled_upvars_ty.expect_ty(), - }, - _ => bug!("coroutine args missing synthetics"), - } - } - - /// Returns the generic parameters of the coroutine's parent. - pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { - self.split().parent_args - } - - // Returns the kind of the coroutine. See docs on the `kind_ty` field. - pub fn kind_ty(self) -> Ty<'tcx> { - self.split().kind_ty - } - - /// This describes the types that can be contained in a coroutine. - /// It will be a type variable initially and unified in the last stages of typeck of a body. - /// It contains a tuple of all the types that could end up on a coroutine frame. - /// The state transformation MIR pass may only produce layouts which mention types - /// in this tuple. Upvars are not counted here. - pub fn witness(self) -> Ty<'tcx> { - self.split().witness - } - - /// Returns an iterator over the list of types of captured paths by the coroutine. - /// In case there was a type error in figuring out the types of the captured path, an - /// empty iterator is returned. - #[inline] - pub fn upvar_tys(self) -> &'tcx List<Ty<'tcx>> { - match *self.tupled_upvars_ty().kind() { - TyKind::Error(_) => ty::List::empty(), - TyKind::Tuple(tys) => tys, - TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"), - ty => bug!("Unexpected representation of upvar types tuple {:?}", ty), - } - } - - /// Returns the tuple type representing the upvars for this coroutine. - #[inline] - pub fn tupled_upvars_ty(self) -> Ty<'tcx> { - self.split().tupled_upvars_ty - } - - /// Returns the type representing the resume type of the coroutine. - pub fn resume_ty(self) -> Ty<'tcx> { - self.split().resume_ty - } - - /// Returns the type representing the yield type of the coroutine. - pub fn yield_ty(self) -> Ty<'tcx> { - self.split().yield_ty - } - - /// Returns the type representing the return type of the coroutine. - pub fn return_ty(self) -> Ty<'tcx> { - self.split().return_ty - } - - /// Returns the "coroutine signature", which consists of its resume, yield - /// and return types. - pub fn sig(self) -> GenSig<'tcx> { - let parts = self.split(); - ty::GenSig { - resume_ty: parts.resume_ty, - yield_ty: parts.yield_ty, - return_ty: parts.return_ty, - } - } -} - -impl<'tcx> CoroutineArgs<'tcx> { +#[extension(pub trait CoroutineArgsExt<'tcx>)] +impl<'tcx> ty::CoroutineArgs<TyCtxt<'tcx>> { /// Coroutine has not been resumed yet. - pub const UNRESUMED: usize = 0; + const UNRESUMED: usize = 0; /// Coroutine has returned or is completed. - pub const RETURNED: usize = 1; + const RETURNED: usize = 1; /// Coroutine has been poisoned. - pub const POISONED: usize = 2; + const POISONED: usize = 2; const UNRESUMED_NAME: &'static str = "Unresumed"; const RETURNED_NAME: &'static str = "Returned"; @@ -731,7 +74,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// The valid variant indices of this coroutine. #[inline] - pub fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range<VariantIdx> { + fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range<VariantIdx> { // FIXME requires optimized MIR FIRST_VARIANT ..tcx.coroutine_layout(def_id, tcx.types.unit).unwrap().variant_fields.next_index() @@ -740,7 +83,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// The discriminant for the given variant. Panics if the `variant_index` is /// out of range. #[inline] - pub fn discriminant_for_variant( + fn discriminant_for_variant( &self, def_id: DefId, tcx: TyCtxt<'tcx>, @@ -755,7 +98,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// The set of all discriminants for the coroutine, enumerated with their /// variant indices. #[inline] - pub fn discriminants( + fn discriminants( self, def_id: DefId, tcx: TyCtxt<'tcx>, @@ -767,7 +110,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// Calls `f` with a reference to the name of the enumerator for the given /// variant `v`. - pub fn variant_name(v: VariantIdx) -> Cow<'static, str> { + fn variant_name(v: VariantIdx) -> Cow<'static, str> { match v.as_usize() { Self::UNRESUMED => Cow::from(Self::UNRESUMED_NAME), Self::RETURNED => Cow::from(Self::RETURNED_NAME), @@ -778,7 +121,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// The type of the state discriminant used in the coroutine type. #[inline] - pub fn discr_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + fn discr_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { tcx.types.u32 } @@ -789,7 +132,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// The locals are grouped by their variant number. Note that some locals may /// be repeated in multiple variants. #[inline] - pub fn state_tys( + fn state_tys( self, def_id: DefId, tcx: TyCtxt<'tcx>, @@ -805,7 +148,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// This is the types of the fields of a coroutine which are not stored in a /// variant. #[inline] - pub fn prefix_tys(self) -> &'tcx List<Ty<'tcx>> { + fn prefix_tys(self) -> &'tcx List<Ty<'tcx>> { self.upvar_tys() } } @@ -859,7 +202,7 @@ impl<'tcx> UpvarArgs<'tcx> { /// /// When the inline const is instantiated, `R` is instantiated as the actual inferred /// type of the constant. The reason that `R` is represented as an extra type parameter -/// is the same reason that [`ClosureArgs`] have `CS` and `U` as type parameters: +/// is the same reason that [`ty::ClosureArgs`] have `CS` and `U` as type parameters: /// inline const can reference lifetimes that are internal to the creating function. #[derive(Copy, Clone, Debug)] pub struct InlineConstArgs<'tcx> { @@ -938,13 +281,6 @@ impl BoundVariableKind { } } -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] -pub struct GenSig<'tcx> { - pub resume_ty: Ty<'tcx>, - pub yield_ty: Ty<'tcx>, - pub return_ty: Ty<'tcx>, -} - pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>; pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>; @@ -1451,6 +787,41 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> { ) -> Self { Ty::new_alias(interner, kind, alias_ty) } + + fn new_coroutine( + interner: TyCtxt<'tcx>, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + ) -> Self { + Ty::new_coroutine(interner, def_id, args) + } + + fn new_tup_from_iter<It, T>(interner: TyCtxt<'tcx>, iter: It) -> T::Output + where + It: Iterator<Item = T>, + T: CollectAndApply<Self, Self>, + { + Ty::new_tup_from_iter(interner, iter) + } + + fn tuple_fields(self) -> &'tcx ty::List<Ty<'tcx>> { + self.tuple_fields() + } + + fn to_opt_closure_kind(self) -> Option<ty::ClosureKind> { + self.to_opt_closure_kind() + } + + fn from_closure_kind(interner: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Self { + Ty::from_closure_kind(interner, kind) + } + + fn from_coroutine_closure_kind( + interner: TyCtxt<'tcx>, + kind: rustc_type_ir::ClosureKind, + ) -> Self { + Ty::from_coroutine_closure_kind(interner, kind) + } } /// Type utilities @@ -2169,8 +1540,8 @@ impl<'tcx> Ty<'tcx> { /// } /// ``` /// - /// After upvar analysis, you should instead use [`ClosureArgs::kind()`] - /// or [`CoroutineClosureArgs::kind()`] to assert that the `ClosureKind` + /// After upvar analysis, you should instead use [`ty::ClosureArgs::kind()`] + /// or [`ty::CoroutineClosureArgs::kind()`] to assert that the `ClosureKind` /// has been constrained instead of manually calling this method. /// /// ```rust,ignore (snippet of compiler code) |
