mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Add iter macro
This adds an `iter!` macro that can be used to create movable generators. This also adds a yield_expr feature so the `yield` keyword can be used within iter! macro bodies. This was needed because several unstable features each need `yield` expressions, so this allows us to stabilize them separately from any individual feature. Co-authored-by: Oli Scherer <github35764891676564198441@oli-obk.de> Co-authored-by: Jieyou Xu <jieyouxu@outlook.com> Co-authored-by: Travis Cross <tc@traviscross.com>
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::ops::ControlFlow;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -1199,11 +1198,13 @@ fn lower_expr_coroutine_closure(
|
||||
let closure_def_id = self.local_def_id(closure_id);
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
assert_matches!(
|
||||
coroutine_kind,
|
||||
CoroutineKind::Async { .. },
|
||||
"only async closures are supported currently"
|
||||
);
|
||||
let coroutine_desugaring = match coroutine_kind {
|
||||
CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
|
||||
CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
|
||||
CoroutineKind::AsyncGen { span, .. } => {
|
||||
span_bug!(span, "only async closures and `iter!` closures are supported currently")
|
||||
}
|
||||
};
|
||||
|
||||
let body = self.with_new_scopes(fn_decl_span, |this| {
|
||||
let inner_decl =
|
||||
@@ -1247,7 +1248,7 @@ fn lower_expr_coroutine_closure(
|
||||
// Lower this as a `CoroutineClosure`. That will ensure that HIR typeck
|
||||
// knows that a `FnDecl` output type like `-> &str` actually means
|
||||
// "coroutine that returns &str", rather than directly returning a `&str`.
|
||||
kind: hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async),
|
||||
kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring),
|
||||
constness: hir::Constness::NotConst,
|
||||
});
|
||||
hir::ExprKind::Closure(c)
|
||||
|
||||
@@ -477,11 +477,12 @@ macro_rules! gate_all {
|
||||
for span in spans {
|
||||
if (!visitor.features.coroutines() && !span.allows_unstable(sym::coroutines))
|
||||
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
|
||||
&& (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr))
|
||||
{
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
// Don't know which of the two features to include in the
|
||||
// error message, so I am arbitrarily picking one.
|
||||
feature_err(&visitor.sess, sym::coroutines, *span, "yield syntax is experimental")
|
||||
// Emit yield_expr as the error, since that will be sufficient. You can think of it
|
||||
// as coroutines and gen_blocks imply yield_expr.
|
||||
feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ pub(super) fn check_signature_annotation(&mut self) {
|
||||
assert_matches!(
|
||||
self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)),
|
||||
Some(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::Gen,
|
||||
hir::CoroutineSource::Closure
|
||||
)),
|
||||
"this needs to be modified if we're lowering non-async closures"
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{CoroutineKind, DUMMY_NODE_ID, Expr, ast, token};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
|
||||
use rustc_span::Span;
|
||||
|
||||
pub(crate) fn expand<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> MacroExpanderResult<'cx> {
|
||||
let closure = match parse_closure(cx, sp, tts) {
|
||||
Ok(parsed) => parsed,
|
||||
Err(err) => {
|
||||
return ExpandResult::Ready(DummyResult::any(sp, err.emit()));
|
||||
}
|
||||
};
|
||||
|
||||
ExpandResult::Ready(base::MacEager::expr(closure))
|
||||
}
|
||||
|
||||
fn parse_closure<'a>(
|
||||
cx: &mut ExtCtxt<'a>,
|
||||
span: Span,
|
||||
stream: TokenStream,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let mut closure_parser = cx.new_parser_from_tts(stream);
|
||||
|
||||
let coroutine_kind = Some(CoroutineKind::Gen {
|
||||
span,
|
||||
closure_id: DUMMY_NODE_ID,
|
||||
return_impl_trait_id: DUMMY_NODE_ID,
|
||||
});
|
||||
|
||||
let mut closure = closure_parser.parse_expr()?;
|
||||
match &mut closure.kind {
|
||||
ast::ExprKind::Closure(c) => {
|
||||
if let Some(kind) = c.coroutine_kind {
|
||||
cx.dcx().span_err(kind.span(), "only plain closures allowed in `iter!`");
|
||||
}
|
||||
c.coroutine_kind = coroutine_kind;
|
||||
if closure_parser.token != token::Eof {
|
||||
closure_parser.unexpected()?;
|
||||
}
|
||||
Ok(closure)
|
||||
}
|
||||
_ => {
|
||||
cx.dcx().span_err(closure.span, "`iter!` body must be a closure");
|
||||
Err(closure_parser.unexpected().unwrap_err())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,7 @@
|
||||
mod format;
|
||||
mod format_foreign;
|
||||
mod global_allocator;
|
||||
mod iter;
|
||||
mod log_syntax;
|
||||
mod pattern_type;
|
||||
mod source_util;
|
||||
@@ -95,6 +96,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
||||
include: source_util::expand_include,
|
||||
include_bytes: source_util::expand_include_bytes,
|
||||
include_str: source_util::expand_include_str,
|
||||
iter: iter::expand,
|
||||
line: source_util::expand_line,
|
||||
log_syntax: log_syntax::expand_log_syntax,
|
||||
module_path: source_util::expand_mod,
|
||||
|
||||
@@ -589,12 +589,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
|
||||
Rvalue::Aggregate(kind, ..) => {
|
||||
if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref()
|
||||
&& let Some(
|
||||
coroutine_kind @ hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
_,
|
||||
),
|
||||
) = self.tcx.coroutine_kind(def_id)
|
||||
&& let Some(coroutine_kind) = self.tcx.coroutine_kind(def_id)
|
||||
{
|
||||
self.check_op(ops::Coroutine(coroutine_kind));
|
||||
}
|
||||
|
||||
@@ -486,24 +486,25 @@ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
pub(crate) struct Coroutine(pub hir::CoroutineKind);
|
||||
impl<'tcx> NonConstOp<'tcx> for Coroutine {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if let hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Block,
|
||||
) = self.0
|
||||
{
|
||||
Status::Unstable {
|
||||
match self.0 {
|
||||
hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Async,
|
||||
hir::CoroutineSource::Block,
|
||||
)
|
||||
// FIXME(coroutines): eventually we want to gate const coroutine coroutines behind a
|
||||
// different feature.
|
||||
| hir::CoroutineKind::Coroutine(_) => Status::Unstable {
|
||||
gate: sym::const_async_blocks,
|
||||
gate_already_checked: false,
|
||||
safe_to_expose_on_stable: false,
|
||||
is_function_call: false,
|
||||
}
|
||||
} else {
|
||||
Status::Forbidden
|
||||
},
|
||||
_ => Status::Forbidden,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind());
|
||||
let msg = format!("{} are not allowed in {}s", self.0.to_plural_string(), ccx.const_kind());
|
||||
if let Status::Unstable { gate, .. } = self.status_in_item(ccx) {
|
||||
ccx.tcx.sess.create_feature_err(errors::UnallowedOpInConstContext { span, msg }, gate)
|
||||
} else {
|
||||
|
||||
@@ -2061,12 +2061,19 @@ pub fn movability(self) -> Movability {
|
||||
CoroutineKind::Coroutine(mov) => mov,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CoroutineKind {
|
||||
pub fn is_fn_like(self) -> bool {
|
||||
matches!(self, CoroutineKind::Desugared(_, CoroutineSource::Fn))
|
||||
}
|
||||
|
||||
pub fn to_plural_string(&self) -> String {
|
||||
match self {
|
||||
CoroutineKind::Desugared(d, CoroutineSource::Fn) => format!("{d:#}fn bodies"),
|
||||
CoroutineKind::Desugared(d, CoroutineSource::Block) => format!("{d:#}blocks"),
|
||||
CoroutineKind::Desugared(d, CoroutineSource::Closure) => format!("{d:#}closure bodies"),
|
||||
CoroutineKind::Coroutine(_) => "coroutines".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CoroutineKind {
|
||||
|
||||
@@ -204,14 +204,19 @@ pub(crate) fn check_expr_closure(
|
||||
)
|
||||
}
|
||||
hir::ClosureKind::CoroutineClosure(kind) => {
|
||||
// async closures always return the type ascribed after the `->` (if present),
|
||||
// and yield `()`.
|
||||
let (bound_return_ty, bound_yield_ty) = match kind {
|
||||
hir::CoroutineDesugaring::Gen => {
|
||||
// `iter!` closures always return unit and yield the `Iterator::Item` type
|
||||
// that we have to infer.
|
||||
(tcx.types.unit, self.infcx.next_ty_var(expr_span))
|
||||
}
|
||||
hir::CoroutineDesugaring::Async => {
|
||||
// async closures always return the type ascribed after the `->` (if present),
|
||||
// and yield `()`.
|
||||
(bound_sig.skip_binder().output(), tcx.types.unit)
|
||||
}
|
||||
hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen => {
|
||||
todo!("`gen` and `async gen` closures not supported yet")
|
||||
hir::CoroutineDesugaring::AsyncGen => {
|
||||
todo!("`async gen` closures not supported yet")
|
||||
}
|
||||
};
|
||||
// Compute all of the variables that will be used to populate the coroutine.
|
||||
@@ -465,7 +470,12 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
|
||||
if let Some(trait_def_id) = trait_def_id {
|
||||
let found_kind = match closure_kind {
|
||||
hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id),
|
||||
hir::ClosureKind::Closure
|
||||
// FIXME(iter_macro): Someday we'll probably want iterator closures instead of
|
||||
// just using Fn* for iterators.
|
||||
| hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => {
|
||||
self.tcx.fn_trait_kind_from_def_id(trait_def_id)
|
||||
}
|
||||
hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => self
|
||||
.tcx
|
||||
.async_fn_trait_kind_from_def_id(trait_def_id)
|
||||
|
||||
@@ -713,7 +713,7 @@ pub(super) fn parse_block_common(
|
||||
|
||||
/// Parses the rest of a block expression or function body.
|
||||
/// Precondition: already parsed the '{'.
|
||||
pub(crate) fn parse_block_tail(
|
||||
pub fn parse_block_tail(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
s: BlockCheckMode,
|
||||
|
||||
@@ -72,8 +72,6 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur
|
||||
|
||||
trait_selection_ascribe_user_type_prove_predicate = ...so that the where clause holds
|
||||
|
||||
trait_selection_async_closure_not_fn = async closure does not implement `{$kind}` because it captures state from its environment
|
||||
|
||||
trait_selection_await_both_futures = consider `await`ing on both `Future`s
|
||||
trait_selection_await_future = consider `await`ing on the `Future`
|
||||
trait_selection_await_note = calling an async function returns a future
|
||||
@@ -123,6 +121,8 @@ trait_selection_closure_kind_requirement = the requirement to implement `{$trait
|
||||
|
||||
trait_selection_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
|
||||
trait_selection_consider_specifying_length = consider specifying the actual array length
|
||||
trait_selection_coro_closure_not_fn = {$coro_kind}closure does not implement `{$kind}` because it captures state from its environment
|
||||
|
||||
trait_selection_data_flows = ...but data{$label_var1_exists ->
|
||||
[true] {" "}from `{$label_var1}`
|
||||
*[false] {""}
|
||||
|
||||
@@ -42,9 +42,7 @@
|
||||
use crate::error_reporting::TypeErrCtxt;
|
||||
use crate::error_reporting::infer::TyCategory;
|
||||
use crate::error_reporting::traits::report_dyn_incompatibility;
|
||||
use crate::errors::{
|
||||
AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch,
|
||||
};
|
||||
use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, CoroClosureNotFn};
|
||||
use crate::infer::{self, InferCtxt, InferCtxtExt as _};
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use crate::traits::{
|
||||
@@ -886,9 +884,18 @@ fn emit_specialized_closure_kind_error(
|
||||
// is unimplemented is because async closures don't implement `Fn`/`FnMut`
|
||||
// if they have captures.
|
||||
if has_self_borrows && expected_kind != ty::ClosureKind::FnOnce {
|
||||
let mut err = self.dcx().create_err(AsyncClosureNotFn {
|
||||
let coro_kind = match self
|
||||
.tcx
|
||||
.coroutine_kind(self.tcx.coroutine_for_closure(closure_def_id))
|
||||
.unwrap()
|
||||
{
|
||||
rustc_hir::CoroutineKind::Desugared(desugaring, _) => desugaring.to_string(),
|
||||
coro => coro.to_string(),
|
||||
};
|
||||
let mut err = self.dcx().create_err(CoroClosureNotFn {
|
||||
span: self.tcx.def_span(closure_def_id),
|
||||
kind: expected_kind.as_str(),
|
||||
coro_kind,
|
||||
});
|
||||
self.note_obligation_cause(&mut err, &obligation);
|
||||
return Some(err.emit());
|
||||
|
||||
@@ -201,11 +201,12 @@ pub struct ClosureFnMutLabel {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(trait_selection_async_closure_not_fn)]
|
||||
pub(crate) struct AsyncClosureNotFn {
|
||||
#[diag(trait_selection_coro_closure_not_fn)]
|
||||
pub(crate) struct CoroClosureNotFn {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub kind: &'static str,
|
||||
pub coro_kind: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
use hir::LangItem;
|
||||
use hir::def_id::DefId;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind};
|
||||
use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
|
||||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode, elaborate};
|
||||
@@ -438,6 +438,7 @@ fn assemble_closure_candidates(
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, candidates))]
|
||||
fn assemble_async_closure_candidates(
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
@@ -446,15 +447,30 @@ fn assemble_async_closure_candidates(
|
||||
let goal_kind =
|
||||
self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap();
|
||||
|
||||
debug!("self_ty = {:?}", obligation.self_ty().skip_binder().kind());
|
||||
match *obligation.self_ty().skip_binder().kind() {
|
||||
ty::CoroutineClosure(_, args) => {
|
||||
ty::CoroutineClosure(def_id, args) => {
|
||||
if let Some(closure_kind) =
|
||||
args.as_coroutine_closure().kind_ty().to_opt_closure_kind()
|
||||
&& !closure_kind.extends(goal_kind)
|
||||
{
|
||||
return;
|
||||
}
|
||||
candidates.vec.push(AsyncClosureCandidate);
|
||||
|
||||
// Make sure this is actually an async closure.
|
||||
let Some(coroutine_kind) =
|
||||
self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(def_id))
|
||||
else {
|
||||
bug!("coroutine with no kind");
|
||||
};
|
||||
|
||||
debug!(?coroutine_kind);
|
||||
match coroutine_kind {
|
||||
CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
|
||||
candidates.vec.push(AsyncClosureCandidate);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
// Closures and fn pointers implement `AsyncFn*` if their return types
|
||||
// implement `Future`, which is checked later.
|
||||
|
||||
@@ -420,6 +420,8 @@ fn $fold<AAA, FFF>(mut self, init: AAA, fold: FFF) -> AAA
|
||||
issue = "42168"
|
||||
)]
|
||||
pub use self::range::Step;
|
||||
#[unstable(feature = "iter_macro", issue = "none", reason = "generators are unstable")]
|
||||
pub use self::sources::iter;
|
||||
#[stable(feature = "iter_empty", since = "1.2.0")]
|
||||
pub use self::sources::{Empty, empty};
|
||||
#[unstable(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
mod empty;
|
||||
mod from_coroutine;
|
||||
mod from_fn;
|
||||
mod generator;
|
||||
mod once;
|
||||
mod once_with;
|
||||
mod repeat;
|
||||
@@ -18,6 +19,8 @@
|
||||
pub use self::from_coroutine::{FromCoroutine, from_coroutine};
|
||||
#[stable(feature = "iter_from_fn", since = "1.34.0")]
|
||||
pub use self::from_fn::{FromFn, from_fn};
|
||||
#[unstable(feature = "iter_macro", issue = "none", reason = "generators are unstable")]
|
||||
pub use self::generator::iter;
|
||||
#[stable(feature = "iter_once", since = "1.2.0")]
|
||||
pub use self::once::{Once, once};
|
||||
#[stable(feature = "iter_once_with", since = "1.43.0")]
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/// Creates a new closure that returns an iterator where each iteration steps the given
|
||||
/// generator to the next `yield` statement.
|
||||
///
|
||||
/// Similar to [`iter::from_fn`], but allows arbitrary control flow.
|
||||
///
|
||||
/// [`iter::from_fn`]: crate::iter::from_fn
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_macro, coroutines)]
|
||||
/// # #[cfg(not(bootstrap))]
|
||||
/// # {
|
||||
///
|
||||
/// let it = std::iter::iter!{|| {
|
||||
/// yield 1;
|
||||
/// yield 2;
|
||||
/// yield 3;
|
||||
/// } }();
|
||||
/// let v: Vec<_> = it.collect();
|
||||
/// assert_eq!(v, [1, 2, 3]);
|
||||
/// # }
|
||||
/// ```
|
||||
#[unstable(feature = "iter_macro", issue = "none", reason = "generators are unstable")]
|
||||
#[allow_internal_unstable(coroutines, iter_from_coroutine)]
|
||||
#[cfg_attr(not(bootstrap), rustc_builtin_macro)]
|
||||
pub macro iter($($t:tt)*) {
|
||||
/* compiler-builtin */
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#![feature(iter_macro, yield_expr)]
|
||||
|
||||
use std::iter::iter;
|
||||
|
||||
fn main() {
|
||||
let i = iter! { || {
|
||||
yield 0;
|
||||
for x in 5..10 {
|
||||
yield x * 2;
|
||||
}
|
||||
} };
|
||||
let mut i = i();
|
||||
assert_eq!(i.next(), Some(0));
|
||||
assert_eq!(i.next(), Some(10));
|
||||
assert_eq!(i.next(), Some(12));
|
||||
assert_eq!(i.next(), Some(14));
|
||||
assert_eq!(i.next(), Some(16));
|
||||
assert_eq!(i.next(), Some(18));
|
||||
assert_eq!(i.next(), None);
|
||||
assert_eq!(i.next(), None);
|
||||
assert_eq!(i.next(), None);
|
||||
}
|
||||
@@ -4,8 +4,10 @@
|
||||
|
||||
const gen fn a() {}
|
||||
//~^ ERROR functions cannot be both `const` and `gen`
|
||||
//~^^ ERROR `gen` fn bodies are not allowed in constant functions
|
||||
|
||||
const async gen fn b() {}
|
||||
//~^ ERROR functions cannot be both `const` and `async gen`
|
||||
//~^^ ERROR `async gen` fn bodies are not allowed in constant functions
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -8,7 +8,7 @@ LL | const gen fn a() {}
|
||||
| `const` because of this
|
||||
|
||||
error: functions cannot be both `const` and `async gen`
|
||||
--> $DIR/const_gen_fn.rs:8:1
|
||||
--> $DIR/const_gen_fn.rs:9:1
|
||||
|
|
||||
LL | const async gen fn b() {}
|
||||
| ^^^^^-^^^^^^^^^----------
|
||||
@@ -16,5 +16,17 @@ LL | const async gen fn b() {}
|
||||
| | `async gen` because of this
|
||||
| `const` because of this
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: `gen` fn bodies are not allowed in constant functions
|
||||
--> $DIR/const_gen_fn.rs:5:18
|
||||
|
|
||||
LL | const gen fn a() {}
|
||||
| ^^
|
||||
|
||||
error: `async gen` fn bodies are not allowed in constant functions
|
||||
--> $DIR/const_gen_fn.rs:9:24
|
||||
|
|
||||
LL | const async gen fn b() {}
|
||||
| ^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ LL | let _ = || yield true;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
|
||||
= help: add `#![feature(coroutines)]` to the crate attributes to enable
|
||||
= help: add `#![feature(yield_expr)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: yield syntax is experimental
|
||||
@@ -41,7 +41,7 @@ LL | let _ = #[coroutine] || yield true;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
|
||||
= help: add `#![feature(coroutines)]` to the crate attributes to enable
|
||||
= help: add `#![feature(yield_expr)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the `#[coroutine]` attribute is an experimental feature
|
||||
|
||||
@@ -5,7 +5,7 @@ LL | yield true;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
|
||||
= help: add `#![feature(coroutines)]` to the crate attributes to enable
|
||||
= help: add `#![feature(yield_expr)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: yield syntax is experimental
|
||||
@@ -15,7 +15,7 @@ LL | let _ = || yield true;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
|
||||
= help: add `#![feature(coroutines)]` to the crate attributes to enable
|
||||
= help: add `#![feature(yield_expr)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: yield syntax is experimental
|
||||
@@ -25,7 +25,7 @@ LL | yield;
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
|
||||
= help: add `#![feature(coroutines)]` to the crate attributes to enable
|
||||
= help: add `#![feature(yield_expr)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: yield syntax is experimental
|
||||
@@ -35,7 +35,7 @@ LL | yield 0;
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
|
||||
= help: add `#![feature(coroutines)]` to the crate attributes to enable
|
||||
= help: add `#![feature(yield_expr)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: yield syntax is experimental
|
||||
|
||||
@@ -5,7 +5,7 @@ LL | yield true;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
|
||||
= help: add `#![feature(coroutines)]` to the crate attributes to enable
|
||||
= help: add `#![feature(yield_expr)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: yield syntax is experimental
|
||||
@@ -15,7 +15,7 @@ LL | let _ = || yield true;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
|
||||
= help: add `#![feature(coroutines)]` to the crate attributes to enable
|
||||
= help: add `#![feature(yield_expr)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: yield syntax is experimental
|
||||
@@ -25,7 +25,7 @@ LL | yield;
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
|
||||
= help: add `#![feature(coroutines)]` to the crate attributes to enable
|
||||
= help: add `#![feature(yield_expr)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: yield syntax is experimental
|
||||
@@ -35,7 +35,7 @@ LL | yield 0;
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
|
||||
= help: add `#![feature(coroutines)]` to the crate attributes to enable
|
||||
= help: add `#![feature(yield_expr)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: yield syntax is experimental
|
||||
|
||||
@@ -5,7 +5,7 @@ LL | yield ();
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
|
||||
= help: add `#![feature(coroutines)]` to the crate attributes to enable
|
||||
= help: add `#![feature(yield_expr)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: yield syntax is experimental
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
//@ run-pass
|
||||
|
||||
#![feature(iter_macro, yield_expr)]
|
||||
|
||||
use std::iter::iter;
|
||||
|
||||
fn main() {
|
||||
let i = iter! { || {
|
||||
yield 0;
|
||||
for x in 5..10 {
|
||||
yield x * 2;
|
||||
}
|
||||
} };
|
||||
let mut i = i();
|
||||
assert_eq!(i.next(), Some(0));
|
||||
assert_eq!(i.next(), Some(10));
|
||||
assert_eq!(i.next(), Some(12));
|
||||
assert_eq!(i.next(), Some(14));
|
||||
assert_eq!(i.next(), Some(16));
|
||||
assert_eq!(i.next(), Some(18));
|
||||
assert_eq!(i.next(), None);
|
||||
assert_eq!(i.next(), None);
|
||||
assert_eq!(i.next(), None);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//@ run-pass
|
||||
|
||||
#![feature(iter_macro, yield_expr)]
|
||||
|
||||
use std::iter::iter;
|
||||
|
||||
fn main() {
|
||||
let i = iter! {|foo| {
|
||||
yield foo;
|
||||
for x in 5..10 {
|
||||
yield x * 2;
|
||||
}
|
||||
}};
|
||||
let mut i = i(3);
|
||||
assert_eq!(i.next(), Some(3));
|
||||
assert_eq!(i.next(), Some(10));
|
||||
assert_eq!(i.next(), Some(12));
|
||||
assert_eq!(i.next(), Some(14));
|
||||
assert_eq!(i.next(), Some(16));
|
||||
assert_eq!(i.next(), Some(18));
|
||||
assert_eq!(i.next(), None);
|
||||
assert_eq!(i.next(), None);
|
||||
assert_eq!(i.next(), None);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
//@ run-pass
|
||||
|
||||
#![feature(iter_macro, yield_expr)]
|
||||
|
||||
use std::iter::iter;
|
||||
|
||||
fn main() {
|
||||
let i = {
|
||||
let s = String::new();
|
||||
iter! { move || {
|
||||
yield s.len();
|
||||
for x in 5..10 {
|
||||
yield x * 2;
|
||||
}
|
||||
}}
|
||||
};
|
||||
let mut i = i();
|
||||
assert_eq!(i.next(), Some(0));
|
||||
assert_eq!(i.next(), Some(10));
|
||||
assert_eq!(i.next(), Some(12));
|
||||
assert_eq!(i.next(), Some(14));
|
||||
assert_eq!(i.next(), Some(16));
|
||||
assert_eq!(i.next(), Some(18));
|
||||
assert_eq!(i.next(), None);
|
||||
assert_eq!(i.next(), None);
|
||||
assert_eq!(i.next(), None);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// This test exercises lending behavior for iterator closures which is not yet supported.
|
||||
|
||||
#![feature(iter_macro, yield_expr)]
|
||||
|
||||
use std::iter::iter;
|
||||
|
||||
fn main() {
|
||||
let f = {
|
||||
let s = "foo".to_string();
|
||||
iter! { move || {
|
||||
for c in s.chars() {
|
||||
yield c;
|
||||
}
|
||||
}}
|
||||
};
|
||||
let mut i = f();
|
||||
assert_eq!(i.next(), Some('f'));
|
||||
assert_eq!(i.next(), Some('o'));
|
||||
assert_eq!(i.next(), Some('o'));
|
||||
assert_eq!(i.next(), None);
|
||||
let mut i = f(); //~ ERROR use of moved value: `f`
|
||||
assert_eq!(i.next(), Some('f'));
|
||||
assert_eq!(i.next(), Some('o'));
|
||||
assert_eq!(i.next(), Some('o'));
|
||||
assert_eq!(i.next(), None);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
error[E0382]: use of moved value: `f`
|
||||
--> $DIR/generator_capture_.rs:21:17
|
||||
|
|
||||
LL | let f = {
|
||||
| - move occurs because `f` has type `{gen closure@$DIR/generator_capture_.rs:10:17: 10:24}`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | let mut i = f();
|
||||
| --- `f` moved due to this call
|
||||
...
|
||||
LL | let mut i = f();
|
||||
| ^ value used here after move
|
||||
|
|
||||
note: this value implements `FnOnce`, which causes it to be moved when called
|
||||
--> $DIR/generator_capture_.rs:16:17
|
||||
|
|
||||
LL | let mut i = f();
|
||||
| ^
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | let mut i = f.clone()();
|
||||
| ++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
||||
@@ -0,0 +1,25 @@
|
||||
#![feature(iter_macro, yield_expr)]
|
||||
|
||||
use std::iter::iter;
|
||||
|
||||
fn main() {
|
||||
let i = {
|
||||
let s = String::new();
|
||||
iter! { || { //~ ERROR `s` does not live long enough
|
||||
yield s.len();
|
||||
for x in 5..10 {
|
||||
yield x * 2;
|
||||
}
|
||||
} }
|
||||
};
|
||||
let mut i = i();
|
||||
assert_eq!(i.next(), Some(0));
|
||||
assert_eq!(i.next(), Some(10));
|
||||
assert_eq!(i.next(), Some(12));
|
||||
assert_eq!(i.next(), Some(14));
|
||||
assert_eq!(i.next(), Some(16));
|
||||
assert_eq!(i.next(), Some(18));
|
||||
assert_eq!(i.next(), None);
|
||||
assert_eq!(i.next(), None);
|
||||
assert_eq!(i.next(), None);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
error[E0597]: `s` does not live long enough
|
||||
--> $DIR/generator_capture_fail.rs:8:17
|
||||
|
|
||||
LL | let i = {
|
||||
| - borrow later stored here
|
||||
LL | let s = String::new();
|
||||
LL | iter! { || {
|
||||
| _________________^
|
||||
LL | | yield s.len();
|
||||
LL | | for x in 5..10 {
|
||||
LL | | yield x * 2;
|
||||
LL | | }
|
||||
LL | | } }
|
||||
| |_________^ borrowed value does not live long enough
|
||||
LL | };
|
||||
| - `s` dropped here while still borrowed
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
||||
@@ -0,0 +1,32 @@
|
||||
//@ run-pass
|
||||
|
||||
#![feature(iter_macro, yield_expr)]
|
||||
|
||||
use std::iter::iter;
|
||||
|
||||
fn main() {
|
||||
let i = {
|
||||
let s = String::new();
|
||||
iter! { move || {
|
||||
yield s.len();
|
||||
for x in 5..10 {
|
||||
yield x * 2;
|
||||
}
|
||||
}}
|
||||
};
|
||||
test_iterator(i);
|
||||
}
|
||||
|
||||
/// Exercise the iterator in a separate function to ensure it's not capturing anything it shoudln't.
|
||||
fn test_iterator<I: Iterator<Item = usize>>(i: impl FnOnce() -> I) {
|
||||
let mut i = i();
|
||||
assert_eq!(i.next(), Some(0));
|
||||
assert_eq!(i.next(), Some(10));
|
||||
assert_eq!(i.next(), Some(12));
|
||||
assert_eq!(i.next(), Some(14));
|
||||
assert_eq!(i.next(), Some(16));
|
||||
assert_eq!(i.next(), Some(18));
|
||||
assert_eq!(i.next(), None);
|
||||
assert_eq!(i.next(), None);
|
||||
assert_eq!(i.next(), None);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
//@ run-pass
|
||||
|
||||
#![feature(iter_macro, yield_expr)]
|
||||
|
||||
// This test creates an iterator that captures a reference and ensure that doesn't force the
|
||||
// iterator to become lending.
|
||||
|
||||
use std::iter::iter;
|
||||
|
||||
fn main() {
|
||||
let s = "foo".to_string();
|
||||
let f = iter! { || {
|
||||
for c in s.chars() {
|
||||
yield c;
|
||||
}
|
||||
}};
|
||||
|
||||
let mut i = f();
|
||||
let mut j = f();
|
||||
|
||||
assert_eq!(i.next(), Some('f'));
|
||||
assert_eq!(i.next(), Some('o'));
|
||||
assert_eq!(i.next(), Some('o'));
|
||||
assert_eq!(i.next(), None);
|
||||
|
||||
assert_eq!(j.next(), Some('f'));
|
||||
assert_eq!(j.next(), Some('o'));
|
||||
assert_eq!(j.next(), Some('o'));
|
||||
assert_eq!(j.next(), None);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#![feature(iter_macro, impl_trait_in_fn_trait_return, yield_expr)]
|
||||
|
||||
use std::iter::iter;
|
||||
|
||||
fn plain() -> impl Fn() -> impl Iterator<Item = u32> {
|
||||
iter! { || {
|
||||
yield 0;
|
||||
for x in 5..10 {
|
||||
yield x * 2;
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
fn arg() -> impl Fn(u32) -> impl Iterator<Item = u32> {
|
||||
iter! { |arg| {
|
||||
yield arg;
|
||||
for x in 5..10 {
|
||||
yield x * 2;
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
fn capture<'a>(a: &'a u32) -> impl Fn() -> (impl Iterator<Item = u32> + 'a) {
|
||||
iter! { || { //~ ERROR cannot return reference to function parameter `a`
|
||||
yield *a;
|
||||
for x in 5..10 {
|
||||
yield x * 2;
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
fn capture_move(a: &u32) -> impl Fn() -> impl Iterator<Item = u32> {
|
||||
iter! { move || { //~ ERROR does not implement `Fn` because it captures
|
||||
yield *a;
|
||||
for x in 5..10 {
|
||||
yield x * 2;
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
fn capture_move_once(a: &u32) -> impl FnOnce() -> impl Iterator<Item = u32> {
|
||||
iter! { move || {
|
||||
//~^ ERROR captures lifetime
|
||||
//~| ERROR: captures lifetime
|
||||
yield *a;
|
||||
for x in 5..10 {
|
||||
yield x * 2;
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
fn capture_move_once_lifetimes<'a>(
|
||||
a: &'a u32,
|
||||
) -> impl FnOnce() -> (impl Iterator<Item = u32> + 'a) {
|
||||
iter! { move || {
|
||||
yield *a;
|
||||
for x in 5..10 {
|
||||
yield x * 2;
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,70 @@
|
||||
error[E0515]: cannot return reference to function parameter `a`
|
||||
--> $DIR/generator_returned_from_fn.rs:24:13
|
||||
|
|
||||
LL | iter! { || {
|
||||
| _____________^
|
||||
LL | | yield *a;
|
||||
LL | | for x in 5..10 {
|
||||
LL | | yield x * 2;
|
||||
LL | | }
|
||||
LL | | } }
|
||||
| |_____^ returns a reference to data owned by the current function
|
||||
|
||||
error: gen closure does not implement `Fn` because it captures state from its environment
|
||||
--> $DIR/generator_returned_from_fn.rs:33:13
|
||||
|
|
||||
LL | iter! { move || {
|
||||
| _____________-^^^^^^
|
||||
LL | | yield *a;
|
||||
LL | | for x in 5..10 {
|
||||
LL | | yield x * 2;
|
||||
LL | | }
|
||||
LL | | } }
|
||||
| |_____- return type was inferred to be `{gen closure@$DIR/generator_returned_from_fn.rs:33:13: 33:20}` here
|
||||
|
||||
error[E0700]: hidden type for `impl FnOnce() -> impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
|
||||
--> $DIR/generator_returned_from_fn.rs:42:13
|
||||
|
|
||||
LL | fn capture_move_once(a: &u32) -> impl FnOnce() -> impl Iterator<Item = u32> {
|
||||
| ---- ------------------------------------------ opaque type defined here
|
||||
| |
|
||||
| hidden type `{gen closure@$DIR/generator_returned_from_fn.rs:42:13: 42:20}` captures the anonymous lifetime defined here
|
||||
LL | iter! { move || {
|
||||
| _____________^
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | yield *a;
|
||||
... |
|
||||
LL | | } }
|
||||
| |_____^
|
||||
|
|
||||
help: add a `use<...>` bound to explicitly capture `'_`
|
||||
|
|
||||
LL | fn capture_move_once(a: &u32) -> impl FnOnce() -> impl Iterator<Item = u32> + use<'_> {
|
||||
| +++++++++
|
||||
|
||||
error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
|
||||
--> $DIR/generator_returned_from_fn.rs:42:13
|
||||
|
|
||||
LL | fn capture_move_once(a: &u32) -> impl FnOnce() -> impl Iterator<Item = u32> {
|
||||
| ---- ------------------------- opaque type defined here
|
||||
| |
|
||||
| hidden type `{gen closure body@$DIR/generator_returned_from_fn.rs:42:21: 49:6}` captures the anonymous lifetime defined here
|
||||
LL | iter! { move || {
|
||||
| _____________^
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | yield *a;
|
||||
... |
|
||||
LL | | } }
|
||||
| |_____^
|
||||
|
|
||||
help: add a `use<...>` bound to explicitly capture `'_`
|
||||
|
|
||||
LL | fn capture_move_once(a: &u32) -> impl FnOnce() -> impl Iterator<Item = u32> + use<'_> {
|
||||
| +++++++++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0515, E0700.
|
||||
For more information about an error, try `rustc --explain E0515`.
|
||||
@@ -0,0 +1,18 @@
|
||||
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure-simplified.rs:21:21: 21:28}: AsyncFnOnce()` is not satisfied
|
||||
--> $DIR/iter-macro-not-async-closure-simplified.rs:27:21
|
||||
|
|
||||
LL | call_async_once(f);
|
||||
| --------------- ^ unsatisfied trait bound
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure-simplified.rs:21:21: 21:28}`
|
||||
note: required by a bound in `call_async_once`
|
||||
--> $DIR/iter-macro-not-async-closure-simplified.rs:18:28
|
||||
|
|
||||
LL | ...pl AsyncFnOnce()) {}
|
||||
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -0,0 +1,29 @@
|
||||
// This test ensures iterators created with the `iter!` macro are not
|
||||
// accidentally async closures.
|
||||
//
|
||||
// We test this both in a `narrow` and `wide` configuration because
|
||||
// the way that the diagnostic is emitted varies depending on the
|
||||
// diagnostic width. If it's too narrow to fit the explanation, that
|
||||
// explanation is moved to the `help` instead of the span label.
|
||||
//
|
||||
//@ edition: 2024
|
||||
//@ revisions: narrow wide
|
||||
//@[narrow] compile-flags: --diagnostic-width=20
|
||||
//@[wide] compile-flags: --diagnostic-width=300
|
||||
|
||||
#![feature(yield_expr, iter_macro)]
|
||||
|
||||
use std::iter::iter;
|
||||
|
||||
fn call_async_once(_: impl AsyncFnOnce()) {}
|
||||
|
||||
fn main() {
|
||||
let f = iter! { move || {
|
||||
for i in 0..10 {
|
||||
yield i;
|
||||
}
|
||||
}};
|
||||
|
||||
call_async_once(f);
|
||||
//~^ ERROR AsyncFnOnce()` is not satisfied
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure-simplified.rs:21:21: 21:28}: AsyncFnOnce()` is not satisfied
|
||||
--> $DIR/iter-macro-not-async-closure-simplified.rs:27:21
|
||||
|
|
||||
LL | call_async_once(f);
|
||||
| --------------- ^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure-simplified.rs:21:21: 21:28}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `call_async_once`
|
||||
--> $DIR/iter-macro-not-async-closure-simplified.rs:18:28
|
||||
|
|
||||
LL | fn call_async_once(_: impl AsyncFnOnce()) {}
|
||||
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -0,0 +1,72 @@
|
||||
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}: AsyncFnOnce()` is not satisfied
|
||||
--> $DIR/iter-macro-not-async-closure.rs:32:34
|
||||
|
|
||||
LL | ...n!(call_async_once(f));
|
||||
| --------------- ^ unsatisfied trait bound
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}`
|
||||
note: required by a bound in `call_async_once`
|
||||
--> $DIR/iter-macro-not-async-closure.rs:21:34
|
||||
|
|
||||
LL | ...pl AsyncFnOnce()) {
|
||||
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
|
||||
|
||||
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}: AsyncFnOnce()` is not satisfied
|
||||
--> $DIR/iter-macro-not-async-closure.rs:32:18
|
||||
|
|
||||
LL | ...n!(call_async_once(f));
|
||||
| ^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
||||
|
|
||||
= help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}`
|
||||
note: required by a bound in `call_async_once`
|
||||
--> $DIR/iter-macro-not-async-closure.rs:21:34
|
||||
|
|
||||
LL | ...pl AsyncFnOnce()) {
|
||||
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
|
||||
|
||||
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}: AsyncFnOnce()` is not satisfied
|
||||
--> $DIR/iter-macro-not-async-closure.rs:32:13
|
||||
|
|
||||
LL | ... = pin!(call_async_once(f));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
||||
|
|
||||
= help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}`
|
||||
note: required by a bound in `call_async_once`
|
||||
--> $DIR/iter-macro-not-async-closure.rs:21:34
|
||||
|
|
||||
LL | ...pl AsyncFnOnce()) {
|
||||
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
|
||||
= note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}: AsyncFnOnce()` is not satisfied
|
||||
--> $DIR/iter-macro-not-async-closure.rs:32:13
|
||||
|
|
||||
LL | ... = pin!(call_async_once(f));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
||||
|
|
||||
= help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}`
|
||||
note: required by a bound in `call_async_once`
|
||||
--> $DIR/iter-macro-not-async-closure.rs:21:34
|
||||
|
|
||||
LL | ...pl AsyncFnOnce()) {
|
||||
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
|
||||
= note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}: AsyncFnOnce()` is not satisfied
|
||||
--> $DIR/iter-macro-not-async-closure.rs:37:5
|
||||
|
|
||||
LL | ...::noop()));
|
||||
| ...^^^^^^^^^^ unsatisfied trait bound
|
||||
|
|
||||
= help: the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:26:21: 26:28}`
|
||||
note: required by a bound in `call_async_once`
|
||||
--> $DIR/iter-macro-not-async-closure.rs:21:34
|
||||
|
|
||||
LL | ...pl AsyncFnOnce()) {
|
||||
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -0,0 +1,32 @@
|
||||
// This test ensures iterators created with the `iter!` macro are not
|
||||
// accidentally async closures.
|
||||
//
|
||||
//@ edition: 2024
|
||||
//@ remap-src-base
|
||||
|
||||
#![feature(yield_expr, iter_macro)]
|
||||
|
||||
use std::task::{Waker, Context};
|
||||
use std::iter::iter;
|
||||
use std::pin::pin;
|
||||
use std::future::Future;
|
||||
|
||||
async fn call_async_once(f: impl AsyncFnOnce()) {
|
||||
f().await
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let f = iter! { move || {
|
||||
for i in 0..10 {
|
||||
yield i;
|
||||
}
|
||||
}};
|
||||
|
||||
let x = pin!(call_async_once(f));
|
||||
//~^ ERROR AsyncFnOnce()` is not satisfied
|
||||
//~^^ ERROR AsyncFnOnce()` is not satisfied
|
||||
//~^^^ ERROR AsyncFnOnce()` is not satisfied
|
||||
//~^^^^ ERROR AsyncFnOnce()` is not satisfied
|
||||
x.poll(&mut Context::from_waker(Waker::noop()));
|
||||
//~^ ERROR AsyncFnOnce()` is not satisfied
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied
|
||||
--> $DIR/iter-macro-not-async-closure.rs:25:34
|
||||
|
|
||||
LL | let x = pin!(call_async_once(f));
|
||||
| --------------- ^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `call_async_once`
|
||||
--> $DIR/iter-macro-not-async-closure.rs:14:34
|
||||
|
|
||||
LL | async fn call_async_once(f: impl AsyncFnOnce()) {
|
||||
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
|
||||
|
||||
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied
|
||||
--> $DIR/iter-macro-not-async-closure.rs:25:18
|
||||
|
|
||||
LL | let x = pin!(call_async_once(f));
|
||||
| ^^^^^^^^^^^^^^^^^^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}`
|
||||
|
|
||||
note: required by a bound in `call_async_once`
|
||||
--> $DIR/iter-macro-not-async-closure.rs:14:34
|
||||
|
|
||||
LL | async fn call_async_once(f: impl AsyncFnOnce()) {
|
||||
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
|
||||
|
||||
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied
|
||||
--> $DIR/iter-macro-not-async-closure.rs:25:13
|
||||
|
|
||||
LL | let x = pin!(call_async_once(f));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}`
|
||||
|
|
||||
note: required by a bound in `call_async_once`
|
||||
--> $DIR/iter-macro-not-async-closure.rs:14:34
|
||||
|
|
||||
LL | async fn call_async_once(f: impl AsyncFnOnce()) {
|
||||
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
|
||||
= note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied
|
||||
--> $DIR/iter-macro-not-async-closure.rs:25:13
|
||||
|
|
||||
LL | let x = pin!(call_async_once(f));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}`
|
||||
|
|
||||
note: required by a bound in `call_async_once`
|
||||
--> $DIR/iter-macro-not-async-closure.rs:14:34
|
||||
|
|
||||
LL | async fn call_async_once(f: impl AsyncFnOnce()) {
|
||||
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
|
||||
= note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied
|
||||
--> $DIR/iter-macro-not-async-closure.rs:30:5
|
||||
|
|
||||
LL | x.poll(&mut Context::from_waker(Waker::noop()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}`
|
||||
|
|
||||
note: required by a bound in `call_async_once`
|
||||
--> $DIR/iter-macro-not-async-closure.rs:14:34
|
||||
|
|
||||
LL | async fn call_async_once(f: impl AsyncFnOnce()) {
|
||||
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -1,7 +1,7 @@
|
||||
// Test that we do not suggest to add type annotations for unnamable types.
|
||||
|
||||
#![crate_type="lib"]
|
||||
#![feature(coroutines, stmt_expr_attributes)]
|
||||
#![feature(coroutines, stmt_expr_attributes, const_async_blocks)]
|
||||
|
||||
const A = 5;
|
||||
//~^ ERROR: missing type for `const` item
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![feature(coroutines, coroutine_trait, rustc_attrs)]
|
||||
#![feature(coroutines, coroutine_trait, rustc_attrs, const_async_blocks)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
//@ check-pass
|
||||
|
||||
Reference in New Issue
Block a user