]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_expand/src/proc_macro_server.rs
Rollup merge of #96329 - aliemjay:fixed-by-90887, r=jackh726
[rust.git] / compiler / rustc_expand / src / proc_macro_server.rs
1 use crate::base::ExtCtxt;
2
3 use rustc_ast as ast;
4 use rustc_ast::token;
5 use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
6 use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
7 use rustc_ast_pretty::pprust;
8 use rustc_data_structures::fx::FxHashMap;
9 use rustc_data_structures::sync::Lrc;
10 use rustc_errors::{Diagnostic, MultiSpan, PResult};
11 use rustc_parse::lexer::nfc_normalize;
12 use rustc_parse::{nt_to_tokenstream, parse_stream_from_source_str};
13 use rustc_session::parse::ParseSess;
14 use rustc_span::def_id::CrateNum;
15 use rustc_span::symbol::{self, kw, sym, Symbol};
16 use rustc_span::{BytePos, FileName, Pos, SourceFile, Span};
17
18 use pm::bridge::{server, TokenTree};
19 use pm::{Delimiter, Level, LineColumn, Spacing};
20 use std::ops::Bound;
21 use std::{ascii, panic};
22
23 trait FromInternal<T> {
24     fn from_internal(x: T) -> Self;
25 }
26
27 trait ToInternal<T> {
28     fn to_internal(self) -> T;
29 }
30
31 impl FromInternal<token::Delimiter> for Delimiter {
32     fn from_internal(delim: token::Delimiter) -> Delimiter {
33         match delim {
34             token::Delimiter::Parenthesis => Delimiter::Parenthesis,
35             token::Delimiter::Brace => Delimiter::Brace,
36             token::Delimiter::Bracket => Delimiter::Bracket,
37             token::Delimiter::Invisible => Delimiter::None,
38         }
39     }
40 }
41
42 impl ToInternal<token::Delimiter> for Delimiter {
43     fn to_internal(self) -> token::Delimiter {
44         match self {
45             Delimiter::Parenthesis => token::Delimiter::Parenthesis,
46             Delimiter::Brace => token::Delimiter::Brace,
47             Delimiter::Bracket => token::Delimiter::Bracket,
48             Delimiter::None => token::Delimiter::Invisible,
49         }
50     }
51 }
52
53 impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_, '_>)>
54     for TokenTree<Group, Punct, Ident, Literal>
55 {
56     fn from_internal(
57         ((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_, '_>),
58     ) -> Self {
59         use rustc_ast::token::*;
60
61         let joint = spacing == Joint;
62         let Token { kind, span } = match tree {
63             tokenstream::TokenTree::Delimited(span, delim, tts) => {
64                 let delimiter = pm::Delimiter::from_internal(delim);
65                 return TokenTree::Group(Group { delimiter, stream: tts, span, flatten: false });
66             }
67             tokenstream::TokenTree::Token(token) => token,
68         };
69
70         macro_rules! tt {
71             ($ty:ident { $($field:ident $(: $value:expr)*),+ $(,)? }) => (
72                 TokenTree::$ty(self::$ty {
73                     $($field $(: $value)*,)+
74                     span,
75                 })
76             );
77             ($ty:ident::$method:ident($($value:expr),*)) => (
78                 TokenTree::$ty(self::$ty::$method($($value,)* span))
79             );
80         }
81         macro_rules! op {
82             ($a:expr) => {
83                 tt!(Punct::new($a, joint))
84             };
85             ($a:expr, $b:expr) => {{
86                 stack.push(tt!(Punct::new($b, joint)));
87                 tt!(Punct::new($a, true))
88             }};
89             ($a:expr, $b:expr, $c:expr) => {{
90                 stack.push(tt!(Punct::new($c, joint)));
91                 stack.push(tt!(Punct::new($b, true)));
92                 tt!(Punct::new($a, true))
93             }};
94         }
95
96         match kind {
97             Eq => op!('='),
98             Lt => op!('<'),
99             Le => op!('<', '='),
100             EqEq => op!('=', '='),
101             Ne => op!('!', '='),
102             Ge => op!('>', '='),
103             Gt => op!('>'),
104             AndAnd => op!('&', '&'),
105             OrOr => op!('|', '|'),
106             Not => op!('!'),
107             Tilde => op!('~'),
108             BinOp(Plus) => op!('+'),
109             BinOp(Minus) => op!('-'),
110             BinOp(Star) => op!('*'),
111             BinOp(Slash) => op!('/'),
112             BinOp(Percent) => op!('%'),
113             BinOp(Caret) => op!('^'),
114             BinOp(And) => op!('&'),
115             BinOp(Or) => op!('|'),
116             BinOp(Shl) => op!('<', '<'),
117             BinOp(Shr) => op!('>', '>'),
118             BinOpEq(Plus) => op!('+', '='),
119             BinOpEq(Minus) => op!('-', '='),
120             BinOpEq(Star) => op!('*', '='),
121             BinOpEq(Slash) => op!('/', '='),
122             BinOpEq(Percent) => op!('%', '='),
123             BinOpEq(Caret) => op!('^', '='),
124             BinOpEq(And) => op!('&', '='),
125             BinOpEq(Or) => op!('|', '='),
126             BinOpEq(Shl) => op!('<', '<', '='),
127             BinOpEq(Shr) => op!('>', '>', '='),
128             At => op!('@'),
129             Dot => op!('.'),
130             DotDot => op!('.', '.'),
131             DotDotDot => op!('.', '.', '.'),
132             DotDotEq => op!('.', '.', '='),
133             Comma => op!(','),
134             Semi => op!(';'),
135             Colon => op!(':'),
136             ModSep => op!(':', ':'),
137             RArrow => op!('-', '>'),
138             LArrow => op!('<', '-'),
139             FatArrow => op!('=', '>'),
140             Pound => op!('#'),
141             Dollar => op!('$'),
142             Question => op!('?'),
143             SingleQuote => op!('\''),
144
145             Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()),
146             Ident(name, is_raw) => tt!(Ident::new(rustc.sess(), name, is_raw)),
147             Lifetime(name) => {
148                 let ident = symbol::Ident::new(name, span).without_first_quote();
149                 stack.push(tt!(Ident::new(rustc.sess(), ident.name, false)));
150                 tt!(Punct::new('\'', true))
151             }
152             Literal(lit) => tt!(Literal { lit }),
153             DocComment(_, attr_style, data) => {
154                 let mut escaped = String::new();
155                 for ch in data.as_str().chars() {
156                     escaped.extend(ch.escape_debug());
157                 }
158                 let stream = [
159                     Ident(sym::doc, false),
160                     Eq,
161                     TokenKind::lit(token::Str, Symbol::intern(&escaped), None),
162                 ]
163                 .into_iter()
164                 .map(|kind| tokenstream::TokenTree::token(kind, span))
165                 .collect();
166                 stack.push(TokenTree::Group(Group {
167                     delimiter: pm::Delimiter::Bracket,
168                     stream,
169                     span: DelimSpan::from_single(span),
170                     flatten: false,
171                 }));
172                 if attr_style == ast::AttrStyle::Inner {
173                     stack.push(tt!(Punct::new('!', false)));
174                 }
175                 tt!(Punct::new('#', false))
176             }
177
178             Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => {
179                 TokenTree::Ident(Ident::new(rustc.sess(), ident.name, is_raw, ident.span))
180             }
181             Interpolated(nt) => {
182                 let stream = nt_to_tokenstream(&nt, rustc.sess(), CanSynthesizeMissingTokens::No);
183                 TokenTree::Group(Group {
184                     delimiter: pm::Delimiter::None,
185                     stream,
186                     span: DelimSpan::from_single(span),
187                     flatten: crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.sess()),
188                 })
189             }
190
191             OpenDelim(..) | CloseDelim(..) => unreachable!(),
192             Eof => unreachable!(),
193         }
194     }
195 }
196
197 impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> {
198     fn to_internal(self) -> TokenStream {
199         use rustc_ast::token::*;
200
201         let (ch, joint, span) = match self {
202             TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
203             TokenTree::Group(Group { delimiter, stream, span, .. }) => {
204                 return tokenstream::TokenTree::Delimited(span, delimiter.to_internal(), stream)
205                     .into();
206             }
207             TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
208                 return tokenstream::TokenTree::token(Ident(sym, is_raw), span).into();
209             }
210             TokenTree::Literal(self::Literal {
211                 lit: token::Lit { kind: token::Integer, symbol, suffix },
212                 span,
213             }) if symbol.as_str().starts_with('-') => {
214                 let minus = BinOp(BinOpToken::Minus);
215                 let symbol = Symbol::intern(&symbol.as_str()[1..]);
216                 let integer = TokenKind::lit(token::Integer, symbol, suffix);
217                 let a = tokenstream::TokenTree::token(minus, span);
218                 let b = tokenstream::TokenTree::token(integer, span);
219                 return [a, b].into_iter().collect();
220             }
221             TokenTree::Literal(self::Literal {
222                 lit: token::Lit { kind: token::Float, symbol, suffix },
223                 span,
224             }) if symbol.as_str().starts_with('-') => {
225                 let minus = BinOp(BinOpToken::Minus);
226                 let symbol = Symbol::intern(&symbol.as_str()[1..]);
227                 let float = TokenKind::lit(token::Float, symbol, suffix);
228                 let a = tokenstream::TokenTree::token(minus, span);
229                 let b = tokenstream::TokenTree::token(float, span);
230                 return [a, b].into_iter().collect();
231             }
232             TokenTree::Literal(self::Literal { lit, span }) => {
233                 return tokenstream::TokenTree::token(Literal(lit), span).into();
234             }
235         };
236
237         let kind = match ch {
238             '=' => Eq,
239             '<' => Lt,
240             '>' => Gt,
241             '!' => Not,
242             '~' => Tilde,
243             '+' => BinOp(Plus),
244             '-' => BinOp(Minus),
245             '*' => BinOp(Star),
246             '/' => BinOp(Slash),
247             '%' => BinOp(Percent),
248             '^' => BinOp(Caret),
249             '&' => BinOp(And),
250             '|' => BinOp(Or),
251             '@' => At,
252             '.' => Dot,
253             ',' => Comma,
254             ';' => Semi,
255             ':' => Colon,
256             '#' => Pound,
257             '$' => Dollar,
258             '?' => Question,
259             '\'' => SingleQuote,
260             _ => unreachable!(),
261         };
262
263         let tree = tokenstream::TokenTree::token(kind, span);
264         TokenStream::new(vec![(tree, if joint { Joint } else { Alone })])
265     }
266 }
267
268 impl ToInternal<rustc_errors::Level> for Level {
269     fn to_internal(self) -> rustc_errors::Level {
270         match self {
271             Level::Error => rustc_errors::Level::Error { lint: false },
272             Level::Warning => rustc_errors::Level::Warning,
273             Level::Note => rustc_errors::Level::Note,
274             Level::Help => rustc_errors::Level::Help,
275             _ => unreachable!("unknown proc_macro::Level variant: {:?}", self),
276         }
277     }
278 }
279
280 pub struct FreeFunctions;
281
282 #[derive(Clone)]
283 pub struct TokenStreamIter {
284     cursor: tokenstream::Cursor,
285     stack: Vec<TokenTree<Group, Punct, Ident, Literal>>,
286 }
287
288 #[derive(Clone)]
289 pub struct Group {
290     delimiter: Delimiter,
291     stream: TokenStream,
292     span: DelimSpan,
293     /// A hack used to pass AST fragments to attribute and derive macros
294     /// as a single nonterminal token instead of a token stream.
295     /// FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
296     flatten: bool,
297 }
298
299 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
300 pub struct Punct {
301     ch: char,
302     // NB. not using `Spacing` here because it doesn't implement `Hash`.
303     joint: bool,
304     span: Span,
305 }
306
307 impl Punct {
308     fn new(ch: char, joint: bool, span: Span) -> Punct {
309         const LEGAL_CHARS: &[char] = &[
310             '=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^', '&', '|', '@', '.', ',', ';',
311             ':', '#', '$', '?', '\'',
312         ];
313         if !LEGAL_CHARS.contains(&ch) {
314             panic!("unsupported character `{:?}`", ch)
315         }
316         Punct { ch, joint, span }
317     }
318 }
319
320 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
321 pub struct Ident {
322     sym: Symbol,
323     is_raw: bool,
324     span: Span,
325 }
326
327 impl Ident {
328     fn new(sess: &ParseSess, sym: Symbol, is_raw: bool, span: Span) -> Ident {
329         let sym = nfc_normalize(sym.as_str());
330         let string = sym.as_str();
331         if !rustc_lexer::is_ident(string) {
332             panic!("`{:?}` is not a valid identifier", string)
333         }
334         if is_raw && !sym.can_be_raw() {
335             panic!("`{}` cannot be a raw identifier", string);
336         }
337         sess.symbol_gallery.insert(sym, span);
338         Ident { sym, is_raw, span }
339     }
340     fn dollar_crate(span: Span) -> Ident {
341         // `$crate` is accepted as an ident only if it comes from the compiler.
342         Ident { sym: kw::DollarCrate, is_raw: false, span }
343     }
344 }
345
346 // FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
347 #[derive(Clone, Debug)]
348 pub struct Literal {
349     lit: token::Lit,
350     span: Span,
351 }
352
353 pub(crate) struct Rustc<'a, 'b> {
354     ecx: &'a mut ExtCtxt<'b>,
355     def_site: Span,
356     call_site: Span,
357     mixed_site: Span,
358     krate: CrateNum,
359     rebased_spans: FxHashMap<usize, Span>,
360 }
361
362 impl<'a, 'b> Rustc<'a, 'b> {
363     pub fn new(ecx: &'a mut ExtCtxt<'b>) -> Self {
364         let expn_data = ecx.current_expansion.id.expn_data();
365         Rustc {
366             def_site: ecx.with_def_site_ctxt(expn_data.def_site),
367             call_site: ecx.with_call_site_ctxt(expn_data.call_site),
368             mixed_site: ecx.with_mixed_site_ctxt(expn_data.call_site),
369             krate: expn_data.macro_def_id.unwrap().krate,
370             rebased_spans: FxHashMap::default(),
371             ecx,
372         }
373     }
374
375     fn sess(&self) -> &ParseSess {
376         self.ecx.parse_sess()
377     }
378
379     fn lit(&mut self, kind: token::LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Literal {
380         Literal { lit: token::Lit::new(kind, symbol, suffix), span: server::Span::call_site(self) }
381     }
382 }
383
384 impl server::Types for Rustc<'_, '_> {
385     type FreeFunctions = FreeFunctions;
386     type TokenStream = TokenStream;
387     type TokenStreamBuilder = tokenstream::TokenStreamBuilder;
388     type TokenStreamIter = TokenStreamIter;
389     type Group = Group;
390     type Punct = Punct;
391     type Ident = Ident;
392     type Literal = Literal;
393     type SourceFile = Lrc<SourceFile>;
394     type MultiSpan = Vec<Span>;
395     type Diagnostic = Diagnostic;
396     type Span = Span;
397 }
398
399 impl server::FreeFunctions for Rustc<'_, '_> {
400     fn track_env_var(&mut self, var: &str, value: Option<&str>) {
401         self.sess()
402             .env_depinfo
403             .borrow_mut()
404             .insert((Symbol::intern(var), value.map(Symbol::intern)));
405     }
406
407     fn track_path(&mut self, path: &str) {
408         self.sess().file_depinfo.borrow_mut().insert(Symbol::intern(path));
409     }
410 }
411
412 impl server::TokenStream for Rustc<'_, '_> {
413     fn new(&mut self) -> Self::TokenStream {
414         TokenStream::default()
415     }
416     fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
417         stream.is_empty()
418     }
419     fn from_str(&mut self, src: &str) -> Self::TokenStream {
420         parse_stream_from_source_str(
421             FileName::proc_macro_source_code(src),
422             src.to_string(),
423             self.sess(),
424             Some(self.call_site),
425         )
426     }
427     fn to_string(&mut self, stream: &Self::TokenStream) -> String {
428         pprust::tts_to_string(stream)
429     }
430     fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
431         // Parse the expression from our tokenstream.
432         let expr: PResult<'_, _> = try {
433             let mut p = rustc_parse::stream_to_parser(
434                 self.sess(),
435                 stream.clone(),
436                 Some("proc_macro expand expr"),
437             );
438             let expr = p.parse_expr()?;
439             if p.token != token::Eof {
440                 p.unexpected()?;
441             }
442             expr
443         };
444         let expr = expr.map_err(|mut err| {
445             err.emit();
446         })?;
447
448         // Perform eager expansion on the expression.
449         let expr = self
450             .ecx
451             .expander()
452             .fully_expand_fragment(crate::expand::AstFragment::Expr(expr))
453             .make_expr();
454
455         // NOTE: For now, limit `expand_expr` to exclusively expand to literals.
456         // This may be relaxed in the future.
457         // We don't use `nt_to_tokenstream` as the tokenstream currently cannot
458         // be recovered in the general case.
459         match &expr.kind {
460             ast::ExprKind::Lit(l) => {
461                 Ok(tokenstream::TokenTree::token(token::Literal(l.token), l.span).into())
462             }
463             ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind {
464                 ast::ExprKind::Lit(l) => match l.token {
465                     token::Lit { kind: token::Integer | token::Float, .. } => {
466                         Ok(Self::TokenStream::from_iter([
467                             // FIXME: The span of the `-` token is lost when
468                             // parsing, so we cannot faithfully recover it here.
469                             tokenstream::TokenTree::token(token::BinOp(token::Minus), e.span),
470                             tokenstream::TokenTree::token(token::Literal(l.token), l.span),
471                         ]))
472                     }
473                     _ => Err(()),
474                 },
475                 _ => Err(()),
476             },
477             _ => Err(()),
478         }
479     }
480     fn from_token_tree(
481         &mut self,
482         tree: TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>,
483     ) -> Self::TokenStream {
484         tree.to_internal()
485     }
486     fn into_iter(&mut self, stream: Self::TokenStream) -> Self::TokenStreamIter {
487         TokenStreamIter { cursor: stream.trees(), stack: vec![] }
488     }
489 }
490
491 impl server::TokenStreamBuilder for Rustc<'_, '_> {
492     fn new(&mut self) -> Self::TokenStreamBuilder {
493         tokenstream::TokenStreamBuilder::new()
494     }
495     fn push(&mut self, builder: &mut Self::TokenStreamBuilder, stream: Self::TokenStream) {
496         builder.push(stream);
497     }
498     fn build(&mut self, builder: Self::TokenStreamBuilder) -> Self::TokenStream {
499         builder.build()
500     }
501 }
502
503 impl server::TokenStreamIter for Rustc<'_, '_> {
504     fn next(
505         &mut self,
506         iter: &mut Self::TokenStreamIter,
507     ) -> Option<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> {
508         loop {
509             let tree = iter.stack.pop().or_else(|| {
510                 let next = iter.cursor.next_with_spacing()?;
511                 Some(TokenTree::from_internal((next, &mut iter.stack, self)))
512             })?;
513             // A hack used to pass AST fragments to attribute and derive macros
514             // as a single nonterminal token instead of a token stream.
515             // Such token needs to be "unwrapped" and not represented as a delimited group.
516             // FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
517             if let TokenTree::Group(ref group) = tree {
518                 if group.flatten {
519                     iter.cursor.append(group.stream.clone());
520                     continue;
521                 }
522             }
523             return Some(tree);
524         }
525     }
526 }
527
528 impl server::Group for Rustc<'_, '_> {
529     fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group {
530         Group {
531             delimiter,
532             stream,
533             span: DelimSpan::from_single(server::Span::call_site(self)),
534             flatten: false,
535         }
536     }
537     fn delimiter(&mut self, group: &Self::Group) -> Delimiter {
538         group.delimiter
539     }
540     fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
541         group.stream.clone()
542     }
543     fn span(&mut self, group: &Self::Group) -> Self::Span {
544         group.span.entire()
545     }
546     fn span_open(&mut self, group: &Self::Group) -> Self::Span {
547         group.span.open
548     }
549     fn span_close(&mut self, group: &Self::Group) -> Self::Span {
550         group.span.close
551     }
552     fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
553         group.span = DelimSpan::from_single(span);
554     }
555 }
556
557 impl server::Punct for Rustc<'_, '_> {
558     fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct {
559         Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self))
560     }
561     fn as_char(&mut self, punct: Self::Punct) -> char {
562         punct.ch
563     }
564     fn spacing(&mut self, punct: Self::Punct) -> Spacing {
565         if punct.joint { Spacing::Joint } else { Spacing::Alone }
566     }
567     fn span(&mut self, punct: Self::Punct) -> Self::Span {
568         punct.span
569     }
570     fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct {
571         Punct { span, ..punct }
572     }
573 }
574
575 impl server::Ident for Rustc<'_, '_> {
576     fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
577         Ident::new(self.sess(), Symbol::intern(string), is_raw, span)
578     }
579     fn span(&mut self, ident: Self::Ident) -> Self::Span {
580         ident.span
581     }
582     fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
583         Ident { span, ..ident }
584     }
585 }
586
587 impl server::Literal for Rustc<'_, '_> {
588     fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
589         let name = FileName::proc_macro_source_code(s);
590         let mut parser = rustc_parse::new_parser_from_source_str(self.sess(), name, s.to_owned());
591
592         let first_span = parser.token.span.data();
593         let minus_present = parser.eat(&token::BinOp(token::Minus));
594
595         let lit_span = parser.token.span.data();
596         let token::Literal(mut lit) = parser.token.kind else {
597             return Err(());
598         };
599
600         // Check no comment or whitespace surrounding the (possibly negative)
601         // literal, or more tokens after it.
602         if (lit_span.hi.0 - first_span.lo.0) as usize != s.len() {
603             return Err(());
604         }
605
606         if minus_present {
607             // If minus is present, check no comment or whitespace in between it
608             // and the literal token.
609             if first_span.hi.0 != lit_span.lo.0 {
610                 return Err(());
611             }
612
613             // Check literal is a kind we allow to be negated in a proc macro token.
614             match lit.kind {
615                 token::LitKind::Bool
616                 | token::LitKind::Byte
617                 | token::LitKind::Char
618                 | token::LitKind::Str
619                 | token::LitKind::StrRaw(_)
620                 | token::LitKind::ByteStr
621                 | token::LitKind::ByteStrRaw(_)
622                 | token::LitKind::Err => return Err(()),
623                 token::LitKind::Integer | token::LitKind::Float => {}
624             }
625
626             // Synthesize a new symbol that includes the minus sign.
627             let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]);
628             lit = token::Lit::new(lit.kind, symbol, lit.suffix);
629         }
630
631         Ok(Literal { lit, span: self.call_site })
632     }
633     fn to_string(&mut self, literal: &Self::Literal) -> String {
634         literal.lit.to_string()
635     }
636     fn debug_kind(&mut self, literal: &Self::Literal) -> String {
637         format!("{:?}", literal.lit.kind)
638     }
639     fn symbol(&mut self, literal: &Self::Literal) -> String {
640         literal.lit.symbol.to_string()
641     }
642     fn suffix(&mut self, literal: &Self::Literal) -> Option<String> {
643         literal.lit.suffix.as_ref().map(Symbol::to_string)
644     }
645     fn integer(&mut self, n: &str) -> Self::Literal {
646         self.lit(token::Integer, Symbol::intern(n), None)
647     }
648     fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal {
649         self.lit(token::Integer, Symbol::intern(n), Some(Symbol::intern(kind)))
650     }
651     fn float(&mut self, n: &str) -> Self::Literal {
652         self.lit(token::Float, Symbol::intern(n), None)
653     }
654     fn f32(&mut self, n: &str) -> Self::Literal {
655         self.lit(token::Float, Symbol::intern(n), Some(sym::f32))
656     }
657     fn f64(&mut self, n: &str) -> Self::Literal {
658         self.lit(token::Float, Symbol::intern(n), Some(sym::f64))
659     }
660     fn string(&mut self, string: &str) -> Self::Literal {
661         let quoted = format!("{:?}", string);
662         assert!(quoted.starts_with('"') && quoted.ends_with('"'));
663         let symbol = &quoted[1..quoted.len() - 1];
664         self.lit(token::Str, Symbol::intern(symbol), None)
665     }
666     fn character(&mut self, ch: char) -> Self::Literal {
667         let quoted = format!("{:?}", ch);
668         assert!(quoted.starts_with('\'') && quoted.ends_with('\''));
669         let symbol = &quoted[1..quoted.len() - 1];
670         self.lit(token::Char, Symbol::intern(symbol), None)
671     }
672     fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
673         let string = bytes
674             .iter()
675             .cloned()
676             .flat_map(ascii::escape_default)
677             .map(Into::<char>::into)
678             .collect::<String>();
679         self.lit(token::ByteStr, Symbol::intern(&string), None)
680     }
681     fn span(&mut self, literal: &Self::Literal) -> Self::Span {
682         literal.span
683     }
684     fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) {
685         literal.span = span;
686     }
687     fn subspan(
688         &mut self,
689         literal: &Self::Literal,
690         start: Bound<usize>,
691         end: Bound<usize>,
692     ) -> Option<Self::Span> {
693         let span = literal.span;
694         let length = span.hi().to_usize() - span.lo().to_usize();
695
696         let start = match start {
697             Bound::Included(lo) => lo,
698             Bound::Excluded(lo) => lo.checked_add(1)?,
699             Bound::Unbounded => 0,
700         };
701
702         let end = match end {
703             Bound::Included(hi) => hi.checked_add(1)?,
704             Bound::Excluded(hi) => hi,
705             Bound::Unbounded => length,
706         };
707
708         // Bounds check the values, preventing addition overflow and OOB spans.
709         if start > u32::MAX as usize
710             || end > u32::MAX as usize
711             || (u32::MAX - start as u32) < span.lo().to_u32()
712             || (u32::MAX - end as u32) < span.lo().to_u32()
713             || start >= end
714             || end > length
715         {
716             return None;
717         }
718
719         let new_lo = span.lo() + BytePos::from_usize(start);
720         let new_hi = span.lo() + BytePos::from_usize(end);
721         Some(span.with_lo(new_lo).with_hi(new_hi))
722     }
723 }
724
725 impl server::SourceFile for Rustc<'_, '_> {
726     fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
727         Lrc::ptr_eq(file1, file2)
728     }
729     fn path(&mut self, file: &Self::SourceFile) -> String {
730         match file.name {
731             FileName::Real(ref name) => name
732                 .local_path()
733                 .expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`")
734                 .to_str()
735                 .expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
736                 .to_string(),
737             _ => file.name.prefer_local().to_string(),
738         }
739     }
740     fn is_real(&mut self, file: &Self::SourceFile) -> bool {
741         file.is_real_file()
742     }
743 }
744
745 impl server::MultiSpan for Rustc<'_, '_> {
746     fn new(&mut self) -> Self::MultiSpan {
747         vec![]
748     }
749     fn push(&mut self, spans: &mut Self::MultiSpan, span: Self::Span) {
750         spans.push(span)
751     }
752 }
753
754 impl server::Diagnostic for Rustc<'_, '_> {
755     fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
756         let mut diag = Diagnostic::new(level.to_internal(), msg);
757         diag.set_span(MultiSpan::from_spans(spans));
758         diag
759     }
760     fn sub(
761         &mut self,
762         diag: &mut Self::Diagnostic,
763         level: Level,
764         msg: &str,
765         spans: Self::MultiSpan,
766     ) {
767         diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None);
768     }
769     fn emit(&mut self, mut diag: Self::Diagnostic) {
770         self.sess().span_diagnostic.emit_diagnostic(&mut diag);
771     }
772 }
773
774 impl server::Span for Rustc<'_, '_> {
775     fn debug(&mut self, span: Self::Span) -> String {
776         if self.ecx.ecfg.span_debug {
777             format!("{:?}", span)
778         } else {
779             format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0)
780         }
781     }
782     fn def_site(&mut self) -> Self::Span {
783         self.def_site
784     }
785     fn call_site(&mut self) -> Self::Span {
786         self.call_site
787     }
788     fn mixed_site(&mut self) -> Self::Span {
789         self.mixed_site
790     }
791     fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
792         self.sess().source_map().lookup_char_pos(span.lo()).file
793     }
794     fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
795         span.parent_callsite()
796     }
797     fn source(&mut self, span: Self::Span) -> Self::Span {
798         span.source_callsite()
799     }
800     fn start(&mut self, span: Self::Span) -> LineColumn {
801         let loc = self.sess().source_map().lookup_char_pos(span.lo());
802         LineColumn { line: loc.line, column: loc.col.to_usize() }
803     }
804     fn end(&mut self, span: Self::Span) -> LineColumn {
805         let loc = self.sess().source_map().lookup_char_pos(span.hi());
806         LineColumn { line: loc.line, column: loc.col.to_usize() }
807     }
808     fn before(&mut self, span: Self::Span) -> Self::Span {
809         span.shrink_to_lo()
810     }
811     fn after(&mut self, span: Self::Span) -> Self::Span {
812         span.shrink_to_hi()
813     }
814     fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
815         let self_loc = self.sess().source_map().lookup_char_pos(first.lo());
816         let other_loc = self.sess().source_map().lookup_char_pos(second.lo());
817
818         if self_loc.file.name != other_loc.file.name {
819             return None;
820         }
821
822         Some(first.to(second))
823     }
824     fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
825         span.with_ctxt(at.ctxt())
826     }
827     fn source_text(&mut self, span: Self::Span) -> Option<String> {
828         self.sess().source_map().span_to_snippet(span).ok()
829     }
830     /// Saves the provided span into the metadata of
831     /// *the crate we are currently compiling*, which must
832     /// be a proc-macro crate. This id can be passed to
833     /// `recover_proc_macro_span` when our current crate
834     /// is *run* as a proc-macro.
835     ///
836     /// Let's suppose that we have two crates - `my_client`
837     /// and `my_proc_macro`. The `my_proc_macro` crate
838     /// contains a procedural macro `my_macro`, which
839     /// is implemented as: `quote! { "hello" }`
840     ///
841     /// When we *compile* `my_proc_macro`, we will execute
842     /// the `quote` proc-macro. This will save the span of
843     /// "hello" into the metadata of `my_proc_macro`. As a result,
844     /// the body of `my_proc_macro` (after expansion) will end
845     /// up containing a call that looks like this:
846     /// `proc_macro::Ident::new("hello", proc_macro::Span::recover_proc_macro_span(0))`
847     ///
848     /// where `0` is the id returned by this function.
849     /// When `my_proc_macro` *executes* (during the compilation of `my_client`),
850     /// the call to `recover_proc_macro_span` will load the corresponding
851     /// span from the metadata of `my_proc_macro` (which we have access to,
852     /// since we've loaded `my_proc_macro` from disk in order to execute it).
853     /// In this way, we have obtained a span pointing into `my_proc_macro`
854     fn save_span(&mut self, span: Self::Span) -> usize {
855         self.sess().save_proc_macro_span(span)
856     }
857     fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span {
858         let (resolver, krate, def_site) = (&*self.ecx.resolver, self.krate, self.def_site);
859         *self.rebased_spans.entry(id).or_insert_with(|| {
860             // FIXME: `SyntaxContext` for spans from proc macro crates is lost during encoding,
861             // replace it with a def-site context until we are encoding it properly.
862             resolver.get_proc_macro_quoted_span(krate, id).with_ctxt(def_site.ctxt())
863         })
864     }
865 }