about summary refs log tree commit diff
path: root/compiler/rustc_builtin_macros/src/iter.rs
blob: 7ad83903a1be73f018de60bcdc4663983d723ac0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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())
        }
    }
}