986 lines · 30.4 KB · Rust
RawDownload
// SPDX-License-Identifier: Apache-2.0 OR MIT use crate::detection::inside_proc_macro;use crate::fallback::{self, FromStr2 as _};#[cfg(span_locations)]use crate::location::LineColumn;#[cfg(proc_macro_span)]use crate::probe::proc_macro_span;#[cfg(all(span_locations, proc_macro_span_file))]use crate::probe::proc_macro_span_file;#[cfg(all(span_locations, proc_macro_span_location))]use crate::probe::proc_macro_span_location;use crate::{Delimiter, Punct, Spacing, TokenTree};use core::fmt::{self, Debug, Display};#[cfg(span_locations)]use core::ops::Range;use core::ops::RangeBounds;use std::ffi::CStr;#[cfg(span_locations)]use std::path::PathBuf; #[derive(Clone)]pub(crate) enum TokenStream {    Compiler(DeferredTokenStream),    Fallback(fallback::TokenStream),} // Work around https://github.com/rust-lang/rust/issues/65080.// In `impl Extend<TokenTree> for TokenStream` which is used heavily by quote,// we hold on to the appended tokens and do proc_macro::TokenStream::extend as// late as possible to batch together consecutive uses of the Extend impl.#[derive(Clone)]pub(crate) struct DeferredTokenStream {    stream: proc_macro::TokenStream,    extra: Vec<proc_macro::TokenTree>,} pub(crate) enum LexError {    Compiler(proc_macro::LexError),    Fallback(fallback::LexError),     // Rustc was supposed to return a LexError, but it panicked instead.    // https://github.com/rust-lang/rust/issues/58736    CompilerPanic,} #[cold]fn mismatch(line: u32) -> ! {    #[cfg(procmacro2_backtrace)]    {        let backtrace = std::backtrace::Backtrace::force_capture();        panic!("compiler/fallback mismatch L{}\n\n{}", line, backtrace)    }    #[cfg(not(procmacro2_backtrace))]    {        panic!("compiler/fallback mismatch L{}", line)    }} impl DeferredTokenStream {    fn new(stream: proc_macro::TokenStream) -> Self {        DeferredTokenStream {            stream,            extra: Vec::new(),        }    }     fn is_empty(&self) -> bool {        self.stream.is_empty() && self.extra.is_empty()    }     fn evaluate_now(&mut self) {        // If-check provides a fast short circuit for the common case of `extra`        // being empty, which saves a round trip over the proc macro bridge.        // Improves macro expansion time in winrt by 6% in debug mode.        if !self.extra.is_empty() {            self.stream.extend(self.extra.drain(..));        }    }     fn into_token_stream(mut self) -> proc_macro::TokenStream {        self.evaluate_now();        self.stream    }} impl TokenStream {    pub(crate) fn new() -> Self {        if inside_proc_macro() {            TokenStream::Compiler(DeferredTokenStream::new(proc_macro::TokenStream::new()))        } else {            TokenStream::Fallback(fallback::TokenStream::new())        }    }     pub(crate) fn from_str_checked(src: &str) -> Result<Self, LexError> {        if inside_proc_macro() {            Ok(TokenStream::Compiler(DeferredTokenStream::new(                proc_macro::TokenStream::from_str_checked(src)?,            )))        } else {            Ok(TokenStream::Fallback(                fallback::TokenStream::from_str_checked(src)?,            ))        }    }     pub(crate) fn is_empty(&self) -> bool {        match self {            TokenStream::Compiler(tts) => tts.is_empty(),            TokenStream::Fallback(tts) => tts.is_empty(),        }    }     fn unwrap_nightly(self) -> proc_macro::TokenStream {        match self {            TokenStream::Compiler(s) => s.into_token_stream(),            TokenStream::Fallback(_) => mismatch(line!()),        }    }     fn unwrap_stable(self) -> fallback::TokenStream {        match self {            TokenStream::Compiler(_) => mismatch(line!()),            TokenStream::Fallback(s) => s,        }    }} impl Display for TokenStream {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        match self {            TokenStream::Compiler(tts) => Display::fmt(&tts.clone().into_token_stream(), f),            TokenStream::Fallback(tts) => Display::fmt(tts, f),        }    }} impl From<proc_macro::TokenStream> for TokenStream {    fn from(inner: proc_macro::TokenStream) -> Self {        TokenStream::Compiler(DeferredTokenStream::new(inner))    }} impl From<TokenStream> for proc_macro::TokenStream {    fn from(inner: TokenStream) -> Self {        match inner {            TokenStream::Compiler(inner) => inner.into_token_stream(),            TokenStream::Fallback(inner) => {                proc_macro::TokenStream::from_str_unchecked(&inner.to_string())            }        }    }} impl From<fallback::TokenStream> for TokenStream {    fn from(inner: fallback::TokenStream) -> Self {        TokenStream::Fallback(inner)    }} // Assumes inside_proc_macro().fn into_compiler_token(token: TokenTree) -> proc_macro::TokenTree {    match token {        TokenTree::Group(tt) => proc_macro::TokenTree::Group(tt.inner.unwrap_nightly()),        TokenTree::Punct(tt) => {            let spacing = match tt.spacing() {                Spacing::Joint => proc_macro::Spacing::Joint,                Spacing::Alone => proc_macro::Spacing::Alone,            };            let mut punct = proc_macro::Punct::new(tt.as_char(), spacing);            punct.set_span(tt.span().inner.unwrap_nightly());            proc_macro::TokenTree::Punct(punct)        }        TokenTree::Ident(tt) => proc_macro::TokenTree::Ident(tt.inner.unwrap_nightly()),        TokenTree::Literal(tt) => proc_macro::TokenTree::Literal(tt.inner.unwrap_nightly()),    }} impl From<TokenTree> for TokenStream {    fn from(token: TokenTree) -> Self {        if inside_proc_macro() {            TokenStream::Compiler(DeferredTokenStream::new(proc_macro::TokenStream::from(                into_compiler_token(token),            )))        } else {            TokenStream::Fallback(fallback::TokenStream::from(token))        }    }} impl FromIterator<TokenTree> for TokenStream {    fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self {        if inside_proc_macro() {            TokenStream::Compiler(DeferredTokenStream::new(                trees.into_iter().map(into_compiler_token).collect(),            ))        } else {            TokenStream::Fallback(trees.into_iter().collect())        }    }} impl FromIterator<TokenStream> for TokenStream {    fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {        let mut streams = streams.into_iter();        match streams.next() {            Some(TokenStream::Compiler(mut first)) => {                first.evaluate_now();                first.stream.extend(streams.map(|s| match s {                    TokenStream::Compiler(s) => s.into_token_stream(),                    TokenStream::Fallback(_) => mismatch(line!()),                }));                TokenStream::Compiler(first)            }            Some(TokenStream::Fallback(mut first)) => {                first.extend(streams.map(|s| match s {                    TokenStream::Fallback(s) => s,                    TokenStream::Compiler(_) => mismatch(line!()),                }));                TokenStream::Fallback(first)            }            None => TokenStream::new(),        }    }} impl Extend<TokenTree> for TokenStream {    fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, stream: I) {        match self {            TokenStream::Compiler(tts) => {                // Here is the reason for DeferredTokenStream.                for token in stream {                    tts.extra.push(into_compiler_token(token));                }            }            TokenStream::Fallback(tts) => tts.extend(stream),        }    }} impl Extend<TokenStream> for TokenStream {    fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {        match self {            TokenStream::Compiler(tts) => {                tts.evaluate_now();                tts.stream                    .extend(streams.into_iter().map(TokenStream::unwrap_nightly));            }            TokenStream::Fallback(tts) => {                tts.extend(streams.into_iter().map(TokenStream::unwrap_stable));            }        }    }} impl Debug for TokenStream {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        match self {            TokenStream::Compiler(tts) => Debug::fmt(&tts.clone().into_token_stream(), f),            TokenStream::Fallback(tts) => Debug::fmt(tts, f),        }    }} impl LexError {    pub(crate) fn span(&self) -> Span {        match self {            LexError::Compiler(_) | LexError::CompilerPanic => Span::call_site(),            LexError::Fallback(e) => Span::Fallback(e.span()),        }    }} impl From<proc_macro::LexError> for LexError {    fn from(e: proc_macro::LexError) -> Self {        LexError::Compiler(e)    }} impl From<fallback::LexError> for LexError {    fn from(e: fallback::LexError) -> Self {        LexError::Fallback(e)    }} impl Debug for LexError {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        match self {            LexError::Compiler(e) => Debug::fmt(e, f),            LexError::Fallback(e) => Debug::fmt(e, f),            LexError::CompilerPanic => {                let fallback = fallback::LexError::call_site();                Debug::fmt(&fallback, f)            }        }    }} impl Display for LexError {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        match self {            LexError::Compiler(e) => Display::fmt(e, f),            LexError::Fallback(e) => Display::fmt(e, f),            LexError::CompilerPanic => {                let fallback = fallback::LexError::call_site();                Display::fmt(&fallback, f)            }        }    }} #[derive(Clone)]pub(crate) enum TokenTreeIter {    Compiler(proc_macro::token_stream::IntoIter),    Fallback(fallback::TokenTreeIter),} impl IntoIterator for TokenStream {    type Item = TokenTree;    type IntoIter = TokenTreeIter;     fn into_iter(self) -> TokenTreeIter {        match self {            TokenStream::Compiler(tts) => {                TokenTreeIter::Compiler(tts.into_token_stream().into_iter())            }            TokenStream::Fallback(tts) => TokenTreeIter::Fallback(tts.into_iter()),        }    }} impl Iterator for TokenTreeIter {    type Item = TokenTree;     fn next(&mut self) -> Option<TokenTree> {        let token = match self {            TokenTreeIter::Compiler(iter) => iter.next()?,            TokenTreeIter::Fallback(iter) => return iter.next(),        };        Some(match token {            proc_macro::TokenTree::Group(tt) => {                TokenTree::Group(crate::Group::_new(Group::Compiler(tt)))            }            proc_macro::TokenTree::Punct(tt) => {                let spacing = match tt.spacing() {                    proc_macro::Spacing::Joint => Spacing::Joint,                    proc_macro::Spacing::Alone => Spacing::Alone,                };                let mut o = Punct::new(tt.as_char(), spacing);                o.set_span(crate::Span::_new(Span::Compiler(tt.span())));                TokenTree::Punct(o)            }            proc_macro::TokenTree::Ident(s) => {                TokenTree::Ident(crate::Ident::_new(Ident::Compiler(s)))            }            proc_macro::TokenTree::Literal(l) => {                TokenTree::Literal(crate::Literal::_new(Literal::Compiler(l)))            }        })    }     fn size_hint(&self) -> (usize, Option<usize>) {        match self {            TokenTreeIter::Compiler(tts) => tts.size_hint(),            TokenTreeIter::Fallback(tts) => tts.size_hint(),        }    }} #[derive(Copy, Clone)]pub(crate) enum Span {    Compiler(proc_macro::Span),    Fallback(fallback::Span),} impl Span {    pub(crate) fn call_site() -> Self {        if inside_proc_macro() {            Span::Compiler(proc_macro::Span::call_site())        } else {            Span::Fallback(fallback::Span::call_site())        }    }     pub(crate) fn mixed_site() -> Self {        if inside_proc_macro() {            Span::Compiler(proc_macro::Span::mixed_site())        } else {            Span::Fallback(fallback::Span::mixed_site())        }    }     #[cfg(super_unstable)]    pub(crate) fn def_site() -> Self {        if inside_proc_macro() {            Span::Compiler(proc_macro::Span::def_site())        } else {            Span::Fallback(fallback::Span::def_site())        }    }     pub(crate) fn resolved_at(&self, other: Span) -> Span {        match (self, other) {            (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.resolved_at(b)),            (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.resolved_at(b)),            (Span::Compiler(_), Span::Fallback(_)) => mismatch(line!()),            (Span::Fallback(_), Span::Compiler(_)) => mismatch(line!()),        }    }     pub(crate) fn located_at(&self, other: Span) -> Span {        match (self, other) {            (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.located_at(b)),            (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.located_at(b)),            (Span::Compiler(_), Span::Fallback(_)) => mismatch(line!()),            (Span::Fallback(_), Span::Compiler(_)) => mismatch(line!()),        }    }     pub(crate) fn unwrap(self) -> proc_macro::Span {        match self {            Span::Compiler(s) => s,            Span::Fallback(_) => panic!("proc_macro::Span is only available in procedural macros"),        }    }     #[cfg(span_locations)]    pub(crate) fn byte_range(&self) -> Range<usize> {        match self {            #[cfg(proc_macro_span)]            Span::Compiler(s) => proc_macro_span::byte_range(s),            #[cfg(not(proc_macro_span))]            Span::Compiler(_) => 0..0,            Span::Fallback(s) => s.byte_range(),        }    }     #[cfg(span_locations)]    pub(crate) fn start(&self) -> LineColumn {        match self {            #[cfg(proc_macro_span_location)]            Span::Compiler(s) => LineColumn {                line: proc_macro_span_location::line(s),                column: proc_macro_span_location::column(s).saturating_sub(1),            },            #[cfg(not(proc_macro_span_location))]            Span::Compiler(_) => LineColumn { line: 0, column: 0 },            Span::Fallback(s) => s.start(),        }    }     #[cfg(span_locations)]    pub(crate) fn end(&self) -> LineColumn {        match self {            #[cfg(proc_macro_span_location)]            Span::Compiler(s) => {                let end = proc_macro_span_location::end(s);                LineColumn {                    line: proc_macro_span_location::line(&end),                    column: proc_macro_span_location::column(&end).saturating_sub(1),                }            }            #[cfg(not(proc_macro_span_location))]            Span::Compiler(_) => LineColumn { line: 0, column: 0 },            Span::Fallback(s) => s.end(),        }    }     #[cfg(span_locations)]    pub(crate) fn file(&self) -> String {        match self {            #[cfg(proc_macro_span_file)]            Span::Compiler(s) => proc_macro_span_file::file(s),            #[cfg(not(proc_macro_span_file))]            Span::Compiler(_) => "<token stream>".to_owned(),            Span::Fallback(s) => s.file(),        }    }     #[cfg(span_locations)]    pub(crate) fn local_file(&self) -> Option<PathBuf> {        match self {            #[cfg(proc_macro_span_file)]            Span::Compiler(s) => proc_macro_span_file::local_file(s),            #[cfg(not(proc_macro_span_file))]            Span::Compiler(_) => None,            Span::Fallback(s) => s.local_file(),        }    }     pub(crate) fn join(&self, other: Span) -> Option<Span> {        let ret = match (self, other) {            #[cfg(proc_macro_span)]            (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(proc_macro_span::join(a, b)?),            (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.join(b)?),            _ => return None,        };        Some(ret)    }

Lines 1–500 of 986.