Skip to content

Commit 32f6260

Browse files
committed
Emit valid HTML from rustdoc
Previously, tidy-html5 (`tidy`) would complain about a few things in our HTML. The main thing is that `<summary>` tags can't contain `<div>`s. That's easily fixed by changing out the `<div>`s for `<span>`s with `display: block`. However, there's also a rule that `<span>`s can't contain heading elements. `<span>` permits only "phrasing content" https://developer.mozilla.org/en-US/docs/Web/HTML/Element/span, and `<h3>` (and friends) are "Flow content, heading content, palpable content". https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements We have a wrapping `<div>` that goes around each `<h3>`/`<h4>`, etc. We turn that into a `<section>` rather than a `<span>` because `<section>` permits "flow content". https://developer.mozilla.org/en-US/docs/Web/HTML/Element/section After this change we get only three warnings from tidy, run on struct.String.html: line 6 column 10790 - Warning: trimming empty <span> line 1 column 1118 - Warning: <link> proprietary attribute "disabled" line 1 column 1193 - Warning: <link> proprietary attribute "disabled" The empty `<span>` is a known issue - there's a span in front of the search box to work around a strange Safari issue. The `<link>` attributes are the non-default stylesheets. We can probably refactor theme application to avoid using this proprietary "disabled" attribute.
1 parent 1ea4851 commit 32f6260

27 files changed

+127
-133
lines changed

src/librustdoc/html/render/mod.rs

+27-35
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,7 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
12651265
if out.is_empty() {
12661266
write!(
12671267
&mut out,
1268-
"<div class=\"notable\">Notable traits for {}</div>\
1268+
"<span class=\"notable\">Notable traits for {}</span>\
12691269
<code class=\"content\">",
12701270
impl_.for_.print(cx)
12711271
);
@@ -1297,9 +1297,9 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
12971297
out.insert_str(
12981298
0,
12991299
"<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ\
1300-
<div class=\"notable-traits-tooltiptext\"><span class=\"docblock\">",
1300+
<span class=\"notable-traits-tooltiptext\"><span class=\"docblock\">",
13011301
);
1302-
out.push_str("</code></span></div></span></span>");
1302+
out.push_str("</code></span></span></span></span>");
13031303
}
13041304

