rustc_type_ir/ty_kind/
closure.rs

1use std::ops::ControlFlow;
2
3use derive_where::derive_where;
4use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
5
6use crate::data_structures::DelayedMap;
7use crate::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region};
8use crate::inherent::*;
9use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
10use crate::{self as ty, Interner};
11
12/// A closure can be modeled as a struct that looks like:
13/// ```ignore (illustrative)
14/// struct Closure<'l0...'li, T0...Tj, CK, CS, U>(...U);
15/// ```
16/// where:
17///
18/// - 'l0...'li and T0...Tj are the generic parameters
19///   in scope on the function that defined the closure,
20/// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This
21///   is rather hackily encoded via a scalar type. See
22///   `Ty::to_opt_closure_kind` for details.
23/// - CS represents the *closure signature*, representing as a `fn()`
24///   type. For example, `fn(u32, u32) -> u32` would mean that the closure
25///   implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait
26///   specified above.
27/// - U is a type parameter representing the types of its upvars, tupled up
28///   (borrowed, if appropriate; that is, if a U field represents a by-ref upvar,
29///    and the up-var has the type `Foo`, then that field of U will be `&Foo`).
30///
31/// So, for example, given this function:
32/// ```ignore (illustrative)
33/// fn foo<'a, T>(data: &'a mut T) {
34///      do(|| data.count += 1)
35/// }
36/// ```
37/// the type of the closure would be something like:
38/// ```ignore (illustrative)
39/// struct Closure<'a, T, U>(...U);
40/// ```
41/// Note that the type of the upvar is not specified in the struct.
42/// You may wonder how the impl would then be able to use the upvar,
43/// if it doesn't know it's type? The answer is that the impl is
44/// (conceptually) not fully generic over Closure but rather tied to
45/// instances with the expected upvar types:
46/// ```ignore (illustrative)
47/// impl<'b, 'a, T> FnMut() for Closure<'a, T, (&'b mut &'a mut T,)> {
48///     ...
49/// }
50/// ```
51/// You can see that the *impl* fully specified the type of the upvar
52/// and thus knows full well that `data` has type `&'b mut &'a mut T`.
53/// (Here, I am assuming that `data` is mut-borrowed.)
54///
55/// Now, the last question you may ask is: Why include the upvar types
56/// in an extra type parameter? The reason for this design is that the
57/// upvar types can reference lifetimes that are internal to the
58/// creating function. In my example above, for example, the lifetime
59/// `'b` represents the scope of the closure itself; this is some
60/// subset of `foo`, probably just the scope of the call to the to
61/// `do()`. If we just had the lifetime/type parameters from the
62/// enclosing function, we couldn't name this lifetime `'b`. Note that
63/// there can also be lifetimes in the types of the upvars themselves,
64/// if one of them happens to be a reference to something that the
65/// creating fn owns.
66///
67/// OK, you say, so why not create a more minimal set of parameters
68/// that just includes the extra lifetime parameters? The answer is
69/// primarily that it would be hard --- we don't know at the time when
70/// we create the closure type what the full types of the upvars are,
71/// nor do we know which are borrowed and which are not. In this
72/// design, we can just supply a fresh type parameter and figure that
73/// out later.
74///
75/// All right, you say, but why include the type parameters from the
76/// original function then? The answer is that codegen may need them
77/// when monomorphizing, and they may not appear in the upvars. A
78/// closure could capture no variables but still make use of some
79/// in-scope type parameter with a bound (e.g., if our example above
80/// had an extra `U: Default`, and the closure called `U::default()`).
81///
82/// There is another reason. This design (implicitly) prohibits
83/// closures from capturing themselves (except via a trait
84/// object). This simplifies closure inference considerably, since it
85/// means that when we infer the kind of a closure or its upvars, we
86/// don't have to handle cycles where the decisions we make for
87/// closure C wind up influencing the decisions we ought to make for
88/// closure C (which would then require fixed point iteration to
89/// handle). Plus it fixes an ICE. :P
90///
91/// ## Coroutines
92///
93/// Coroutines are handled similarly in `CoroutineArgs`. The set of
94/// type parameters is similar, but `CK` and `CS` are replaced by the
95/// following type parameters:
96///
97/// * `GS`: The coroutine's "resume type", which is the type of the
98///   argument passed to `resume`, and the type of `yield` expressions
99///   inside the coroutine.
100/// * `GY`: The "yield type", which is the type of values passed to
101///   `yield` inside the coroutine.
102/// * `GR`: The "return type", which is the type of value returned upon
103///   completion of the coroutine.
104#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
105#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
106pub struct ClosureArgs<I: Interner> {
107    /// Lifetime and type parameters from the enclosing function,
108    /// concatenated with a tuple containing the types of the upvars.
109    ///
110    /// These are separated out because codegen wants to pass them around
111    /// when monomorphizing.
112    pub args: I::GenericArgs,
113}
114
115impl<I: Interner> Eq for ClosureArgs<I> {}
116
117/// Struct returned by `split()`.
118pub struct ClosureArgsParts<I: Interner> {
119    /// This is the args of the typeck root.
120    pub parent_args: I::GenericArgsSlice,
121    /// Represents the maximum calling capability of the closure.
122    pub closure_kind_ty: I::Ty,
123    /// Captures the closure's signature. This closure signature is "tupled", and
124    /// thus has a peculiar signature of `extern "rust-call" fn((Args, ...)) -> Ty`.
125    pub closure_sig_as_fn_ptr_ty: I::Ty,
126    /// The upvars captured by the closure. Remains an inference variable
127    /// until the upvar analysis, which happens late in HIR typeck.
128    pub tupled_upvars_ty: I::Ty,
129}
130
131impl<I: Interner> ClosureArgs<I> {
132    /// Construct `ClosureArgs` from `ClosureArgsParts`, containing `Args`
133    /// for the closure parent, alongside additional closure-specific components.
134    pub fn new(cx: I, parts: ClosureArgsParts<I>) -> ClosureArgs<I> {
135        ClosureArgs {
136            args: cx.mk_args_from_iter(parts.parent_args.iter().chain([
137                parts.closure_kind_ty.into(),
138                parts.closure_sig_as_fn_ptr_ty.into(),
139                parts.tupled_upvars_ty.into(),
140            ])),
141        }
142    }
143
144    /// Divides the closure args into their respective components.
145    /// The ordering assumed here must match that used by `ClosureArgs::new` above.
146    fn split(self) -> ClosureArgsParts<I> {
147        self.args.split_closure_args()
148    }
149
150    /// Returns the generic parameters of the closure's parent.
151    pub fn parent_args(self) -> I::GenericArgsSlice {
152        self.split().parent_args
153    }
154
155    /// Returns an iterator over the list of types of captured paths by the closure.
156    /// In case there was a type error in figuring out the types of the captured path, an
157    /// empty iterator is returned.
158    #[inline]
159    pub fn upvar_tys(self) -> I::Tys {
160        match self.tupled_upvars_ty().kind() {
161            ty::Error(_) => Default::default(),
162            ty::Tuple(tys) => tys,
163            ty::Infer(_) => panic!("upvar_tys called before capture types are inferred"),
164            ty => panic!("Unexpected representation of upvar types tuple {:?}", ty),
165        }
166    }
167
168    /// Returns the tuple type representing the upvars for this closure.
169    #[inline]
170    pub fn tupled_upvars_ty(self) -> I::Ty {
171        self.split().tupled_upvars_ty
172    }
173
174    /// Returns the closure kind for this closure; may return a type
175    /// variable during inference. To get the closure kind during
176    /// inference, use `infcx.closure_kind(args)`.
177    pub fn kind_ty(self) -> I::Ty {
178        self.split().closure_kind_ty
179    }
180
181    /// Returns the `fn` pointer type representing the closure signature for this
182    /// closure.
183    // FIXME(eddyb) this should be unnecessary, as the shallowly resolved
184    // type is known at the time of the creation of `ClosureArgs`,
185    // see `rustc_hir_analysis::check::closure`.
186    pub fn sig_as_fn_ptr_ty(self) -> I::Ty {
187        self.split().closure_sig_as_fn_ptr_ty
188    }
189
190    /// Returns the closure kind for this closure; only usable outside
191    /// of an inference context, because in that context we know that
192    /// there are no type variables.
193    ///
194    /// If you have an inference context, use `infcx.closure_kind()`.
195    pub fn kind(self) -> ty::ClosureKind {
196        self.kind_ty().to_opt_closure_kind().unwrap()
197    }
198
199    /// Extracts the signature from the closure.
200    pub fn sig(self) -> ty::Binder<I, ty::FnSig<I>> {
201        match self.sig_as_fn_ptr_ty().kind() {
202            ty::FnPtr(sig_tys, hdr) => sig_tys.with(hdr),
203            ty => panic!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {ty:?}"),
204        }
205    }
206}
207
208#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
209#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
210pub struct CoroutineClosureArgs<I: Interner> {
211    pub args: I::GenericArgs,
212}
213
214impl<I: Interner> Eq for CoroutineClosureArgs<I> {}
215
216/// See docs for explanation of how each argument is used.
217///
218/// See [`CoroutineClosureSignature`] for how these arguments are put together
219/// to make a callable [`ty::FnSig`] suitable for typeck and borrowck.
220pub struct CoroutineClosureArgsParts<I: Interner> {
221    /// This is the args of the typeck root.
222    pub parent_args: I::GenericArgsSlice,
223    /// Represents the maximum calling capability of the closure.
224    pub closure_kind_ty: I::Ty,
225    /// Represents all of the relevant parts of the coroutine returned by this
226    /// coroutine-closure. This signature parts type will have the general
227    /// shape of `fn(tupled_inputs, resume_ty) -> (return_ty, yield_ty)`, where
228    /// `resume_ty`, `return_ty`, and `yield_ty` are the respective types for the
229    /// coroutine returned by the coroutine-closure.
230    ///
231    /// Use `coroutine_closure_sig` to break up this type rather than using it
232    /// yourself.
233    pub signature_parts_ty: I::Ty,
234    /// The upvars captured by the closure. Remains an inference variable
235    /// until the upvar analysis, which happens late in HIR typeck.
236    pub tupled_upvars_ty: I::Ty,
237    /// a function pointer that has the shape `for<'env> fn() -> (&'env T, ...)`.
238    /// This allows us to represent the binder of the self-captures of the closure.
239    ///
240    /// For example, if the coroutine returned by the closure borrows `String`
241    /// from the closure's upvars, this will be `for<'env> fn() -> (&'env String,)`,
242    /// while the `tupled_upvars_ty`, representing the by-move version of the same
243    /// captures, will be `(String,)`.
244    pub coroutine_captures_by_ref_ty: I::Ty,
245}
246
247impl<I: Interner> CoroutineClosureArgs<I> {
248    pub fn new(cx: I, parts: CoroutineClosureArgsParts<I>) -> CoroutineClosureArgs<I> {
249        CoroutineClosureArgs {
250            args: cx.mk_args_from_iter(parts.parent_args.iter().chain([
251                parts.closure_kind_ty.into(),
252                parts.signature_parts_ty.into(),
253                parts.tupled_upvars_ty.into(),
254                parts.coroutine_captures_by_ref_ty.into(),
255            ])),
256        }
257    }
258
259    fn split(self) -> CoroutineClosureArgsParts<I> {
260        self.args.split_coroutine_closure_args()
261    }
262
263    pub fn parent_args(self) -> I::GenericArgsSlice {
264        self.split().parent_args
265    }
266
267    #[inline]
268    pub fn upvar_tys(self) -> I::Tys {
269        match self.tupled_upvars_ty().kind() {
270            ty::Error(_) => Default::default(),
271            ty::Tuple(..) => self.tupled_upvars_ty().tuple_fields(),
272            ty::Infer(_) => panic!("upvar_tys called before capture types are inferred"),
273            ty => panic!("Unexpected representation of upvar types tuple {:?}", ty),
274        }
275    }
276
277    #[inline]
278    pub fn tupled_upvars_ty(self) -> I::Ty {
279        self.split().tupled_upvars_ty
280    }
281
282    pub fn kind_ty(self) -> I::Ty {
283        self.split().closure_kind_ty
284    }
285
286    pub fn kind(self) -> ty::ClosureKind {
287        self.kind_ty().to_opt_closure_kind().unwrap()
288    }
289
290    pub fn signature_parts_ty(self) -> I::Ty {
291        self.split().signature_parts_ty
292    }
293
294    pub fn coroutine_closure_sig(self) -> ty::Binder<I, CoroutineClosureSignature<I>> {
295        let ty::FnPtr(sig_tys, hdr) = self.signature_parts_ty().kind() else { panic!() };
296        sig_tys.map_bound(|sig_tys| {
297            let [resume_ty, tupled_inputs_ty] = *sig_tys.inputs().as_slice() else {
298                panic!();
299            };
300            let [yield_ty, return_ty] = *sig_tys.output().tuple_fields().as_slice() else {
301                panic!()
302            };
303            CoroutineClosureSignature {
304                tupled_inputs_ty,
305                resume_ty,
306                yield_ty,
307                return_ty,
308                c_variadic: hdr.c_variadic,
309                safety: hdr.safety,
310                abi: hdr.abi,
311            }
312        })
313    }
314
315    pub fn coroutine_captures_by_ref_ty(self) -> I::Ty {
316        self.split().coroutine_captures_by_ref_ty
317    }
318
319    pub fn has_self_borrows(&self) -> bool {
320        match self.coroutine_captures_by_ref_ty().kind() {
321            ty::FnPtr(sig_tys, _) => sig_tys
322                .skip_binder()
323                .visit_with(&mut HasRegionsBoundAt { binder: ty::INNERMOST })
324                .is_break(),
325            ty::Error(_) => true,
326            _ => panic!(),
327        }
328    }
329}
330
331/// Unlike `has_escaping_bound_vars` or `outermost_exclusive_binder`, this will
332/// detect only regions bound *at* the debruijn index.
333struct HasRegionsBoundAt {
334    binder: ty::DebruijnIndex,
335}
336// FIXME: Could be optimized to not walk into components with no escaping bound vars.
337impl<I: Interner> TypeVisitor<I> for HasRegionsBoundAt {
338    type Result = ControlFlow<()>;
339    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
340        self.binder.shift_in(1);
341        t.super_visit_with(self)?;
342        self.binder.shift_out(1);
343        ControlFlow::Continue(())
344    }
345
346    fn visit_region(&mut self, r: I::Region) -> Self::Result {
347        if matches!(r.kind(), ty::ReBound(ty::BoundVarIndexKind::Bound(binder), _) if self.binder == binder)
348        {
349            ControlFlow::Break(())
350        } else {
351            ControlFlow::Continue(())
352        }
353    }
354}
355
356#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
357#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
358pub struct CoroutineClosureSignature<I: Interner> {
359    pub tupled_inputs_ty: I::Ty,
360    pub resume_ty: I::Ty,
361    pub yield_ty: I::Ty,
362    pub return_ty: I::Ty,
363
364    // Like the `fn_sig_as_fn_ptr_ty` of a regular closure, these types
365    // never actually differ. But we save them rather than recreating them
366    // from scratch just for good measure.
367    /// Always false
368    pub c_variadic: bool,
369    /// Always `Normal` (safe)
370    #[type_visitable(ignore)]
371    #[type_foldable(identity)]
372    pub safety: I::Safety,
373    /// Always `RustCall`
374    #[type_visitable(ignore)]
375    #[type_foldable(identity)]
376    pub abi: I::Abi,
377}
378
379impl<I: Interner> Eq for CoroutineClosureSignature<I> {}
380
381impl<I: Interner> CoroutineClosureSignature<I> {
382    /// Construct a coroutine from the closure signature. Since a coroutine signature
383    /// is agnostic to the type of generator that is returned (by-ref/by-move),
384    /// the caller must specify what "flavor" of generator that they'd like to
385    /// create. Additionally, they must manually compute the upvars of the closure.
386    ///
387    /// This helper is not really meant to be used directly except for early on
388    /// during typeck, when we want to put inference vars into the kind and upvars tys.
389    /// When the kind and upvars are known, use the other helper functions.
390    pub fn to_coroutine(
391        self,
392        cx: I,
393        parent_args: I::GenericArgsSlice,
394        coroutine_kind_ty: I::Ty,
395        coroutine_def_id: I::CoroutineId,
396        tupled_upvars_ty: I::Ty,
397    ) -> I::Ty {
398        let coroutine_args = ty::CoroutineArgs::new(
399            cx,
400            ty::CoroutineArgsParts {
401                parent_args,
402                kind_ty: coroutine_kind_ty,
403                resume_ty: self.resume_ty,
404                yield_ty: self.yield_ty,
405                return_ty: self.return_ty,
406                tupled_upvars_ty,
407            },
408        );
409
410        Ty::new_coroutine(cx, coroutine_def_id, coroutine_args.args)
411    }
412
413    /// Given known upvars and a [`ClosureKind`](ty::ClosureKind), compute the coroutine
414    /// returned by that corresponding async fn trait.
415    ///
416    /// This function expects the upvars to have been computed already, and doesn't check
417    /// that the `ClosureKind` is actually supported by the coroutine-closure.
418    pub fn to_coroutine_given_kind_and_upvars(
419        self,
420        cx: I,
421        parent_args: I::GenericArgsSlice,
422        coroutine_def_id: I::CoroutineId,
423        goal_kind: ty::ClosureKind,
424        env_region: I::Region,
425        closure_tupled_upvars_ty: I::Ty,
426        coroutine_captures_by_ref_ty: I::Ty,
427    ) -> I::Ty {
428        let tupled_upvars_ty = Self::tupled_upvars_by_closure_kind(
429            cx,
430            goal_kind,
431            self.tupled_inputs_ty,
432            closure_tupled_upvars_ty,
433            coroutine_captures_by_ref_ty,
434            env_region,
435        );
436
437        self.to_coroutine(
438            cx,
439            parent_args,
440            Ty::from_coroutine_closure_kind(cx, goal_kind),
441            coroutine_def_id,
442            tupled_upvars_ty,
443        )
444    }
445
446    /// Compute the tupled upvars that a coroutine-closure's output coroutine
447    /// would return for the given `ClosureKind`.
448    ///
449    /// When `ClosureKind` is `FnMut`/`Fn`, then this will use the "captures by ref"
450    /// to return a set of upvars which are borrowed with the given `env_region`.
451    ///
452    /// This ensures that the `AsyncFn::call` will return a coroutine whose upvars'
453    /// lifetimes are related to the lifetime of the borrow on the closure made for
454    /// the call. This allows borrowck to enforce the self-borrows correctly.
455    pub fn tupled_upvars_by_closure_kind(
456        cx: I,
457        kind: ty::ClosureKind,
458        tupled_inputs_ty: I::Ty,
459        closure_tupled_upvars_ty: I::Ty,
460        coroutine_captures_by_ref_ty: I::Ty,
461        env_region: I::Region,
462    ) -> I::Ty {
463        match kind {
464            ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
465                let ty::FnPtr(sig_tys, _) = coroutine_captures_by_ref_ty.kind() else {
466                    panic!();
467                };
468                let coroutine_captures_by_ref_ty =
469                    sig_tys.output().skip_binder().fold_with(&mut FoldEscapingRegions {
470                        interner: cx,
471                        region: env_region,
472                        debruijn: ty::INNERMOST,
473                        cache: Default::default(),
474                    });
475                Ty::new_tup_from_iter(
476                    cx,
477                    tupled_inputs_ty
478                        .tuple_fields()
479                        .iter()
480                        .chain(coroutine_captures_by_ref_ty.tuple_fields().iter()),
481                )
482            }
483            ty::ClosureKind::FnOnce => Ty::new_tup_from_iter(
484                cx,
485                tupled_inputs_ty
486                    .tuple_fields()
487                    .iter()
488                    .chain(closure_tupled_upvars_ty.tuple_fields().iter()),
489            ),
490        }
491    }
492}
493
494/// Instantiates a `for<'env> ...` binder with a specific region.
495// FIXME(async_closures): Get rid of this in favor of `BoundVarReplacerDelegate`
496// when that is uplifted.
497struct FoldEscapingRegions<I: Interner> {
498    interner: I,
499    debruijn: ty::DebruijnIndex,
500    region: I::Region,
501
502    // Depends on `debruijn` because we may have types with regions of different
503    // debruijn depths depending on the binders we've entered.
504    cache: DelayedMap<(ty::DebruijnIndex, I::Ty), I::Ty>,
505}
506
507impl<I: Interner> TypeFolder<I> for FoldEscapingRegions<I> {
508    fn cx(&self) -> I {
509        self.interner
510    }
511
512    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
513        if !t.has_vars_bound_at_or_above(self.debruijn) {
514            t
515        } else if let Some(&t) = self.cache.get(&(self.debruijn, t)) {
516            t
517        } else {
518            let res = t.super_fold_with(self);
519            assert!(self.cache.insert((self.debruijn, t), res));
520            res
521        }
522    }
523
524    fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
525    where
526        T: TypeFoldable<I>,
527    {
528        self.debruijn.shift_in(1);
529        let result = t.super_fold_with(self);
530        self.debruijn.shift_out(1);
531        result
532    }
533
534    fn fold_region(&mut self, r: <I as Interner>::Region) -> <I as Interner>::Region {
535        if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind() {
536            assert!(
537                debruijn <= self.debruijn,
538                "cannot instantiate binder with escaping bound vars"
539            );
540            if self.debruijn == debruijn {
541                shift_region(self.interner, self.region, self.debruijn.as_u32())
542            } else {
543                r
544            }
545        } else {
546            r
547        }
548    }
549}
550
551#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
552#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
553pub struct GenSig<I: Interner> {
554    pub resume_ty: I::Ty,
555    pub yield_ty: I::Ty,
556    pub return_ty: I::Ty,
557}
558
559impl<I: Interner> Eq for GenSig<I> {}
560/// Similar to `ClosureArgs`; see the above documentation for more.
561#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
562#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
563pub struct CoroutineArgs<I: Interner> {
564    pub args: I::GenericArgs,
565}
566
567impl<I: Interner> Eq for CoroutineArgs<I> {}
568
569pub struct CoroutineArgsParts<I: Interner> {
570    /// This is the args of the typeck root.
571    pub parent_args: I::GenericArgsSlice,
572
573    /// The coroutines returned by a coroutine-closure's `AsyncFnOnce`/`AsyncFnMut`
574    /// implementations must be distinguished since the former takes the closure's
575    /// upvars by move, and the latter takes the closure's upvars by ref.
576    ///
577    /// This field distinguishes these fields so that codegen can select the right
578    /// body for the coroutine. This has the same type representation as the closure
579    /// kind: `i8`/`i16`/`i32`.
580    ///
581    /// For regular coroutines, this field will always just be `()`.
582    pub kind_ty: I::Ty,
583
584    pub resume_ty: I::Ty,
585    pub yield_ty: I::Ty,
586    pub return_ty: I::Ty,
587
588    /// The upvars captured by the closure. Remains an inference variable
589    /// until the upvar analysis, which happens late in HIR typeck.
590    pub tupled_upvars_ty: I::Ty,
591}
592
593impl<I: Interner> CoroutineArgs<I> {
594    /// Construct `CoroutineArgs` from `CoroutineArgsParts`, containing `Args`
595    /// for the coroutine parent, alongside additional coroutine-specific components.
596    pub fn new(cx: I, parts: CoroutineArgsParts<I>) -> CoroutineArgs<I> {
597        CoroutineArgs {
598            args: cx.mk_args_from_iter(parts.parent_args.iter().chain([
599                parts.kind_ty.into(),
600                parts.resume_ty.into(),
601                parts.yield_ty.into(),
602                parts.return_ty.into(),
603                parts.tupled_upvars_ty.into(),
604            ])),
605        }
606    }
607
608    /// Divides the coroutine args into their respective components.
609    /// The ordering assumed here must match that used by `CoroutineArgs::new` above.
610    fn split(self) -> CoroutineArgsParts<I> {
611        self.args.split_coroutine_args()
612    }
613
614    /// Returns the generic parameters of the coroutine's parent.
615    pub fn parent_args(self) -> I::GenericArgsSlice {
616        self.split().parent_args
617    }
618
619    // Returns the kind of the coroutine. See docs on the `kind_ty` field.
620    pub fn kind_ty(self) -> I::Ty {
621        self.split().kind_ty
622    }
623
624    /// Returns an iterator over the list of types of captured paths by the coroutine.
625    /// In case there was a type error in figuring out the types of the captured path, an
626    /// empty iterator is returned.
627    #[inline]
628    pub fn upvar_tys(self) -> I::Tys {
629        match self.tupled_upvars_ty().kind() {
630            ty::Error(_) => Default::default(),
631            ty::Tuple(tys) => tys,
632            ty::Infer(_) => panic!("upvar_tys called before capture types are inferred"),
633            ty => panic!("Unexpected representation of upvar types tuple {:?}", ty),
634        }
635    }
636
637    /// Returns the tuple type representing the upvars for this coroutine.
638    #[inline]
639    pub fn tupled_upvars_ty(self) -> I::Ty {
640        self.split().tupled_upvars_ty
641    }
642
643    /// Returns the type representing the resume type of the coroutine.
644    pub fn resume_ty(self) -> I::Ty {
645        self.split().resume_ty
646    }
647
648    /// Returns the type representing the yield type of the coroutine.
649    pub fn yield_ty(self) -> I::Ty {
650        self.split().yield_ty
651    }
652
653    /// Returns the type representing the return type of the coroutine.
654    pub fn return_ty(self) -> I::Ty {
655        self.split().return_ty
656    }
657
658    /// Returns the "coroutine signature", which consists of its resume, yield
659    /// and return types.
660    pub fn sig(self) -> GenSig<I> {
661        let parts = self.split();
662        GenSig { resume_ty: parts.resume_ty, yield_ty: parts.yield_ty, return_ty: parts.return_ty }
663    }
664}