]> git.proxmox.com Git - rustc.git/blob - vendor/rustc-ap-rustc_expand/src/proc_macro_server.rs
New upstream version 1.52.1+dfsg1
[rustc.git] / vendor / rustc-ap-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::sync::Lrc;
9 use rustc_errors::Diagnostic;
10 use rustc_parse::lexer::nfc_normalize;
11 use rustc_parse::{nt_to_tokenstream, parse_stream_from_source_str};
12 use rustc_session::parse::ParseSess;
13 use rustc_span::symbol::{self, kw, sym, Symbol};
14 use rustc_span::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
15
16 use pm::bridge::{server, TokenTree};
17 use pm::{Delimiter, Level, LineColumn, Spacing};
18 use std::ops::Bound;
19 use std::{ascii, panic};
20
21 trait FromInternal<T> {
22 fn from_internal(x: T) -> Self;
23 }
24
25 trait ToInternal<T> {
26 fn to_internal(self) -> T;
27 }
28
29 impl FromInternal<token::DelimToken> for Delimiter {
30 fn from_internal(delim: token::DelimToken) -> Delimiter {
31 match delim {
32 token::Paren => Delimiter::Parenthesis,
33 token::Brace => Delimiter::Brace,
34 token::Bracket => Delimiter::Bracket,
35 token::NoDelim => Delimiter::None,
36 }
37 }
38 }
39
40 impl ToInternal<token::DelimToken> for Delimiter {
41 fn to_internal(self) -> token::DelimToken {
42 match self {
43 Delimiter::Parenthesis => token::Paren,
44 Delimiter::Brace => token::Brace,
45 Delimiter::Bracket => token::Bracket,
46 Delimiter::None => token::NoDelim,
47 }
48 }
49 }
50
51 impl FromInternal<(TreeAndSpacing, &'_ ParseSess, &'_ mut Vec<Self>)>
52 for TokenTree<Group, Punct, Ident, Literal>
53 {
54 fn from_internal(
55 ((tree, spacing), sess, stack): (TreeAndSpacing, &ParseSess, &mut Vec<Self>),
56 ) -> Self {
57 use rustc_ast::token::*;
58
59 let joint = spacing == Joint;
60 let Token { kind, span } = match tree {
61 tokenstream::TokenTree::Delimited(span, delim, tts) => {
62 let delimiter = Delimiter::from_internal(delim);
63 return TokenTree::Group(Group { delimiter, stream: tts, span, flatten: false });
64 }
65 tokenstream::TokenTree::Token(token) => token,
66 };
67
68 macro_rules! tt {
69 ($ty:ident { $($field:ident $(: $value:expr)*),+ $(,)? }) => (
70 TokenTree::$ty(self::$ty {
71 $($field $(: $value)*,)+
72 span,
73 })
74 );
75 ($ty:ident::$method:ident($($value:expr),*)) => (
76 TokenTree::$ty(self::$ty::$method($($value,)* span))
77 );
78 }
79 macro_rules! op {
80 ($a:expr) => {
81 tt!(Punct::new($a, joint))
82 };
83 ($a:expr, $b:expr) => {{
84 stack.push(tt!(Punct::new($b, joint)));
85 tt!(Punct::new($a, true))
86 }};
87 ($a:expr, $b:expr, $c:expr) => {{
88 stack.push(tt!(Punct::new($c, joint)));
89 stack.push(tt!(Punct::new($b, true)));
90 tt!(Punct::new($a, true))
91 }};
92 }
93
94 match kind {
95 Eq => op!('='),
96 Lt => op!('<'),
97 Le => op!('<', '='),
98 EqEq => op!('=', '='),
99 Ne => op!('!', '='),
100 Ge => op!('>', '='),
101 Gt => op!('>'),
102 AndAnd => op!('&', '&'),
103 OrOr => op!('|', '|'),
104 Not => op!('!'),
105 Tilde => op!('~'),
106 BinOp(Plus) => op!('+'),
107 BinOp(Minus) => op!('-'),
108 BinOp(Star) => op!('*'),
109 BinOp(Slash) => op!('/'),
110 BinOp(Percent) => op!('%'),
111 BinOp(Caret) => op!('^'),
112 BinOp(And) => op!('&'),
113 BinOp(Or) => op!('|'),
114 BinOp(Shl) => op!('<', '<'),
115 BinOp(Shr) => op!('>', '>'),
116 BinOpEq(Plus) => op!('+', '='),
117 BinOpEq(Minus) => op!('-', '='),
118 BinOpEq(Star) => op!('*', '='),
119 BinOpEq(Slash) => op!('/', '='),
120 BinOpEq(Percent) => op!('%', '='),
121 BinOpEq(Caret) => op!('^', '='),
122 BinOpEq(And) => op!('&', '='),
123 BinOpEq(Or) => op!('|', '='),
124 BinOpEq(Shl) => op!('<', '<', '='),
125 BinOpEq(Shr) => op!('>', '>', '='),
126 At => op!('@'),
127 Dot => op!('.'),
128 DotDot => op!('.', '.'),
129 DotDotDot => op!('.', '.', '.'),
130 DotDotEq => op!('.', '.', '='),
131 Comma => op!(','),
132 Semi => op!(';'),
133 Colon => op!(':'),
134 ModSep => op!(':', ':'),
135 RArrow => op!('-', '>'),
136 LArrow => op!('<', '-'),
137 FatArrow => op!('=', '>'),
138 Pound => op!('#'),
139 Dollar => op!('$'),
140 Question => op!('?'),
141 SingleQuote => op!('\''),
142
143 Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()),
144 Ident(name, is_raw) => tt!(Ident::new(sess, name, is_raw)),
145 Lifetime(name) => {
146 let ident = symbol::Ident::new(name, span).without_first_quote();
147 stack.push(tt!(Ident::new(sess, ident.name, false)));
148 tt!(Punct::new('\'', true))
149 }
150 Literal(lit) => tt!(Literal { lit }),
151 DocComment(_, attr_style, data) => {
152 let mut escaped = String::new();
153 for ch in data.as_str().chars() {
154 escaped.extend(ch.escape_debug());
155 }
156 let stream = vec![
157 Ident(sym::doc, false),
158 Eq,
159 TokenKind::lit(token::Str, Symbol::intern(&escaped), None),
160 ]
161 .into_iter()
162 .map(|kind| tokenstream::TokenTree::token(kind, span))
163 .collect();
164 stack.push(TokenTree::Group(Group {
165 delimiter: Delimiter::Bracket,
166 stream,
167 span: DelimSpan::from_single(span),
168 flatten: false,
169 }));
170 if attr_style == ast::AttrStyle::Inner {
171 stack.push(tt!(Punct::new('!', false)));
172 }
173 tt!(Punct::new('#', false))
174 }
175
176 Interpolated(nt) => {
177 if let Some((name, is_raw)) =
178 nt.ident_name_compatibility_hack(span, sess.source_map())
179 {
180 TokenTree::Ident(Ident::new(sess, name.name, is_raw, name.span))
181 } else {
182 let stream = nt_to_tokenstream(&nt, sess, CanSynthesizeMissingTokens::No);
183 TokenTree::Group(Group {
184 delimiter: Delimiter::None,
185 stream,
186 span: DelimSpan::from_single(span),
187 flatten: nt.pretty_printing_compatibility_hack(),
188 })
189 }
190 }
191
192 OpenDelim(..) | CloseDelim(..) => unreachable!(),
193 Eof => unreachable!(),
194 }
195 }
196 }
197
198 impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> {
199 fn to_internal(self) -> TokenStream {
200 use rustc_ast::token::*;
201
202 let (ch, joint, span) = match self {
203 TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
204 TokenTree::Group(Group { delimiter, stream, span, .. }) => {
205 return tokenstream::TokenTree::Delimited(span, delimiter.to_internal(), stream)
206 .into();
207 }
208 TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
209 return tokenstream::TokenTree::token(Ident(sym, is_raw), span).into();
210 }
211 TokenTree::Literal(self::Literal {
212 lit: token::Lit { kind: token::Integer, symbol, suffix },
213 span,
214 }) if symbol.as_str().starts_with('-') => {
215 let minus = BinOp(BinOpToken::Minus);
216 let symbol = Symbol::intern(&symbol.as_str()[1..]);
217 let integer = TokenKind::lit(token::Integer, symbol, suffix);
218 let a = tokenstream::TokenTree::token(minus, span);
219 let b = tokenstream::TokenTree::token(integer, span);
220 return vec![a, b].into_iter().collect();
221 }
222 TokenTree::Literal(self::Literal {
223 lit: token::Lit { kind: token::Float, symbol, suffix },
224 span,
225 }) if symbol.as_str().starts_with('-') => {
226 let minus = BinOp(BinOpToken::Minus);
227 let symbol = Symbol::intern(&symbol.as_str()[1..]);
228 let float = TokenKind::lit(token::Float, symbol, suffix);
229 let a = tokenstream::TokenTree::token(minus, span);
230 let b = tokenstream::TokenTree::token(float, span);
231 return vec![a, b].into_iter().collect();
232 }
233 TokenTree::Literal(self::Literal { lit, span }) => {
234 return tokenstream::TokenTree::token(Literal(lit), span).into();
235 }
236 };
237
238 let kind = match ch {
239 '=' => Eq,
240 '<' => Lt,
241 '>' => Gt,
242 '!' => Not,
243 '~' => Tilde,
244 '+' => BinOp(Plus),
245 '-' => BinOp(Minus),
246 '*' => BinOp(Star),
247 '/' => BinOp(Slash),
248 '%' => BinOp(Percent),
249 '^' => BinOp(Caret),
250 '&' => BinOp(And),
251 '|' => BinOp(Or),
252 '@' => At,
253 '.' => Dot,
254 ',' => Comma,
255 ';' => Semi,
256 ':' => Colon,
257 '#' => Pound,
258 '$' => Dollar,
259 '?' => Question,
260 '\'' => SingleQuote,
261 _ => unreachable!(),
262 };
263
264 let tree = tokenstream::TokenTree::token(kind, span);
265 TokenStream::new(vec![(tree, if joint { Joint } else { Alone })])
266 }
267 }
268
269 impl ToInternal<rustc_errors::Level> for Level {
270 fn to_internal(self) -> rustc_errors::Level {
271 match self {
272 Level::Error => rustc_errors::Level::Error,
273 Level::Warning => rustc_errors::Level::Warning,
274 Level::Note => rustc_errors::Level::Note,
275 Level::Help => rustc_errors::Level::Help,
276 _ => unreachable!("unknown proc_macro::Level variant: {:?}", self),
277 }
278 }
279 }
280
281 pub struct FreeFunctions;
282
283 #[derive(Clone)]
284 pub struct TokenStreamIter {
285 cursor: tokenstream::Cursor,
286 stack: Vec<TokenTree<Group, Punct, Ident, Literal>>,
287 }
288
289 #[derive(Clone)]
290 pub struct Group {
291 delimiter: Delimiter,
292 stream: TokenStream,
293 span: DelimSpan,
294 /// A hack used to pass AST fragments to attribute and derive macros
295 /// as a single nonterminal token instead of a token stream.
296 /// FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
297 flatten: bool,
298 }
299
300 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
301 pub struct Punct {
302 ch: char,
303 // NB. not using `Spacing` here because it doesn't implement `Hash`.
304 joint: bool,
305 span: Span,
306 }
307
308 impl Punct {
309 fn new(ch: char, joint: bool, span: Span) -> Punct {
310 const LEGAL_CHARS: &[char] = &[
311 '=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^', '&', '|', '@', '.', ',', ';',
312 ':', '#', '$', '?', '\'',
313 ];
314 if !LEGAL_CHARS.contains(&ch) {
315 panic!("unsupported character `{:?}`", ch)
316 }
317 Punct { ch, joint, span }
318 }
319 }
320
321 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
322 pub struct Ident {
323 sym: Symbol,
324 is_raw: bool,
325 span: Span,
326 }
327
328 impl Ident {
329 fn new(sess: &ParseSess, sym: Symbol, is_raw: bool, span: Span) -> Ident {
330 let sym = nfc_normalize(&sym.as_str());
331 let string = sym.as_str();
332 if !rustc_lexer::is_ident(&string) {
333 panic!("`{:?}` is not a valid identifier", string)
334 }
335 if is_raw && !sym.can_be_raw() {
336 panic!("`{}` cannot be a raw identifier", string);
337 }
338 sess.symbol_gallery.insert(sym, span);
339 Ident { sym, is_raw, span }
340 }
341 fn dollar_crate(span: Span) -> Ident {
342 // `$crate` is accepted as an ident only if it comes from the compiler.
343 Ident { sym: kw::DollarCrate, is_raw: false, span }
344 }
345 }
346
347 // FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
348 #[derive(Clone, Debug)]
349 pub struct Literal {
350 lit: token::Lit,
351 span: Span,
352 }
353
354 pub(crate) struct Rustc<'a> {
355 sess: &'a ParseSess,
356 def_site: Span,
357 call_site: Span,
358 mixed_site: Span,
359 span_debug: bool,
360 }
361
362 impl<'a> Rustc<'a> {
363 pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
364 let expn_data = cx.current_expansion.id.expn_data();
365 Rustc {
366 sess: &cx.sess.parse_sess,
367 def_site: cx.with_def_site_ctxt(expn_data.def_site),
368 call_site: cx.with_call_site_ctxt(expn_data.call_site),
369 mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site),
370 span_debug: cx.ecfg.span_debug,
371 }
372 }
373
374 fn lit(&mut self, kind: token::LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Literal {
375 Literal { lit: token::Lit::new(kind, symbol, suffix), span: server::Span::call_site(self) }
376 }
377 }
378
379 impl server::Types for Rustc<'_> {
380 type FreeFunctions = FreeFunctions;
381 type TokenStream = TokenStream;
382 type TokenStreamBuilder = tokenstream::TokenStreamBuilder;
383 type TokenStreamIter = TokenStreamIter;
384 type Group = Group;
385 type Punct = Punct;
386 type Ident = Ident;
387 type Literal = Literal;
388 type SourceFile = Lrc<SourceFile>;
389 type MultiSpan = Vec<Span>;
390 type Diagnostic = Diagnostic;
391 type Span = Span;
392 }
393
394 impl server::FreeFunctions for Rustc<'_> {
395 fn track_env_var(&mut self, var: &str, value: Option<&str>) {
396 self.sess.env_depinfo.borrow_mut().insert((Symbol::intern(var), value.map(Symbol::intern)));
397 }
398 }
399
400 impl server::TokenStream for Rustc<'_> {
401 fn new(&mut self) -> Self::TokenStream {
402 TokenStream::default()
403 }
404 fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
405 stream.is_empty()
406 }
407 fn from_str(&mut self, src: &str) -> Self::TokenStream {
408 parse_stream_from_source_str(
409 FileName::proc_macro_source_code(src),
410 src.to_string(),
411 self.sess,
412 Some(self.call_site),
413 )
414 }
415 fn to_string(&mut self, stream: &Self::TokenStream) -> String {
416 pprust::tts_to_string(stream)
417 }
418 fn from_token_tree(
419 &mut self,
420 tree: TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>,
421 ) -> Self::TokenStream {
422 tree.to_internal()
423 }
424 fn into_iter(&mut self, stream: Self::TokenStream) -> Self::TokenStreamIter {
425 TokenStreamIter { cursor: stream.trees(), stack: vec![] }
426 }
427 }
428
429 impl server::TokenStreamBuilder for Rustc<'_> {
430 fn new(&mut self) -> Self::TokenStreamBuilder {
431 tokenstream::TokenStreamBuilder::new()
432 }
433 fn push(&mut self, builder: &mut Self::TokenStreamBuilder, stream: Self::TokenStream) {
434 builder.push(stream);
435 }
436 fn build(&mut self, builder: Self::TokenStreamBuilder) -> Self::TokenStream {
437 builder.build()
438 }
439 }
440
441 impl server::TokenStreamIter for Rustc<'_> {
442 fn next(
443 &mut self,
444 iter: &mut Self::TokenStreamIter,
445 ) -> Option<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> {
446 loop {
447 let tree = iter.stack.pop().or_else(|| {
448 let next = iter.cursor.next_with_spacing()?;
449 Some(TokenTree::from_internal((next, self.sess, &mut iter.stack)))
450 })?;
451 // A hack used to pass AST fragments to attribute and derive macros
452 // as a single nonterminal token instead of a token stream.
453 // Such token needs to be "unwrapped" and not represented as a delimited group.
454 // FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
455 if let TokenTree::Group(ref group) = tree {
456 if group.flatten {
457 iter.cursor.append(group.stream.clone());
458 continue;
459 }
460 }
461 return Some(tree);
462 }
463 }
464 }
465
466 impl server::Group for Rustc<'_> {
467 fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group {
468 Group {
469 delimiter,
470 stream,
471 span: DelimSpan::from_single(server::Span::call_site(self)),
472 flatten: false,
473 }
474 }
475 fn delimiter(&mut self, group: &Self::Group) -> Delimiter {
476 group.delimiter
477 }
478 fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
479 group.stream.clone()
480 }
481 fn span(&mut self, group: &Self::Group) -> Self::Span {
482 group.span.entire()
483 }
484 fn span_open(&mut self, group: &Self::Group) -> Self::Span {
485 group.span.open
486 }
487 fn span_close(&mut self, group: &Self::Group) -> Self::Span {
488 group.span.close
489 }
490 fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
491 group.span = DelimSpan::from_single(span);
492 }
493 }
494
495 impl server::Punct for Rustc<'_> {
496 fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct {
497 Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self))
498 }
499 fn as_char(&mut self, punct: Self::Punct) -> char {
500 punct.ch
501 }
502 fn spacing(&mut self, punct: Self::Punct) -> Spacing {
503 if punct.joint { Spacing::Joint } else { Spacing::Alone }
504 }
505 fn span(&mut self, punct: Self::Punct) -> Self::Span {
506 punct.span
507 }
508 fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct {
509 Punct { span, ..punct }
510 }
511 }
512
513 impl server::Ident for Rustc<'_> {
514 fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
515 Ident::new(self.sess, Symbol::intern(string), is_raw, span)
516 }
517 fn span(&mut self, ident: Self::Ident) -> Self::Span {
518 ident.span
519 }
520 fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
521 Ident { span, ..ident }
522 }
523 }
524
525 impl server::Literal for Rustc<'_> {
526 fn debug_kind(&mut self, literal: &Self::Literal) -> String {
527 format!("{:?}", literal.lit.kind)
528 }
529 fn symbol(&mut self, literal: &Self::Literal) -> String {
530 literal.lit.symbol.to_string()
531 }
532 fn suffix(&mut self, literal: &Self::Literal) -> Option<String> {
533 literal.lit.suffix.as_ref().map(Symbol::to_string)
534 }
535 fn integer(&mut self, n: &str) -> Self::Literal {
536 self.lit(token::Integer, Symbol::intern(n), None)
537 }
538 fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal {
539 self.lit(token::Integer, Symbol::intern(n), Some(Symbol::intern(kind)))
540 }
541 fn float(&mut self, n: &str) -> Self::Literal {
542 self.lit(token::Float, Symbol::intern(n), None)
543 }
544 fn f32(&mut self, n: &str) -> Self::Literal {
545 self.lit(token::Float, Symbol::intern(n), Some(sym::f32))
546 }
547 fn f64(&mut self, n: &str) -> Self::Literal {
548 self.lit(token::Float, Symbol::intern(n), Some(sym::f64))
549 }
550 fn string(&mut self, string: &str) -> Self::Literal {
551 let mut escaped = String::new();
552 for ch in string.chars() {
553 escaped.extend(ch.escape_debug());
554 }
555 self.lit(token::Str, Symbol::intern(&escaped), None)
556 }
557 fn character(&mut self, ch: char) -> Self::Literal {
558 let mut escaped = String::new();
559 escaped.extend(ch.escape_unicode());
560 self.lit(token::Char, Symbol::intern(&escaped), None)
561 }
562 fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
563 let string = bytes
564 .iter()
565 .cloned()
566 .flat_map(ascii::escape_default)
567 .map(Into::<char>::into)
568 .collect::<String>();
569 self.lit(token::ByteStr, Symbol::intern(&string), None)
570 }
571 fn span(&mut self, literal: &Self::Literal) -> Self::Span {
572 literal.span
573 }
574 fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) {
575 literal.span = span;
576 }
577 fn subspan(
578 &mut self,
579 literal: &Self::Literal,
580 start: Bound<usize>,
581 end: Bound<usize>,
582 ) -> Option<Self::Span> {
583 let span = literal.span;
584 let length = span.hi().to_usize() - span.lo().to_usize();
585
586 let start = match start {
587 Bound::Included(lo) => lo,
588 Bound::Excluded(lo) => lo.checked_add(1)?,
589 Bound::Unbounded => 0,
590 };
591
592 let end = match end {
593 Bound::Included(hi) => hi.checked_add(1)?,
594 Bound::Excluded(hi) => hi,
595 Bound::Unbounded => length,
596 };
597
598 // Bounds check the values, preventing addition overflow and OOB spans.
599 if start > u32::MAX as usize
600 || end > u32::MAX as usize
601 || (u32::MAX - start as u32) < span.lo().to_u32()
602 || (u32::MAX - end as u32) < span.lo().to_u32()
603 || start >= end
604 || end > length
605 {
606 return None;
607 }
608
609 let new_lo = span.lo() + BytePos::from_usize(start);
610 let new_hi = span.lo() + BytePos::from_usize(end);
611 Some(span.with_lo(new_lo).with_hi(new_hi))
612 }
613 }
614
615 impl server::SourceFile for Rustc<'_> {
616 fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
617 Lrc::ptr_eq(file1, file2)
618 }
619 fn path(&mut self, file: &Self::SourceFile) -> String {
620 match file.name {
621 FileName::Real(ref name) => name
622 .local_path()
623 .to_str()
624 .expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
625 .to_string(),
626 _ => file.name.to_string(),
627 }
628 }
629 fn is_real(&mut self, file: &Self::SourceFile) -> bool {
630 file.is_real_file()
631 }
632 }
633
634 impl server::MultiSpan for Rustc<'_> {
635 fn new(&mut self) -> Self::MultiSpan {
636 vec![]
637 }
638 fn push(&mut self, spans: &mut Self::MultiSpan, span: Self::Span) {
639 spans.push(span)
640 }
641 }
642
643 impl server::Diagnostic for Rustc<'_> {
644 fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
645 let mut diag = Diagnostic::new(level.to_internal(), msg);
646 diag.set_span(MultiSpan::from_spans(spans));
647 diag
648 }
649 fn sub(
650 &mut self,
651 diag: &mut Self::Diagnostic,
652 level: Level,
653 msg: &str,
654 spans: Self::MultiSpan,
655 ) {
656 diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None);
657 }
658 fn emit(&mut self, diag: Self::Diagnostic) {
659 self.sess.span_diagnostic.emit_diagnostic(&diag);
660 }
661 }
662
663 impl server::Span for Rustc<'_> {
664 fn debug(&mut self, span: Self::Span) -> String {
665 if self.span_debug {
666 format!("{:?}", span)
667 } else {
668 format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0)
669 }
670 }
671 fn def_site(&mut self) -> Self::Span {
672 self.def_site
673 }
674 fn call_site(&mut self) -> Self::Span {
675 self.call_site
676 }
677 fn mixed_site(&mut self) -> Self::Span {
678 self.mixed_site
679 }
680 fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
681 self.sess.source_map().lookup_char_pos(span.lo()).file
682 }
683 fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
684 span.parent()
685 }
686 fn source(&mut self, span: Self::Span) -> Self::Span {
687 span.source_callsite()
688 }
689 fn start(&mut self, span: Self::Span) -> LineColumn {
690 let loc = self.sess.source_map().lookup_char_pos(span.lo());
691 LineColumn { line: loc.line, column: loc.col.to_usize() }
692 }
693 fn end(&mut self, span: Self::Span) -> LineColumn {
694 let loc = self.sess.source_map().lookup_char_pos(span.hi());
695 LineColumn { line: loc.line, column: loc.col.to_usize() }
696 }
697 fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
698 let self_loc = self.sess.source_map().lookup_char_pos(first.lo());
699 let other_loc = self.sess.source_map().lookup_char_pos(second.lo());
700
701 if self_loc.file.name != other_loc.file.name {
702 return None;
703 }
704
705 Some(first.to(second))
706 }
707 fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
708 span.with_ctxt(at.ctxt())
709 }
710 fn source_text(&mut self, span: Self::Span) -> Option<String> {
711 self.sess.source_map().span_to_snippet(span).ok()
712 }
713 }