rustc_builtin_macros/
iter.rs

1use rustc_ast::ptr::P;
2use rustc_ast::tokenstream::TokenStream;
3use rustc_ast::{CoroutineKind, DUMMY_NODE_ID, Expr, ast, token};
4use rustc_errors::PResult;
5use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
6use rustc_span::Span;
7
8pub(crate) fn expand<'cx>(
9    cx: &'cx mut ExtCtxt<'_>,
10    sp: Span,
11    tts: TokenStream,
12) -> MacroExpanderResult<'cx> {
13    let closure = match parse_closure(cx, sp, tts) {
14        Ok(parsed) => parsed,
15        Err(err) => {
16            return ExpandResult::Ready(DummyResult::any(sp, err.emit()));
17        }
18    };
19
20    ExpandResult::Ready(base::MacEager::expr(closure))
21}
22
23fn parse_closure<'a>(
24    cx: &mut ExtCtxt<'a>,
25    span: Span,
26    stream: TokenStream,
27) -> PResult<'a, P<Expr>> {
28    let mut closure_parser = cx.new_parser_from_tts(stream);
29
30    let coroutine_kind = Some(CoroutineKind::Gen {
31        span,
32        closure_id: DUMMY_NODE_ID,
33        return_impl_trait_id: DUMMY_NODE_ID,
34    });
35
36    let mut closure = closure_parser.parse_expr()?;
37    match &mut closure.kind {
38        ast::ExprKind::Closure(c) => {
39            if let Some(kind) = c.coroutine_kind {
40                cx.dcx().span_err(kind.span(), "only plain closures allowed in `iter!`");
41            }
42            c.coroutine_kind = coroutine_kind;
43            if closure_parser.token != token::Eof {
44                closure_parser.unexpected()?;
45            }
46            Ok(closure)
47        }
48        _ => {
49            cx.dcx().span_err(closure.span, "`iter!` body must be a closure");
50            Err(closure_parser.unexpected().unwrap_err())
51        }
52    }
53}