@@ -115,6 +115,9 @@ crate struct Context<'tcx> {
115
115
crate render_redirect_pages : bool ,
116
116
/// The map used to ensure all generated 'id=' attributes are unique.
117
117
id_map : Rc < RefCell < IdMap > > ,
118
+ /// Tracks section IDs for `Deref` targets so they match in both the main
119
+ /// body and the sidebar.
120
+ deref_id_map : Rc < RefCell < FxHashMap < DefId , String > > > ,
118
121
crate shared : Arc < SharedContext < ' tcx > > ,
119
122
all : Rc < RefCell < AllTypes > > ,
120
123
/// Storage for the errors produced while generating documentation so they
@@ -372,7 +375,6 @@ crate fn initial_ids() -> Vec<String> {
372
375
"implementors-list" ,
373
376
"synthetic-implementors-list" ,
374
377
"methods" ,
375
- "deref-methods" ,
376
378
"implementations" ,
377
379
]
378
380
. iter ( )
@@ -506,6 +508,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
506
508
dst,
507
509
render_redirect_pages : false ,
508
510
id_map : Rc :: new ( RefCell :: new ( id_map) ) ,
511
+ deref_id_map : Rc :: new ( RefCell :: new ( FxHashMap :: default ( ) ) ) ,
509
512
shared : Arc :: new ( scx) ,
510
513
all : Rc :: new ( RefCell :: new ( AllTypes :: new ( ) ) ) ,
511
514
errors : Rc :: new ( receiver) ,
@@ -3517,14 +3520,18 @@ fn render_assoc_items(
3517
3520
RenderMode :: Normal
3518
3521
}
3519
3522
AssocItemRender :: DerefFor { trait_, type_, deref_mut_ } => {
3523
+ let id =
3524
+ cx. derive_id ( small_url_encode ( & format ! ( "deref-methods-{:#}" , type_. print( ) ) ) ) ;
3525
+ cx. deref_id_map . borrow_mut ( ) . insert ( type_. def_id ( ) . unwrap ( ) , id. clone ( ) ) ;
3520
3526
write ! (
3521
3527
w,
3522
- "<h2 id=\" deref-methods \" class=\" small-section-header\" >\
3523
- Methods from {}<Target = {}>\
3524
- <a href=\" #deref-methods \" class=\" anchor\" ></a>\
3528
+ "<h2 id=\" {id} \" class=\" small-section-header\" >\
3529
+ Methods from {trait_ }<Target = {type_ }>\
3530
+ <a href=\" #{id} \" class=\" anchor\" ></a>\
3525
3531
</h2>",
3526
- trait_. print( ) ,
3527
- type_. print( )
3532
+ id = id,
3533
+ trait_ = trait_. print( ) ,
3534
+ type_ = type_. print( ) ,
3528
3535
) ;
3529
3536
RenderMode :: ForDeref { mut_ : deref_mut_ }
3530
3537
}
@@ -3548,9 +3555,6 @@ fn render_assoc_items(
3548
3555
) ;
3549
3556
}
3550
3557
}
3551
- if let AssocItemRender :: DerefFor { .. } = what {
3552
- return ;
3553
- }
3554
3558
if !traits. is_empty ( ) {
3555
3559
let deref_impl =
3556
3560
traits. iter ( ) . find ( |t| t. inner_impl ( ) . trait_ . def_id ( ) == cache. deref_trait_did ) ;
@@ -3560,6 +3564,12 @@ fn render_assoc_items(
3560
3564
render_deref_methods ( w, cx, impl_, containing_item, has_deref_mut, cache) ;
3561
3565
}
3562
3566
3567
+ // If we were already one level into rendering deref methods, we don't want to render
3568
+ // anything after recursing into any further deref methods above.
3569
+ if let AssocItemRender :: DerefFor { .. } = what {
3570
+ return ;
3571
+ }
3572
+
3563
3573
let ( synthetic, concrete) : ( Vec < & & Impl > , Vec < & & Impl > ) =
3564
3574
traits. iter ( ) . partition ( |t| t. inner_impl ( ) . synthetic ) ;
3565
3575
let ( blanket_impl, concrete) : ( Vec < & & Impl > , _ ) =
@@ -3631,6 +3641,13 @@ fn render_deref_methods(
3631
3641
let what =
3632
3642
AssocItemRender :: DerefFor { trait_ : deref_type, type_ : real_target, deref_mut_ : deref_mut } ;
3633
3643
if let Some ( did) = target. def_id ( ) {
3644
+ if let Some ( type_did) = impl_. inner_impl ( ) . for_ . def_id ( ) {
3645
+ // `impl Deref<Target = S> for S`
3646
+ if did == type_did {
3647
+ // Avoid infinite cycles
3648
+ return ;
3649
+ }
3650
+ }
3634
3651
render_assoc_items ( w, cx, container_item, did, what, cache) ;
3635
3652
} else {
3636
3653
if let Some ( prim) = target. primitive_type ( ) {
@@ -4165,14 +4182,14 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache:
4165
4182
) ;
4166
4183
}
4167
4184
match * it. kind {
4168
- clean:: StructItem ( ref s) => sidebar_struct ( buffer, it, s) ,
4169
- clean:: TraitItem ( ref t) => sidebar_trait ( buffer, it, t) ,
4170
- clean:: PrimitiveItem ( _) => sidebar_primitive ( buffer, it) ,
4171
- clean:: UnionItem ( ref u) => sidebar_union ( buffer, it, u) ,
4172
- clean:: EnumItem ( ref e) => sidebar_enum ( buffer, it, e) ,
4173
- clean:: TypedefItem ( _, _) => sidebar_typedef ( buffer, it) ,
4185
+ clean:: StructItem ( ref s) => sidebar_struct ( cx , buffer, it, s) ,
4186
+ clean:: TraitItem ( ref t) => sidebar_trait ( cx , buffer, it, t) ,
4187
+ clean:: PrimitiveItem ( _) => sidebar_primitive ( cx , buffer, it) ,
4188
+ clean:: UnionItem ( ref u) => sidebar_union ( cx , buffer, it, u) ,
4189
+ clean:: EnumItem ( ref e) => sidebar_enum ( cx , buffer, it, e) ,
4190
+ clean:: TypedefItem ( _, _) => sidebar_typedef ( cx , buffer, it) ,
4174
4191
clean:: ModuleItem ( ref m) => sidebar_module ( buffer, & m. items ) ,
4175
- clean:: ForeignTypeItem => sidebar_foreign_type ( buffer, it) ,
4192
+ clean:: ForeignTypeItem => sidebar_foreign_type ( cx , buffer, it) ,
4176
4193
_ => ( ) ,
4177
4194
}
4178
4195
@@ -4273,7 +4290,7 @@ fn small_url_encode(s: &str) -> String {
4273
4290
. replace ( "\" " , "%22" )
4274
4291
}
4275
4292
4276
- fn sidebar_assoc_items ( it : & clean:: Item ) -> String {
4293
+ fn sidebar_assoc_items ( cx : & Context < ' _ > , it : & clean:: Item ) -> String {
4277
4294
let mut out = String :: new ( ) ;
4278
4295
let c = cache ( ) ;
4279
4296
if let Some ( v) = c. impls . get ( & it. def_id ) {
@@ -4303,58 +4320,7 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
4303
4320
. filter ( |i| i. inner_impl ( ) . trait_ . is_some ( ) )
4304
4321
. find ( |i| i. inner_impl ( ) . trait_ . def_id ( ) == c. deref_trait_did )
4305
4322
{
4306
- debug ! ( "found Deref: {:?}" , impl_) ;
4307
- if let Some ( ( target, real_target) ) =
4308
- impl_. inner_impl ( ) . items . iter ( ) . find_map ( |item| match * item. kind {
4309
- clean:: TypedefItem ( ref t, true ) => Some ( match * t {
4310
- clean:: Typedef { item_type : Some ( ref type_) , .. } => ( type_, & t. type_ ) ,
4311
- _ => ( & t. type_ , & t. type_ ) ,
4312
- } ) ,
4313
- _ => None ,
4314
- } )
4315
- {
4316
- debug ! ( "found target, real_target: {:?} {:?}" , target, real_target) ;
4317
- let deref_mut = v
4318
- . iter ( )
4319
- . filter ( |i| i. inner_impl ( ) . trait_ . is_some ( ) )
4320
- . any ( |i| i. inner_impl ( ) . trait_ . def_id ( ) == c. deref_mut_trait_did ) ;
4321
- let inner_impl = target
4322
- . def_id ( )
4323
- . or_else ( || {
4324
- target
4325
- . primitive_type ( )
4326
- . and_then ( |prim| c. primitive_locations . get ( & prim) . cloned ( ) )
4327
- } )
4328
- . and_then ( |did| c. impls . get ( & did) ) ;
4329
- if let Some ( impls) = inner_impl {
4330
- debug ! ( "found inner_impl: {:?}" , impls) ;
4331
- out. push_str ( "<a class=\" sidebar-title\" href=\" #deref-methods\" >" ) ;
4332
- out. push_str ( & format ! (
4333
- "Methods from {}<Target={}>" ,
4334
- Escape ( & format!(
4335
- "{:#}" ,
4336
- impl_. inner_impl( ) . trait_. as_ref( ) . unwrap( ) . print( )
4337
- ) ) ,
4338
- Escape ( & format!( "{:#}" , real_target. print( ) ) )
4339
- ) ) ;
4340
- out. push_str ( "</a>" ) ;
4341
- let mut ret = impls
4342
- . iter ( )
4343
- . filter ( |i| i. inner_impl ( ) . trait_ . is_none ( ) )
4344
- . flat_map ( |i| {
4345
- get_methods ( i. inner_impl ( ) , true , & mut used_links, deref_mut)
4346
- } )
4347
- . collect :: < Vec < _ > > ( ) ;
4348
- // We want links' order to be reproducible so we don't use unstable sort.
4349
- ret. sort ( ) ;
4350
- if !ret. is_empty ( ) {
4351
- out. push_str ( & format ! (
4352
- "<div class=\" sidebar-links\" >{}</div>" ,
4353
- ret. join( "" )
4354
- ) ) ;
4355
- }
4356
- }
4357
- }
4323
+ out. push_str ( & sidebar_deref_methods ( cx, impl_, v) ) ;
4358
4324
}
4359
4325
let format_impls = |impls : Vec < & Impl > | {
4360
4326
let mut links = FxHashSet :: default ( ) ;
@@ -4422,7 +4388,81 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
4422
4388
out
4423
4389
}
4424
4390
4425
- fn sidebar_struct ( buf : & mut Buffer , it : & clean:: Item , s : & clean:: Struct ) {
4391
+ fn sidebar_deref_methods ( cx : & Context < ' _ > , impl_ : & Impl , v : & Vec < Impl > ) -> String {
4392
+ let mut out = String :: new ( ) ;
4393
+ let c = cache ( ) ;
4394
+
4395
+ debug ! ( "found Deref: {:?}" , impl_) ;
4396
+ if let Some ( ( target, real_target) ) =
4397
+ impl_. inner_impl ( ) . items . iter ( ) . find_map ( |item| match * item. kind {
4398
+ clean:: TypedefItem ( ref t, true ) => Some ( match * t {
4399
+ clean:: Typedef { item_type : Some ( ref type_) , .. } => ( type_, & t. type_ ) ,
4400
+ _ => ( & t. type_ , & t. type_ ) ,
4401
+ } ) ,
4402
+ _ => None ,
4403
+ } )
4404
+ {
4405
+ debug ! ( "found target, real_target: {:?} {:?}" , target, real_target) ;
4406
+ let deref_mut = v
4407
+ . iter ( )
4408
+ . filter ( |i| i. inner_impl ( ) . trait_ . is_some ( ) )
4409
+ . any ( |i| i. inner_impl ( ) . trait_ . def_id ( ) == c. deref_mut_trait_did ) ;
4410
+ let inner_impl = target
4411
+ . def_id ( )
4412
+ . or_else ( || {
4413
+ target. primitive_type ( ) . and_then ( |prim| c. primitive_locations . get ( & prim) . cloned ( ) )
4414
+ } )
4415
+ . and_then ( |did| c. impls . get ( & did) ) ;
4416
+ if let Some ( impls) = inner_impl {
4417
+ debug ! ( "found inner_impl: {:?}" , impls) ;
4418
+ let mut used_links = FxHashSet :: default ( ) ;
4419
+ let mut ret = impls
4420
+ . iter ( )
4421
+ . filter ( |i| i. inner_impl ( ) . trait_ . is_none ( ) )
4422
+ . flat_map ( |i| get_methods ( i. inner_impl ( ) , true , & mut used_links, deref_mut) )
4423
+ . collect :: < Vec < _ > > ( ) ;
4424
+ if !ret. is_empty ( ) {
4425
+ let deref_id_map = cx. deref_id_map . borrow ( ) ;
4426
+ let id = deref_id_map
4427
+ . get ( & real_target. def_id ( ) . unwrap ( ) )
4428
+ . expect ( "Deref section without derived id" ) ;
4429
+ out. push_str ( & format ! (
4430
+ "<a class=\" sidebar-title\" href=\" #{}\" >Methods from {}<Target={}></a>" ,
4431
+ id,
4432
+ Escape ( & format!( "{:#}" , impl_. inner_impl( ) . trait_. as_ref( ) . unwrap( ) . print( ) ) ) ,
4433
+ Escape ( & format!( "{:#}" , real_target. print( ) ) ) ,
4434
+ ) ) ;
4435
+ // We want links' order to be reproducible so we don't use unstable sort.
4436
+ ret. sort ( ) ;
4437
+ out. push_str ( & format ! ( "<div class=\" sidebar-links\" >{}</div>" , ret. join( "" ) ) ) ;
4438
+ }
4439
+ }
4440
+
4441
+ // Recurse into any further impls that might exist for `target`
4442
+ if let Some ( target_did) = target. def_id ( ) {
4443
+ if let Some ( target_impls) = c. impls . get ( & target_did) {
4444
+ if let Some ( target_deref_impl) = target_impls
4445
+ . iter ( )
4446
+ . filter ( |i| i. inner_impl ( ) . trait_ . is_some ( ) )
4447
+ . find ( |i| i. inner_impl ( ) . trait_ . def_id ( ) == c. deref_trait_did )
4448
+ {
4449
+ if let Some ( type_did) = impl_. inner_impl ( ) . for_ . def_id ( ) {
4450
+ // `impl Deref<Target = S> for S`
4451
+ if target_did == type_did {
4452
+ // Avoid infinite cycles
4453
+ return out;
4454
+ }
4455
+ }
4456
+ out. push_str ( & sidebar_deref_methods ( cx, target_deref_impl, target_impls) ) ;
4457
+ }
4458
+ }
4459
+ }
4460
+ }
4461
+
4462
+ out
4463
+ }
4464
+
4465
+ fn sidebar_struct ( cx : & Context < ' _ > , buf : & mut Buffer , it : & clean:: Item , s : & clean:: Struct ) {
4426
4466
let mut sidebar = String :: new ( ) ;
4427
4467
let fields = get_struct_fields_name ( & s. fields ) ;
4428
4468
@@ -4436,7 +4476,7 @@ fn sidebar_struct(buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) {
4436
4476
}
4437
4477
}
4438
4478
4439
- sidebar. push_str ( & sidebar_assoc_items ( it) ) ;
4479
+ sidebar. push_str ( & sidebar_assoc_items ( cx , it) ) ;
4440
4480
4441
4481
if !sidebar. is_empty ( ) {
4442
4482
write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar) ;
@@ -4467,7 +4507,7 @@ fn is_negative_impl(i: &clean::Impl) -> bool {
4467
4507
i. polarity == Some ( clean:: ImplPolarity :: Negative )
4468
4508
}
4469
4509
4470
- fn sidebar_trait ( buf : & mut Buffer , it : & clean:: Item , t : & clean:: Trait ) {
4510
+ fn sidebar_trait ( cx : & Context < ' _ > , buf : & mut Buffer , it : & clean:: Item , t : & clean:: Trait ) {
4471
4511
let mut sidebar = String :: new ( ) ;
4472
4512
4473
4513
let mut types = t
@@ -4567,7 +4607,7 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
4567
4607
}
4568
4608
}
4569
4609
4570
- sidebar. push_str ( & sidebar_assoc_items ( it) ) ;
4610
+ sidebar. push_str ( & sidebar_assoc_items ( cx , it) ) ;
4571
4611
4572
4612
sidebar. push_str ( "<a class=\" sidebar-title\" href=\" #implementors\" >Implementors</a>" ) ;
4573
4613
if t. is_auto {
@@ -4580,16 +4620,16 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
4580
4620
write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar)
4581
4621
}
4582
4622
4583
- fn sidebar_primitive ( buf : & mut Buffer , it : & clean:: Item ) {
4584
- let sidebar = sidebar_assoc_items ( it) ;
4623
+ fn sidebar_primitive ( cx : & Context < ' _ > , buf : & mut Buffer , it : & clean:: Item ) {
4624
+ let sidebar = sidebar_assoc_items ( cx , it) ;
4585
4625
4586
4626
if !sidebar. is_empty ( ) {
4587
4627
write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar) ;
4588
4628
}
4589
4629
}
4590
4630
4591
- fn sidebar_typedef ( buf : & mut Buffer , it : & clean:: Item ) {
4592
- let sidebar = sidebar_assoc_items ( it) ;
4631
+ fn sidebar_typedef ( cx : & Context < ' _ > , buf : & mut Buffer , it : & clean:: Item ) {
4632
+ let sidebar = sidebar_assoc_items ( cx , it) ;
4593
4633
4594
4634
if !sidebar. is_empty ( ) {
4595
4635
write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar) ;
@@ -4611,7 +4651,7 @@ fn get_struct_fields_name(fields: &[clean::Item]) -> String {
4611
4651
fields. join ( "" )
4612
4652
}
4613
4653
4614
- fn sidebar_union ( buf : & mut Buffer , it : & clean:: Item , u : & clean:: Union ) {
4654
+ fn sidebar_union ( cx : & Context < ' _ > , buf : & mut Buffer , it : & clean:: Item , u : & clean:: Union ) {
4615
4655
let mut sidebar = String :: new ( ) ;
4616
4656
let fields = get_struct_fields_name ( & u. fields ) ;
4617
4657
@@ -4623,14 +4663,14 @@ fn sidebar_union(buf: &mut Buffer, it: &clean::Item, u: &clean::Union) {
4623
4663
) ) ;
4624
4664
}
4625
4665
4626
- sidebar. push_str ( & sidebar_assoc_items ( it) ) ;
4666
+ sidebar. push_str ( & sidebar_assoc_items ( cx , it) ) ;
4627
4667
4628
4668
if !sidebar. is_empty ( ) {
4629
4669
write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar) ;
4630
4670
}
4631
4671
}
4632
4672
4633
- fn sidebar_enum ( buf : & mut Buffer , it : & clean:: Item , e : & clean:: Enum ) {
4673
+ fn sidebar_enum ( cx : & Context < ' _ > , buf : & mut Buffer , it : & clean:: Item , e : & clean:: Enum ) {
4634
4674
let mut sidebar = String :: new ( ) ;
4635
4675
4636
4676
let mut variants = e
@@ -4650,7 +4690,7 @@ fn sidebar_enum(buf: &mut Buffer, it: &clean::Item, e: &clean::Enum) {
4650
4690
) ) ;
4651
4691
}
4652
4692
4653
- sidebar. push_str ( & sidebar_assoc_items ( it) ) ;
4693
+ sidebar. push_str ( & sidebar_assoc_items ( cx , it) ) ;
4654
4694
4655
4695
if !sidebar. is_empty ( ) {
4656
4696
write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar) ;
@@ -4739,8 +4779,8 @@ fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
4739
4779
}
4740
4780
}
4741
4781
4742
- fn sidebar_foreign_type ( buf : & mut Buffer , it : & clean:: Item ) {
4743
- let sidebar = sidebar_assoc_items ( it) ;
4782
+ fn sidebar_foreign_type ( cx : & Context < ' _ > , buf : & mut Buffer , it : & clean:: Item ) {
4783
+ let sidebar = sidebar_assoc_items ( cx , it) ;
4744
4784
if !sidebar. is_empty ( ) {
4745
4785
write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar) ;
4746
4786
}
0 commit comments