1 use crate::base
::ExtCtxt
;
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}
;
16 use pm
::bridge
::{server, TokenTree}
;
17 use pm
::{Delimiter, Level, LineColumn, Spacing}
;
19 use std
::{ascii, panic}
;
21 trait FromInternal
<T
> {
22 fn from_internal(x
: T
) -> Self;
26 fn to_internal(self) -> T
;
29 impl FromInternal
<token
::DelimToken
> for Delimiter
{
30 fn from_internal(delim
: token
::DelimToken
) -> Delimiter
{
32 token
::Paren
=> Delimiter
::Parenthesis
,
33 token
::Brace
=> Delimiter
::Brace
,
34 token
::Bracket
=> Delimiter
::Bracket
,
35 token
::NoDelim
=> Delimiter
::None
,
40 impl ToInternal
<token
::DelimToken
> for Delimiter
{
41 fn to_internal(self) -> token
::DelimToken
{
43 Delimiter
::Parenthesis
=> token
::Paren
,
44 Delimiter
::Brace
=> token
::Brace
,
45 Delimiter
::Bracket
=> token
::Bracket
,
46 Delimiter
::None
=> token
::NoDelim
,
51 impl FromInternal
<(TreeAndSpacing
, &'_ ParseSess
, &'_
mut Vec
<Self>)>
52 for TokenTree
<Group
, Punct
, Ident
, Literal
>
55 ((tree
, spacing
), sess
, stack
): (TreeAndSpacing
, &ParseSess
, &mut Vec
<Self>),
57 use rustc_ast
::token
::*;
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 }
);
65 tokenstream
::TokenTree
::Token(token
) => token
,
69 ($ty
:ident { $($field:ident $(: $value:expr)*),+ $(,)? }
) => (
70 TokenTree
::$
ty(self::$ty
{
71 $
($field $
(: $value
)*,)+
75 ($ty
:ident
::$method
:ident($
($value
:expr
),*)) => (
76 TokenTree
::$
ty(self::$ty
::$
method($
($value
,)* span
))
81 tt
!(Punct
::new($a
, joint
))
83 ($a
:expr
, $b
:expr
) => {{
84 stack
.push(tt
!(Punct
::new($b
, joint
)));
85 tt
!(Punct
::new($a
, true))
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))
98 EqEq
=> op
!('
='
, '
='
),
102 AndAnd
=> op
!('
&'
, '
&'
),
103 OrOr
=> 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
!('
>'
, '
>'
, '
='
),
128 DotDot
=> op
!('
.'
, '
.'
),
129 DotDotDot
=> op
!('
.'
, '
.'
, '
.'
),
130 DotDotEq
=> op
!('
.'
, '
.'
, '
='
),
134 ModSep
=> op
!('
:'
, '
:'
),
135 RArrow
=> op
!('
-'
, '
>'
),
136 LArrow
=> op
!('
<'
, '
-'
),
137 FatArrow
=> op
!('
='
, '
>'
),
140 Question
=> op
!('?'
),
141 SingleQuote
=> op
!('
\''
),
143 Ident(name
, false) if name
== kw
::DollarCrate
=> tt
!(Ident
::dollar_crate()),
144 Ident(name
, is_raw
) => tt
!(Ident
::new(sess
, name
, is_raw
)),
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))
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());
157 Ident(sym
::doc
, false),
159 TokenKind
::lit(token
::Str
, Symbol
::intern(&escaped
), None
),
162 .map(|kind
| tokenstream
::TokenTree
::token(kind
, span
))
164 stack
.push(TokenTree
::Group(Group
{
165 delimiter
: Delimiter
::Bracket
,
167 span
: DelimSpan
::from_single(span
),
170 if attr_style
== ast
::AttrStyle
::Inner
{
171 stack
.push(tt
!(Punct
::new('
!'
, false)));
173 tt
!(Punct
::new('
#', false))
176 Interpolated(nt
) => {
177 if let Some((name
, is_raw
)) =
178 nt
.ident_name_compatibility_hack(span
, sess
.source_map())
180 TokenTree
::Ident(Ident
::new(sess
, name
.name
, is_raw
, name
.span
))
182 let stream
= nt_to_tokenstream(&nt
, sess
, CanSynthesizeMissingTokens
::No
);
183 TokenTree
::Group(Group
{
184 delimiter
: Delimiter
::None
,
186 span
: DelimSpan
::from_single(span
),
187 flatten
: nt
.pretty_printing_compatibility_hack(),
192 OpenDelim(..) | CloseDelim(..) => unreachable
!(),
193 Eof
=> unreachable
!(),
198 impl ToInternal
<TokenStream
> for TokenTree
<Group
, Punct
, Ident
, Literal
> {
199 fn to_internal(self) -> TokenStream
{
200 use rustc_ast
::token
::*;
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
)
208 TokenTree
::Ident(self::Ident { sym, is_raw, span }
) => {
209 return tokenstream
::TokenTree
::token(Ident(sym
, is_raw
), span
).into();
211 TokenTree
::Literal(self::Literal
{
212 lit
: token
::Lit { kind: token::Integer, symbol, suffix }
,
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();
222 TokenTree
::Literal(self::Literal
{
223 lit
: token
::Lit { kind: token::Float, symbol, suffix }
,
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();
233 TokenTree
::Literal(self::Literal { lit, span }
) => {
234 return tokenstream
::TokenTree
::token(Literal(lit
), span
).into();
238 let kind
= match ch
{
248 '
%'
=> BinOp(Percent
),
264 let tree
= tokenstream
::TokenTree
::token(kind
, span
);
265 TokenStream
::new(vec
![(tree
, if joint { Joint }
else { Alone }
)])
269 impl ToInternal
<rustc_errors
::Level
> for Level
{
270 fn to_internal(self) -> rustc_errors
::Level
{
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),
281 pub struct FreeFunctions
;
284 pub struct TokenStreamIter
{
285 cursor
: tokenstream
::Cursor
,
286 stack
: Vec
<TokenTree
<Group
, Punct
, Ident
, Literal
>>,
291 delimiter
: Delimiter
,
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).
300 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
303 // NB. not using `Spacing` here because it doesn't implement `Hash`.
309 fn new(ch
: char, joint
: bool
, span
: Span
) -> Punct
{
310 const LEGAL_CHARS
: &[char] = &[
311 '
='
, '
<'
, '
>'
, '
!'
, '
~'
, '
+'
, '
-'
, '
*'
, '
/'
, '
%'
, '
^', '
&'
, '
|'
, '@'
, '
.'
, '
,'
, '
;'
,
312 '
:'
, '
#', '$', '?', '\'',
314 if !LEGAL_CHARS
.contains(&ch
) {
315 panic
!("unsupported character `{:?}`", ch
)
317 Punct { ch, joint, span }
321 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
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
)
335 if is_raw
&& !sym
.can_be_raw() {
336 panic
!("`{}` cannot be a raw identifier", string
);
338 sess
.symbol_gallery
.insert(sym
, span
);
339 Ident { sym, is_raw, span }
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 }
347 // FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
348 #[derive(Clone, Debug)]
354 pub(crate) struct Rustc
<'a
> {
363 pub fn new(cx
: &'a ExtCtxt
<'_
>) -> Self {
364 let expn_data
= cx
.current_expansion
.id
.expn_data();
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
,
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) }
379 impl server
::Types
for Rustc
<'_
> {
380 type FreeFunctions
= FreeFunctions
;
381 type TokenStream
= TokenStream
;
382 type TokenStreamBuilder
= tokenstream
::TokenStreamBuilder
;
383 type TokenStreamIter
= TokenStreamIter
;
387 type Literal
= Literal
;
388 type SourceFile
= Lrc
<SourceFile
>;
389 type MultiSpan
= Vec
<Span
>;
390 type Diagnostic
= Diagnostic
;
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
)));
400 impl server
::TokenStream
for Rustc
<'_
> {
401 fn new(&mut self) -> Self::TokenStream
{
402 TokenStream
::default()
404 fn is_empty(&mut self, stream
: &Self::TokenStream
) -> bool
{
407 fn from_str(&mut self, src
: &str) -> Self::TokenStream
{
408 parse_stream_from_source_str(
409 FileName
::proc_macro_source_code(src
),
412 Some(self.call_site
),
415 fn to_string(&mut self, stream
: &Self::TokenStream
) -> String
{
416 pprust
::tts_to_string(stream
)
420 tree
: TokenTree
<Self::Group
, Self::Punct
, Self::Ident
, Self::Literal
>,
421 ) -> Self::TokenStream
{
424 fn into_iter(&mut self, stream
: Self::TokenStream
) -> Self::TokenStreamIter
{
425 TokenStreamIter { cursor: stream.trees(), stack: vec![] }
429 impl server
::TokenStreamBuilder
for Rustc
<'_
> {
430 fn new(&mut self) -> Self::TokenStreamBuilder
{
431 tokenstream
::TokenStreamBuilder
::new()
433 fn push(&mut self, builder
: &mut Self::TokenStreamBuilder
, stream
: Self::TokenStream
) {
434 builder
.push(stream
);
436 fn build(&mut self, builder
: Self::TokenStreamBuilder
) -> Self::TokenStream
{
441 impl server
::TokenStreamIter
for Rustc
<'_
> {
444 iter
: &mut Self::TokenStreamIter
,
445 ) -> Option
<TokenTree
<Self::Group
, Self::Punct
, Self::Ident
, Self::Literal
>> {
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
)))
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
{
457 iter
.cursor
.append(group
.stream
.clone());
466 impl server
::Group
for Rustc
<'_
> {
467 fn new(&mut self, delimiter
: Delimiter
, stream
: Self::TokenStream
) -> Self::Group
{
471 span
: DelimSpan
::from_single(server
::Span
::call_site(self)),
475 fn delimiter(&mut self, group
: &Self::Group
) -> Delimiter
{
478 fn stream(&mut self, group
: &Self::Group
) -> Self::TokenStream
{
481 fn span(&mut self, group
: &Self::Group
) -> Self::Span
{
484 fn span_open(&mut self, group
: &Self::Group
) -> Self::Span
{
487 fn span_close(&mut self, group
: &Self::Group
) -> Self::Span
{
490 fn set_span(&mut self, group
: &mut Self::Group
, span
: Self::Span
) {
491 group
.span
= DelimSpan
::from_single(span
);
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))
499 fn as_char(&mut self, punct
: Self::Punct
) -> char {
502 fn spacing(&mut self, punct
: Self::Punct
) -> Spacing
{
503 if punct
.joint { Spacing::Joint }
else { Spacing::Alone }
505 fn span(&mut self, punct
: Self::Punct
) -> Self::Span
{
508 fn with_span(&mut self, punct
: Self::Punct
, span
: Self::Span
) -> Self::Punct
{
509 Punct { span, ..punct }
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
)
517 fn span(&mut self, ident
: Self::Ident
) -> Self::Span
{
520 fn with_span(&mut self, ident
: Self::Ident
, span
: Self::Span
) -> Self::Ident
{
521 Ident { span, ..ident }
525 impl server
::Literal
for Rustc
<'_
> {
526 fn debug_kind(&mut self, literal
: &Self::Literal
) -> String
{
527 format
!("{:?}", literal
.lit
.kind
)
529 fn symbol(&mut self, literal
: &Self::Literal
) -> String
{
530 literal
.lit
.symbol
.to_string()
532 fn suffix(&mut self, literal
: &Self::Literal
) -> Option
<String
> {
533 literal
.lit
.suffix
.as_ref().map(Symbol
::to_string
)
535 fn integer(&mut self, n
: &str) -> Self::Literal
{
536 self.lit(token
::Integer
, Symbol
::intern(n
), None
)
538 fn typed_integer(&mut self, n
: &str, kind
: &str) -> Self::Literal
{
539 self.lit(token
::Integer
, Symbol
::intern(n
), Some(Symbol
::intern(kind
)))
541 fn float(&mut self, n
: &str) -> Self::Literal
{
542 self.lit(token
::Float
, Symbol
::intern(n
), None
)
544 fn f32(&mut self, n
: &str) -> Self::Literal
{
545 self.lit(token
::Float
, Symbol
::intern(n
), Some(sym
::f32))
547 fn f64(&mut self, n
: &str) -> Self::Literal
{
548 self.lit(token
::Float
, Symbol
::intern(n
), Some(sym
::f64))
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());
555 self.lit(token
::Str
, Symbol
::intern(&escaped
), None
)
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
)
562 fn byte_string(&mut self, bytes
: &[u8]) -> Self::Literal
{
566 .flat_map(ascii
::escape_default
)
567 .map(Into
::<char>::into
)
568 .collect
::<String
>();
569 self.lit(token
::ByteStr
, Symbol
::intern(&string
), None
)
571 fn span(&mut self, literal
: &Self::Literal
) -> Self::Span
{
574 fn set_span(&mut self, literal
: &mut Self::Literal
, span
: Self::Span
) {
579 literal
: &Self::Literal
,
582 ) -> Option
<Self::Span
> {
583 let span
= literal
.span
;
584 let length
= span
.hi().to_usize() - span
.lo().to_usize();
586 let start
= match start
{
587 Bound
::Included(lo
) => lo
,
588 Bound
::Excluded(lo
) => lo
.checked_add(1)?
,
589 Bound
::Unbounded
=> 0,
592 let end
= match end
{
593 Bound
::Included(hi
) => hi
.checked_add(1)?
,
594 Bound
::Excluded(hi
) => hi
,
595 Bound
::Unbounded
=> length
,
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()
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
))
615 impl server
::SourceFile
for Rustc
<'_
> {
616 fn eq(&mut self, file1
: &Self::SourceFile
, file2
: &Self::SourceFile
) -> bool
{
617 Lrc
::ptr_eq(file1
, file2
)
619 fn path(&mut self, file
: &Self::SourceFile
) -> String
{
621 FileName
::Real(ref name
) => name
624 .expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
626 _
=> file
.name
.to_string(),
629 fn is_real(&mut self, file
: &Self::SourceFile
) -> bool
{
634 impl server
::MultiSpan
for Rustc
<'_
> {
635 fn new(&mut self) -> Self::MultiSpan
{
638 fn push(&mut self, spans
: &mut Self::MultiSpan
, span
: Self::Span
) {
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
));
651 diag
: &mut Self::Diagnostic
,
654 spans
: Self::MultiSpan
,
656 diag
.sub(level
.to_internal(), msg
, MultiSpan
::from_spans(spans
), None
);
658 fn emit(&mut self, diag
: Self::Diagnostic
) {
659 self.sess
.span_diagnostic
.emit_diagnostic(&diag
);
663 impl server
::Span
for Rustc
<'_
> {
664 fn debug(&mut self, span
: Self::Span
) -> String
{
666 format
!("{:?}", span
)
668 format
!("{:?} bytes({}..{})", span
.ctxt(), span
.lo().0, span
.hi().0)
671 fn def_site(&mut self) -> Self::Span
{
674 fn call_site(&mut self) -> Self::Span
{
677 fn mixed_site(&mut self) -> Self::Span
{
680 fn source_file(&mut self, span
: Self::Span
) -> Self::SourceFile
{
681 self.sess
.source_map().lookup_char_pos(span
.lo()).file
683 fn parent(&mut self, span
: Self::Span
) -> Option
<Self::Span
> {
686 fn source(&mut self, span
: Self::Span
) -> Self::Span
{
687 span
.source_callsite()
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() }
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() }
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());
701 if self_loc
.file
.name
!= other_loc
.file
.name
{
705 Some(first
.to(second
))
707 fn resolved_at(&mut self, span
: Self::Span
, at
: Self::Span
) -> Self::Span
{
708 span
.with_ctxt(at
.ctxt())
710 fn source_text(&mut self, span
: Self::Span
) -> Option
<String
> {
711 self.sess
.source_map().span_to_snippet(span
).ok()