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:
53
compiler/rustc_builtin_macros/src/iter.rs
Normal file
53
compiler/rustc_builtin_macros/src/iter.rs
Normal file
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user