negative_proc_macros/
_mod.rs1#![allow(nonstandard_style, unused_imports)]
5
6use ::core::{
7 mem,
8 ops::Not as _,
9};
10use ::proc_macro::{
11 TokenStream,
12};
13use ::proc_macro2::{*,
14 TokenStream as TokenStream2,
15};
16use ::quote::{
17 format_ident,
18 quote,
19 quote_spanned,
20 ToTokens,
21};
22use ::syn::{*,
23 parse::{Parse, Parser, ParseStream},
24 punctuated::Punctuated,
25 Result, spanned::Spanned,
27};
28
29#[proc_macro_attribute] pub
31fn negative_impl(
32 args: TokenStream,
33 input: TokenStream,
34) -> TokenStream
35{
36 negative_impl_impl(args.into(), input.into())
37 .unwrap_or_else(|err| {
39 let mut errors =
40 err .into_iter()
41 .map(|err| Error::new(
42 err.span(),
43 format_args!("`#[negative::negative_impl]`: {}", err),
44 ))
45 ;
46 let mut err = errors.next().unwrap();
47 errors.for_each(|cur| err.combine(cur));
48 err.combine(Error::new(
49 Span::mixed_site(),
50 "expected syntax: `[unsafe] impl<…> !Trait for Type [where …] {}`",
51 ));
52 err.to_compile_error()
53 })
54 .into()
55}
56
57struct ItemImpl {
58 mb_unsafe: Option<Token![unsafe]>,
59 impl_: Token![impl],
60 generics: Generics,
61 bang_: Token![!],
62 Trait: Path,
63 for_: Token![for],
64 Receiver: Type,
65 where_: Option<Token![where]>,
66 rest: Vec<TokenTree>,
67}
68
69impl Parse for ItemImpl {
70 fn parse(input: ParseStream<'_>)
71 -> Result<Self>
72 {
73 let input = ItemImpl {
74 mb_unsafe: input.parse()?,
75 impl_: input.parse()?,
76 generics: input.parse()?,
77 bang_: input.parse()?,
78 Trait: input.parse()?,
79 for_: input.parse()?,
80 Receiver: input.parse()?,
81 where_: input.parse()?,
82 rest: input.parse::<TokenStream2>()?.into_iter().collect(),
83 };
84 let last = input.rest.last().ok_or_else(|| Error::new(
85 Span::mixed_site(),
86 "unexpected end of input",
87 ))?;
88 if matches!(
89 last,
90 TokenTree::Group(g)
91 if g.delimiter() == Delimiter::Brace
92 && g.stream().is_empty()
93 )
94 .not()
95 {
96 return Err(Error::new_spanned(
97 last,
98 "expected `{}`",
99 ));
100 }
101 Ok(input)
102 }
103}
104
105fn negative_impl_impl(
106 args: TokenStream2,
107 input: TokenStream2,
108) -> Result<TokenStream2>
109{
110 let _: parse::Nothing = parse2(args)?;
112
113 let ItemImpl {
114 mb_unsafe,
115 impl_,
116 generics,
117 bang_,
118 Trait,
119 for_,
120 Receiver,
121 where_,
122 rest,
123 } = parse2(input)?;
124
125 let bang_span = bang_.span();
126 let where_ = where_.unwrap_or_else(|| Token);
127 let trivially_false_extra_where_predicate = quote_spanned!(bang_span=>
128 for<'ඞ > [()] : ::core::marker::Sized,
129 );
130
131 Ok(quote!(
132 #mb_unsafe
133 #impl_ #generics #Trait #for_ #Receiver
134 #where_
135 #trivially_false_extra_where_predicate
136 #(#rest)*
137 ))
138}