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}