@@ -3,17 +3,17 @@ extern crate proc_macro;
33use proc_macro2:: { Span , TokenStream } ;
44use quote:: quote;
55use quote:: ToTokens ;
6- use syn:: { parse_quote, DeriveInput , GenericParam , Ident , TypeParamBound } ;
6+ use syn:: { parse_quote, DeriveInput , Ident , TypeParam , TypeParamBound } ;
77
88use synstructure:: decl_derive;
99
1010/// Checks whether a generic parameter has a `: HasInterner` bound
11- fn has_interner ( param : & GenericParam ) -> Option < & Ident > {
11+ fn has_interner ( param : & TypeParam ) -> Option < & Ident > {
1212 bounded_by_trait ( param, "HasInterner" )
1313}
1414
1515/// Checks whether a generic parameter has a `: Interner` bound
16- fn is_interner ( param : & GenericParam ) -> Option < & Ident > {
16+ fn is_interner ( param : & TypeParam ) -> Option < & Ident > {
1717 bounded_by_trait ( param, "Interner" )
1818}
1919
@@ -28,48 +28,44 @@ fn has_interner_attr(input: &DeriveInput) -> Option<TokenStream> {
2828 )
2929}
3030
31- fn bounded_by_trait < ' p > ( param : & ' p GenericParam , name : & str ) -> Option < & ' p Ident > {
31+ fn bounded_by_trait < ' p > ( param : & ' p TypeParam , name : & str ) -> Option < & ' p Ident > {
3232 let name = Some ( String :: from ( name) ) ;
33- match param {
34- GenericParam :: Type ( ref t) => t. bounds . iter ( ) . find_map ( |b| {
35- if let TypeParamBound :: Trait ( trait_bound) = b {
36- if trait_bound
37- . path
38- . segments
39- . last ( )
40- . map ( |s| s. ident . to_string ( ) )
41- == name
42- {
43- return Some ( & t. ident ) ;
44- }
33+ param. bounds . iter ( ) . find_map ( |b| {
34+ if let TypeParamBound :: Trait ( trait_bound) = b {
35+ if trait_bound
36+ . path
37+ . segments
38+ . last ( )
39+ . map ( |s| s. ident . to_string ( ) )
40+ == name
41+ {
42+ return Some ( & param. ident ) ;
4543 }
46- None
47- } ) ,
48- _ => None ,
49- }
44+ }
45+ None
46+ } )
5047}
5148
52- fn get_generic_param ( input : & DeriveInput ) -> & GenericParam {
53- match input. generics . params . len ( ) {
54- 1 => { }
49+ fn get_intern_param ( input : & DeriveInput ) -> Option < ( DeriveKind , & Ident ) > {
50+ let mut params = input. generics . type_params ( ) . filter_map ( |param| {
51+ has_interner ( param)
52+ . map ( |ident| ( DeriveKind :: FromHasInterner , ident) )
53+ . or_else ( || is_interner ( param) . map ( |ident| ( DeriveKind :: FromInterner , ident) ) )
54+ } ) ;
5555
56- 0 => panic ! (
57- "deriving this trait requires a single type parameter or a `#[has_interner]` attr"
58- ) ,
56+ let param = params. next ( ) ;
57+ assert ! ( params. next( ) . is_none( ) , "deriving this trait only works with at most one type parameter that implements HasInterner or Interner" ) ;
5958
60- _ => panic ! ( "deriving this trait only works with a single type parameter" ) ,
61- } ;
62- & input. generics . params [ 0 ]
59+ param
6360}
6461
65- fn get_generic_param_name ( input : & DeriveInput ) -> Option < & Ident > {
66- match get_generic_param ( input) {
67- GenericParam :: Type ( t) => Some ( & t. ident ) ,
68- _ => None ,
69- }
62+ fn get_intern_param_name ( input : & DeriveInput ) -> & Ident {
63+ get_intern_param ( input)
64+ . expect ( "deriving this trait requires a parameter that implements HasInterner or Interner" )
65+ . 1
7066}
7167
72- fn find_interner ( s : & mut synstructure:: Structure ) -> ( TokenStream , DeriveKind ) {
68+ fn try_find_interner ( s : & mut synstructure:: Structure ) -> Option < ( TokenStream , DeriveKind ) > {
7369 let input = s. ast ( ) ;
7470
7571 if let Some ( arg) = has_interner_attr ( input) {
@@ -79,35 +75,40 @@ fn find_interner(s: &mut synstructure::Structure) -> (TokenStream, DeriveKind) {
7975 // struct S {
8076 //
8177 // }
82- return ( arg, DeriveKind :: FromHasInternerAttr ) ;
78+ return Some ( ( arg, DeriveKind :: FromHasInternerAttr ) ) ;
8379 }
8480
85- let generic_param0 = get_generic_param ( input) ;
86-
87- if let Some ( param) = has_interner ( generic_param0) {
88- // HasInterner bound:
89- //
90- // Example:
91- //
92- // struct Binders<T: HasInterner> { }
93- s. add_impl_generic ( parse_quote ! { _I } ) ;
94-
95- s. add_where_predicate ( parse_quote ! { _I: :: chalk_ir:: interner:: Interner } ) ;
96- s. add_where_predicate (
97- parse_quote ! { #param: :: chalk_ir:: interner:: HasInterner <Interner = _I> } ,
98- ) ;
81+ get_intern_param ( input) . map ( |generic_param0| match generic_param0 {
82+ ( DeriveKind :: FromHasInterner , param) => {
83+ // HasInterner bound:
84+ //
85+ // Example:
86+ //
87+ // struct Binders<T: HasInterner> { }
88+ s. add_impl_generic ( parse_quote ! { _I } ) ;
89+
90+ s. add_where_predicate ( parse_quote ! { _I: :: chalk_ir:: interner:: Interner } ) ;
91+ s. add_where_predicate (
92+ parse_quote ! { #param: :: chalk_ir:: interner:: HasInterner <Interner = _I> } ,
93+ ) ;
94+
95+ ( quote ! { _I } , DeriveKind :: FromHasInterner )
96+ }
97+ ( DeriveKind :: FromInterner , i) => {
98+ // Interner bound:
99+ //
100+ // Example:
101+ //
102+ // struct Foo<I: Interner> { }
103+ ( quote ! { #i } , DeriveKind :: FromInterner )
104+ }
105+ _ => unreachable ! ( ) ,
106+ } )
107+ }
99108
100- ( quote ! { _I } , DeriveKind :: FromHasInterner )
101- } else if let Some ( i) = is_interner ( generic_param0) {
102- // Interner bound:
103- //
104- // Example:
105- //
106- // struct Foo<I: Interner> { }
107- ( quote ! { #i } , DeriveKind :: FromInterner )
108- } else {
109- panic ! ( "deriving this trait requires a parameter that implements HasInterner or Interner" , ) ;
110- }
109+ fn find_interner ( s : & mut synstructure:: Structure ) -> ( TokenStream , DeriveKind ) {
110+ try_find_interner ( s)
111+ . expect ( "deriving this trait requires a `#[has_interner]` attr or a parameter that implements HasInterner or Interner" )
111112}
112113
113114#[ derive( Copy , Clone , PartialEq ) ]
@@ -117,6 +118,7 @@ enum DeriveKind {
117118 FromInterner ,
118119}
119120
121+ decl_derive ! ( [ FallibleTypeFolder , attributes( has_interner) ] => derive_fallible_type_folder) ;
120122decl_derive ! ( [ HasInterner , attributes( has_interner) ] => derive_has_interner) ;
121123decl_derive ! ( [ TypeVisitable , attributes( has_interner) ] => derive_type_visitable) ;
122124decl_derive ! ( [ TypeSuperVisitable , attributes( has_interner) ] => derive_type_super_visitable) ;
@@ -173,7 +175,7 @@ fn derive_any_type_visitable(
173175 } ) ;
174176
175177 if kind == DeriveKind :: FromHasInterner {
176- let param = get_generic_param_name ( input) . unwrap ( ) ;
178+ let param = get_intern_param_name ( input) ;
177179 s. add_where_predicate ( parse_quote ! { #param: :: chalk_ir:: visit:: TypeVisitable <#interner> } ) ;
178180 }
179181
@@ -269,29 +271,183 @@ fn derive_type_foldable(mut s: synstructure::Structure) -> TokenStream {
269271 vi. construct ( |_, index| {
270272 let bind = & bindings[ index] ;
271273 quote ! {
272- :: chalk_ir:: fold:: TypeFoldable :: fold_with ( #bind, folder, outer_binder) ?
274+ :: chalk_ir:: fold:: TypeFoldable :: try_fold_with ( #bind, folder, outer_binder) ?
273275 }
274276 } )
275277 } ) ;
276278
277279 let input = s. ast ( ) ;
278280
279281 if kind == DeriveKind :: FromHasInterner {
280- let param = get_generic_param_name ( input) . unwrap ( ) ;
282+ let param = get_intern_param_name ( input) ;
281283 s. add_where_predicate ( parse_quote ! { #param: :: chalk_ir:: fold:: TypeFoldable <#interner> } ) ;
282284 } ;
283285
284286 s. add_bounds ( synstructure:: AddBounds :: None ) ;
285287 s. bound_impl (
286288 quote ! ( :: chalk_ir:: fold:: TypeFoldable <#interner>) ,
287289 quote ! {
288- fn fold_with <E >(
290+ fn try_fold_with <E >(
289291 self ,
290- folder: & mut dyn :: chalk_ir:: fold:: TypeFolder < #interner, Error = E >,
292+ folder: & mut dyn :: chalk_ir:: fold:: FallibleTypeFolder < #interner, Error = E >,
291293 outer_binder: :: chalk_ir:: DebruijnIndex ,
292294 ) -> :: std:: result:: Result <Self , E > {
293295 Ok ( match self { #body } )
294296 }
295297 } ,
296298 )
297299}
300+
301+ fn derive_fallible_type_folder ( mut s : synstructure:: Structure ) -> TokenStream {
302+ let interner = try_find_interner ( & mut s) . map_or_else (
303+ || {
304+ s. add_impl_generic ( parse_quote ! { _I } ) ;
305+ s. add_where_predicate ( parse_quote ! { _I: :: chalk_ir:: interner:: Interner } ) ;
306+ quote ! { _I }
307+ } ,
308+ |( interner, _) | interner,
309+ ) ;
310+ s. underscore_const ( true ) ;
311+ s. unbound_impl (
312+ quote ! ( :: chalk_ir:: fold:: FallibleTypeFolder <#interner>) ,
313+ quote ! {
314+ type Error = :: core:: convert:: Infallible ;
315+
316+ fn as_dyn( & mut self ) -> & mut dyn :: chalk_ir:: fold:: FallibleTypeFolder <I , Error = Self :: Error > {
317+ self
318+ }
319+
320+ fn try_fold_ty(
321+ & mut self ,
322+ ty: :: chalk_ir:: Ty <#interner>,
323+ outer_binder: :: chalk_ir:: DebruijnIndex ,
324+ ) -> :: core:: result:: Result <:: chalk_ir:: Ty <#interner>, Self :: Error > {
325+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_ty( self , ty, outer_binder) )
326+ }
327+
328+ fn try_fold_lifetime(
329+ & mut self ,
330+ lifetime: :: chalk_ir:: Lifetime <#interner>,
331+ outer_binder: :: chalk_ir:: DebruijnIndex ,
332+ ) -> :: core:: result:: Result <:: chalk_ir:: Lifetime <#interner>, Self :: Error > {
333+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_lifetime( self , lifetime, outer_binder) )
334+ }
335+
336+ fn try_fold_const(
337+ & mut self ,
338+ constant: :: chalk_ir:: Const <#interner>,
339+ outer_binder: :: chalk_ir:: DebruijnIndex ,
340+ ) -> :: core:: result:: Result <:: chalk_ir:: Const <#interner>, Self :: Error > {
341+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_const( self , constant, outer_binder) )
342+ }
343+
344+ fn try_fold_program_clause(
345+ & mut self ,
346+ clause: :: chalk_ir:: ProgramClause <#interner>,
347+ outer_binder: :: chalk_ir:: DebruijnIndex ,
348+ ) -> :: core:: result:: Result <:: chalk_ir:: ProgramClause <#interner>, Self :: Error > {
349+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_program_clause( self , clause, outer_binder) )
350+ }
351+
352+ fn try_fold_goal(
353+ & mut self ,
354+ goal: :: chalk_ir:: Goal <#interner>,
355+ outer_binder: :: chalk_ir:: DebruijnIndex ,
356+ ) -> :: core:: result:: Result <:: chalk_ir:: Goal <#interner>, Self :: Error > {
357+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_goal( self , goal, outer_binder) )
358+ }
359+
360+ fn forbid_free_vars( & self ) -> bool {
361+ :: chalk_ir:: fold:: TypeFolder :: forbid_free_vars( self )
362+ }
363+
364+ fn try_fold_free_var_ty(
365+ & mut self ,
366+ bound_var: :: chalk_ir:: BoundVar ,
367+ outer_binder: :: chalk_ir:: DebruijnIndex ,
368+ ) -> :: core:: result:: Result <:: chalk_ir:: Ty <#interner>, Self :: Error > {
369+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_free_var_ty( self , bound_var, outer_binder) )
370+ }
371+
372+ fn try_fold_free_var_lifetime(
373+ & mut self ,
374+ bound_var: :: chalk_ir:: BoundVar ,
375+ outer_binder: :: chalk_ir:: DebruijnIndex ,
376+ ) -> :: core:: result:: Result <:: chalk_ir:: Lifetime <#interner>, Self :: Error > {
377+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_free_var_lifetime( self , bound_var, outer_binder) )
378+ }
379+
380+ fn try_fold_free_var_const(
381+ & mut self ,
382+ ty: :: chalk_ir:: Ty <#interner>,
383+ bound_var: :: chalk_ir:: BoundVar ,
384+ outer_binder: :: chalk_ir:: DebruijnIndex ,
385+ ) -> :: core:: result:: Result <:: chalk_ir:: Const <#interner>, Self :: Error > {
386+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_free_var_const( self , ty, bound_var, outer_binder) )
387+ }
388+
389+ fn forbid_free_placeholders( & self ) -> bool {
390+ :: chalk_ir:: fold:: TypeFolder :: forbid_free_placeholders( self )
391+ }
392+
393+ fn try_fold_free_placeholder_ty(
394+ & mut self ,
395+ universe: :: chalk_ir:: PlaceholderIndex ,
396+ outer_binder: :: chalk_ir:: DebruijnIndex ,
397+ ) -> :: core:: result:: Result <:: chalk_ir:: Ty <#interner>, Self :: Error > {
398+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_free_placeholder_ty( self , universe, outer_binder) )
399+ }
400+
401+ fn try_fold_free_placeholder_lifetime(
402+ & mut self ,
403+ universe: :: chalk_ir:: PlaceholderIndex ,
404+ outer_binder: :: chalk_ir:: DebruijnIndex ,
405+ ) -> :: core:: result:: Result <:: chalk_ir:: Lifetime <#interner>, Self :: Error > {
406+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_free_placeholder_lifetime( self , universe, outer_binder) )
407+ }
408+
409+ fn try_fold_free_placeholder_const(
410+ & mut self ,
411+ ty: :: chalk_ir:: Ty <#interner>,
412+ universe: :: chalk_ir:: PlaceholderIndex ,
413+ outer_binder: :: chalk_ir:: DebruijnIndex ,
414+ ) -> :: core:: result:: Result <:: chalk_ir:: Const <#interner>, Self :: Error > {
415+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_free_placeholder_const( self , ty, universe, outer_binder) )
416+ }
417+
418+ fn forbid_inference_vars( & self ) -> bool {
419+ :: chalk_ir:: fold:: TypeFolder :: forbid_inference_vars( self )
420+ }
421+
422+ fn try_fold_inference_ty(
423+ & mut self ,
424+ var: :: chalk_ir:: InferenceVar ,
425+ kind: :: chalk_ir:: TyVariableKind ,
426+ outer_binder: :: chalk_ir:: DebruijnIndex ,
427+ ) -> :: core:: result:: Result <:: chalk_ir:: Ty <#interner>, Self :: Error > {
428+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_inference_ty( self , var, kind, outer_binder) )
429+ }
430+
431+ fn try_fold_inference_lifetime(
432+ & mut self ,
433+ var: :: chalk_ir:: InferenceVar ,
434+ outer_binder: :: chalk_ir:: DebruijnIndex ,
435+ ) -> :: core:: result:: Result <:: chalk_ir:: Lifetime <#interner>, Self :: Error > {
436+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_inference_lifetime( self , var, outer_binder) )
437+ }
438+
439+ fn try_fold_inference_const(
440+ & mut self ,
441+ ty: :: chalk_ir:: Ty <#interner>,
442+ var: :: chalk_ir:: InferenceVar ,
443+ outer_binder: :: chalk_ir:: DebruijnIndex ,
444+ ) -> :: core:: result:: Result <:: chalk_ir:: Const <#interner>, Self :: Error > {
445+ :: core:: result:: Result :: Ok ( :: chalk_ir:: fold:: TypeFolder :: fold_inference_const( self , ty, var, outer_binder) )
446+ }
447+
448+ fn interner( & self ) -> #interner {
449+ :: chalk_ir:: fold:: TypeFolder :: interner( self )
450+ }
451+ } ,
452+ )
453+ }
0 commit comments