@@ -3,17 +3,17 @@ extern crate proc_macro;
3
3
use proc_macro2:: { Span , TokenStream } ;
4
4
use quote:: quote;
5
5
use quote:: ToTokens ;
6
- use syn:: { parse_quote, DeriveInput , GenericParam , Ident , TypeParamBound } ;
6
+ use syn:: { parse_quote, DeriveInput , Ident , TypeParam , TypeParamBound } ;
7
7
8
8
use synstructure:: decl_derive;
9
9
10
10
/// 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 > {
12
12
bounded_by_trait ( param, "HasInterner" )
13
13
}
14
14
15
15
/// 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 > {
17
17
bounded_by_trait ( param, "Interner" )
18
18
}
19
19
@@ -28,48 +28,44 @@ fn has_interner_attr(input: &DeriveInput) -> Option<TokenStream> {
28
28
)
29
29
}
30
30
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 > {
32
32
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 ) ;
45
43
}
46
- None
47
- } ) ,
48
- _ => None ,
49
- }
44
+ }
45
+ None
46
+ } )
50
47
}
51
48
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
+ } ) ;
55
55
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" ) ;
59
58
60
- _ => panic ! ( "deriving this trait only works with a single type parameter" ) ,
61
- } ;
62
- & input. generics . params [ 0 ]
59
+ param
63
60
}
64
61
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
70
66
}
71
67
72
- fn find_interner ( s : & mut synstructure:: Structure ) -> ( TokenStream , DeriveKind ) {
68
+ fn try_find_interner ( s : & mut synstructure:: Structure ) -> Option < ( TokenStream , DeriveKind ) > {
73
69
let input = s. ast ( ) ;
74
70
75
71
if let Some ( arg) = has_interner_attr ( input) {
@@ -79,35 +75,40 @@ fn find_interner(s: &mut synstructure::Structure) -> (TokenStream, DeriveKind) {
79
75
// struct S {
80
76
//
81
77
// }
82
- return ( arg, DeriveKind :: FromHasInternerAttr ) ;
78
+ return Some ( ( arg, DeriveKind :: FromHasInternerAttr ) ) ;
83
79
}
84
80
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
+ }
99
108
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" )
111
112
}
112
113
113
114
#[ derive( Copy , Clone , PartialEq ) ]
@@ -117,6 +118,7 @@ enum DeriveKind {
117
118
FromInterner ,
118
119
}
119
120
121
+ decl_derive ! ( [ FallibleTypeFolder , attributes( has_interner) ] => derive_fallible_type_folder) ;
120
122
decl_derive ! ( [ HasInterner , attributes( has_interner) ] => derive_has_interner) ;
121
123
decl_derive ! ( [ TypeVisitable , attributes( has_interner) ] => derive_type_visitable) ;
122
124
decl_derive ! ( [ TypeSuperVisitable , attributes( has_interner) ] => derive_type_super_visitable) ;
@@ -173,7 +175,7 @@ fn derive_any_type_visitable(
173
175
} ) ;
174
176
175
177
if kind == DeriveKind :: FromHasInterner {
176
- let param = get_generic_param_name ( input) . unwrap ( ) ;
178
+ let param = get_intern_param_name ( input) ;
177
179
s. add_where_predicate ( parse_quote ! { #param: :: chalk_ir:: visit:: TypeVisitable <#interner> } ) ;
178
180
}
179
181
@@ -269,29 +271,183 @@ fn derive_type_foldable(mut s: synstructure::Structure) -> TokenStream {
269
271
vi. construct ( |_, index| {
270
272
let bind = & bindings[ index] ;
271
273
quote ! {
272
- :: chalk_ir:: fold:: TypeFoldable :: fold_with ( #bind, folder, outer_binder) ?
274
+ :: chalk_ir:: fold:: TypeFoldable :: try_fold_with ( #bind, folder, outer_binder) ?
273
275
}
274
276
} )
275
277
} ) ;
276
278
277
279
let input = s. ast ( ) ;
278
280
279
281
if kind == DeriveKind :: FromHasInterner {
280
- let param = get_generic_param_name ( input) . unwrap ( ) ;
282
+ let param = get_intern_param_name ( input) ;
281
283
s. add_where_predicate ( parse_quote ! { #param: :: chalk_ir:: fold:: TypeFoldable <#interner> } ) ;
282
284
} ;
283
285
284
286
s. add_bounds ( synstructure:: AddBounds :: None ) ;
285
287
s. bound_impl (
286
288
quote ! ( :: chalk_ir:: fold:: TypeFoldable <#interner>) ,
287
289
quote ! {
288
- fn fold_with <E >(
290
+ fn try_fold_with <E >(
289
291
self ,
290
- folder: & mut dyn :: chalk_ir:: fold:: TypeFolder < #interner, Error = E >,
292
+ folder: & mut dyn :: chalk_ir:: fold:: FallibleTypeFolder < #interner, Error = E >,
291
293
outer_binder: :: chalk_ir:: DebruijnIndex ,
292
294
) -> :: std:: result:: Result <Self , E > {
293
295
Ok ( match self { #body } )
294
296
}
295
297
} ,
296
298
)
297
299
}
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