55
66//! Implementation of the `#[autoimpl]` attribute
77
8- use crate :: generics:: { impl_generics , GenericParam , Generics , TypeParamBound , WherePredicate } ;
8+ use crate :: generics:: { GenericParam , Generics , TypeParamBound , WherePredicate } ;
99use proc_macro2:: { Span , TokenStream } ;
1010use proc_macro_error:: { emit_call_site_error, emit_error} ;
1111use quote:: { quote, ToTokens , TokenStreamExt } ;
1212use std:: { iter, slice} ;
1313use syn:: punctuated:: Punctuated ;
1414use syn:: spanned:: Spanned ;
1515use syn:: token:: { Colon2 , Comma , Eq } ;
16- use syn:: { Attribute , FnArg , Ident , Item , Token , TraitItem , Type , TypePath } ;
16+ use syn:: { parse_quote , Attribute , FnArg , Ident , Item , Token , TraitItem , Type , TypePath } ;
1717
1818/// Autoimpl for types supporting `Deref`
1919pub struct ForDeref {
@@ -143,9 +143,9 @@ impl ForDeref {
143143 /// Expand over the given `item`
144144 ///
145145 /// This attribute does not modify the item.
146- /// The caller should append the result to `item` impl_items .
146+ /// The caller should append the result to `item` tokens .
147147 pub fn expand ( self , item : TokenStream ) -> TokenStream {
148- let item = match syn:: parse2 :: < Item > ( item) {
148+ let trait_def = match syn:: parse2 :: < Item > ( item) {
149149 Ok ( Item :: Trait ( item) ) => item,
150150 Ok ( item) => {
151151 emit_error ! ( item, "expected trait" ) ;
@@ -157,100 +157,160 @@ impl ForDeref {
157157 }
158158 } ;
159159
160- let trait_ident = & item. ident ;
161- let ( _, ty_generics, _) = item. generics . split_for_impl ( ) ;
162- let trait_ty = quote ! { #trait_ident #ty_generics } ;
163- let ( impl_generics, where_clause) = impl_generics ( self . generics , & item. generics , & trait_ty) ;
160+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , PartialOrd , Ord ) ]
161+ enum Bound {
162+ None ,
163+ Deref ( bool ) , // true if DerefMut
164+ ErrorEmitted ,
165+ }
166+ let mut bound = Bound :: None ;
167+
168+ let trait_ident = & trait_def. ident ;
169+ let ( _, trait_generics, _) = trait_def. generics . split_for_impl ( ) ;
170+ let trait_ty = quote ! { #trait_ident #trait_generics } ;
171+ let ty_generics = self . generics . ty_generics ( & trait_def. generics ) ;
172+ let ( impl_generics, where_clause) =
173+ self . generics . impl_generics ( & trait_def. generics , & trait_ty) ;
174+
175+ let definitive_ty = self . definitive ;
176+ let definitive = quote ! { < #definitive_ty as #trait_ty > } ;
177+
178+ // Tokenize, like ToTokens impls for syn::TraitItem*, but for definition
179+ let mut impl_items = TokenStream :: new ( ) ;
180+ let tokens = & mut impl_items;
181+ for item in & trait_def. items {
182+ match item {
183+ TraitItem :: Const ( item) => {
184+ item. const_token . to_tokens ( tokens) ;
185+ item. ident . to_tokens ( tokens) ;
186+ item. colon_token . to_tokens ( tokens) ;
187+ item. ty . to_tokens ( tokens) ;
188+
189+ Eq :: default ( ) . to_tokens ( tokens) ;
190+ definitive. to_tokens ( tokens) ;
191+ Colon2 :: default ( ) . to_tokens ( tokens) ;
192+ item. ident . to_tokens ( tokens) ;
193+
194+ item. semi_token . to_tokens ( tokens) ;
195+ }
196+ TraitItem :: Method ( item) => {
197+ if has_bound_on_self ( & item. sig . generics ) {
198+ // If the method has a bound on Self, we cannot use a dereferencing
199+ // implementation since the definitive type is not guaranteed to match
200+ // the bound (we also cannot add a bound).
164201
165- let definitive = self . definitive ;
166- let definitive = quote ! { < #definitive as #trait_ty > } ;
202+ if item. default . is_none ( ) {
203+ emit_call_site_error ! (
204+ "cannot autoimpl trait with Deref" ;
205+ note = item. span( ) => "method has a bound on Self and no default implementation" ;
206+ ) ;
207+ }
167208
168- let mut toks = TokenStream :: new ( ) ;
169- for target in self . targets {
170- // Tokenize, like ToTokens impls for syn::TraitItem*, but for definition
171- let mut impl_items = TokenStream :: new ( ) ;
172- let tokens = & mut impl_items;
173- for item in & item. items {
174- match item {
175- TraitItem :: Const ( item) => {
176- item. const_token . to_tokens ( tokens) ;
177- item. ident . to_tokens ( tokens) ;
178- item. colon_token . to_tokens ( tokens) ;
179- item. ty . to_tokens ( tokens) ;
180-
181- Eq :: default ( ) . to_tokens ( tokens) ;
182- definitive. to_tokens ( tokens) ;
183- Colon2 :: default ( ) . to_tokens ( tokens) ;
184- item. ident . to_tokens ( tokens) ;
185-
186- item. semi_token . to_tokens ( tokens) ;
209+ continue ;
187210 }
188- TraitItem :: Method ( item) => {
189- if has_bound_on_self ( & item. sig . generics ) {
190- // If the method has a bound on Self, we cannot use a dereferencing
191- // implementation since the definitive type is not guaranteed to match
192- // the bound (we also cannot add a bound).
193211
194- if item. default . is_none ( ) {
212+ item. sig . to_tokens ( tokens) ;
213+
214+ bound = bound. max ( match item. sig . inputs . first ( ) {
215+ Some ( FnArg :: Receiver ( rec) ) => {
216+ if rec. reference . is_some ( ) {
217+ Bound :: Deref ( rec. mutability . is_some ( ) )
218+ } else {
195219 emit_call_site_error ! (
196- "unable to write automatic trait implementations " ;
197- note = item . span( ) => "this method has a bound on Self and no default implementation " ;
220+ "cannot autoimpl trait with Deref " ;
221+ note = rec . span( ) => "deref cannot yield `self` by value " ;
198222 ) ;
223+ Bound :: ErrorEmitted
199224 }
200-
201- continue ;
202225 }
226+ Some ( FnArg :: Typed ( ref pat) ) => match & * pat. ty {
227+ Type :: Reference ( rf) if rf. elem == parse_quote ! { Self } => {
228+ Bound :: Deref ( rf. mutability . is_some ( ) )
229+ }
230+ _ => Bound :: None ,
231+ } ,
232+ _ => Bound :: None ,
233+ } ) ;
234+
235+ let ident = & item. sig . ident ;
236+ let params = item. sig . inputs . iter ( ) . map ( |arg| match arg {
237+ FnArg :: Receiver ( arg) => & arg. self_token as & dyn ToTokens ,
238+ FnArg :: Typed ( arg) => & arg. pat ,
239+ } ) ;
240+ tokens. append_all ( quote ! { {
241+ #definitive :: #ident ( #( #params) , * )
242+ } } ) ;
243+ }
244+ TraitItem :: Type ( item) => {
245+ if has_bound_on_self ( & item. generics ) {
246+ emit_call_site_error ! (
247+ "cannot autoimpl trait with Deref" ;
248+ note = item. span( ) => "type has a bound on Self" ;
249+ ) ;
250+ }
203251
204- item. sig . to_tokens ( tokens) ;
252+ item. type_token . to_tokens ( tokens) ;
253+ item. ident . to_tokens ( tokens) ;
205254
206- let ident = & item. sig . ident ;
207- let params = item. sig . inputs . iter ( ) . map ( |arg| match arg {
208- FnArg :: Receiver ( arg) => & arg. self_token as & dyn ToTokens ,
209- FnArg :: Typed ( arg) => & arg. pat ,
210- } ) ;
211- tokens. append_all ( quote ! { {
212- #definitive :: #ident ( #( #params) , * )
213- } } ) ;
214- }
215- TraitItem :: Type ( item) => {
216- if has_bound_on_self ( & item. generics ) {
217- emit_call_site_error ! (
218- "unable to write automatic trait implementations" ;
219- note = item. span( ) => "this type has a bound on Self" ;
220- ) ;
221- }
255+ let ( _, ty_generics, where_clause) = item. generics . split_for_impl ( ) ;
256+ ty_generics. to_tokens ( tokens) ;
222257
223- item. type_token . to_tokens ( tokens) ;
224- item. ident . to_tokens ( tokens) ;
258+ Eq :: default ( ) . to_tokens ( tokens) ;
259+ definitive. to_tokens ( tokens) ;
260+ Colon2 :: default ( ) . to_tokens ( tokens) ;
261+ item. ident . to_tokens ( tokens) ;
262+ ty_generics. to_tokens ( tokens) ;
225263
226- let ( _, ty_generics, where_clause) = item. generics . split_for_impl ( ) ;
227- ty_generics. to_tokens ( tokens) ;
264+ where_clause. to_tokens ( tokens) ;
265+ item. semi_token . to_tokens ( tokens) ;
266+ }
267+ TraitItem :: Macro ( item) => {
268+ emit_error ! ( item, "unsupported: macro item in trait" ) ;
269+ }
270+ TraitItem :: Verbatim ( item) => {
271+ emit_error ! ( item, "unsupported: verbatim item in trait" ) ;
272+ }
228273
229- Eq :: default ( ) . to_tokens ( tokens) ;
230- definitive. to_tokens ( tokens) ;
231- Colon2 :: default ( ) . to_tokens ( tokens) ;
232- item. ident . to_tokens ( tokens) ;
233- ty_generics. to_tokens ( tokens) ;
274+ /* Testing of exhaustive matching is disabled: syn 1.0.90 breaks it.
275+ #[cfg(test)]
276+ TraitItem::__TestExhaustive(_) => unimplemented!(),
277+ #[cfg(not(test))]
278+ */
279+ _ => ( ) ,
280+ }
281+ }
234282
235- where_clause. to_tokens ( tokens) ;
236- item. semi_token . to_tokens ( tokens) ;
237- }
238- TraitItem :: Macro ( item) => {
239- emit_error ! ( item, "unsupported: macro item in trait" ) ;
240- }
241- TraitItem :: Verbatim ( item) => {
242- emit_error ! ( item, "unsupported: verbatim item in trait" ) ;
283+ let mut toks = TokenStream :: new ( ) ;
284+ match bound {
285+ Bound :: None => ( ) ,
286+ Bound :: Deref ( is_mut) => {
287+ // Emit a bound to improve error messages (see issue 27)
288+ let bound = match is_mut {
289+ false => quote ! { :: core:: ops:: Deref } ,
290+ true => quote ! { :: core:: ops:: DerefMut } ,
291+ } ;
292+
293+ let target_impls = self . targets . iter ( ) . map ( |target| {
294+ quote ! {
295+ impl #impl_generics TargetMustImplDeref #ty_generics for #target
296+ #where_clause { }
243297 }
298+ } ) ;
244299
245- /* Testing of exhaustive matching is disabled: syn 1.0.90 breaks it.
246- #[cfg(test)]
247- TraitItem::__TestExhaustive(_) => unimplemented!(),
248- #[cfg(not(test))]
249- */
250- _ => ( ) ,
251- }
300+ toks. append_all ( quote ! {
301+ #[ automatically_derived]
302+ const _: ( ) = {
303+ trait TargetMustImplDeref #impl_generics: #bound<Target = #definitive_ty>
304+ #where_clause { }
305+
306+ #( #target_impls) *
307+ } ;
308+ } ) ;
252309 }
310+ Bound :: ErrorEmitted => return toks,
311+ }
253312
313+ for target in self . targets {
254314 toks. append_all ( quote ! {
255315 #[ automatically_derived]
256316 impl #impl_generics #trait_ty for #target #where_clause {
0 commit comments