Uplift TypeRelation and Relate

This commit is contained in:
Michael Goulet 2024-05-31 14:13:46 -04:00
parent ee47480f4c
commit 333458c2cb
27 changed files with 882 additions and 752 deletions

View File

@ -27,8 +27,9 @@ use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{
self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic,
OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt,
Dynamic, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType,
UserTypeAnnotationIndex,
};
use rustc_middle::ty::{GenericArgsRef, UserArgs};
use rustc_middle::{bug, span_bug};

View File

@ -5,7 +5,7 @@ use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeM
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt};
use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
use rustc_target::abi::{
self, Abi, Align, FieldsShape, Float, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface,

View File

@ -31,7 +31,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::{
self, AdtKind, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt, Visibility,
self, AdtKind, CoroutineArgsExt, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt,
Visibility,
};
use rustc_session::config::{self, DebugInfo, Lto};
use rustc_span::symbol::Symbol;

View File

@ -12,7 +12,7 @@ use rustc_middle::{
ty::{
self,
layout::{LayoutOf, TyAndLayout},
AdtDef, CoroutineArgs, Ty,
AdtDef, CoroutineArgs, CoroutineArgsExt, Ty,
},
};
use rustc_target::abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants};

View File

@ -10,7 +10,7 @@ use rustc_middle::{
ty::{
self,
layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout},
AdtDef, CoroutineArgs, Ty, VariantDef,
AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef,
},
};
use rustc_span::Symbol;

View File

@ -4,7 +4,7 @@ use rustc_codegen_ssa::traits::*;
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt};
use rustc_target::abi::{Abi, Align, FieldsShape};
use rustc_target::abi::{Float, Int, Pointer};
use rustc_target::abi::{Scalar, Size, Variants};

View File

@ -3,7 +3,7 @@
use rustc_middle::mir;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt};
use rustc_middle::ty::{self, ScalarInt, Ty};
use rustc_middle::ty::{self, CoroutineArgsExt, ScalarInt, Ty};
use rustc_target::abi::{self, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants};
use tracing::{instrument, trace};

View File

@ -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;

View File

@ -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>;
@ -190,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);

View File

@ -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 }
}

View File

@ -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,

View File

