diff options
Diffstat (limited to 'src')
27 files changed, 307 insertions, 307 deletions
diff --git a/src/doc/unstable-book/src/language-features/coroutines.md b/src/doc/unstable-book/src/language-features/coroutines.md new file mode 100644 index 00000000000..fb1ba791aef --- /dev/null +++ b/src/doc/unstable-book/src/language-features/coroutines.md @@ -0,0 +1,246 @@ +# `coroutines` + +The tracking issue for this feature is: [#43122] + +[#43122]: https://github.com/rust-lang/rust/issues/43122 + +------------------------ + +The `coroutines` feature gate in Rust allows you to define coroutine or +coroutine literals. A coroutine is a "resumable function" that syntactically +resembles a closure but compiles to much different semantics in the compiler +itself. The primary feature of a coroutine is that it can be suspended during +execution to be resumed at a later date. Coroutines use the `yield` keyword to +"return", and then the caller can `resume` a coroutine to resume execution just +after the `yield` keyword. + +Coroutines are an extra-unstable feature in the compiler right now. Added in +[RFC 2033] they're mostly intended right now as a information/constraint +gathering phase. The intent is that experimentation can happen on the nightly +compiler before actual stabilization. A further RFC will be required to +stabilize coroutines/coroutines and will likely contain at least a few small +tweaks to the overall design. + +[RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033 + +A syntactical example of a coroutine is: + +```rust +#![feature(coroutines, coroutine_trait)] + +use std::ops::{Coroutine, CoroutineState}; +use std::pin::Pin; + +fn main() { + let mut coroutine = || { + yield 1; + return "foo" + }; + + match Pin::new(&mut coroutine).resume(()) { + CoroutineState::Yielded(1) => {} + _ => panic!("unexpected value from resume"), + } + match Pin::new(&mut coroutine).resume(()) { + CoroutineState::Complete("foo") => {} + _ => panic!("unexpected value from resume"), + } +} +``` + +Coroutines are closure-like literals which can contain a `yield` statement. The +`yield` statement takes an optional expression of a value to yield out of the +coroutine. All coroutine literals implement the `Coroutine` trait in the +`std::ops` module. The `Coroutine` trait has one main method, `resume`, which +resumes execution of the coroutine at the previous suspension point. + +An example of the control flow of coroutines is that the following example +prints all numbers in order: + +```rust +#![feature(coroutines, coroutine_trait)] + +use std::ops::Coroutine; +use std::pin::Pin; + +fn main() { + let mut coroutine = || { + println!("2"); + yield; + println!("4"); + }; + + println!("1"); + Pin::new(&mut coroutine).resume(()); + println!("3"); + Pin::new(&mut coroutine).resume(()); + println!("5"); +} +``` + +At this time the main intended use case of coroutines is an implementation +primitive for async/await syntax, but coroutines will likely be extended to +ergonomic implementations of iterators and other primitives in the future. +Feedback on the design and usage is always appreciated! + +### The `Coroutine` trait + +The `Coroutine` trait in `std::ops` currently looks like: + +```rust +# #![feature(arbitrary_self_types, coroutine_trait)] +# use std::ops::CoroutineState; +# use std::pin::Pin; + +pub trait Coroutine<R = ()> { + type Yield; + type Return; + fn resume(self: Pin<&mut Self>, resume: R) -> CoroutineState<Self::Yield, Self::Return>; +} +``` + +The `Coroutine::Yield` type is the type of values that can be yielded with the +`yield` statement. The `Coroutine::Return` type is the returned type of the +coroutine. This is typically the last expression in a coroutine's definition or +any value passed to `return` in a coroutine. The `resume` function is the entry +point for executing the `Coroutine` itself. + +The return value of `resume`, `CoroutineState`, looks like: + +```rust +pub enum CoroutineState<Y, R> { + Yielded(Y), + Complete(R), +} +``` + +The `Yielded` variant indicates that the coroutine can later be resumed. This +corresponds to a `yield` point in a coroutine. The `Complete` variant indicates +that the coroutine is complete and cannot be resumed again. Calling `resume` +after a coroutine has returned `Complete` will likely result in a panic of the +program. + +### Closure-like semantics + +The closure-like syntax for coroutines alludes to the fact that they also have +closure-like semantics. Namely: + +* When created, a coroutine executes no code. A closure literal does not + actually execute any of the closure's code on construction, and similarly a + coroutine literal does not execute any code inside the coroutine when + constructed. + +* Coroutines can capture outer variables by reference or by move, and this can + be tweaked with the `move` keyword at the beginning of the closure. Like + closures all coroutines will have an implicit environment which is inferred by + the compiler. Outer variables can be moved into a coroutine for use as the + coroutine progresses. + +* Coroutine literals produce a value with a unique type which implements the + `std::ops::Coroutine` trait. This allows actual execution of the coroutine + through the `Coroutine::resume` method as well as also naming it in return + types and such. + +* Traits like `Send` and `Sync` are automatically implemented for a `Coroutine` + depending on the captured variables of the environment. Unlike closures, + coroutines also depend on variables live across suspension points. This means + that although the ambient environment may be `Send` or `Sync`, the coroutine + itself may not be due to internal variables live across `yield` points being + not-`Send` or not-`Sync`. Note that coroutines do + not implement traits like `Copy` or `Clone` automatically. + +* Whenever a coroutine is dropped it will drop all captured environment + variables. + +### Coroutines as state machines + +In the compiler, coroutines are currently compiled as state machines. Each +`yield` expression will correspond to a different state that stores all live +variables over that suspension point. Resumption of a coroutine will dispatch on +the current state and then execute internally until a `yield` is reached, at +which point all state is saved off in the coroutine and a value is returned. + +Let's take a look at an example to see what's going on here: + +```rust +#![feature(coroutines, coroutine_trait)] + +use std::ops::Coroutine; +use std::pin::Pin; + +fn main() { + let ret = "foo"; + let mut coroutine = move || { + yield 1; + return ret + }; + + Pin::new(&mut coroutine).resume(()); + Pin::new(&mut coroutine).resume(()); +} +``` + +This coroutine literal will compile down to something similar to: + +```rust +#![feature(arbitrary_self_types, coroutines, coroutine_trait)] + +use std::ops::{Coroutine, CoroutineState}; +use std::pin::Pin; + +fn main() { + let ret = "foo"; + let mut coroutine = { + enum __Coroutine { + Start(&'static str), + Yield1(&'static str), + Done, + } + + impl Coroutine for __Coroutine { + type Yield = i32; + type Return = &'static str; + + fn resume(mut self: Pin<&mut Self>, resume: ()) -> CoroutineState<i32, &'static str> { + use std::mem; + match mem::replace(&mut *self, __Coroutine::Done) { + __Coroutine::Start(s) => { + *self = __Coroutine::Yield1(s); + CoroutineState::Yielded(1) + } + + __Coroutine::Yield1(s) => { + *self = __Coroutine::Done; + CoroutineState::Complete(s) + } + + __Coroutine::Done => { + panic!("coroutine resumed after completion") + } + } + } + } + + __Coroutine::Start(ret) + }; + + Pin::new(&mut coroutine).resume(()); + Pin::new(&mut coroutine).resume(()); +} +``` + +Notably here we can see that the compiler is generating a fresh type, +`__Coroutine` in this case. This type has a number of states (represented here +as an `enum`) corresponding to each of the conceptual states of the coroutine. +At the beginning we're closing over our outer variable `foo` and then that +variable is also live over the `yield` point, so it's stored in both states. + +When the coroutine starts it'll immediately yield 1, but it saves off its state +just before it does so indicating that it has reached the yield point. Upon +resuming again we'll execute the `return ret` which returns the `Complete` +state. + +Here we can also note that the `Done` state, if resumed, panics immediately as +it's invalid to resume a completed coroutine. It's also worth noting that this +is just a rough desugaring, not a normative specification for what the compiler +does. diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md deleted file mode 100644 index 7b865c9c679..00000000000 --- a/src/doc/unstable-book/src/language-features/generators.md +++ /dev/null @@ -1,246 +0,0 @@ -# `generators` - -The tracking issue for this feature is: [#43122] - -[#43122]: https://github.com/rust-lang/rust/issues/43122 - ------------------------- - -The `generators` feature gate in Rust allows you to define generator or -coroutine literals. A generator is a "resumable function" that syntactically -resembles a closure but compiles to much different semantics in the compiler -itself. The primary feature of a generator is that it can be suspended during -execution to be resumed at a later date. Generators use the `yield` keyword to -"return", and then the caller can `resume` a generator to resume execution just -after the `yield` keyword. - -Generators are an extra-unstable feature in the compiler right now. Added in -[RFC 2033] they're mostly intended right now as a information/constraint -gathering phase. The intent is that experimentation can happen on the nightly -compiler before actual stabilization. A further RFC will be required to -stabilize generators/coroutines and will likely contain at least a few small -tweaks to the overall design. - -[RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033 - -A syntactical example of a generator is: - -```rust -#![feature(generators, generator_trait)] - -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - -fn main() { - let mut generator = || { - yield 1; - return "foo" - }; - - match Pin::new(&mut generator).resume(()) { - GeneratorState::Yielded(1) => {} - _ => panic!("unexpected value from resume"), - } - match Pin::new(&mut generator).resume(()) { - GeneratorState::Complete("foo") => {} - _ => panic!("unexpected value from resume"), - } -} -``` - -Generators are closure-like literals which can contain a `yield` statement. The -`yield` statement takes an optional expression of a value to yield out of the -generator. All generator literals implement the `Generator` trait in the -`std::ops` module. The `Generator` trait has one main method, `resume`, which -resumes execution of the generator at the previous suspension point. - -An example of the control flow of generators is that the following example -prints all numbers in order: - -```rust -#![feature(generators, generator_trait)] - -use std::ops::Generator; -use std::pin::Pin; - -fn main() { - let mut generator = || { - println!("2"); - yield; - println!("4"); - }; - - println!("1"); - Pin::new(&mut generator).resume(()); - println!("3"); - Pin::new(&mut generator).resume(()); - println!("5"); -} -``` - -At this time the main intended use case of generators is an implementation -primitive for async/await syntax, but generators will likely be extended to -ergonomic implementations of iterators and other primitives in the future. -Feedback on the design and usage is always appreciated! - -### The `Generator` trait - -The `Generator` trait in `std::ops` currently looks like: - -```rust -# #![feature(arbitrary_self_types, generator_trait)] -# use std::ops::GeneratorState; -# use std::pin::Pin; - -pub trait Generator<R = ()> { - type Yield; - type Return; - fn resume(self: Pin<&mut Self>, resume: R) -> GeneratorState<Self::Yield, Self::Return>; -} -``` - -The `Generator::Yield` type is the type of values that can be yielded with the -`yield` statement. The `Generator::Return` type is the returned type of the -generator. This is typically the last expression in a generator's definition or -any value passed to `return` in a generator. The `resume` function is the entry -point for executing the `Generator` itself. - -The return value of `resume`, `GeneratorState`, looks like: - -```rust -pub enum GeneratorState<Y, R> { - Yielded(Y), - Complete(R), -} -``` - -The `Yielded` variant indicates that the generator can later be resumed. This -corresponds to a `yield` point in a generator. The `Complete` variant indicates -that the generator is complete and cannot be resumed again. Calling `resume` -after a generator has returned `Complete` will likely result in a panic of the -program. - -### Closure-like semantics - -The closure-like syntax for generators alludes to the fact that they also have -closure-like semantics. Namely: - -* When created, a generator executes no code. A closure literal does not - actually execute any of the closure's code on construction, and similarly a - generator literal does not execute any code inside the generator when - constructed. - -* Generators can capture outer variables by reference or by move, and this can - be tweaked with the `move` keyword at the beginning of the closure. Like - closures all generators will have an implicit environment which is inferred by - the compiler. Outer variables can be moved into a generator for use as the - generator progresses. - -* Generator literals produce a value with a unique type which implements the - `std::ops::Generator` trait. This allows actual execution of the generator - through the `Generator::resume` method as well as also naming it in return - types and such. - -* Traits like `Send` and `Sync` are automatically implemented for a `Generator` - depending on the captured variables of the environment. Unlike closures, - generators also depend on variables live across suspension points. This means - that although the ambient environment may be `Send` or `Sync`, the generator - itself may not be due to internal variables live across `yield` points being - not-`Send` or not-`Sync`. Note that generators do - not implement traits like `Copy` or `Clone` automatically. - -* Whenever a generator is dropped it will drop all captured environment - variables. - -### Generators as state machines - -In the compiler, generators are currently compiled as state machines. Each -`yield` expression will correspond to a different state that stores all live -variables over that suspension point. Resumption of a generator will dispatch on -the current state and then execute internally until a `yield` is reached, at -which point all state is saved off in the generator and a value is returned. - -Let's take a look at an example to see what's going on here: - -```rust -#![feature(generators, generator_trait)] - -use std::ops::Generator; -use std::pin::Pin; - -fn main() { - let ret = "foo"; - let mut generator = move || { - yield 1; - return ret - }; - - Pin::new(&mut generator).resume(()); - Pin::new(&mut generator).resume(()); -} -``` - -This generator literal will compile down to something similar to: - -```rust -#![feature(arbitrary_self_types, generators, generator_trait)] - -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - -fn main() { - let ret = "foo"; - let mut generator = { - enum __Generator { - Start(&'static str), - Yield1(&'static str), - Done, - } - - impl Generator for __Generator { - type Yield = i32; - type Return = &'static str; - - fn resume(mut self: Pin<&mut Self>, resume: ()) -> GeneratorState<i32, &'static str> { - use std::mem; - match mem::replace(&mut *self, __Generator::Done) { - __Generator::Start(s) => { - *self = __Generator::Yield1(s); - GeneratorState::Yielded(1) - } - - __Generator::Yield1(s) => { - *self = __Generator::Done; - GeneratorState::Complete(s) - } - - __Generator::Done => { - panic!("generator resumed after completion") - } - } - } - } - - __Generator::Start(ret) - }; - - Pin::new(&mut generator).resume(()); - Pin::new(&mut generator).resume(()); -} -``` - -Notably here we can see that the compiler is generating a fresh type, -`__Generator` in this case. This type has a number of states (represented here -as an `enum`) corresponding to each of the conceptual states of the generator. -At the beginning we're closing over our outer variable `foo` and then that -variable is also live over the `yield` point, so it's stored in both states. - -When the generator starts it'll immediately yield 1, but it saves off its state -just before it does so indicating that it has reached the yield point. Upon -resuming again we'll execute the `return ret` which returns the `Complete` -state. - -Here we can also note that the `Done` state, if resumed, panics immediately as -it's invalid to resume a completed generator. It's also worth noting that this -is just a rough desugaring, not a normative specification for what the compiler -does. diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs index 99daec560e7..96a90d599ab 100644 --- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { use AsyncCoroutineKind::{Block, Closure}; // For functions, with explicitly defined types, don't warn. // XXXkhuey maybe we should? - if let Some(CoroutineKind::Async(Block | Closure)) = body.generator_kind { + if let Some(CoroutineKind::Async(Block | Closure)) = body.coroutine_kind { if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { let body_id = BodyId { hir_id: body.value.hir_id, diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index 65d131c5751..60f9bbd7458 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -196,25 +196,25 @@ impl LateLintPass<'_> for AwaitHolding { fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { use AsyncCoroutineKind::{Block, Closure, Fn}; - if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.generator_kind { + if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.coroutine_kind { let def_id = cx.tcx.hir().body_owner_def_id(body.id()); - if let Some(generator_layout) = cx.tcx.mir_generator_witnesses(def_id) { - self.check_interior_types(cx, generator_layout); + if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) { + self.check_interior_types(cx, coroutine_layout); } } } } impl AwaitHolding { - fn check_interior_types(&self, cx: &LateContext<'_>, generator: &CoroutineLayout<'_>) { - for (ty_index, ty_cause) in generator.field_tys.iter_enumerated() { + fn check_interior_types(&self, cx: &LateContext<'_>, coroutine: &CoroutineLayout<'_>) { + for (ty_index, ty_cause) in coroutine.field_tys.iter_enumerated() { if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() { let await_points = || { - generator + coroutine .variant_source_info .iter_enumerated() .filter_map(|(variant, source_info)| { - generator.variant_fields[variant] + coroutine.variant_fields[variant] .raw .contains(&ty_index) .then_some(source_info.span) diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index ca9defc2bf3..fc9b381664a 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -437,7 +437,7 @@ fn lint_for_missing_headers( let ret_ty = typeck.expr_ty(body.value); if implements_trait(cx, ret_ty, future, &[]); if let ty::Coroutine(_, subs, _) = ret_ty.kind(); - if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::Result); + if is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result); then { span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 49976334751..914ceca2995 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -188,7 +188,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) .. } = block_expr; let closure_body = cx.tcx.hir().body(body); - if closure_body.generator_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block)); + if closure_body.coroutine_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block)); then { return Some(closure_body); } diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index 674d3451748..b44a2716dde 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -26,7 +26,7 @@ pub(super) fn check<'tcx>( if_chain! { if !expr.span.from_expansion(); if let ExprKind::Closure(c) = m_arg.kind; - if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body); + if let Body {params: [p], value: body_expr, coroutine_kind: _ } = cx.tcx.hir().body(c.body); if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind; let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index f2c823323bb..d267b3de7f2 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -87,7 +87,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.generator_kind { + if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.coroutine_kind { if let ExprKind::Block( Block { expr: diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs index 59aecd23278..b8f787e1f1f 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && let body = cx.tcx.hir().body(*body) && - matches!(body.generator_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block))) + matches!(body.coroutine_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block))) { cx .typeck_results() diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index f42836611ca..c18237e887d 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { // without this check, we'd end up linting twice. && !matches!(recv.kind, hir::ExprKind::Call(..)) && let (full_expr, call_depth) = get_parent_call_exprs(cx, expr) - && let Some((body, fn_decl, generator_kind)) = find_innermost_closure(cx, recv, call_depth) + && let Some((body, fn_decl, coroutine_kind)) = find_innermost_closure(cx, recv, call_depth) { span_lint_and_then( cx, @@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { let mut applicability = Applicability::MachineApplicable; let mut hint = Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability); - if generator_kind.is_async() + if coroutine_kind.is_async() && let hir::ExprKind::Closure(closure) = body.kind { let async_closure_body = cx.tcx.hir().body(closure.body); diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs index 5e1ba1b0dc0..3649f8792ae 100644 --- a/src/tools/clippy/clippy_lints/src/unused_async.rs +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { } fn visit_body(&mut self, b: &'tcx Body<'tcx>) { - let is_async_block = matches!(b.generator_kind, Some(rustc_hir::CoroutineKind::Async(_))); + let is_async_block = matches!(b.coroutine_kind, Some(rustc_hir::CoroutineKind::Async(_))); if is_async_block { self.async_depth += 1; diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 0d8fd9d2adf..f6096ea546d 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -306,7 +306,7 @@ fn check_terminator<'tcx>( }, TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body), TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => { - Err((span, "const fn generators are unstable".into())) + Err((span, "const fn coroutines are unstable".into())) }, TerminatorKind::Call { func, diff --git a/src/tools/clippy/tests/ui/crashes/ice-5238.rs b/src/tools/clippy/tests/ui/crashes/ice-5238.rs index 989eb6d4485..b1fc3fb9d25 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5238.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5238.rs @@ -1,6 +1,6 @@ // Regression test for #5238 / https://github.com/rust-lang/rust/pull/69562 -#![feature(generators, generator_trait)] +#![feature(coroutines, coroutine_trait)] fn main() { let _ = || { diff --git a/src/tools/clippy/tests/ui/large_futures.fixed b/src/tools/clippy/tests/ui/large_futures.fixed index 4c192d1c8d1..aa8c3021b97 100644 --- a/src/tools/clippy/tests/ui/large_futures.fixed +++ b/src/tools/clippy/tests/ui/large_futures.fixed @@ -1,4 +1,4 @@ -#![feature(generators)] +#![feature(coroutines)] #![warn(clippy::large_futures)] #![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] diff --git a/src/tools/clippy/tests/ui/large_futures.rs b/src/tools/clippy/tests/ui/large_futures.rs index 557d89a9cf9..fc6ea458d3d 100644 --- a/src/tools/clippy/tests/ui/large_futures.rs +++ b/src/tools/clippy/tests/ui/large_futures.rs @@ -1,4 +1,4 @@ -#![feature(generators)] +#![feature(coroutines)] #![warn(clippy::large_futures)] #![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 0dc472bc486..690c6619aba 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -492,7 +492,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // `Variants::Multiple`. match v.layout.variants { Variants::Multiple { .. } => { - // A multi-variant enum, or generator, or so. + // A multi-variant enum, or coroutine, or so. // Treat this like a union: without reading from memory, // we cannot determine the variant we are in. Reading from // memory would be subject to Stacked Borrows rules, leading diff --git a/src/tools/miri/tests/fail/generator-pinned-moved.rs b/src/tools/miri/tests/fail/generator-pinned-moved.rs index 5a1dbc8a0ed..005ae7e9132 100644 --- a/src/tools/miri/tests/fail/generator-pinned-moved.rs +++ b/src/tools/miri/tests/fail/generator-pinned-moved.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -#![feature(generators, generator_trait)] +#![feature(coroutines, coroutine_trait)] use std::{ ops::{Coroutine, CoroutineState}, @@ -35,12 +35,12 @@ where } fn main() { - let mut generator_iterator_2 = { - let mut generator_iterator = Box::new(CoroutineIteratorAdapter(firstn())); - generator_iterator.next(); // pin it + let mut coroutine_iterator_2 = { + let mut coroutine_iterator = Box::new(CoroutineIteratorAdapter(firstn())); + coroutine_iterator.next(); // pin it - Box::new(*generator_iterator) // move it - }; // *deallocate* generator_iterator + Box::new(*coroutine_iterator) // move it + }; // *deallocate* coroutine_iterator - generator_iterator_2.next(); // and use moved value + coroutine_iterator_2.next(); // and use moved value } diff --git a/src/tools/miri/tests/fail/generator-pinned-moved.stderr b/src/tools/miri/tests/fail/generator-pinned-moved.stderr index 7465ec2bc83..547b63f7e2c 100644 --- a/src/tools/miri/tests/fail/generator-pinned-moved.stderr +++ b/src/tools/miri/tests/fail/generator-pinned-moved.stderr @@ -9,25 +9,25 @@ LL | *num += 1; help: ALLOC was allocated here: --> $DIR/generator-pinned-moved.rs:LL:CC | -LL | let mut generator_iterator = Box::new(CoroutineIteratorAdapter(firstn())); +LL | let mut coroutine_iterator = Box::new(CoroutineIteratorAdapter(firstn())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: ALLOC was deallocated here: --> $DIR/generator-pinned-moved.rs:LL:CC | -LL | }; // *deallocate* generator_iterator +LL | }; // *deallocate* coroutine_iterator | ^ = note: BACKTRACE (of the first span): = note: inside closure at $DIR/generator-pinned-moved.rs:LL:CC -note: inside `<CoroutineIteratorAdapter<{static generator@$DIR/generator-pinned-moved.rs:LL:CC}> as std::iter::Iterator>::next` +note: inside `<CoroutineIteratorAdapter<{static coroutine@$DIR/generator-pinned-moved.rs:LL:CC}> as std::iter::Iterator>::next` --> $DIR/generator-pinned-moved.rs:LL:CC | LL | match me.resume(()) { | ^^^^^^^^^^^^^ - = note: inside `<std::boxed::Box<CoroutineIteratorAdapter<{static generator@$DIR/generator-pinned-moved.rs:LL:CC}>> as std::iter::Iterator>::next` at RUSTLIB/alloc/src/boxed.rs:LL:CC + = note: inside `<std::boxed::Box<CoroutineIteratorAdapter<{static coroutine@$DIR/generator-pinned-moved.rs:LL:CC}>> as std::iter::Iterator>::next` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` --> $DIR/generator-pinned-moved.rs:LL:CC | -LL | generator_iterator_2.next(); // and use moved value +LL | coroutine_iterator_2.next(); // and use moved value | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/pass/generator.rs b/src/tools/miri/tests/pass/coroutine.rs index a1d3e9462bf..49bfa92a052 100644 --- a/src/tools/miri/tests/pass/generator.rs +++ b/src/tools/miri/tests/pass/coroutine.rs @@ -1,6 +1,6 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -#![feature(generators, generator_trait, never_type)] +#![feature(coroutines, coroutine_trait, never_type)] use std::fmt::Debug; use std::mem::ManuallyDrop; @@ -21,8 +21,8 @@ fn basic() { let mut t = unsafe { Pin::new_unchecked(&mut t) }; loop { let state = t.as_mut().resume(()); - // Test if the generator is valid (according to type invariants). - // For self-referential generators however this is UB! + // Test if the coroutine is valid (according to type invariants). + // For self-referential coroutines however this is UB! if !self_referential { let _ = unsafe { ManuallyDrop::new(ptr::read(t.as_mut().get_unchecked_mut())) }; } @@ -86,7 +86,7 @@ fn basic() { yield 1; }); - // also test self-referential generators + // also test self-referential coroutines assert_eq!( finish(5, true, static || { let mut x = 5; @@ -145,7 +145,7 @@ fn smoke_resume_arg() { for (input, out) in inout { assert_eq!(gen.as_mut().resume(input), out); - // Test if the generator is valid (according to type invariants). + // Test if the coroutine is valid (according to type invariants). let _ = unsafe { ManuallyDrop::new(ptr::read(gen.as_mut().get_unchecked_mut())) }; } } diff --git a/src/tools/miri/tests/pass/move-data-across-await-point.rs b/src/tools/miri/tests/pass/move-data-across-await-point.rs index 489fae66ffb..5990d66fbdd 100644 --- a/src/tools/miri/tests/pass/move-data-across-await-point.rs +++ b/src/tools/miri/tests/pass/move-data-across-await-point.rs @@ -15,7 +15,7 @@ async fn data_moved_async() { // `raw_pointer` points to the original location where the Vec was stored in the caller. // `data` is where that Vec (to be precise, its ptr+capacity+len on-stack data) // got moved to. Those will usually not be the same since the Vec got moved twice - // (into the function call, and then into the generator upvar). + // (into the function call, and then into the coroutine upvar). assert_ne!(raw_pointer, raw_pointer2); unsafe { // This writes into the `x` in `data_moved_async`, re-initializing it. diff --git a/src/tools/miri/tests/pass/stacked-borrows/generators-self-referential.rs b/src/tools/miri/tests/pass/stacked-borrows/generators-self-referential.rs index d727cf6e886..c4b15c8758b 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/generators-self-referential.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/generators-self-referential.rs @@ -1,6 +1,6 @@ // See https://github.com/rust-lang/unsafe-code-guidelines/issues/148: // this fails when Stacked Borrows is strictly applied even to `!Unpin` types. -#![feature(generators, generator_trait)] +#![feature(coroutines, coroutine_trait)] use std::{ ops::{Coroutine, CoroutineState}, @@ -24,8 +24,8 @@ fn firstn() -> impl Coroutine<Yield = u64, Return = ()> { } fn main() { - let mut generator_iterator = firstn(); - let mut pin = unsafe { Pin::new_unchecked(&mut generator_iterator) }; + let mut coroutine_iterator = firstn(); + let mut pin = unsafe { Pin::new_unchecked(&mut coroutine_iterator) }; let mut sum = 0; while let CoroutineState::Yielded(x) = pin.as_mut().resume(()) { sum += x; diff --git a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs b/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs index d2ba1841844..dd3ee36f988 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs @@ -223,7 +223,7 @@ fn wide_raw_ptr_in_tuple() { fn not_unpin_not_protected() { // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also // don't add protectors. (We could, but until we have a better idea for where we want to go with - // the self-referential-generator situation, it does not seem worth the potential trouble.) + // the self-referential-coroutine situation, it does not seem worth the potential trouble.) use std::marker::PhantomPinned; pub struct NotUnpin(i32, PhantomPinned); diff --git a/src/tools/miri/tests/pass/track-caller-attribute.rs b/src/tools/miri/tests/pass/track-caller-attribute.rs index bf59617d80f..d88bcc98858 100644 --- a/src/tools/miri/tests/pass/track-caller-attribute.rs +++ b/src/tools/miri/tests/pass/track-caller-attribute.rs @@ -1,8 +1,8 @@ #![feature(core_intrinsics)] #![feature(stmt_expr_attributes)] #![feature(closure_track_caller)] -#![feature(generator_trait)] -#![feature(generators)] +#![feature(coroutine_trait)] +#![feature(coroutines)] use std::ops::{Coroutine, CoroutineState}; use std::panic::Location; @@ -210,9 +210,9 @@ fn test_closure() { assert_eq!(non_tracked_loc.column(), 33); } -fn test_generator() { +fn test_coroutine() { #[track_caller] - fn mono_generator<F: Coroutine<String, Yield = (&'static str, String, Loc), Return = ()>>( + fn mono_coroutine<F: Coroutine<String, Yield = (&'static str, String, Loc), Return = ()>>( val: Pin<&mut F>, ) -> (&'static str, String, Loc) { match val.resume("Mono".to_string()) { @@ -222,7 +222,7 @@ fn test_generator() { } #[track_caller] - fn dyn_generator( + fn dyn_coroutine( val: Pin<&mut dyn Coroutine<String, Yield = (&'static str, String, Loc), Return = ()>>, ) -> (&'static str, String, Loc) { match val.resume("Dyn".to_string()) { @@ -232,32 +232,32 @@ fn test_generator() { } #[rustfmt::skip] - let generator = #[track_caller] |arg: String| { + let coroutine = #[track_caller] |arg: String| { yield ("first", arg.clone(), Location::caller()); yield ("second", arg.clone(), Location::caller()); }; - let mut pinned = Box::pin(generator); - let (dyn_ret, dyn_arg, dyn_loc) = dyn_generator(pinned.as_mut()); + let mut pinned = Box::pin(coroutine); + let (dyn_ret, dyn_arg, dyn_loc) = dyn_coroutine(pinned.as_mut()); assert_eq!(dyn_ret, "first"); assert_eq!(dyn_arg, "Dyn".to_string()); // The `Coroutine` trait does not have `#[track_caller]` on `resume`, so // this will not match. assert_ne!(dyn_loc.file(), file!()); - let (mono_ret, mono_arg, mono_loc) = mono_generator(pinned.as_mut()); + let (mono_ret, mono_arg, mono_loc) = mono_coroutine(pinned.as_mut()); let mono_line = line!() - 1; assert_eq!(mono_ret, "second"); - // The generator ignores the argument to the second `resume` call + // The coroutine ignores the argument to the second `resume` call assert_eq!(mono_arg, "Dyn".to_string()); assert_eq!(mono_loc.file(), file!()); assert_eq!(mono_loc.line(), mono_line); assert_eq!(mono_loc.column(), 42); #[rustfmt::skip] - let non_tracked_generator = || { yield Location::caller(); }; - let non_tracked_line = line!() - 1; // This is the line of the generator, not its caller - let non_tracked_loc = match Box::pin(non_tracked_generator).as_mut().resume(()) { + let non_tracked_coroutine = || { yield Location::caller(); }; + let non_tracked_line = line!() - 1; // This is the line of the coroutine, not its caller + let non_tracked_loc = match Box::pin(non_tracked_coroutine).as_mut().resume(()) { CoroutineState::Yielded(val) => val, _ => unreachable!(), }; @@ -272,5 +272,5 @@ fn main() { test_trait_obj(); test_trait_obj2(); test_closure(); - test_generator(); + test_coroutine(); } diff --git a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs index 89752bffe9f..d45be91afcc 100644 --- a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs +++ b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs @@ -315,7 +315,7 @@ fn wide_raw_ptr_in_tuple() { fn not_unpin_not_protected() { // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also // don't add protectors. (We could, but until we have a better idea for where we want to go with - // the self-referential-generator situation, it does not seem worth the potential trouble.) + // the self-referential-coroutine situation, it does not seem worth the potential trouble.) use std::marker::PhantomPinned; pub struct NotUnpin(i32, PhantomPinned); diff --git a/src/tools/rustfmt/tests/source/immovable_generators.rs b/src/tools/rustfmt/tests/source/immovable_generators.rs index c57a1e14483..3b94af0c96c 100644 --- a/src/tools/rustfmt/tests/source/immovable_generators.rs +++ b/src/tools/rustfmt/tests/source/immovable_generators.rs @@ -1,4 +1,4 @@ -#![feature(generators)] +#![feature(coroutines)] unsafe fn foo() { let mut ga = static || { diff --git a/src/tools/rustfmt/tests/target/immovable_generators.rs b/src/tools/rustfmt/tests/target/immovable_generators.rs index 0bf7a2d91ba..f52cfa00f97 100644 --- a/src/tools/rustfmt/tests/target/immovable_generators.rs +++ b/src/tools/rustfmt/tests/target/immovable_generators.rs @@ -1,4 +1,4 @@ -#![feature(generators)] +#![feature(coroutines)] unsafe fn foo() { let mut ga = static || { diff --git a/src/tools/rustfmt/tests/target/issue_4110.rs b/src/tools/rustfmt/tests/target/issue_4110.rs index d3734e90b7f..ea8fa3b73d2 100644 --- a/src/tools/rustfmt/tests/target/issue_4110.rs +++ b/src/tools/rustfmt/tests/target/issue_4110.rs @@ -12,7 +12,7 @@ fn bindings() { span, .. }, - ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self + ) if borrow_spans.for_coroutine() | borrow_spans.for_closure() => self .report_escaping_closure_capture( borrow_spans, borrow_span, |
