rustc_builtin_macros/
pattern_type.rs1use rustc_ast::tokenstream::TokenStream;
2use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token};
3use rustc_errors::PResult;
4use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
5use rustc_parse::exp;
6use rustc_parse::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};
7use rustc_span::Span;
8
9pub(crate) fn expand<'cx>(
10 cx: &'cx mut ExtCtxt<'_>,
11 sp: Span,
12 tts: TokenStream,
13) -> MacroExpanderResult<'cx> {
14 let (ty, pat) = match parse_pat_ty(cx, tts) {
15 Ok(parsed) => parsed,
16 Err(err) => {
17 return ExpandResult::Ready(DummyResult::any(sp, err.emit()));
18 }
19 };
20
21 ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::Pat(ty, pat))))
22}
23
24fn parse_pat_ty<'a>(
25 cx: &mut ExtCtxt<'a>,
26 stream: TokenStream,
27) -> PResult<'a, (Box<Ty>, Box<TyPat>)> {
28 let mut parser = cx.new_parser_from_tts(stream);
29
30 let ty = parser.parse_ty()?;
31 parser.expect_keyword(exp!(Is))?;
32
33 let start = parser.token.span;
34 let pat = if parser.eat(exp!(Bang)) {
35 parser.expect_keyword(exp!(Null))?;
36 ty_pat(TyPatKind::NotNull, start.to(parser.token.span))
37 } else {
38 pat_to_ty_pat(
39 cx,
40 parser.parse_pat_no_top_guard(
41 None,
42 RecoverComma::No,
43 RecoverColon::No,
44 CommaRecoveryMode::EitherTupleOrPipe,
45 )?,
46 )
47 };
48
49 if parser.token != token::Eof {
50 parser.unexpected()?;
51 }
52
53 Ok((ty, Box::new(pat)))
54}
55
56fn ty_pat(kind: TyPatKind, span: Span) -> TyPat {
57 TyPat { id: DUMMY_NODE_ID, kind, span, tokens: None }
58}
59
60fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> TyPat {
61 let kind = match pat.kind {
62 ast::PatKind::Range(start, end, include_end) => TyPatKind::Range(
63 start.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })),
64 end.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })),
65 include_end,
66 ),
67 ast::PatKind::Or(variants) => {
68 TyPatKind::Or(variants.into_iter().map(|pat| pat_to_ty_pat(cx, pat)).collect())
69 }
70 ast::PatKind::Err(guar) => TyPatKind::Err(guar),
71 _ => TyPatKind::Err(cx.dcx().span_err(pat.span, "pattern not supported in pattern types")),
72 };
73 ty_pat(kind, pat.span)
74}