@ -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::{

View File

@ -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 {

View File

@ -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,

View File

@ -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)

View File

@ -69,7 +69,7 @@ use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::CoroutineArgs;
use rustc_middle::ty::InstanceDef;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_mir_dataflow::impls::{
MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,

View File

@ -4,7 +4,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::*;
use rustc_middle::query::Providers;
use rustc_middle::ty::GenericArgs;
use rustc_middle::ty::{self, CoroutineArgs, EarlyBinder, Ty, TyCtxt};
use rustc_middle::ty::{self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
@ -634,7 +634,7 @@ impl<'tcx> CloneShimBuilder<'tcx> {
dest: Place<'tcx>,
src: Place<'tcx>,
coroutine_def_id: DefId,
args: CoroutineArgs<'tcx>,
args: CoroutineArgs<TyCtxt<'tcx>>,
) {
self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false);
let unwind = self.block(vec![], TerminatorKind::UnwindResume, true);

View File

@ -8,7 +8,9 @@ use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance};
use rustc_middle::ty::{
self, CoroutineArgsExt, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance,
};
use rustc_middle::{bug, span_bug};
use rustc_target::abi::{Size, FIRST_VARIANT};
use rustc_target::spec::abi::Abi;

View File

@ -554,8 +554,8 @@ fn coroutine_closure_to_certain_coroutine<'tcx>(
goal_kind: ty::ClosureKind,
goal_region: ty::Region<'tcx>,
def_id: DefId,
args: ty::CoroutineClosureArgs<'tcx>,
sig: ty::CoroutineClosureSignature<'tcx>,
args: ty::CoroutineClosureArgs<TyCtxt<'tcx>>,
sig: ty::CoroutineClosureSignature<TyCtxt<'tcx>>,
) -> Ty<'tcx> {
sig.to_coroutine_given_kind_and_upvars(
tcx,
@ -578,8 +578,8 @@ fn coroutine_closure_to_ambiguous_coroutine<'tcx>(
goal_kind: ty::ClosureKind,
goal_region: ty::Region<'tcx>,
def_id: DefId,
args: ty::CoroutineClosureArgs<'tcx>,
sig: ty::CoroutineClosureSignature<'tcx>,
args: ty::CoroutineClosureArgs<TyCtxt<'tcx>>,
sig: ty::CoroutineClosureSignature<TyCtxt<'tcx>>,
) -> Ty<'tcx> {
let upvars_projection_def_id = tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None);
let tupled_upvars_ty = Ty::new_projection(

View File

@ -295,7 +295,7 @@ pub fn coroutine_trait_ref_and_outputs<'tcx>(
tcx: TyCtxt<'tcx>,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
sig: ty::GenSig<'tcx>,
sig: ty::GenSig<TyCtxt<'tcx>>,
) -> (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>) {
assert!(!self_ty.has_escaping_bound_vars());
let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.resume_ty]);
@ -306,7 +306,7 @@ pub fn future_trait_ref_and_outputs<'tcx>(
tcx: TyCtxt<'tcx>,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
sig: ty::GenSig<'tcx>,
sig: ty::GenSig<TyCtxt<'tcx>>,
) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
assert!(!self_ty.has_escaping_bound_vars());
let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty]);
@ -317,7 +317,7 @@ pub fn iterator_trait_ref_and_outputs<'tcx>(
tcx: TyCtxt<'tcx>,
iterator_def_id: DefId,
self_ty: Ty<'tcx>,
sig: ty::GenSig<'tcx>,
sig: ty::GenSig<TyCtxt<'tcx>>,
) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
assert!(!self_ty.has_escaping_bound_vars());
let trait_ref = ty::TraitRef::new(tcx, iterator_def_id, [self_ty]);
@ -328,7 +328,7 @@ pub fn async_iterator_trait_ref_and_outputs<'tcx>(
tcx: TyCtxt<'tcx>,
async_iterator_def_id: DefId,
self_ty: Ty<'tcx>,
sig: ty::GenSig<'tcx>,
sig: ty::GenSig<TyCtxt<'tcx>>,
) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
assert!(!self_ty.has_escaping_bound_vars());
let trait_ref = ty::TraitRef::new(tcx, async_iterator_def_id, [self_ty]);

View File

@ -10,7 +10,8 @@ use rustc_middle::ty::layout::{
};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{
self, AdtDef, EarlyBinder, FieldDef, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt,
self, AdtDef, CoroutineArgsExt, EarlyBinder, FieldDef, GenericArgsRef, Ty, TyCtxt,
TypeVisitableExt,
};
use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
use rustc_span::sym;

View File

