rustc_builtin_macros/
iter.rs1use rustc_ast::tokenstream::TokenStream;
2use rustc_ast::{CoroutineKind, CoroutineMarker, 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_marker = Some(CoroutineMarker::new(CoroutineKind::Gen, span));
30
31 let mut closure = closure_parser.parse_expr()?;
32 match &mut closure.kind {
33 ast::ExprKind::Closure(c) => {
34 if let Some(marker) = c.coroutine_marker {
35 cx.dcx().span_err(marker.span, "only plain closures allowed in `iter!`");
36 }
37 c.coroutine_marker = coroutine_marker;
38 if closure_parser.token != token::Eof {
39 closure_parser.unexpected()?;
40 }
41 Ok(closure)
42 }
43 _ => {
44 cx.dcx().span_err(closure.span, "`iter!` body must be a closure");
45 Err(closure_parser.unexpected().unwrap_err())
46 }
47 }
48}