|
37 | 37 |
|
38 | 38 | use rustc_ast::node_id::NodeMap;
|
39 | 39 | use rustc_ast::token::{self, DelimToken, Nonterminal, Token};
|
40 |
| -use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; |
| 40 | +use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, DelimSpan, TokenStream, TokenTree}; |
41 | 41 | use rustc_ast::visit::{self, AssocCtxt, Visitor};
|
42 | 42 | use rustc_ast::walk_list;
|
43 | 43 | use rustc_ast::{self as ast, *};
|
@@ -206,7 +206,8 @@ pub trait ResolverAstLowering {
|
206 | 206 | ) -> LocalDefId;
|
207 | 207 | }
|
208 | 208 |
|
209 |
| -type NtToTokenstream = fn(&Nonterminal, &ParseSess, Span) -> TokenStream; |
| 209 | +type NtToTokenstream = |
| 210 | + fn(&Nonterminal, &ParseSess, Span, CanSynthesizeMissingTokens) -> TokenStream; |
210 | 211 |
|
211 | 212 | /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
|
212 | 213 | /// and if so, what meaning it has.
|
@@ -393,6 +394,47 @@ enum AnonymousLifetimeMode {
|
393 | 394 | PassThrough,
|
394 | 395 | }
|
395 | 396 |
|
| 397 | +struct TokenStreamLowering<'a> { |
| 398 | + parse_sess: &'a ParseSess, |
| 399 | + synthesize_tokens: CanSynthesizeMissingTokens, |
| 400 | + nt_to_tokenstream: NtToTokenstream, |
| 401 | +} |
| 402 | + |
| 403 | +impl<'a> TokenStreamLowering<'a> { |
| 404 | + fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream { |
| 405 | + tokens.into_trees().flat_map(|tree| self.lower_token_tree(tree).into_trees()).collect() |
| 406 | + } |
| 407 | + |
| 408 | + fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream { |
| 409 | + match tree { |
| 410 | + TokenTree::Token(token) => self.lower_token(token), |
| 411 | + TokenTree::Delimited(span, delim, tts) => { |
| 412 | + TokenTree::Delimited(span, delim, self.lower_token_stream(tts)).into() |
| 413 | + } |
| 414 | + } |
| 415 | + } |
| 416 | + |
| 417 | + fn lower_token(&mut self, token: Token) -> TokenStream { |
| 418 | + match token.kind { |
| 419 | + token::Interpolated(nt) => { |
| 420 | + let tts = (self.nt_to_tokenstream)( |
| 421 | + &nt, |
| 422 | + self.parse_sess, |
| 423 | + token.span, |
| 424 | + self.synthesize_tokens, |
| 425 | + ); |
| 426 | + TokenTree::Delimited( |
| 427 | + DelimSpan::from_single(token.span), |
| 428 | + DelimToken::NoDelim, |
| 429 | + self.lower_token_stream(tts), |
| 430 | + ) |
| 431 | + .into() |
| 432 | + } |
| 433 | + _ => TokenTree::Token(token).into(), |
| 434 | + } |
| 435 | + } |
| 436 | +} |
| 437 | + |
396 | 438 | struct ImplTraitTypeIdVisitor<'a> {
|
397 | 439 | ids: &'a mut SmallVec<[NodeId; 1]>,
|
398 | 440 | }
|
@@ -955,40 +997,49 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
955 | 997 | match *args {
|
956 | 998 | MacArgs::Empty => MacArgs::Empty,
|
957 | 999 | MacArgs::Delimited(dspan, delim, ref tokens) => {
|
958 |
| - MacArgs::Delimited(dspan, delim, self.lower_token_stream(tokens.clone())) |
959 |
| - } |
960 |
| - MacArgs::Eq(eq_span, ref tokens) => { |
961 |
| - MacArgs::Eq(eq_span, self.lower_token_stream(tokens.clone())) |
962 |
| - } |
963 |
| - } |
964 |
| - } |
965 |
| - |
966 |
| - fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream { |
967 |
| - tokens.into_trees().flat_map(|tree| self.lower_token_tree(tree).into_trees()).collect() |
968 |
| - } |
969 |
| - |
970 |
| - fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream { |
971 |
| - match tree { |
972 |
| - TokenTree::Token(token) => self.lower_token(token), |
973 |
| - TokenTree::Delimited(span, delim, tts) => { |
974 |
| - TokenTree::Delimited(span, delim, self.lower_token_stream(tts)).into() |
| 1000 | + // This is either a non-key-value attribute, or a `macro_rules!` body. |
| 1001 | + // We either not have any nonterminals present (in the case of an attribute), |
| 1002 | + // or have tokens available for all nonterminals in the case of a nested |
| 1003 | + // `macro_rules`: e.g: |
| 1004 | + // |
| 1005 | + // ```rust |
| 1006 | + // macro_rules! outer { |
| 1007 | + // ($e:expr) => { |
| 1008 | + // macro_rules! inner { |
| 1009 | + // () => { $e } |
| 1010 | + // } |
| 1011 | + // } |
| 1012 | + // } |
| 1013 | + // ``` |
| 1014 | + // |
| 1015 | + // In both cases, we don't want to synthesize any tokens |
| 1016 | + MacArgs::Delimited( |
| 1017 | + dspan, |
| 1018 | + delim, |
| 1019 | + self.lower_token_stream(tokens.clone(), CanSynthesizeMissingTokens::No), |
| 1020 | + ) |
975 | 1021 | }
|
| 1022 | + // This is an inert key-value attribute - it will never be visible to macros |
| 1023 | + // after it gets lowered to HIR. Therefore, we can synthesize tokens with fake |
| 1024 | + // spans to handle nonterminals in `#[doc]` (e.g. `#[doc = $e]`). |
| 1025 | + MacArgs::Eq(eq_span, ref tokens) => MacArgs::Eq( |
| 1026 | + eq_span, |
| 1027 | + self.lower_token_stream(tokens.clone(), CanSynthesizeMissingTokens::Yes), |
| 1028 | + ), |
976 | 1029 | }
|
977 | 1030 | }
|
978 | 1031 |
|
979 |
| - fn lower_token(&mut self, token: Token) -> TokenStream { |
980 |
| - match token.kind { |
981 |
| - token::Interpolated(nt) => { |
982 |
| - let tts = (self.nt_to_tokenstream)(&nt, &self.sess.parse_sess, token.span); |
983 |
| - TokenTree::Delimited( |
984 |
| - DelimSpan::from_single(token.span), |
985 |
| - DelimToken::NoDelim, |
986 |
| - self.lower_token_stream(tts), |
987 |
| - ) |
988 |
| - .into() |
989 |
| - } |
990 |
| - _ => TokenTree::Token(token).into(), |
| 1032 | + fn lower_token_stream( |
| 1033 | + &self, |
| 1034 | + tokens: TokenStream, |
| 1035 | + synthesize_tokens: CanSynthesizeMissingTokens, |
| 1036 | + ) -> TokenStream { |
| 1037 | + TokenStreamLowering { |
| 1038 | + parse_sess: &self.sess.parse_sess, |
| 1039 | + synthesize_tokens, |
| 1040 | + nt_to_tokenstream: self.nt_to_tokenstream, |
991 | 1041 | }
|
| 1042 | + .lower_token_stream(tokens) |
992 | 1043 | }
|
993 | 1044 |
|
994 | 1045 | /// Given an associated type constraint like one of these:
|
|
0 commit comments