@ -9,7 +9,7 @@ use std::ops::Deref;
use crate::fold::{TypeFoldable, TypeSuperFoldable};
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::{self as ty, DebugWithInfcx, Interner, UpcastFrom};
use crate::{self as ty, CollectAndApply, DebugWithInfcx, Interner, UpcastFrom};
pub trait Ty<I: Interner<Ty = Self>>:
Copy
@ -34,6 +34,21 @@ pub trait Ty<I: Interner<Ty = Self>>:
fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self;
fn new_coroutine(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
fn new_tup_from_iter<It, T>(interner: I, iter: It) -> T::Output
where
It: Iterator<Item = T>,
T: CollectAndApply<Self, Self>;
fn tuple_fields(self) -> I::Tys;
fn to_opt_closure_kind(self) -> Option<ty::ClosureKind>;
fn from_closure_kind(interner: I, kind: ty::ClosureKind) -> Self;
fn from_coroutine_closure_kind(interner: I, kind: ty::ClosureKind) -> Self;
}
pub trait Tys<I: Interner<Tys = Self>>:
@ -43,17 +58,18 @@ pub trait Tys<I: Interner<Tys = Self>>:
+ Eq
+ IntoIterator<Item = I::Ty>
+ Deref<Target: Deref<Target = [I::Ty]>>
+ TypeVisitable<I>
+ TypeFoldable<I>
+ Default
{
fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty);
}
pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq {
pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq + TypeVisitable<I> {
/// Whether this ABI is `extern "Rust"`.
fn is_rust(self) -> bool;
}
pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq {
pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq + TypeVisitable<I> {
fn is_safe(self) -> bool;
fn prefix_str(self) -> &'static str;
@ -129,6 +145,10 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
def_id: I::DefId,
original_args: &[I::GenericArg],
) -> I::GenericArgs;
fn split_closure_args(self) -> ty::ClosureArgsParts<I>;
fn split_coroutine_closure_args(self) -> ty::CoroutineClosureArgsParts<I>;
fn split_coroutine_args(self) -> ty::CoroutineArgsParts<I>;
}
pub trait Predicate<I: Interner<Predicate = Self>>:

View File

@ -29,9 +29,7 @@ pub trait Interner:
type AdtDef: Copy + Debug + Hash + Eq;
type GenericArgs: GenericArgs<Self>;
/// The slice of args for a specific item. For a GAT like `type Foo<'a>`, it will be `['a]`,
/// not including the args from the parent item (trait or impl).
type OwnItemArgs: Copy + Debug + Hash + Eq;
type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>;
type GenericArg: Copy
+ DebugWithInfcx<Self>
+ Hash
@ -111,7 +109,7 @@ pub trait Interner:
self,
def_id: Self::DefId,
args: Self::GenericArgs,
) -> (ty::TraitRef<Self>, Self::OwnItemArgs);
) -> (ty::TraitRef<Self>, Self::GenericArgsSlice);
fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs;
fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs;

View File

@ -604,7 +604,7 @@ impl<I: Interner> AliasTerm<I> {
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
/// then this function would return a `T: StreamingIterator` trait reference and
/// `['a]` as the own args.
pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::OwnItemArgs) {
pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
}

View File

