mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
Uplift TypeRelation and Relate
This commit is contained in:
parent
ee47480f4c
commit
333458c2cb
@ -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};
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 }
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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::{
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
|
@ -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>>:
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
696
compiler/rustc_type_ir/src/ty_kind/closure.rs
Normal file
696
compiler/rustc_type_ir/src/ty_kind/closure.rs
Normal 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 }
|
||||
}
|
||||
}
|
@ -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(),
|
||||
|
Loading…
Reference in New Issue
Block a user