#![feature(prelude_import)]
#![feature(proc_macro_diagnostic)]
#![forbid(unsafe_code)]
#![allow(clippy::needless_doctest_main)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
extern crate proc_macro;
mod diagnostic {
use proc_macro2::{Span, TokenStream};
use quote::{quote_spanned, ToTokens};
use crate::{abort_now, check_correctness, sealed::Sealed, SpanRange};
pub enum Level {
Error,
Warning,
#[doc(hidden)]
NonExhaustive,
}
#[automatically_derived]
impl ::core::fmt::Debug for Level {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(
f,
match self {
Level::Error => "Error",
Level::Warning => "Warning",
Level::NonExhaustive => "NonExhaustive",
},
)
}
}
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Level {}
#[automatically_derived]
impl ::core::cmp::PartialEq for Level {
#[inline]
fn eq(&self, other: &Level) -> bool {
let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
__self_tag == __arg1_tag
}
}
pub struct Diagnostic {
pub(crate) level: Level,
pub(crate) span_range: SpanRange,
pub(crate) msg: String,
pub(crate) suggestions: Vec<(SuggestionKind, String, Option<SpanRange>)>,
pub(crate) children: Vec<(SpanRange, String)>,
}
#[automatically_derived]
impl ::core::fmt::Debug for Diagnostic {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field5_finish(
f,
"Diagnostic",
"level",
&self.level,
"span_range",
&self.span_range,
"msg",
&self.msg,
"suggestions",
&self.suggestions,
"children",
&&self.children,
)
}
}
pub trait DiagnosticExt: Sealed {
fn spanned_range(span_range: SpanRange, level: Level, message: String) -> Self;
fn span_range_error(self, span_range: SpanRange, msg: String) -> Self;
fn span_range_help(self, span_range: SpanRange, msg: String) -> Self;
fn span_range_note(self, span_range: SpanRange, msg: String) -> Self;
}
impl DiagnosticExt for Diagnostic {
fn spanned_range(span_range: SpanRange, level: Level, message: String) -> Self {
Diagnostic {
level,
span_range,
msg: message,
suggestions: ::alloc::vec::Vec::new(),
children: ::alloc::vec::Vec::new(),
}
}
fn span_range_error(mut self, span_range: SpanRange, msg: String) -> Self {
self.children.push((span_range, msg));
self
}
fn span_range_help(mut self, span_range: SpanRange, msg: String) -> Self {
self.suggestions.push((SuggestionKind::Help, msg, Some(span_range)));
self
}
fn span_range_note(mut self, span_range: SpanRange, msg: String) -> Self {
self.suggestions.push((SuggestionKind::Note, msg, Some(span_range)));
self
}
}
impl Diagnostic {
pub fn new(level: Level, message: String) -> Self {
Diagnostic::spanned(Span::call_site(), level, message)
}
pub fn spanned(span: Span, level: Level, message: String) -> Self {
Diagnostic::spanned_range(
SpanRange {
first: span,
last: span,
},
level,
message,
)
}
pub fn span_error(self, span: Span, msg: String) -> Self {
self.span_range_error(
SpanRange {
first: span,
last: span,
},
msg,
)
}
pub fn span_help(self, span: Span, msg: String) -> Self {
self.span_range_help(
SpanRange {
first: span,
last: span,
},
msg,
)
}
pub fn help(mut self, msg: String) -> Self {
self.suggestions.push((SuggestionKind::Help, msg, None));
self
}
pub fn span_note(self, span: Span, msg: String) -> Self {
self.span_range_note(
SpanRange {
first: span,
last: span,
},
msg,
)
}
pub fn note(mut self, msg: String) -> Self {
self.suggestions.push((SuggestionKind::Note, msg, None));
self
}
pub fn message(&self) -> &str {
&self.msg
}
pub fn abort(self) -> ! {
self.emit();
abort_now()
}
pub fn emit(self) {
check_correctness();
crate::imp::emit_diagnostic(self);
}
}
#[doc(hidden)]
impl Diagnostic {
pub fn span_suggestion(self, span: Span, suggestion: &str, msg: String) -> Self {
match suggestion {
"help" | "hint" => self.span_help(span, msg),
_ => self.span_note(span, msg),
}
}
pub fn suggestion(self, suggestion: &str, msg: String) -> Self {
match suggestion {
"help" | "hint" => self.help(msg),
_ => self.note(msg),
}
}
}
impl ToTokens for Diagnostic {
fn to_tokens(&self, ts: &mut TokenStream) {
use std::borrow::Cow;
fn ensure_lf(buf: &mut String, s: &str) {
if s.ends_with('\n') {
buf.push_str(s);
} else {
buf.push_str(s);
buf.push('\n');
}
}
fn diag_to_tokens(
span_range: SpanRange,
level: &Level,
msg: &str,
suggestions: &[(SuggestionKind, String, Option<SpanRange>)],
) -> TokenStream {
if *level == Level::Warning {
return TokenStream::new();
}
let message = if suggestions.is_empty() {
Cow::Borrowed(msg)
} else {
let mut message = String::new();
ensure_lf(&mut message, msg);
message.push('\n');
for (kind, note, _span) in suggestions {
message.push_str(" = ");
message.push_str(kind.name());
message.push_str(": ");
ensure_lf(&mut message, note);
}
message.push('\n');
Cow::Owned(message)
};
let mut msg = proc_macro2::Literal::string(&message);
msg.set_span(span_range.last);
let group = {
let mut _s = ::quote::__private::TokenStream::new();
let _span: ::quote::__private::Span = ::quote::__private::get_span(
span_range.last,
)
.__into_span();
::quote::__private::push_group_spanned(
&mut _s,
_span,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
let _: ::quote::__private::Span = ::quote::__private::get_span(
_span,
)
.__into_span();
::quote::ToTokens::to_tokens(&msg, &mut _s);
_s
},
);
_s
};
{
let mut _s = ::quote::__private::TokenStream::new();
let _span: ::quote::__private::Span = ::quote::__private::get_span(
span_range.first,
)
.__into_span();
::quote::__private::push_ident_spanned(
&mut _s,
_span,
"compile_error",
);
::quote::__private::push_bang_spanned(&mut _s, _span);
::quote::ToTokens::to_tokens(&group, &mut _s);
_s
}
}
ts.extend(
diag_to_tokens(
self.span_range,
&self.level,
&self.msg,
&self.suggestions,
),
);
ts.extend(
self
.children
.iter()
.map(|(span_range, msg)| diag_to_tokens(
*span_range,
&Level::Error,
&msg,
&[],
)),
);
}
}
pub(crate) enum SuggestionKind {
Help,
Note,
}
#[automatically_derived]
impl ::core::fmt::Debug for SuggestionKind {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(
f,
match self {
SuggestionKind::Help => "Help",
SuggestionKind::Note => "Note",
},
)
}
}
impl SuggestionKind {
fn name(&self) -> &'static str {
match self {
SuggestionKind::Note => "note",
SuggestionKind::Help => "help",
}
}
}
#[cfg(feature = "syn")]
impl From<syn::Error> for Diagnostic {
fn from(err: syn::Error) -> Self {
use proc_macro2::{Delimiter, TokenTree};
fn gut_error(
ts: &mut impl Iterator<Item = TokenTree>,
) -> Option<(SpanRange, String)> {
let first = match ts.next() {
None => return None,
Some(tt) => tt.span(),
};
ts.next().unwrap();
let lit = match ts.next().unwrap() {
TokenTree::Group(group) => {
if group.delimiter() == Delimiter::Parenthesis
|| group.delimiter() == Delimiter::Bracket
{
ts.next().unwrap();
}
match group.stream().into_iter().next().unwrap() {
TokenTree::Literal(lit) => lit,
_ => {
::core::panicking::panic(
"internal error: entered unreachable code",
)
}
}
}
_ => {
::core::panicking::panic(
"internal error: entered unreachable code",
)
}
};
let last = lit.span();
let mut msg = lit.to_string();
msg.pop();
msg.remove(0);
Some((SpanRange { first, last }, msg))
}
let mut ts = err.to_compile_error().into_iter();
let (span_range, msg) = gut_error(&mut ts).unwrap();
let mut res = Diagnostic::spanned_range(span_range, Level::Error, msg);
while let Some((span_range, msg)) = gut_error(&mut ts) {
res = res.span_range_error(span_range, msg);
}
res
}
}
}
pub mod dummy {
use std::cell::RefCell;
use proc_macro2::TokenStream;
use crate::check_correctness;
const DUMMY_IMPL: ::std::thread::LocalKey<RefCell<Option<TokenStream>>> = {
#[inline]
fn __init() -> RefCell<Option<TokenStream>> {
RefCell::new(None)
}
#[inline]
unsafe fn __getit(
init: ::std::option::Option<
&mut ::std::option::Option<RefCell<Option<TokenStream>>>,
>,
) -> ::std::option::Option<&'static RefCell<Option<TokenStream>>> {
#[thread_local]
static __KEY: ::std::thread::local_impl::Key<RefCell<Option<TokenStream>>> = ::std::thread::local_impl::Key::<
RefCell<Option<TokenStream>>,
>::new();
unsafe {
__KEY
.get(move || {
if let ::std::option::Option::Some(init) = init {
if let ::std::option::Option::Some(value) = init.take() {
return value;
} else if true {
{
::core::panicking::panic_fmt(
format_args!(
"internal error: entered unreachable code: {0}",
format_args!("missing default value"),
),
);
};
}
}
__init()
})
}
}
unsafe { ::std::thread::LocalKey::new(__getit) }
};
pub fn set_dummy(dummy: TokenStream) -> Option<TokenStream> {
check_correctness();
DUMMY_IMPL.with(|old_dummy| old_dummy.replace(Some(dummy)))
}
pub fn append_dummy(dummy: TokenStream) {
check_correctness();
DUMMY_IMPL
.with(|old_dummy| {
let mut cell = old_dummy.borrow_mut();
if let Some(ts) = cell.as_mut() {
ts.extend(dummy);
} else {
*cell = Some(dummy);
}
});
}
pub(crate) fn cleanup() -> Option<TokenStream> {
DUMMY_IMPL.with(|old_dummy| old_dummy.replace(None))
}
}
mod macros {}
mod imp {
use std::cell::Cell;
use proc_macro::{Diagnostic as PDiag, Level as PLevel};
use crate::{
abort_now, check_correctness, diagnostic::{Diagnostic, Level, SuggestionKind},
};
pub fn abort_if_dirty() {
check_correctness();
if IS_DIRTY.with(|c| c.get()) {
abort_now()
}
}
pub(crate) fn cleanup() -> Vec<Diagnostic> {
IS_DIRTY.with(|c| c.set(false));
::alloc::vec::Vec::new()
}
pub(crate) fn emit_diagnostic(diag: Diagnostic) {
let Diagnostic { level, span_range, msg, suggestions, children } = diag;
let span = span_range.collapse().unwrap();
let level = match level {
Level::Warning => PLevel::Warning,
Level::Error => {
IS_DIRTY.with(|c| c.set(true));
PLevel::Error
}
_ => ::core::panicking::panic("internal error: entered unreachable code"),
};
let mut res = PDiag::spanned(span, level, msg);
for (kind, msg, span) in suggestions {
res = match (kind, span) {
(SuggestionKind::Note, Some(span_range)) => {
res.span_note(span_range.collapse().unwrap(), msg)
}
(SuggestionKind::Help, Some(span_range)) => {
res.span_help(span_range.collapse().unwrap(), msg)
}
(SuggestionKind::Note, None) => res.note(msg),
(SuggestionKind::Help, None) => res.help(msg),
};
}
for (span_range, msg) in children {
let span = span_range.collapse().unwrap();
res = res.span_error(span, msg);
}
res.emit()
}
const IS_DIRTY: ::std::thread::LocalKey<Cell<bool>> = {
#[inline]
fn __init() -> Cell<bool> {
Cell::new(false)
}
#[inline]
unsafe fn __getit(
init: ::std::option::Option<&mut ::std::option::Option<Cell<bool>>>,
) -> ::std::option::Option<&'static Cell<bool>> {
#[thread_local]
static __KEY: ::std::thread::local_impl::Key<Cell<bool>> = ::std::thread::local_impl::Key::<
Cell<bool>,
>::new();
unsafe {
__KEY
.get(move || {
if let ::std::option::Option::Some(init) = init {
if let ::std::option::Option::Some(value) = init.take() {
return value;
} else if true {
{
::core::panicking::panic_fmt(
format_args!(
"internal error: entered unreachable code: {0}",
format_args!("missing default value"),
),
);
};
}
}
__init()
})
}
}
unsafe { ::std::thread::LocalKey::new(__getit) }
};
}
mod sealed {
pub trait Sealed {}
impl Sealed for crate::Diagnostic {}
}
use std::cell::Cell;
use std::panic::{catch_unwind, resume_unwind, UnwindSafe};
use proc_macro2::Span;
use quote::{quote, ToTokens};
pub use proc_macro_error2_attr::proc_macro_error;
pub use crate::{
diagnostic::{Diagnostic, DiagnosticExt, Level},
dummy::{append_dummy, set_dummy},
imp::abort_if_dirty,
};
pub struct SpanRange {
pub first: Span,
pub last: Span,
}
#[automatically_derived]
impl ::core::fmt::Debug for SpanRange {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(
f,
"SpanRange",
"first",
&self.first,
"last",
&&self.last,
)
}
}
#[automatically_derived]
impl ::core::clone::Clone for SpanRange {
#[inline]
fn clone(&self) -> SpanRange {
let _: ::core::clone::AssertParamIsClone<Span>;
*self
}
}
#[automatically_derived]
impl ::core::marker::Copy for SpanRange {}
impl SpanRange {
pub fn single_span(span: Span) -> Self {
SpanRange {
first: span,
last: span,
}
}
pub fn call_site() -> Self {
SpanRange::single_span(Span::call_site())
}
pub fn from_tokens(ts: &dyn ToTokens) -> Self {
let mut spans = ts.to_token_stream().into_iter().map(|tt| tt.span());
let first = spans.next().unwrap_or_else(|| Span::call_site());
let last = spans.last().unwrap_or(first);
SpanRange { first, last }
}
pub fn join_range(self, other: SpanRange) -> Self {
SpanRange {
first: self.first,
last: other.last,
}
}
pub fn collapse(self) -> Span {
self.first.join(self.last).unwrap_or(self.first)
}
}
pub trait ResultExt {
type Ok;
fn unwrap_or_abort(self) -> Self::Ok;
fn expect_or_abort(self, msg: &str) -> Self::Ok;
}
pub trait OptionExt {
type Some;
fn expect_or_abort(self, msg: &str) -> Self::Some;
}
impl<T, E: Into<Diagnostic>> ResultExt for Result<T, E> {
type Ok = T;
fn unwrap_or_abort(self) -> T {
match self {
Ok(res) => res,
Err(e) => e.into().abort(),
}
}
fn expect_or_abort(self, message: &str) -> T {
match self {
Ok(res) => res,
Err(e) => {
let mut e = e.into();
e
.msg = {
let res = ::alloc::fmt::format(
format_args!("{0}: {1}", message, e.msg),
);
res
};
e.abort()
}
}
}
}
impl<T> OptionExt for Option<T> {
type Some = T;
fn expect_or_abort(self, message: &str) -> T {
match self {
Some(res) => res,
None => {
{
#[allow(unused_imports)]
use crate::__export::{
ToTokensAsSpanRange, Span2AsSpanRange, SpanAsSpanRange,
SpanRangeAsSpanRange,
};
use crate::DiagnosticExt;
let span_range = (&crate::__export::proc_macro2::Span::call_site())
.FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
crate::Diagnostic::spanned_range(
span_range,
crate::Level::Error,
message.to_string(),
)
}
.abort()
}
}
}
}
#[doc(hidden)]
pub fn entry_point<F>(f: F, proc_macro_hack: bool) -> proc_macro::TokenStream
where
F: FnOnce() -> proc_macro::TokenStream + UnwindSafe,
{
ENTERED_ENTRY_POINT.with(|flag| flag.set(flag.get() + 1));
let caught = catch_unwind(f);
let dummy = dummy::cleanup();
let err_storage = imp::cleanup();
ENTERED_ENTRY_POINT.with(|flag| flag.set(flag.get() - 1));
let gen_error = || {
if proc_macro_hack {
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(
&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "macro_rules");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_ident(&mut _s, "proc_macro_call");
::quote::__private::push_group(
&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(
&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new(),
);
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_group(
&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unimplemented");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(
&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new(),
);
_s
},
);
_s
},
);
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::ThereIsNoIteratorInRepetition;
#[allow(unused_mut)]
let (mut err_storage, i) = err_storage.quote_into_iter();
let has_iter = has_iter | i;
let _: ::quote::__private::HasIterator = has_iter;
while true {
let err_storage = match err_storage.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&err_storage, &mut _s);
}
}
::quote::ToTokens::to_tokens(&dummy, &mut _s);
::quote::__private::push_ident(&mut _s, "unimplemented");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(
&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new(),
);
_s
},
);
_s
}
} else {
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::ThereIsNoIteratorInRepetition;
#[allow(unused_mut)]
let (mut err_storage, i) = err_storage.quote_into_iter();
let has_iter = has_iter | i;
let _: ::quote::__private::HasIterator = has_iter;
while true {
let err_storage = match err_storage.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&err_storage, &mut _s);
}
}
::quote::ToTokens::to_tokens(&dummy, &mut _s);
_s
}
}
};
match caught {
Ok(ts) => if err_storage.is_empty() { ts } else { gen_error().into() }
Err(boxed) => {
match boxed.downcast::<AbortNow>() {
Ok(_) => gen_error().into(),
Err(boxed) => resume_unwind(boxed),
}
}
}
}
fn abort_now() -> ! {
check_correctness();
std::panic::panic_any(AbortNow)
}
const ENTERED_ENTRY_POINT: ::std::thread::LocalKey<Cell<usize>> = {
#[inline]
fn __init() -> Cell<usize> {
Cell::new(0)
}
#[inline]
unsafe fn __getit(
init: ::std::option::Option<&mut ::std::option::Option<Cell<usize>>>,
) -> ::std::option::Option<&'static Cell<usize>> {
#[thread_local]
static __KEY: ::std::thread::local_impl::Key<Cell<usize>> = ::std::thread::local_impl::Key::<
Cell<usize>,
>::new();
unsafe {
__KEY
.get(move || {
if let ::std::option::Option::Some(init) = init {
if let ::std::option::Option::Some(value) = init.take() {
return value;
} else if true {
{
::core::panicking::panic_fmt(
format_args!(
"internal error: entered unreachable code: {0}",
format_args!("missing default value"),
),
);
};
}
}
__init()
})
}
}
unsafe { ::std::thread::LocalKey::new(__getit) }
};
struct AbortNow;
fn check_correctness() {
if ENTERED_ENTRY_POINT.with(|flag| flag.get()) == 0 {
{
::core::panicking::panic_fmt(
format_args!(
"proc-macro-error API cannot be used outside of `entry_point` invocation, perhaps you forgot to annotate your #[proc_macro] function with `#[proc_macro_error]",
),
);
};
}
}
#[doc(hidden)]
pub mod __export {
pub extern crate proc_macro;
pub extern crate proc_macro2;
use proc_macro2::Span;
use quote::ToTokens;
use crate::SpanRange;
pub trait SpanAsSpanRange {
#[allow(non_snake_case)]
fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(
&self,
) -> SpanRange;
}
pub trait Span2AsSpanRange {
#[allow(non_snake_case)]
fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(
&self,
) -> SpanRange;
}
pub trait ToTokensAsSpanRange {
#[allow(non_snake_case)]
fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(
&self,
) -> SpanRange;
}
pub trait SpanRangeAsSpanRange {
#[allow(non_snake_case)]
fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(
&self,
) -> SpanRange;
}
impl<T: ToTokens> ToTokensAsSpanRange for &T {
fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(
&self,
) -> SpanRange {
let mut ts = self.to_token_stream().into_iter();
let first = ts.next().map(|tt| tt.span()).unwrap_or_else(Span::call_site);
let last = ts.last().map(|tt| tt.span()).unwrap_or(first);
SpanRange { first, last }
}
}
impl Span2AsSpanRange for Span {
fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(
&self,
) -> SpanRange {
SpanRange {
first: *self,
last: *self,
}
}
}
impl SpanAsSpanRange for proc_macro::Span {
fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(
&self,
) -> SpanRange {
SpanRange {
first: self.clone().into(),
last: self.clone().into(),
}
}
}
impl SpanRangeAsSpanRange for SpanRange {
fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(
&self,
) -> SpanRange {
*self
}
}
}