@ -7,13 +7,15 @@ use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEn
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use std::fmt;
pub use self::closure::*;
use self::TyKind::*;
use crate::inherent::*;
use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
use self::TyKind::*;
use rustc_ast_ir::Mutability;
mod closure;
/// Specifies how a trait object is represented.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
@ -514,7 +516,7 @@ impl<I: Interner> AliasTy<I> {
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
/// then this function would return a `T: StreamingIterator` trait reference and
/// `['a]` as the own args.
pub fn trait_ref_and_own_args(self, interner: I) -> (ty::TraitRef<I>, I::OwnItemArgs) {
pub fn trait_ref_and_own_args(self, interner: I) -> (ty::TraitRef<I>, I::GenericArgsSlice) {
debug_assert_eq!(self.kind(interner), AliasTyKind::Projection);
interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
}

View File

@ -0,0 +1,696 @@
use std::ops::ControlFlow;
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use crate::fold::{shift_region, TypeFoldable, TypeFolder, TypeSuperFoldable};
use crate::inherent::*;
use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
use crate::{self as ty, Interner};
/// 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(derivative::Derivative)]
#[derivative(
Clone(bound = ""),
Copy(bound = ""),
Hash(bound = ""),
PartialEq(bound = ""),
Eq(bound = ""),
Debug(bound = "")
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
pub struct ClosureArgs<I: Interner> {
/// 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: I::GenericArgs,
}
/// Struct returned by `split()`.
pub struct ClosureArgsParts<I: Interner> {
/// This is the args of the typeck root.
pub parent_args: I::GenericArgsSlice,
/// Represents the maximum calling capability of the closure.
pub closure_kind_ty: I::Ty,
/// 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: I::Ty,
/// The upvars captured by the closure. Remains an inference variable
/// until the upvar analysis, which happens late in HIR typeck.
pub tupled_upvars_ty: I::Ty,
}
impl<I: Interner> ClosureArgs<I> {
/// Construct `ClosureArgs` from `ClosureArgsParts`, containing `Args`
/// for the closure parent, alongside additional closure-specific components.
pub fn new(tcx: I, parts: ClosureArgsParts<I>) -> ClosureArgs<I> {
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<I> {
self.args.split_closure_args()
}
/// Returns the generic parameters of the closure's parent.
pub fn parent_args(self) -> I::GenericArgsSlice {
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) -> I::Tys {
match self.tupled_upvars_ty().kind() {
ty::Error(_) => Default::default(),
ty::Tuple(tys) => tys,
ty::Infer(_) => panic!("upvar_tys called before capture types are inferred"),
ty => panic!("Unexpected representation of upvar types tuple {:?}", ty),
}
}
/// Returns the tuple type representing the upvars for this closure.
#[inline]
pub fn tupled_upvars_ty(self) -> I::Ty {
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) -> I::Ty {
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) -> I::Ty {
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::Binder<I, ty::FnSig<I>> {
match self.sig_as_fn_ptr_ty().kind() {
ty::FnPtr(sig) => sig,
ty => panic!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {ty:?}"),
}
}
}
#[derive(derivative::Derivative)]
#[derivative(
Clone(bound = ""),
Copy(bound = ""),
Hash(bound = ""),
PartialEq(bound = ""),
Eq(bound = ""),
Debug(bound = "")
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
pub struct CoroutineClosureArgs<I: Interner> {
pub args: I::GenericArgs,
}
/// See docs for explanation of how each argument is used.
///
/// See [`CoroutineClosureSignature`] for how these arguments are put together
/// to make a callable [`ty::FnSig`] suitable for typeck and borrowck.
pub struct CoroutineClosureArgsParts<I: Interner> {
/// This is the args of the typeck root.
pub parent_args: I::GenericArgsSlice,
/// Represents the maximum calling capability of the closure.
pub closure_kind_ty: I::Ty,
/// 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: I::Ty,
/// The upvars captured by the closure. Remains an inference variable
/// until the upvar analysis, which happens late in HIR typeck.
pub tupled_upvars_ty: I::Ty,
/// 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: I::Ty,
/// Witness type returned by the generator produced by this coroutine-closure.
pub coroutine_witness_ty: I::Ty,
}
impl<I: Interner> CoroutineClosureArgs<I> {
pub fn new(tcx: I, parts: CoroutineClosureArgsParts<I>) -> CoroutineClosureArgs<I> {
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<I> {
self.args.split_coroutine_closure_args()
}
pub fn parent_args(self) -> I::GenericArgsSlice {
self.split().parent_args
}
#[inline]
pub fn upvar_tys(self) -> I::Tys {
match self.tupled_upvars_ty().kind() {
ty::Error(_) => Default::default(),
ty::Tuple(..) => self.tupled_upvars_ty().tuple_fields(),
ty::Infer(_) => panic!("upvar_tys called before capture types are inferred"),
ty => panic!("Unexpected representation of upvar types tuple {:?}", ty),
}
}
#[inline]
pub fn tupled_upvars_ty(self) -> I::Ty {
self.split().tupled_upvars_ty
}
pub fn kind_ty(self) -> I::Ty {
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) -> I::Ty {
self.split().signature_parts_ty
}
pub fn coroutine_closure_sig(self) -> ty::Binder<I, CoroutineClosureSignature<I>> {
let interior = self.coroutine_witness_ty();
let ty::FnPtr(sig) = self.signature_parts_ty().kind() else { panic!() };
sig.map_bound(|sig| {
let [resume_ty, tupled_inputs_ty] = *sig.inputs() else {
panic!();
};
let [yield_ty, return_ty] = **sig.output().tuple_fields() else { panic!() };
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) -> I::Ty {
self.split().coroutine_captures_by_ref_ty
}
pub fn coroutine_witness_ty(self) -> I::Ty {
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,
_ => panic!(),
}
}
}
/// 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<I: Interner> TypeVisitor<I> for HasRegionsBoundAt {
type Result = ControlFlow<()>;
fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, 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: I::Region) -> Self::Result {
if matches!(r.kind(), ty::ReBound(binder, _) if self.binder == binder) {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
}
}
#[derive(derivative::Derivative)]
#[derivative(
Clone(bound = ""),
Copy(bound = ""),
Hash(bound = ""),
PartialEq(bound = ""),
Eq(bound = ""),
Debug(bound = "")
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
pub struct CoroutineClosureSignature<I: Interner> {
pub interior: I::Ty,
pub tupled_inputs_ty: I::Ty,
pub resume_ty: I::Ty,
pub yield_ty: I::Ty,
pub return_ty: I::Ty,
// 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 `Normal` (safe)
pub safety: I::Safety,
/// Always `RustCall`
pub abi: I::Abi,
}
impl<I: Interner> CoroutineClosureSignature<I> {
/// 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: I,
parent_args: I::GenericArgsSlice,
coroutine_kind_ty: I::Ty,
coroutine_def_id: I::DefId,
tupled_upvars_ty: I::Ty,
) -> I::Ty {
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: I,
parent_args: I::GenericArgsSlice,
coroutine_def_id: I::DefId,
goal_kind: ty::ClosureKind,
env_region: I::Region,
closure_tupled_upvars_ty: I::Ty,
coroutine_captures_by_ref_ty: I::Ty,
) -> I::Ty {
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: I,
kind: ty::ClosureKind,
tupled_inputs_ty: I::Ty,
closure_tupled_upvars_ty: I::Ty,
coroutine_captures_by_ref_ty: I::Ty,
env_region: I::Region,
) -> I::Ty {
match kind {
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
let ty::FnPtr(sig) = coroutine_captures_by_ref_ty.kind() else {
panic!();
};
let coroutine_captures_by_ref_ty =
sig.output().skip_binder().fold_with(&mut FoldEscapingRegions {
interner: tcx,
region: env_region,
debruijn: ty::INNERMOST,
});
Ty::new_tup_from_iter(
tcx,
tupled_inputs_ty
.tuple_fields()
.into_iter()
.chain(coroutine_captures_by_ref_ty.tuple_fields()),
)
}
ty::ClosureKind::FnOnce => Ty::new_tup_from_iter(
tcx,
tupled_inputs_ty
.tuple_fields()
.into_iter()
.chain(closure_tupled_upvars_ty.tuple_fields()),
),
}
}
}
/// Instantiates a `for<'env> ...` binder with a specific region.
// FIXME(async_closures): Get rid of this in favor of `BoundVarReplacerDelegate`
// when that is uplifted.
struct FoldEscapingRegions<I: Interner> {
interner: I,
debruijn: ty::DebruijnIndex,
region: I::Region,
}
impl<I: Interner> TypeFolder<I> for FoldEscapingRegions<I> {
fn interner(&self) -> I {
self.interner
}
fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
where
T: TypeFoldable<I>,
{
self.debruijn.shift_in(1);
let result = t.super_fold_with(self);
self.debruijn.shift_out(1);
result
}
fn fold_region(&mut self, r: <I as Interner>::Region) -> <I as Interner>::Region {
if let ty::ReBound(debruijn, _) = r.kind() {
assert!(
debruijn <= self.debruijn,
"cannot instantiate binder with escaping bound vars"
);
if self.debruijn == debruijn {
shift_region(self.interner, self.region, self.debruijn.as_u32())
} else {
r
}
} else {
r
}
}
}
#[derive(derivative::Derivative)]
#[derivative(
Clone(bound = ""),
Copy(bound = ""),
Hash(bound = ""),
PartialEq(bound = ""),
Eq(bound = ""),
Debug(bound = "")
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
pub struct GenSig<I: Interner> {
pub resume_ty: I::Ty,
pub yield_ty: I::Ty,
pub return_ty: I::Ty,
}
/// Similar to `ClosureArgs`; see the above documentation for more.
#[derive(derivative::Derivative)]
#[derivative(
Clone(bound = ""),
Copy(bound = ""),
Hash(bound = ""),
PartialEq(bound = ""),
Eq(bound = ""),
Debug(bound = "")
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
pub struct CoroutineArgs<I: Interner> {
pub args: I::GenericArgs,
}
pub struct CoroutineArgsParts<I: Interner> {
/// This is the args of the typeck root.
pub parent_args: I::GenericArgsSlice,
/// 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: I::Ty,
pub resume_ty: I::Ty,
pub yield_ty: I::Ty,
pub return_ty: I::Ty,
/// The interior type of the coroutine.
/// Represents all types that are stored in locals
/// in the coroutine's body.
pub witness: I::Ty,
/// The upvars captured by the closure. Remains an inference variable
/// until the upvar analysis, which happens late in HIR typeck.
pub tupled_upvars_ty: I::Ty,
}
impl<I: Interner> CoroutineArgs<I> {
/// Construct `CoroutineArgs` from `CoroutineArgsParts`, containing `Args`
/// for the coroutine parent, alongside additional coroutine-specific components.
pub fn new(tcx: I, parts: CoroutineArgsParts<I>) -> CoroutineArgs<I> {
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<I> {
self.args.split_coroutine_args()
}
/// Returns the generic parameters of the coroutine's parent.
pub fn parent_args(self) -> I::GenericArgsSlice {
self.split().parent_args
}
// Returns the kind of the coroutine. See docs on the `kind_ty` field.
pub fn kind_ty(self) -> I::Ty {
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) -> I::Ty {
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) -> I::Tys {
match self.tupled_upvars_ty().kind() {
ty::Error(_) => Default::default(),
ty::Tuple(tys) => tys,
ty::Infer(_) => panic!("upvar_tys called before capture types are inferred"),
ty => panic!("Unexpected representation of upvar types tuple {:?}", ty),
}
}
/// Returns the tuple type representing the upvars for this coroutine.
#[inline]
pub fn tupled_upvars_ty(self) -> I::Ty {
self.split().tupled_upvars_ty
}
/// Returns the type representing the resume type of the coroutine.
pub fn resume_ty(self) -> I::Ty {
self.split().resume_ty
}
/// Returns the type representing the yield type of the coroutine.
pub fn yield_ty(self) -> I::Ty {
self.split().yield_ty
}
/// Returns the type representing the return type of the coroutine.
pub fn return_ty(self) -> I::Ty {
self.split().return_ty
}
/// Returns the "coroutine signature", which consists of its resume, yield
/// and return types.
pub fn sig(self) -> GenSig<I> {
let parts = self.split();
GenSig { resume_ty: parts.resume_ty, yield_ty: parts.yield_ty, return_ty: parts.return_ty }
}
}

View File

@ -10,7 +10,7 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{
self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty,
TypeVisitableExt, TypeckResults,
TypeVisitableExt, TypeckResults, TyCtxt,
};
use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
@ -240,7 +240,7 @@ fn check_inputs(
})
}
fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<'tcx>, call_sig: FnSig<'_>) -> bool {
fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<TyCtxt<'tcx>>, call_sig: FnSig<'_>) -> bool {
call_sig.safety == Safety::Safe
&& !has_late_bound_to_non_late_bound_regions(
cx.tcx.signature_unclosure(closure.sig(), Safety::Safe).skip_binder(),