rustc_builtin_macros/
iter.rs

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