@@ -57,11 +57,13 @@ pub fn derive_fetch_impl(input: TokenStream) -> TokenStream {
57
57
quote ! { }
58
58
} ;
59
59
60
+ // Add `'state` and `'fetch` lifetimes that will be used in `Fetch` implementation.
60
61
let mut fetch_generics = ast. generics . clone ( ) ;
61
62
fetch_generics. params . insert ( 1 , state_lifetime) ;
62
- fetch_generics. params . push ( fetch_lifetime. clone ( ) ) ;
63
+ fetch_generics. params . insert ( 2 , fetch_lifetime. clone ( ) ) ;
63
64
let ( fetch_impl_generics, _, _) = fetch_generics. split_for_impl ( ) ;
64
65
66
+ // Replace lifetime `'world` with `'fetch`. See `replace_lifetime_for_type` for more details.
65
67
let mut fetch_generics = ast. generics . clone ( ) ;
66
68
* fetch_generics. params . first_mut ( ) . unwrap ( ) = fetch_lifetime;
67
69
let ( _, fetch_ty_generics, _) = fetch_generics. split_for_impl ( ) ;
@@ -283,10 +285,11 @@ pub fn derive_filter_fetch_impl(input: TokenStream) -> TokenStream {
283
285
panic ! ( "Expected a struct without a lifetime" ) ;
284
286
}
285
287
288
+ // Add `'world`, `'state` and `'fetch` lifetimes that will be used in `Fetch` implementation.
286
289
let mut fetch_generics = ast. generics . clone ( ) ;
287
290
fetch_generics. params . insert ( 0 , world_lifetime) ;
288
291
fetch_generics. params . insert ( 1 , state_lifetime) ;
289
- fetch_generics. params . push ( fetch_lifetime) ;
292
+ fetch_generics. params . insert ( 2 , fetch_lifetime) ;
290
293
let ( fetch_impl_generics, _, _) = fetch_generics. split_for_impl ( ) ;
291
294
292
295
let path = bevy_ecs_path ( ) ;
@@ -417,19 +420,19 @@ fn fetch_impl_tokens(ast: &DeriveInput) -> FetchImplTokens {
417
420
// enough to try to find a better work around, I'll leave playground links here:
418
421
// - https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=da5e260a5c2f3e774142d60a199e854a (this fails)
419
422
// - https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=802517bb3d8f83c45ee8c0be360bb250 (this compiles)
420
- let fetch_lifetime =
423
+ let fetch_lifetime_param =
421
424
GenericParam :: Lifetime ( LifetimeDef :: new ( Lifetime :: new ( "'fetch" , Span :: call_site ( ) ) ) ) ;
422
425
423
426
let has_world_lifetime = world_lifetime. is_some ( ) ;
424
- let world_lifetime = world_lifetime. unwrap_or_else ( || {
427
+ let world_lifetime_param = world_lifetime. unwrap_or_else ( || {
425
428
GenericParam :: Lifetime ( LifetimeDef :: new ( Lifetime :: new ( "'world" , Span :: call_site ( ) ) ) )
426
429
} ) ;
427
- let state_lifetime =
430
+ let state_lifetime_param =
428
431
GenericParam :: Lifetime ( LifetimeDef :: new ( Lifetime :: new ( "'state" , Span :: call_site ( ) ) ) ) ;
429
432
430
433
let mut fetch_trait_punctuated_lifetimes = Punctuated :: < _ , Token ! [ , ] > :: new ( ) ;
431
- fetch_trait_punctuated_lifetimes. push ( world_lifetime . clone ( ) ) ;
432
- fetch_trait_punctuated_lifetimes. push ( state_lifetime . clone ( ) ) ;
434
+ fetch_trait_punctuated_lifetimes. push ( world_lifetime_param . clone ( ) ) ;
435
+ fetch_trait_punctuated_lifetimes. push ( state_lifetime_param . clone ( ) ) ;
433
436
434
437
let ( impl_generics, ty_generics, where_clause) = ast. generics . split_for_impl ( ) ;
435
438
@@ -462,13 +465,13 @@ fn fetch_impl_tokens(ast: &DeriveInput) -> FetchImplTokens {
462
465
let mut query_types = Vec :: new ( ) ;
463
466
let mut fetch_init_types = Vec :: new ( ) ;
464
467
468
+ let ( world_lifetime, fetch_lifetime) = match ( & world_lifetime_param, & fetch_lifetime_param) {
469
+ ( GenericParam :: Lifetime ( world) , GenericParam :: Lifetime ( fetch) ) => {
470
+ ( & world. lifetime , & fetch. lifetime )
471
+ }
472
+ _ => unreachable ! ( ) ,
473
+ } ;
465
474
for field in fields. iter ( ) {
466
- let ( world_lifetime, fetch_lifetime) = match ( & world_lifetime, & fetch_lifetime) {
467
- ( GenericParam :: Lifetime ( world) , GenericParam :: Lifetime ( fetch) ) => {
468
- ( & world. lifetime , & fetch. lifetime )
469
- }
470
- _ => unreachable ! ( ) ,
471
- } ;
472
475
let WorldQueryFieldTypeInfo {
473
476
query_type,
474
477
fetch_init_type : init_type,
@@ -499,9 +502,9 @@ fn fetch_impl_tokens(ast: &DeriveInput) -> FetchImplTokens {
499
502
where_clause,
500
503
has_mutable_attr,
501
504
has_world_lifetime,
502
- world_lifetime,
503
- state_lifetime,
504
- fetch_lifetime,
505
+ world_lifetime : world_lifetime_param ,
506
+ state_lifetime : state_lifetime_param ,
507
+ fetch_lifetime : fetch_lifetime_param ,
505
508
phantom_field_idents,
506
509
phantom_field_types,
507
510
field_idents,
@@ -527,8 +530,8 @@ fn read_world_query_field_type_info(
527
530
) -> WorldQueryFieldTypeInfo {
528
531
let path = bevy_ecs_path ( ) ;
529
532
530
- let query_type = parse_quote ! ( <#ty as #path:: query:: FetchedItem >:: Query ) ;
531
- let mut fetch_init_type = parse_quote ! ( <#ty as #path :: query :: FetchedItem > :: Query ) ;
533
+ let query_type: Type = parse_quote ! ( <#ty as #path:: query:: FetchedItem >:: Query ) ;
534
+ let mut fetch_init_type: Type = query_type . clone ( ) ;
532
535
533
536
let is_phantom_data = match ty {
534
537
Type :: Path ( path) => {
@@ -550,6 +553,11 @@ fn read_world_query_field_type_info(
550
553
}
551
554
}
552
555
556
+ // Fetch's HRTBs require substituting world lifetime with an additional one to make the
557
+ // implementation compile. I don't fully understand why this works though. If anyone's curious
558
+ // enough to try to find a better work around, I'll leave playground links here:
559
+ // - https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=da5e260a5c2f3e774142d60a199e854a (this fails)
560
+ // - https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=802517bb3d8f83c45ee8c0be360bb250 (this compiles)
553
561
fn replace_lifetime_for_type ( ty : & mut Type , world_lifetime : & Lifetime , fetch_lifetime : & Lifetime ) {
554
562
match ty {
555
563
Type :: Path ( ref mut path) => {
0 commit comments