13051305
out.into_inner()
@@ -1431,7 +1431,7 @@ fn render_impl(
14311431
.map(|item| format!("{}.{}", item.type_(), name));
14321432
write!(
14331433
w,
1434-
"<div id=\"{}\" class=\"{}{} has-srclink\">",
1434+
"<section id=\"{}\" class=\"{}{} has-srclink\">",
14351435
id, item_type, in_trait_class,
14361436
);
14371437
render_rightside(w, cx, item, containing_item, render_mode);
@@ -1446,15 +1446,15 @@ fn render_impl(
14461446
render_mode,
14471447
);
14481448
w.write_str("</h4>");
1449-
w.write_str("</div>");
1449+
w.write_str("</section>");
14501450
}
14511451
}
14521452
clean::TypedefItem(ref tydef, _) => {
14531453
let source_id = format!("{}.{}", ItemType::AssocType, name);
14541454
let id = cx.derive_id(source_id.clone());
14551455
write!(
14561456
w,
1457-
"<div id=\"{}\" class=\"{}{} has-srclink\">",
1457+
"<section id=\"{}\" class=\"{}{} has-srclink\">",
14581458
id, item_type, in_trait_class
14591459
);
14601460
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
@@ -1469,14 +1469,14 @@ fn render_impl(
14691469
cx,
14701470
);
14711471
w.write_str("</h4>");
1472-
w.write_str("</div>");
1472+
w.write_str("</section>");
14731473
}
14741474
clean::AssocConstItem(ref ty, _) => {
14751475
let source_id = format!("{}.{}", item_type, name);
14761476
let id = cx.derive_id(source_id.clone());
14771477
write!(
14781478
w,
1479-
"<div id=\"{}\" class=\"{}{} has-srclink\">",
1479+
"<section id=\"{}\" class=\"{}{} has-srclink\">",
14801480
id, item_type, in_trait_class
14811481
);
14821482
render_rightside(w, cx, item, containing_item, render_mode);
@@ -1491,12 +1491,12 @@ fn render_impl(
14911491
cx,
14921492
);
14931493
w.write_str("</h4>");
1494-
w.write_str("</div>");
1494+
w.write_str("</section>");
14951495
}
14961496
clean::AssocTypeItem(ref bounds, ref default) => {
14971497
let source_id = format!("{}.{}", item_type, name);
14981498
let id = cx.derive_id(source_id.clone());
1499-
write!(w, "<div id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
1499+
write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
15001500
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
15011501
w.write_str("<h4 class=\"code-header\">");
15021502
assoc_type(
@@ -1509,7 +1509,7 @@ fn render_impl(
15091509
cx,
15101510
);
15111511
w.write_str("</h4>");
1512-
w.write_str("</div>");
1512+
w.write_str("</section>");
15131513
}
15141514
clean::StrippedItem(..) => return,
15151515
_ => panic!("can't make docs for trait item with name {:?}", item.name),
@@ -1668,21 +1668,23 @@ fn render_rightside(
16681668
RenderMode::ForDeref { .. } => (None, None),
16691669
};
16701670

1671-
write!(w, "<div class=\"rightside\">");
1671+
let mut rightside = Buffer::new();
16721672
let has_stability = render_stability_since_raw(
1673-
w,
1673+
&mut rightside,
16741674
item.stable_since(tcx),
16751675
const_stability,
16761676
containing_item.stable_since(tcx),
16771677
const_stable_since,
16781678
);
1679-
let mut tmp_buf = Buffer::empty_from(w);
1680-
write_srclink(cx, item, &mut tmp_buf);
1681-
if has_stability && !tmp_buf.is_empty() {
1682-
w.write_str(" · ");
1679+
let mut srclink = Buffer::empty_from(w);
1680+
write_srclink(cx, item, &mut srclink);
1681+
if has_stability && !srclink.is_empty() {
1682+
rightside.write_str(" · ");
1683+
}
1684+
rightside.push_buffer(srclink);
1685+
if !rightside.is_empty() {
1686+
write!(w, "<span class=\"rightside\">{}</span>", rightside.into_inner());
16831687
}
1684-
w.push_buffer(tmp_buf);
1685-
w.write_str("</div>");
16861688
}
16871689

16881690
pub(crate) fn render_impl_summary(
@@ -1713,7 +1715,7 @@ pub(crate) fn render_impl_summary(
17131715
} else {
17141716
format!(" data-aliases=\"{}\"", aliases.join(","))
17151717
};
1716-
write!(w, "<div id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
1718+
write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
17171719
render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
17181720
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
17191721
write!(w, "<h3 class=\"code-header in-band\">");
@@ -1737,11 +1739,11 @@ pub(crate) fn render_impl_summary(
17371739
let is_trait = i.inner_impl().trait_.is_some();
17381740
if is_trait {
17391741
if let Some(portability) = portability(&i.impl_item, Some(parent)) {
1740-
write!(w, "<div class=\"item-info\">{}</div>", portability);
1742+
write!(w, "<span class=\"item-info\">{}</span>", portability);
17411743
}
17421744
}
17431745

1744-
w.write_str("</div>");
1746+
w.write_str("</section>");
17451747
}
17461748

17471749
fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
@@ -1802,19 +1804,9 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
18021804
// to navigate the documentation (though slightly inefficiently).
18031805

18041806
if !it.is_mod() {
1805-
buffer.write_str("<h2 class=\"location\">In ");
1806-
for (i, name) in cx.current.iter().take(parentlen).enumerate() {
1807-
if i > 0 {
1808-
buffer.write_str("::<wbr>");
1809-
}
1810-
write!(
1811-
buffer,
1812-
"<a href=\"{}index.html\">{}</a>",
1813-
&cx.root_path()[..(cx.current.len() - i - 1) * 3],
1814-
*name
1815-
);
1816-
}
1817-
buffer.write_str("</h2>");
1807+
let path: String = cx.current.iter().map(|s| s.as_str()).intersperse("::").collect();
1808+
1809+
write!(buffer, "<h2 class=\"location\"><a href=\"index.html\">In {}</a></h2>", path);
18181810
}
18191811

18201812
// Sidebar refers to the enclosing module, not this module.

src/librustdoc/html/static/css/rustdoc.css

+1
Original file line numberDiff line numberDiff line change
@@ -1336,6 +1336,7 @@ h3.variant {
13361336
margin-bottom: 13px;
13371337
font-size: 1.1875rem;
13381338
font-weight: 600;
1339+
display: block;
13391340
}
13401341

13411342
.notable-traits .docblock code.content{

src/test/rustdoc/async-fn.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T }
7777

7878
impl Foo {
7979
// @has async_fn/struct.Foo.html
80-
// @has - '//div[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
80+
// @has - '//*[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
8181
pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
8282
// taken from `tokio` as an example of a method that was particularly bad before
83-
// @has - '//div[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
83+
// @has - '//*[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
8484
pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
85-
// @has - '//div[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
85+
// @has - '//*[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
8686
pub async fn mut_self(&mut self) {}
8787
}
8888

src/test/rustdoc/auto_aliases.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![feature(auto_traits)]
22

3-
// @has auto_aliases/trait.Bar.html '//div[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
3+
// @has auto_aliases/trait.Bar.html '//*[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
44
pub struct Foo;
55

66
pub auto trait Bar {}

src/test/rustdoc/blanket-reexport-item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![crate_name = "foo"]
22

3-
// @has foo/struct.S.html '//div[@id="impl-Into%3CU%3E"]//h3[@class="code-header in-band"]' 'impl<T, U> Into<U> for T'
3+
// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E"]//h3[@class="code-header in-band"]' 'impl<T, U> Into<U> for T'
44
pub struct S2 {}
55
mod m {
66
pub struct S {}

src/test/rustdoc/const-display.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,19 @@ pub const unsafe fn bar_not_gated() -> u32 { 42 }
4949
pub struct Foo;
5050

5151
impl Foo {
52-
// @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/h4[@class="code-header"]' 'pub fn gated() -> u32'
52+
// @has 'foo/struct.Foo.html' '//*[@id="method.gated"]/h4[@class="code-header"]' 'pub fn gated() -> u32'
5353
// @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
5454
#[stable(feature = "rust1", since = "1.0.0")]
5555
#[rustc_const_unstable(feature="foo", issue = "none")]
5656
pub const fn gated() -> u32 { 42 }
5757

58-
// @has 'foo/struct.Foo.html' '//div[@id="method.gated_unsafe"]/h4[@class="code-header"]' 'pub unsafe fn gated_unsafe() -> u32'
58+
// @has 'foo/struct.Foo.html' '//*[@id="method.gated_unsafe"]/h4[@class="code-header"]' 'pub unsafe fn gated_unsafe() -> u32'
5959
// @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
6060
#[stable(feature = "rust1", since = "1.0.0")]
6161
#[rustc_const_unstable(feature="foo", issue = "none")]
6262
pub const unsafe fn gated_unsafe() -> u32 { 42 }
6363

64-
// @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/h4[@class="code-header"]' 'pub const fn stable_impl() -> u32'
64+
// @has 'foo/struct.Foo.html' '//*[@id="method.stable_impl"]/h4[@class="code-header"]' 'pub const fn stable_impl() -> u32'
6565
// @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)'
6666
#[stable(feature = "rust1", since = "1.0.0")]
6767
#[rustc_const_stable(feature = "rust1", since = "1.2.0")]

src/test/rustdoc/const-generics/add-impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub struct Simd<T, const WIDTH: usize> {
77
inner: T,
88
}
99

10-
// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//div/h3[@class="code-header in-band"]' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
10+
// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
1111
impl Add for Simd<u8, 16> {
1212
type Output = Self;
1313

src/test/rustdoc/const-generics/const-generic-slice.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub trait Array {
55
}
66

77
// @has foo/trait.Array.html
8-
// @has - '//div[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]'
9-
impl <T, const N: usize> Array for [T; N] {
8+
// @has - '//*[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]'
9+
impl<T, const N: usize> Array for [T; N] {
1010
type Item = T;
1111
}

src/test/rustdoc/const-generics/const-generics-docs.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub struct Foo<const N: usize> where u8: Trait<N>;
3636
// @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
3737
pub struct Bar<T, const N: usize>([T; N]);
3838

39-
// @has foo/struct.Foo.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
39+
// @has foo/struct.Foo.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
4040
impl<const M: usize> Foo<M> where u8: Trait<M> {
4141
// @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
4242
pub const FOO_ASSOC: usize = M + 13;
@@ -47,7 +47,7 @@ impl<const M: usize> Foo<M> where u8: Trait<M> {
4747
}
4848
}
4949

50-
// @has foo/struct.Bar.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>'
50+
// @has foo/struct.Bar.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>'
5151
impl<const M: usize> Bar<u8, M> {
5252
// @has - '//*[@id="method.hey"]' \
5353
// 'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>'
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#![allow(incomplete_features)]
2-
32
#![feature(adt_const_params)]
4-
53
#![crate_name = "foo"]
64

75
#[derive(PartialEq, Eq)]
@@ -11,20 +9,20 @@ pub enum Order {
119
}
1210

1311
// @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
14-
// @has foo/struct.VSet.html '//div[@id="impl-Send"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
15-
// @has foo/struct.VSet.html '//div[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
12+
// @has foo/struct.VSet.html '//*[@id="impl-Send"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
13+
// @has foo/struct.VSet.html '//*[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
1614
pub struct VSet<T, const ORDER: Order> {
1715
inner: Vec<T>,
1816
}
1917

20-
// @has foo/struct.VSet.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>'
18+
// @has foo/struct.VSet.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>'
2119
impl<T> VSet<T, { Order::Sorted }> {
2220
pub fn new() -> Self {
2321
Self { inner: Vec::new() }
2422
}
2523
}
2624

27-
// @has foo/struct.VSet.html '//div[@id="impl-1"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>'
25+
// @has foo/struct.VSet.html '//*[@id="impl-1"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>'
2826
impl<T> VSet<T, { Order::Unsorted }> {
2927
pub fn new() -> Self {
3028
Self { inner: Vec::new() }
@@ -33,7 +31,7 @@ impl<T> VSet<T, { Order::Unsorted }> {
3331

3432
pub struct Escape<const S: &'static str>;
3533

36-
// @has foo/struct.Escape.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
34+
// @has foo/struct.Escape.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
3735
impl Escape<r#"<script>alert("Escape");</script>"#> {
3836
pub fn f() {}
3937
}

src/test/rustdoc/empty-impls.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
#![crate_name = "foo"]
22

33
// @has foo/struct.Foo.html
4-
// @has - '//div[@id="synthetic-implementations-list"]/div[@id="impl-Send"]' 'impl Send for Foo'
4+
// @has - '//div[@id="synthetic-implementations-list"]/*[@id="impl-Send"]' 'impl Send for Foo'
55
pub struct Foo;
66

77
pub trait EmptyTrait {}
88

9-
// @has - '//div[@id="trait-implementations-list"]/div[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
9+
// @has - '//div[@id="trait-implementations-list"]/*[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
1010
impl EmptyTrait for Foo {}
1111

1212
pub trait NotEmpty {
1313
fn foo(&self);
1414
}
1515

16-
// @has - '//div[@id="trait-implementations-list"]/details/summary/div[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
16+
// @has - '//div[@id="trait-implementations-list"]/details/summary/*[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
1717
impl NotEmpty for Foo {
1818
fn foo(&self) {}
1919
}

src/test/rustdoc/ensure-src-link.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22

33
// This test ensures that the [src] link is present on traits items.
44

5-
// @has foo/trait.Iterator.html '//div[@id="method.zip"]//a[@class="srclink"]' "source"
5+
// @has foo/trait.Iterator.html '//*[@id="method.zip"]//a[@class="srclink"]' "source"
66
pub use std::iter::Iterator;

src/test/rustdoc/extern-default-method.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
extern crate rustdoc_extern_default_method as ext;
55

66
// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]' 1
7-
// @has extern_default_method/struct.Struct.html '//div[@id="method.provided"]//a[@class="fnname"]/@href' #method.provided
8-
// @has extern_default_method/struct.Struct.html '//div[@id="method.provided"]//a[@class="anchor"]/@href' #method.provided
7+
// @has extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="fnname"]/@href' #method.provided
8+
// @has extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="anchor"]/@href' #method.provided
99
pub use ext::Struct;

src/test/rustdoc/generic-impl.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
use std::fmt;
44

5-
// @!has foo/struct.Bar.html '//div[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
5+
// @!has foo/struct.Bar.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
66
pub struct Bar;
77

8-
// @has foo/struct.Foo.html '//div[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
8+
// @has foo/struct.Foo.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
99
pub struct Foo;
1010
// @has foo/struct.Foo.html '//div[@class="sidebar-links"]/a[@href="#impl-ToString"]' 'ToString'
1111

src/test/rustdoc/issue-29503.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ pub trait MyTrait {
55
fn my_string(&self) -> String;
66
}
77

8-
// @has - "//div[@id='implementors-list']//div[@id='impl-MyTrait']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug"
9-
impl<T> MyTrait for T where T: fmt::Debug {
8+
// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug"
9+
impl<T> MyTrait for T
10+
where
11+
T: fmt::Debug,
12+
{
1013
fn my_string(&self) -> String {
1114
format!("{:?}", self)
1215
}
1316
}
1417

15-
pub fn main() {
16-
}
18+
pub fn main() {}

0 commit comments

Comments
 (0)