@@ -115,6 +115,9 @@ crate struct Context<'tcx> {
115115 crate render_redirect_pages : bool ,
116116 /// The map used to ensure all generated 'id=' attributes are unique.
117117 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 > > > ,
118121 crate shared : Arc < SharedContext < ' tcx > > ,
119122 all : Rc < RefCell < AllTypes > > ,
120123 /// Storage for the errors produced while generating documentation so they
@@ -372,7 +375,6 @@ crate fn initial_ids() -> Vec<String> {
372375 "implementors-list" ,
373376 "synthetic-implementors-list" ,
374377 "methods" ,
375- "deref-methods" ,
376378 "implementations" ,
377379 ]
378380 . iter ( )
@@ -506,6 +508,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
506508 dst,
507509 render_redirect_pages : false ,
508510 id_map : Rc :: new ( RefCell :: new ( id_map) ) ,
511+ deref_id_map : Rc :: new ( RefCell :: new ( FxHashMap :: default ( ) ) ) ,
509512 shared : Arc :: new ( scx) ,
510513 all : Rc :: new ( RefCell :: new ( AllTypes :: new ( ) ) ) ,
511514 errors : Rc :: new ( receiver) ,
@@ -3517,14 +3520,18 @@ fn render_assoc_items(
35173520 RenderMode :: Normal
35183521 }
35193522 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 ( ) ) ;
35203526 write ! (
35213527 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>\
35253531 </h2>",
3526- trait_. print( ) ,
3527- type_. print( )
3532+ id = id,
3533+ trait_ = trait_. print( ) ,
3534+ type_ = type_. print( ) ,
35283535 ) ;
35293536 RenderMode :: ForDeref { mut_ : deref_mut_ }
35303537 }
@@ -3548,9 +3555,6 @@ fn render_assoc_items(
35483555 ) ;
35493556 }
35503557 }
3551- if let AssocItemRender :: DerefFor { .. } = what {
3552- return ;
3553- }
35543558 if !traits. is_empty ( ) {
35553559 let deref_impl =
35563560 traits. iter ( ) . find ( |t| t. inner_impl ( ) . trait_ . def_id ( ) == cache. deref_trait_did ) ;
@@ -3560,6 +3564,12 @@ fn render_assoc_items(
35603564 render_deref_methods ( w, cx, impl_, containing_item, has_deref_mut, cache) ;
35613565 }
35623566
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+
35633573 let ( synthetic, concrete) : ( Vec < & & Impl > , Vec < & & Impl > ) =
35643574 traits. iter ( ) . partition ( |t| t. inner_impl ( ) . synthetic ) ;
35653575 let ( blanket_impl, concrete) : ( Vec < & & Impl > , _ ) =
@@ -3631,6 +3641,13 @@ fn render_deref_methods(
36313641 let what =
36323642 AssocItemRender :: DerefFor { trait_ : deref_type, type_ : real_target, deref_mut_ : deref_mut } ;
36333643 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+ }
36343651 render_assoc_items ( w, cx, container_item, did, what, cache) ;
36353652 } else {
36363653 if let Some ( prim) = target. primitive_type ( ) {
@@ -4165,14 +4182,14 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer, cache:
41654182 ) ;
41664183 }
41674184 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) ,
41744191 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) ,
41764193 _ => ( ) ,
41774194 }
41784195
@@ -4273,7 +4290,7 @@ fn small_url_encode(s: &str) -> String {
42734290 . replace ( "\" " , "%22" )
42744291}
42754292
4276- fn sidebar_assoc_items ( it : & clean:: Item ) -> String {
4293+ fn sidebar_assoc_items ( cx : & Context < ' _ > , it : & clean:: Item ) -> String {
42774294 let mut out = String :: new ( ) ;
42784295 let c = cache ( ) ;
42794296 if let Some ( v) = c. impls . get ( & it. def_id ) {
@@ -4303,58 +4320,7 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
43034320 . filter ( |i| i. inner_impl ( ) . trait_ . is_some ( ) )
43044321 . find ( |i| i. inner_impl ( ) . trait_ . def_id ( ) == c. deref_trait_did )
43054322 {
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) ) ;
43584324 }
43594325 let format_impls = |impls : Vec < & Impl > | {
43604326 let mut links = FxHashSet :: default ( ) ;
@@ -4422,7 +4388,81 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
44224388 out
44234389}
44244390
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 ) {
44264466 let mut sidebar = String :: new ( ) ;
44274467 let fields = get_struct_fields_name ( & s. fields ) ;
44284468
@@ -4436,7 +4476,7 @@ fn sidebar_struct(buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) {
44364476 }
44374477 }
44384478
4439- sidebar. push_str ( & sidebar_assoc_items ( it) ) ;
4479+ sidebar. push_str ( & sidebar_assoc_items ( cx , it) ) ;
44404480
44414481 if !sidebar. is_empty ( ) {
44424482 write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar) ;
@@ -4467,7 +4507,7 @@ fn is_negative_impl(i: &clean::Impl) -> bool {
44674507 i. polarity == Some ( clean:: ImplPolarity :: Negative )
44684508}
44694509
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 ) {
44714511 let mut sidebar = String :: new ( ) ;
44724512
44734513 let mut types = t
@@ -4567,7 +4607,7 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
45674607 }
45684608 }
45694609
4570- sidebar. push_str ( & sidebar_assoc_items ( it) ) ;
4610+ sidebar. push_str ( & sidebar_assoc_items ( cx , it) ) ;
45714611
45724612 sidebar. push_str ( "<a class=\" sidebar-title\" href=\" #implementors\" >Implementors</a>" ) ;
45734613 if t. is_auto {
@@ -4580,16 +4620,16 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
45804620 write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar)
45814621}
45824622
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) ;
45854625
45864626 if !sidebar. is_empty ( ) {
45874627 write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar) ;
45884628 }
45894629}
45904630
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) ;
45934633
45944634 if !sidebar. is_empty ( ) {
45954635 write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar) ;
@@ -4611,7 +4651,7 @@ fn get_struct_fields_name(fields: &[clean::Item]) -> String {
46114651 fields. join ( "" )
46124652}
46134653
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 ) {
46154655 let mut sidebar = String :: new ( ) ;
46164656 let fields = get_struct_fields_name ( & u. fields ) ;
46174657
@@ -4623,14 +4663,14 @@ fn sidebar_union(buf: &mut Buffer, it: &clean::Item, u: &clean::Union) {
46234663 ) ) ;
46244664 }
46254665
4626- sidebar. push_str ( & sidebar_assoc_items ( it) ) ;
4666+ sidebar. push_str ( & sidebar_assoc_items ( cx , it) ) ;
46274667
46284668 if !sidebar. is_empty ( ) {
46294669 write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar) ;
46304670 }
46314671}
46324672
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 ) {
46344674 let mut sidebar = String :: new ( ) ;
46354675
46364676 let mut variants = e
@@ -4650,7 +4690,7 @@ fn sidebar_enum(buf: &mut Buffer, it: &clean::Item, e: &clean::Enum) {
46504690 ) ) ;
46514691 }
46524692
4653- sidebar. push_str ( & sidebar_assoc_items ( it) ) ;
4693+ sidebar. push_str ( & sidebar_assoc_items ( cx , it) ) ;
46544694
46554695 if !sidebar. is_empty ( ) {
46564696 write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar) ;
@@ -4739,8 +4779,8 @@ fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
47394779 }
47404780}
47414781
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) ;
47444784 if !sidebar. is_empty ( ) {
47454785 write ! ( buf, "<div class=\" block items\" >{}</div>" , sidebar) ;
47464786 }
0 commit comments