| 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, Box<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()) | |
| } | |
| } | |
| } |