impl_tools_lib/autoimpl/
for_deref.rs1use crate::generics::{GenericParam, Generics, TypeParamBound, WherePredicate};
9use crate::utils::propegate_attr_to_impl;
10use proc_macro_error3::{emit_call_site_error, emit_call_site_warning, emit_error};
11use proc_macro2::{Span, TokenStream};
12use quote::{ToTokens, TokenStreamExt, quote};
13use syn::punctuated::Punctuated;
14use syn::spanned::Spanned;
15use syn::token::{Comma, Eq, PathSep};
16use syn::{FnArg, Ident, Item, Member, Pat, Token, TraitItem, Type, TypePath, parse_quote};
17
18mod kw {
19 syn::custom_keyword!(using);
20}
21
22#[derive(Debug)]
24pub struct ForDeref {
25 generics: Generics,
26 definitive: Option<Ident>,
27 targets: Punctuated<Type, Comma>,
28 using: Option<Member>,
29}
30
31mod parsing {
32 use super::*;
33 use syn::parse::{Parse, ParseStream, Result};
34
35 impl Parse for ForDeref {
36 fn parse(input: ParseStream) -> Result<Self> {
37 let _ = input.parse::<Token![for]>()?;
38 let mut generics: Generics = input.parse()?;
39
40 let targets = Punctuated::parse_separated_nonempty(input)?;
41
42 let mut using = None;
43 if input.peek(kw::using) {
44 let _: kw::using = input.parse()?;
45 let _: Token![self] = input.parse()?;
46 let _: Token![.] = input.parse()?;
47 using = Some(input.parse()?);
48 }
49
50 if input.peek(Token![where]) {
51 generics.where_clause = Some(input.parse()?);
52 }
53
54 let mut definitive: Option<Ident> = None;
55 for param in &generics.params {
56 if let GenericParam::Type(param) = param {
57 for bound in ¶m.bounds {
58 if matches!(bound, TypeParamBound::TraitSubst(_)) {
59 definitive = Some(param.ident.clone());
60 break;
61 }
62 }
63 }
64 }
65 if definitive.is_none() {
66 if let Some(clause) = generics.where_clause.as_ref() {
67 for pred in &clause.predicates {
68 if let WherePredicate::Type(pred) = pred {
69 for bound in &pred.bounds {
70 if matches!(bound, TypeParamBound::TraitSubst(_)) {
71 if let Type::Path(TypePath { qself: None, path }) =
72 &pred.bounded_ty
73 {
74 if let Some(ident) = path.get_ident() {
75 definitive = Some(ident.clone());
76 break;
77 }
78 }
79 }
80 }
81 }
82 }
83 }
84 }
85
86 Ok(ForDeref {
87 generics,
88 definitive,
89 targets,
90 using,
91 })
92 }
93 }
94}
95
96fn has_bound_on_self(generics: &syn::Generics) -> bool {
97 if let Some(ref clause) = generics.where_clause {
98 for pred in clause.predicates.iter() {
99 if let syn::WherePredicate::Type(ty) = pred {
100 if let Type::Path(ref bounded) = ty.bounded_ty {
101 if bounded.qself.is_none() && bounded.path.is_ident("Self") {
102 if ty
103 .bounds
104 .iter()
105 .any(|bound| matches!(bound, syn::TypeParamBound::Trait(_)))
106 {
107 return true;
108 }
109 }
110 }
111 }
112 }
116 }
117
118 false
119}
120
121impl ForDeref {
122 pub fn expand(self, item: TokenStream) -> TokenStream {
127 let trait_def = match syn::parse2::<Item>(item) {
128 Ok(Item::Trait(item)) => item,
129 Ok(item) => {
130 emit_error!(item, "expected trait");
131 return TokenStream::new();
132 }
133 Err(err) => return err.into_compile_error(),
134 };
135
136 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
137 enum Bound {
138 None,
139 Deref(bool), ErrorEmitted,
141 }
142 let mut bound = Bound::None;
143
144 let trait_ident = &trait_def.ident;
145 let (_, trait_generics, _) = trait_def.generics.split_for_impl();
146 let trait_ty = quote! { #trait_ident #trait_generics };
147 let ty_generics = self.generics.ty_generics(&trait_def.generics);
148 let (impl_generics, where_clause) =
149 self.generics.impl_generics(&trait_def.generics, &trait_ty);
150
151 let opt_definitive = self
152 .definitive
153 .as_ref()
154 .map(|ty| quote! { < #ty as #trait_ty > });
155 let fn_definitive = opt_definitive
156 .clone()
157 .unwrap_or_else(|| quote! { #trait_ty });
158
159 let mut impl_items = TokenStream::new();
161 let tokens = &mut impl_items;
162 for item in trait_def.items.into_iter() {
163 match item {
164 TraitItem::Const(item) => {
165 let Some(definitive) = opt_definitive.as_ref() else {
166 emit_error!(
167 item,
168 "cannot autoimpl an associated constant without a definitive type (e.g. `T: trait`)"
169 );
170 continue;
171 };
172
173 for attr in item.attrs.iter() {
174 if *attr.path() == parse_quote! { cfg } {
175 attr.to_tokens(tokens);
176 }
177 }
178
179 item.const_token.to_tokens(tokens);
180 item.ident.to_tokens(tokens);
181 item.colon_token.to_tokens(tokens);
182 item.ty.to_tokens(tokens);
183
184 Eq::default().to_tokens(tokens);
185 definitive.to_tokens(tokens);
186 PathSep::default().to_tokens(tokens);
187 item.ident.to_tokens(tokens);
188
189 item.semi_token.to_tokens(tokens);
190 }
191 TraitItem::Fn(mut item) => {
192 for attr in item.attrs.iter() {
193 if propegate_attr_to_impl(attr) {
194 attr.to_tokens(tokens);
195 }
196 }
197
198 if has_bound_on_self(&item.sig.generics) {
199 if item.default.is_none() {
204 emit_call_site_error!(
205 "cannot autoimpl trait with Deref";
206 note = item.span() => "method has a bound on Self and no default implementation";
207 );
208 } else if !cfg!(feature = "allow-trait-autoimpl-with-sized-fn-bound") {
209 emit_call_site_warning!(
211 "autoimpl on trait that has a method with Self: Sized bound";
212 note = item.span() => "method impl uses default implementation, not deref";
213 );
214 }
215
216 continue;
217 }
218
219 for (i, arg) in item.sig.inputs.iter_mut().enumerate() {
220 if let FnArg::Typed(ty) = arg {
221 if let Pat::Ident(pat) = &mut *ty.pat {
222 pat.by_ref = None;
224 pat.mutability = None;
225 assert_eq!(pat.subpat, None);
226 } else {
227 let name = format!("arg{i}");
229 let ident = Ident::new(&name, Span::call_site());
230 *ty.pat = Pat::Ident(syn::PatIdent {
231 attrs: vec![],
232 by_ref: None,
233 mutability: None,
234 ident,
235 subpat: None,
236 });
237 }
238 }
239 }
240 item.sig.to_tokens(tokens);
241
242 if self.using.is_none() {
243 bound = bound.max(match item.sig.inputs.first() {
244 Some(FnArg::Receiver(rec)) => {
245 if rec.reference.is_some() {
246 Bound::Deref(rec.mutability.is_some())
247 } else {
248 emit_call_site_error!(
249 "cannot autoimpl trait with Deref";
250 note = rec.span() => "deref cannot yield `self` by value";
251 );
252 Bound::ErrorEmitted
253 }
254 }
255 Some(FnArg::Typed(pat)) => match &*pat.ty {
256 Type::Reference(rf) if rf.elem == parse_quote! { Self } => {
257 Bound::Deref(rf.mutability.is_some())
258 }
259 _ => Bound::None,
260 },
261 _ => Bound::None,
262 });
263 }
264
265 let ident = &item.sig.ident;
266 let params = item.sig.inputs.iter().map(|arg| {
267 let mut toks = TokenStream::new();
268 match arg {
269 FnArg::Receiver(arg) => {
270 for attr in &arg.attrs {
271 if propegate_attr_to_impl(&attr) {
272 attr.to_tokens(&mut toks);
273 }
274 }
275 if let Some(member) = self.using.as_ref() {
276 if let Some((r, _)) = arg.reference {
277 r.to_tokens(&mut toks);
278 }
279 if let Some(m) = arg.mutability {
280 m.to_tokens(&mut toks);
281 }
282 let self_ = &arg.self_token;
283 toks.append_all(quote! { #self_ . #member });
284 } else {
285 arg.self_token.to_tokens(&mut toks);
286 }
287 }
288 FnArg::Typed(arg) => {
289 for attr in &arg.attrs {
290 if propegate_attr_to_impl(&attr) {
291 attr.to_tokens(&mut toks);
292 };
293 }
294
295 arg.pat.to_tokens(&mut toks);
296 }
297 };
298 toks
299 });
300 tokens.append_all(quote! { {
301 #fn_definitive :: #ident ( #(#params),* )
302 } });
303 }
304 TraitItem::Type(item) => {
305 let Some(definitive) = opt_definitive.as_ref() else {
306 emit_error!(
307 item,
308 "cannot autoimpl an associated type without a definitive type (e.g. `T: trait`)"
309 );
310 continue;
311 };
312
313 for attr in item.attrs.iter() {
314 if *attr.path() == parse_quote! { cfg } {
315 attr.to_tokens(tokens);
316 }
317 }
318
319 if has_bound_on_self(&item.generics) {
320 emit_call_site_error!(
321 "cannot autoimpl trait with Deref";
322 note = item.span() => "type has a bound on Self";
323 );
324 }
325
326 item.type_token.to_tokens(tokens);
327 item.ident.to_tokens(tokens);
328
329 let (_, ty_generics, where_clause) = item.generics.split_for_impl();
330 ty_generics.to_tokens(tokens);
331
332 Eq::default().to_tokens(tokens);
333 definitive.to_tokens(tokens);
334 PathSep::default().to_tokens(tokens);
335 item.ident.to_tokens(tokens);
336 ty_generics.to_tokens(tokens);
337
338 where_clause.to_tokens(tokens);
339 item.semi_token.to_tokens(tokens);
340 }
341 TraitItem::Macro(item) => {
342 emit_error!(item, "unsupported: macro item in trait");
343 }
344 TraitItem::Verbatim(item) => {
345 emit_error!(item, "unsupported: verbatim item in trait");
346 }
347
348 _ => (),
354 }
355 }
356
357 let mut toks = TokenStream::new();
358 match bound {
359 Bound::None => (),
360 Bound::Deref(is_mut) => {
361 let Some(definitive_ty) = self.definitive.as_ref() else {
362 emit_call_site_error!("require a definitive type (e.g. `T: trait`)");
363 return toks;
364 };
365
366 let bound = match is_mut {
368 false => quote! { ::core::ops::Deref },
369 true => quote! { ::core::ops::DerefMut },
370 };
371
372 let target_impls = self.targets.iter().map(|target| {
373 quote! {
374 impl #impl_generics TargetMustImplDeref #ty_generics for #target
375 #where_clause {}
376 }
377 });
378
379 toks.append_all(quote! {
380 #[automatically_derived]
381 const _: () = {
382 trait TargetMustImplDeref #impl_generics: #bound<Target = #definitive_ty>
383 #where_clause {}
384
385 #(#target_impls)*
386 };
387 });
388 }
389 Bound::ErrorEmitted => return toks,
390 }
391
392 for target in self.targets {
393 toks.append_all(quote! {
394 #[automatically_derived]
395 impl #impl_generics #trait_ty for #target #where_clause {
396 #impl_items
397 }
398 });
399 }
400 toks
401 }
402}