Rollup merge of #39944 - GuillaumeGomez:associated-consts, r=frewsxcv

Improve associated constant rendering in rustdoc

Before:

<img width="1440" alt="screen shot 2017-02-19 at 00 30 51" src="https://cloud.githubusercontent.com/assets/3050060/23097697/caeed80e-f63a-11e6-98c2-5d27e4efd76d.png">

After:

<img width="1440" alt="screen shot 2017-02-19 at 00 30 39" src="https://cloud.githubusercontent.com/assets/3050060/23097698/cfb4874e-f63a-11e6-80cf-ffbf5c5c6162.png">

cc @SergioBenitez

r? @rust-lang/docs
This commit is contained in:
Corey Farwell 2017-02-28 22:55:28 -05:00 committed by GitHub
commit fda3f98746
9 changed files with 176 additions and 63 deletions

View File

@ -1476,7 +1476,7 @@ pub struct PolyTrait {
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
/// type out of the AST/TyCtxt given one of these, if more information is needed. Most importantly
/// it does not preserve mutability or boxes.
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq)]
pub enum Type {
/// structs/enums/traits (most that'd be an hir::TyPath)
ResolvedPath {

View File

@ -90,6 +90,16 @@ impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> {
}
}
impl<'a, T: fmt::Debug> fmt::Debug for CommaSep<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, item) in self.0.iter().enumerate() {
if i != 0 { write!(f, ", ")?; }
fmt::Debug::fmt(item, f)?;
}
Ok(())
}
}
impl<'a> fmt::Display for TyParamBounds<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let &TyParamBounds(bounds) = self;
@ -165,7 +175,7 @@ impl<'a> fmt::Display for WhereClause<'a> {
if f.alternate() {
clause.push_str(" where ");
} else {
clause.push_str(" <span class='where fmt-newline'>where ");
clause.push_str(" <span class=\"where fmt-newline\">where ");
}
for (i, pred) in gens.where_predicates.iter().enumerate() {
if i > 0 {
@ -449,8 +459,8 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
} else {
root.push_str(&seg.name);
root.push_str("/");
write!(w, "<a class='mod'
href='{}index.html'>{}</a>::",
write!(w, "<a class=\"mod\"
href=\"{}index.html\">{}</a>::",
root,
seg.name)?;
}
@ -491,7 +501,7 @@ fn primitive_link(f: &mut fmt::Formatter,
Some(&def_id) if def_id.is_local() => {
let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
let len = if len == 0 {0} else {len - 1};
write!(f, "<a class='primitive' href='{}primitive.{}.html'>",
write!(f, "<a class=\"primitive\" href=\"{}primitive.{}.html\">",
repeat("../").take(len).collect::<String>(),
prim.to_url_str())?;
needs_termination = true;
@ -508,7 +518,7 @@ fn primitive_link(f: &mut fmt::Formatter,
(.., render::Unknown) => None,
};
if let Some((cname, root)) = loc {
write!(f, "<a class='primitive' href='{}{}/primitive.{}.html'>",
write!(f, "<a class=\"primitive\" href=\"{}{}/primitive.{}.html\">",
root,
cname,
prim.to_url_str())?;
@ -550,7 +560,7 @@ impl<'a> fmt::Display for HRef<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match href(self.did) {
Some((url, shortty, fqp)) => if !f.alternate() {
write!(f, "<a class='{}' href='{}' title='{} {}'>{}</a>",
write!(f, "<a class=\"{}\" href=\"{}\" title=\"{} {}\">{}</a>",
shortty, url, shortty, fqp.join("::"), self.text)
} else {
write!(f, "{}", self.text)
@ -560,7 +570,8 @@ impl<'a> fmt::Display for HRef<'a> {
}
}
fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt::Result {
fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool,
is_not_debug: bool) -> fmt::Result {
match *t {
clean::Generic(ref name) => {
f.write_str(name)
@ -571,7 +582,8 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
tybounds(f, typarams)
}
clean::Infer => write!(f, "_"),
clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
clean::Primitive(prim) if is_not_debug => primitive_link(f, prim, prim.as_str()),
clean::Primitive(prim) => write!(f, "{}", prim.as_str()),
clean::BareFunction(ref decl) => {
if f.alternate() {
write!(f, "{}{}fn{:#}{:#}",
@ -589,26 +601,30 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
}
clean::Tuple(ref typs) => {
match &typs[..] {
&[] => primitive_link(f, PrimitiveType::Tuple, "()"),
&[ref one] => {
&[] if is_not_debug => primitive_link(f, PrimitiveType::Tuple, "()"),
&[] => write!(f, "()"),
&[ref one] if is_not_debug => {
primitive_link(f, PrimitiveType::Tuple, "(")?;
//carry f.alternate() into this display w/o branching manually
fmt::Display::fmt(one, f)?;
primitive_link(f, PrimitiveType::Tuple, ",)")
}
many => {
&[ref one] => write!(f, "({:?},)", one),
many if is_not_debug => {
primitive_link(f, PrimitiveType::Tuple, "(")?;
fmt::Display::fmt(&CommaSep(&many), f)?;
primitive_link(f, PrimitiveType::Tuple, ")")
}
many => write!(f, "({:?})", &CommaSep(&many)),
}
}
clean::Vector(ref t) => {
clean::Vector(ref t) if is_not_debug => {
primitive_link(f, PrimitiveType::Slice, &format!("["))?;
fmt::Display::fmt(t, f)?;
primitive_link(f, PrimitiveType::Slice, &format!("]"))
}
clean::FixedVector(ref t, ref s) => {
clean::Vector(ref t) => write!(f, "[{:?}]", t),
clean::FixedVector(ref t, ref s) if is_not_debug => {
primitive_link(f, PrimitiveType::Array, "[")?;
fmt::Display::fmt(t, f)?;
if f.alternate() {
@ -619,10 +635,17 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
&format!("; {}]", Escape(s)))
}
}
clean::FixedVector(ref t, ref s) => {
if f.alternate() {
write!(f, "[{:?}; {}]", t, s)
} else {
write!(f, "[{:?}; {}]", t, Escape(s))
}
}
clean::Never => f.write_str("!"),
clean::RawPointer(m, ref t) => {
match **t {
clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} if is_not_debug => {
if f.alternate() {
primitive_link(f, clean::PrimitiveType::RawPointer,
&format!("*{}{:#}", RawMutableSpace(m), t))
@ -631,11 +654,21 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
&format!("*{}{}", RawMutableSpace(m), t))
}
}
_ => {
clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
if f.alternate() {
write!(f, "*{}{:#?}", RawMutableSpace(m), t)
} else {
write!(f, "*{}{:?}", RawMutableSpace(m), t)
}
}
_ if is_not_debug => {
primitive_link(f, clean::PrimitiveType::RawPointer,
&format!("*{}", RawMutableSpace(m)))?;
fmt::Display::fmt(t, f)
}
_ => {
write!(f, "*{}{:?}", RawMutableSpace(m), t)
}
}
}
clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
@ -647,15 +680,23 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
match **ty {
clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
match **bt {
clean::Generic(_) =>
clean::Generic(_) if is_not_debug => {
if f.alternate() {
primitive_link(f, PrimitiveType::Slice,
&format!("&{}{}[{:#}]", lt, m, **bt))
} else {
primitive_link(f, PrimitiveType::Slice,
&format!("&amp;{}{}[{}]", lt, m, **bt))
},
_ => {
}
}
clean::Generic(_) => {
if f.alternate() {
write!(f, "&{}{}[{:#?}]", lt, m, **bt)
} else {
write!(f, "&{}{}[{:?}]", lt, m, **bt)
}
}
_ if is_not_debug => {
if f.alternate() {
primitive_link(f, PrimitiveType::Slice,
&format!("&{}{}[", lt, m))?;
@ -667,15 +708,26 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
}
primitive_link(f, PrimitiveType::Slice, "]")
}
_ => {
if f.alternate() {
write!(f, "&{}{}[{:#?}]", lt, m, **bt)
} else {
write!(f, "&{}{}[{:?}]", lt, m, **bt)
}
}
}
}
_ => {
if f.alternate() {
write!(f, "&{}{}", lt, m)?;
fmt_type(&ty, f, use_absolute)
fmt_type(&ty, f, use_absolute, is_not_debug)
} else {
write!(f, "&amp;{}{}", lt, m)?;
fmt_type(&ty, f, use_absolute)
if is_not_debug {
write!(f, "&amp;{}{}", lt, m)?;
} else {
write!(f, "&{}{}", lt, m)?;
}
fmt_type(&ty, f, use_absolute, is_not_debug)
}
}
}
@ -723,9 +775,17 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
}
clean::QPath { ref name, ref self_type, ref trait_ } => {
if f.alternate() {
write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
if is_not_debug {
write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
} else {
write!(f, "<{:#?} as {:#?}>::{}", self_type, trait_, name)
}
} else {
write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
if is_not_debug {
write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
} else {
write!(f, "<{:?} as {:?}>::{}", self_type, trait_, name)
}
}
}
clean::Unique(..) => {
@ -736,7 +796,13 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
impl fmt::Display for clean::Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt_type(self, f, false)
fmt_type(self, f, false, true)
}
}
impl fmt::Debug for clean::Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt_type(self, f, false, false)
}
}
@ -777,7 +843,7 @@ fn fmt_impl(i: &clean::Impl,
plain.push_str(" for ");
}
fmt_type(&i.for_, f, use_absolute)?;
fmt_type(&i.for_, f, use_absolute, true)?;
plain.push_str(&format!("{:#}", i.for_));
fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?;

View File

@ -144,12 +144,12 @@ impl<U: Write> Writer for U {
-> io::Result<()> {
match klass {
Class::None => write!(self, "{}", text),
klass => write!(self, "<span class='{}'>{}</span>", klass.rustdoc_class(), text),
klass => write!(self, "<span class=\"{}\">{}</span>", klass.rustdoc_class(), text),
}
}
fn enter_span(&mut self, klass: Class) -> io::Result<()> {
write!(self, "<span class='{}'>", klass.rustdoc_class())
write!(self, "<span class=\"{}\">", klass.rustdoc_class())
}
fn exit_span(&mut self) -> io::Result<()> {
@ -363,7 +363,7 @@ fn write_header(class: Option<&str>,
if let Some(id) = id {
write!(out, "id='{}' ", id)?;
}
write!(out, "class='rust {}'>\n", class.unwrap_or(""))
write!(out, "class=\"rust {}\">\n", class.unwrap_or(""))
}
fn write_footer(out: &mut Write) -> io::Result<()> {

View File

@ -1547,7 +1547,7 @@ impl<'a> fmt::Display for Item<'a> {
component)?;
}
}
write!(fmt, "<a class='{}' href=''>{}</a>",
write!(fmt, "<a class=\"{}\" href=''>{}</a>",
self.item.type_(), self.item.name.as_ref().unwrap())?;
write!(fmt, "</span>")?; // in-band
@ -1654,9 +1654,35 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin
Ok(())
}
fn md_render_assoc_item(item: &clean::Item) -> String {
match item.inner {
clean::AssociatedConstItem(ref ty, ref default) => {
if let Some(default) = default.as_ref() {
format!("```\n{}: {:?} = {}\n```\n\n", item.name.as_ref().unwrap(), ty, default)
} else {
format!("```\n{}: {:?}\n```\n\n", item.name.as_ref().unwrap(), ty)
}
}
_ => String::new(),
}
}
fn get_doc_value(item: &clean::Item) -> Option<&str> {
let x = item.doc_value();
if x.is_none() {
match item.inner {
clean::AssociatedConstItem(_, _) => Some(""),
_ => None,
}
} else {
x
}
}
fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
if let Some(s) = item.doc_value() {
write!(w, "<div class='docblock'>{}</div>", Markdown(s))?;
if let Some(s) = get_doc_value(item) {
write!(w, "<div class='docblock'>{}</div>",
Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?;
}
Ok(())
}
@ -1817,7 +1843,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
let doc_value = myitem.doc_value().unwrap_or("");
write!(w, "
<tr class='{stab} module-item'>
<td><a class='{class}' href='{href}'
<td><a class=\"{class}\" href=\"{href}\"
title='{title_type} {title}'>{name}</a>{unsafety_flag}</td>
<td class='docblock-short'>
{stab_docs} {docs}
@ -2215,16 +2241,12 @@ fn naive_assoc_href(it: &clean::Item, link: AssocItemLink) -> String {
fn assoc_const(w: &mut fmt::Formatter,
it: &clean::Item,
ty: &clean::Type,
default: Option<&String>,
_default: Option<&String>,
link: AssocItemLink) -> fmt::Result {
write!(w, "const <a href='{}' class='constant'>{}</a>",
write!(w, "const <a href='{}' class=\"constant\"><b>{}</b></a>: {}",
naive_assoc_href(it, link),
it.name.as_ref().unwrap())?;
write!(w, ": {}", ty)?;
if let Some(default) = default {
write!(w, " = {}", Escape(default))?;
}
it.name.as_ref().unwrap(),
ty)?;
Ok(())
}
@ -2232,7 +2254,7 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
bounds: &Vec<clean::TyParamBound>,
default: Option<&clean::Type>,
link: AssocItemLink) -> fmt::Result {
write!(w, "type <a href='{}' class='type'>{}</a>",
write!(w, "type <a href='{}' class=\"type\">{}</a>",
naive_assoc_href(it, link),
it.name.as_ref().unwrap())?;
if !bounds.is_empty() {
@ -2375,7 +2397,7 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
let ns_id = derive_id(format!("{}.{}",
field.name.as_ref().unwrap(),
ItemType::StructField.name_space()));
write!(w, "<span id='{id}' class='{item_type}'>
write!(w, "<span id='{id}' class=\"{item_type}\">
<span id='{ns_id}' class='invisible'>
<code>{name}: {ty}</code>
</span></span>",
@ -2417,7 +2439,7 @@ fn item_union(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
if fields.peek().is_some() {
write!(w, "<h2 class='fields'>Fields</h2>")?;
for (field, ty) in fields {
write!(w, "<span id='{shortty}.{name}' class='{shortty}'><code>{name}: {ty}</code>
write!(w, "<span id='{shortty}.{name}' class=\"{shortty}\"><code>{name}: {ty}</code>
</span>",
shortty = ItemType::StructField,
name = field.name.as_ref().unwrap(),
@ -2902,7 +2924,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
if render_method_item {
let id = derive_id(format!("{}.{}", item_type, name));
let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class='{}'>", id, item_type)?;
write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
write!(w, "<span id='{}' class='invisible'>", ns_id)?;
write!(w, "<code>")?;
render_assoc_item(w, item, link.anchor(&id), ItemType::Impl)?;
@ -2914,7 +2936,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
clean::TypedefItem(ref tydef, _) => {
let id = derive_id(format!("{}.{}", ItemType::AssociatedType, name));
let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class='{}'>", id, item_type)?;
write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?;
write!(w, "</code></span></h4>\n")?;
@ -2922,7 +2944,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
clean::AssociatedConstItem(ref ty, ref default) => {
let id = derive_id(format!("{}.{}", item_type, name));
let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class='{}'>", id, item_type)?;
write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?;
write!(w, "</code></span></h4>\n")?;
@ -2930,7 +2952,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
clean::ConstantItem(ref c) => {
let id = derive_id(format!("{}.{}", item_type, name));
let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class='{}'>", id, item_type)?;
write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_const(w, item, &c.type_, Some(&c.expr), link.anchor(&id))?;
write!(w, "</code></span></h4>\n")?;
@ -2938,7 +2960,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
clean::AssociatedTypeItem(ref bounds, ref default) => {
let id = derive_id(format!("{}.{}", item_type, name));
let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class='{}'>", id, item_type)?;
write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?;
write!(w, "</code></span></h4>\n")?;
@ -2956,7 +2978,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
// We need the stability of the item from the trait
// because impls can't have a stability.
document_stability(w, cx, it)?;
if item.doc_value().is_some() {
if get_doc_value(item).is_some() {
document_full(w, item)?;
} else {
// In case the item isn't documented,

View File

@ -979,7 +979,7 @@
.html("[<span class='inner'></span>]");
toggle.children(".inner").text(labelForToggleButton(false));
$(".method").each(function() {
$(".method, .impl-items > .associatedconstant").each(function() {
if ($(this).next().is(".docblock") ||
($(this).next().is(".stability") && $(this).next().next().is(".docblock"))) {
$(this).children().last().after(toggle.clone());

View File

@ -89,7 +89,7 @@ h2 {
h3 {
font-size: 1.3em;
}
h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {
h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
font-weight: 500;
margin: 20px 0 15px 0;
padding-bottom: 6px;
@ -99,10 +99,10 @@ h1.fqn {
margin-top: 0;
position: relative;
}
h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {
h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
border-bottom: 1px solid;
}
h3.impl, h3.method, h4.method, h3.type, h4.type {
h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant {
font-weight: 600;
margin-top: 10px;
margin-bottom: 10px;
@ -382,7 +382,7 @@ h4 > code, h3 > code, .invisible > code {
.content .impl-items .docblock, .content .impl-items .stability {
margin-left: 40px;
}
.content .impl-items .method, .content .impl-items > .type {
.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
margin-left: 20px;
}

View File

@ -13,14 +13,16 @@
pub trait Foo {
// @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \
// 'const FOO: usize;'
// @has - '//*[@id="associatedconstant.FOO"]' 'const FOO'
const FOO: usize;
// @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
// @has - '//*[@class="docblock"]' 'FOO: usize = 12'
const FOO: usize = 12;
}
pub struct Bar;
impl Bar {
// @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.BAR"]' \
// 'const BAR: usize = 3'
// 'const BAR: usize'
// @has - '//*[@class="docblock"]' 'BAR: usize = 3'
pub const BAR: usize = 3;
}

View File

@ -16,7 +16,8 @@ pub trait Bar {
// @has - '//*[@id="associatedtype.Bar"]' 'type Bar = ()'
// @has - '//*[@href="#associatedtype.Bar"]' 'Bar'
type Bar = ();
// @has - '//*[@id="associatedconstant.Baz"]' 'const Baz: usize = 7'
// @has - '//*[@id="associatedconstant.Baz"]' 'const Baz: usize'
// @has - '//*[@class="docblock"]' 'Baz: usize = 7'
// @has - '//*[@href="#associatedconstant.Baz"]' 'Baz'
const Baz: usize = 7;
// @has - '//*[@id="tymethod.bar"]' 'fn bar'

View File

@ -28,18 +28,40 @@ macro_rules! make {
fn ignore(_: &X) {}
const C: X;
// @has issue_33302/trait.T.html \
// '//*[@class="rust trait"]' 'const D: i32 = 4 * 4;'
// @has - '//*[@id="associatedconstant.D"]' 'const D: i32 = 4 * 4'
// '//*[@class="rust trait"]' 'const D: i32'
// @has - '//*[@class="docblock"]' 'D: i32 = 4 * 4'
// @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
const D: i32 = ($n * $n);
}
// @has issue_33302/struct.S.html \
// '//h3[@class="impl"]' 'impl T<[i32; 16]> for S'
// @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16] = [0; 4 * 4]'
// @has - '//*[@id="associatedconstant.D"]' 'const D: i32 = 4 * 4'
// @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]'
// @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
// @has - '//*[@class="docblock"]' 'C: [i32; 16] = [0; 4 * 4]'
impl T<[i32; ($n * $n)]> for S {
const C: [i32; ($n * $n)] = [0; ($n * $n)];
}
// @has issue_33302/struct.S.html \
// '//h3[@class="impl"]' 'impl T<[i32; 16]> for S'
// @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)'
// @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32'
// @has - '//*[@class="docblock"]' 'C: (i32,) = (4,)'
impl T<(i32,)> for S {
const C: (i32,) = ($n,);
}
// @has issue_33302/struct.S.html \
// '//h3[@class="impl"]' 'impl T<(i32, i32)> for S'
// @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)'
// @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32'
// @has - '//*[@class="docblock"]' 'C: (i32, i32) = (4, 4)'
// @has - '//*[@class="docblock"]' 'D: i32 = 4 / 4'
impl T<(i32, i32)> for S {
const C: (i32, i32) = ($n, $n);
const D: i32 = ($n / $n);
}
}
}