-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rustdoc-Json: Document HRTB's on DynTrait #99787
Changes from all commits
95729dc
2143e48
a856e57
625c4d7
6290f92
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -119,6 +119,16 @@ where | |||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
impl<I, T, U> FromWithTcx<I> for Vec<U> | ||||||||||
where | ||||||||||
I: IntoIterator<Item = T>, | ||||||||||
U: FromWithTcx<T>, | ||||||||||
{ | ||||||||||
fn from_tcx(f: I, tcx: TyCtxt<'_>) -> Vec<U> { | ||||||||||
f.into_iter().map(|x| x.into_tcx(tcx)).collect() | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation { | ||||||||||
#[rustfmt::skip] | ||||||||||
let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation; | ||||||||||
|
@@ -130,11 +140,11 @@ impl FromWithTcx<clean::GenericArgs> for GenericArgs { | |||||||||
use clean::GenericArgs::*; | ||||||||||
match args { | ||||||||||
AngleBracketed { args, bindings } => GenericArgs::AngleBracketed { | ||||||||||
args: args.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(), | ||||||||||
bindings: bindings.into_iter().map(|a| a.into_tcx(tcx)).collect(), | ||||||||||
args: args.into_vec().into_tcx(tcx), | ||||||||||
bindings: bindings.into_tcx(tcx), | ||||||||||
}, | ||||||||||
Parenthesized { inputs, output } => GenericArgs::Parenthesized { | ||||||||||
inputs: inputs.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(), | ||||||||||
inputs: inputs.into_vec().into_tcx(tcx), | ||||||||||
output: output.map(|a| (*a).into_tcx(tcx)), | ||||||||||
}, | ||||||||||
} | ||||||||||
|
@@ -145,7 +155,7 @@ impl FromWithTcx<clean::GenericArg> for GenericArg { | |||||||||
fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self { | ||||||||||
use clean::GenericArg::*; | ||||||||||
match arg { | ||||||||||
Lifetime(l) => GenericArg::Lifetime(l.0.to_string()), | ||||||||||
Lifetime(l) => GenericArg::Lifetime(convert_lifetime(l)), | ||||||||||
Type(t) => GenericArg::Type(t.into_tcx(tcx)), | ||||||||||
Const(box c) => GenericArg::Const(c.into_tcx(tcx)), | ||||||||||
Infer => GenericArg::Infer, | ||||||||||
|
@@ -177,9 +187,7 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind { | |||||||||
use clean::TypeBindingKind::*; | ||||||||||
match kind { | ||||||||||
Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)), | ||||||||||
Constraint { bounds } => { | ||||||||||
TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect()) | ||||||||||
} | ||||||||||
Constraint { bounds } => TypeBindingKind::Constraint(bounds.into_tcx(tcx)), | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
@@ -244,7 +252,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { | |||||||||
TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)), | ||||||||||
MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, header.unwrap(), tcx)), | ||||||||||
TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, header.unwrap(), tcx)), | ||||||||||
ImplItem(i) => ItemEnum::Impl(i.into_tcx(tcx)), | ||||||||||
ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)), | ||||||||||
StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), | ||||||||||
ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), | ||||||||||
ForeignTypeItem => ItemEnum::ForeignType, | ||||||||||
|
@@ -260,12 +268,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { | |||||||||
} | ||||||||||
TyAssocTypeItem(g, b) => ItemEnum::AssocType { | ||||||||||
generics: (*g).into_tcx(tcx), | ||||||||||
bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(), | ||||||||||
bounds: b.into_tcx(tcx), | ||||||||||
default: None, | ||||||||||
}, | ||||||||||
AssocTypeItem(t, b) => ItemEnum::AssocType { | ||||||||||
generics: t.generics.into_tcx(tcx), | ||||||||||
bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(), | ||||||||||
bounds: b.into_tcx(tcx), | ||||||||||
default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)), | ||||||||||
}, | ||||||||||
// `convert_item` early returns `None` for stripped items and keywords. | ||||||||||
|
@@ -347,15 +355,15 @@ fn convert_abi(a: RustcAbi) -> Abi { | |||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
fn convert_lifetime(l: clean::Lifetime) -> String { | ||||||||||
l.0.to_string() | ||||||||||
} | ||||||||||
|
||||||||||
impl FromWithTcx<clean::Generics> for Generics { | ||||||||||
fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self { | ||||||||||
Generics { | ||||||||||
params: generics.params.into_iter().map(|x| x.into_tcx(tcx)).collect(), | ||||||||||
where_predicates: generics | ||||||||||
.where_predicates | ||||||||||
.into_iter() | ||||||||||
.map(|x| x.into_tcx(tcx)) | ||||||||||
.collect(), | ||||||||||
params: generics.params.into_tcx(tcx), | ||||||||||
where_predicates: generics.where_predicates.into_tcx(tcx), | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
@@ -374,10 +382,10 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind { | |||||||||
use clean::GenericParamDefKind::*; | ||||||||||
match kind { | ||||||||||
Lifetime { outlives } => GenericParamDefKind::Lifetime { | ||||||||||
outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(), | ||||||||||
outlives: outlives.into_iter().map(convert_lifetime).collect(), | ||||||||||
}, | ||||||||||
Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type { | ||||||||||
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), | ||||||||||
bounds: bounds.into_tcx(tcx), | ||||||||||
default: default.map(|x| (*x).into_tcx(tcx)), | ||||||||||
synthetic, | ||||||||||
}, | ||||||||||
|
@@ -395,7 +403,7 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate { | |||||||||
match predicate { | ||||||||||
BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate { | ||||||||||
type_: ty.into_tcx(tcx), | ||||||||||
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), | ||||||||||
bounds: bounds.into_tcx(tcx), | ||||||||||
generic_params: bound_params | ||||||||||
.into_iter() | ||||||||||
.map(|x| GenericParamDef { | ||||||||||
|
@@ -405,8 +413,8 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate { | |||||||||
.collect(), | ||||||||||
}, | ||||||||||
RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate { | ||||||||||
lifetime: lifetime.0.to_string(), | ||||||||||
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), | ||||||||||
lifetime: convert_lifetime(lifetime), | ||||||||||
bounds: bounds.into_tcx(tcx), | ||||||||||
}, | ||||||||||
EqPredicate { lhs, rhs } => { | ||||||||||
WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) } | ||||||||||
|
@@ -424,11 +432,11 @@ impl FromWithTcx<clean::GenericBound> for GenericBound { | |||||||||
let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx); | ||||||||||
GenericBound::TraitBound { | ||||||||||
trait_, | ||||||||||
generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), | ||||||||||
generic_params: generic_params.into_tcx(tcx), | ||||||||||
modifier: from_trait_bound_modifier(modifier), | ||||||||||
} | ||||||||||
} | ||||||||||
Outlives(lifetime) => GenericBound::Outlives(lifetime.0.to_string()), | ||||||||||
Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)), | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
@@ -447,8 +455,8 @@ pub(crate) fn from_trait_bound_modifier( | |||||||||
impl FromWithTcx<clean::Type> for Type { | ||||||||||
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { | ||||||||||
use clean::Type::{ | ||||||||||
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, | ||||||||||
QPath, RawPointer, Slice, Tuple, | ||||||||||
Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath, | ||||||||||
RawPointer, Slice, Tuple, | ||||||||||
}; | ||||||||||
|
||||||||||
match ty { | ||||||||||
|
@@ -458,40 +466,24 @@ impl FromWithTcx<clean::Type> for Type { | |||||||||
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))), | ||||||||||
param_names: Vec::new(), | ||||||||||
}, | ||||||||||
DynTrait(mut bounds, lt) => { | ||||||||||
let first_trait = bounds.remove(0).trait_; | ||||||||||
|
||||||||||
Type::ResolvedPath { | ||||||||||
name: first_trait.whole_name(), | ||||||||||
id: from_item_id(first_trait.def_id().into(), tcx), | ||||||||||
args: first_trait | ||||||||||
.segments | ||||||||||
.last() | ||||||||||
.map(|args| Box::new(args.clone().args.into_tcx(tcx))), | ||||||||||
param_names: bounds | ||||||||||
.into_iter() | ||||||||||
.map(|t| { | ||||||||||
clean::GenericBound::TraitBound(t, rustc_hir::TraitBoundModifier::None) | ||||||||||
}) | ||||||||||
.chain(lt.map(clean::GenericBound::Outlives)) | ||||||||||
.map(|bound| bound.into_tcx(tcx)) | ||||||||||
.collect(), | ||||||||||
} | ||||||||||
} | ||||||||||
clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait { | ||||||||||
lifetime: lt.map(convert_lifetime), | ||||||||||
traits: bounds.into_tcx(tcx), | ||||||||||
}), | ||||||||||
Generic(s) => Type::Generic(s.to_string()), | ||||||||||
Primitive(p) => Type::Primitive(p.as_sym().to_string()), | ||||||||||
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))), | ||||||||||
Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()), | ||||||||||
Tuple(t) => Type::Tuple(t.into_tcx(tcx)), | ||||||||||
Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))), | ||||||||||
Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s }, | ||||||||||
ImplTrait(g) => Type::ImplTrait(g.into_iter().map(|x| x.into_tcx(tcx)).collect()), | ||||||||||
ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)), | ||||||||||
Infer => Type::Infer, | ||||||||||
RawPointer(mutability, type_) => Type::RawPointer { | ||||||||||
mutable: mutability == ast::Mutability::Mut, | ||||||||||
type_: Box::new((*type_).into_tcx(tcx)), | ||||||||||
}, | ||||||||||
BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef { | ||||||||||
lifetime: lifetime.map(|l| l.0.to_string()), | ||||||||||
lifetime: lifetime.map(convert_lifetime), | ||||||||||
mutable: mutability == ast::Mutability::Mut, | ||||||||||
type_: Box::new((*type_).into_tcx(tcx)), | ||||||||||
}, | ||||||||||
|
@@ -528,7 +520,7 @@ impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer { | |||||||||
async_: false, | ||||||||||
abi: convert_abi(abi), | ||||||||||
}, | ||||||||||
generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), | ||||||||||
generic_params: generic_params.into_tcx(tcx), | ||||||||||
decl: decl.into_tcx(tcx), | ||||||||||
} | ||||||||||
} | ||||||||||
|
@@ -562,16 +554,28 @@ impl FromWithTcx<clean::Trait> for Trait { | |||||||||
is_unsafe, | ||||||||||
items: ids(items, tcx), | ||||||||||
generics: generics.into_tcx(tcx), | ||||||||||
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), | ||||||||||
bounds: bounds.into_tcx(tcx), | ||||||||||
implementations: Vec::new(), // Added in JsonRenderer::item | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
impl FromWithTcx<Box<clean::Impl>> for Impl { | ||||||||||
fn from_tcx(impl_: Box<clean::Impl>, tcx: TyCtxt<'_>) -> Self { | ||||||||||
impl FromWithTcx<clean::PolyTrait> for PolyTrait { | ||||||||||
fn from_tcx( | ||||||||||
clean::PolyTrait { trait_, generic_params }: clean::PolyTrait, | ||||||||||
tcx: TyCtxt<'_>, | ||||||||||
) -> Self { | ||||||||||
PolyTrait { | ||||||||||
trait_: clean::Type::Path { path: trait_ }.into_tcx(tcx), | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally we keep it in Path form rather than allowing it to be any type. (Type definition needs to be updated too.)
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't yet have a rust/src/librustdoc/json/conversions.rs Line 423 in e141246
rust/src/librustdoc/json/conversions.rs Line 500 in e141246
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, makes sense to hold off then. |
||||||||||
generic_params: generic_params.into_tcx(tcx), | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
impl FromWithTcx<clean::Impl> for Impl { | ||||||||||
fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self { | ||||||||||
let provided_trait_methods = impl_.provided_trait_methods(tcx); | ||||||||||
let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = *impl_; | ||||||||||
let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_; | ||||||||||
// FIXME: should `trait_` be a clean::Path equivalent in JSON? | ||||||||||
let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx)); | ||||||||||
// FIXME: use something like ImplKind in JSON? | ||||||||||
|
@@ -730,10 +734,7 @@ impl FromWithTcx<Box<clean::Typedef>> for Typedef { | |||||||||
|
||||||||||
impl FromWithTcx<clean::OpaqueTy> for OpaqueTy { | ||||||||||
fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self { | ||||||||||
OpaqueTy { | ||||||||||
bounds: opaque.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), | ||||||||||
generics: opaque.generics.into_tcx(tcx), | ||||||||||
} | ||||||||||
OpaqueTy { bounds: opaque.bounds.into_tcx(tcx), generics: opaque.generics.into_tcx(tcx) } | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
|
@@ -749,10 +750,7 @@ impl FromWithTcx<clean::Static> for Static { | |||||||||
|
||||||||||
impl FromWithTcx<clean::TraitAlias> for TraitAlias { | ||||||||||
fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self { | ||||||||||
TraitAlias { | ||||||||||
generics: alias.generics.into_tcx(tcx), | ||||||||||
params: alias.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), | ||||||||||
} | ||||||||||
TraitAlias { generics: alias.generics.into_tcx(tcx), params: alias.bounds.into_tcx(tcx) } | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ use std::path::PathBuf; | |
use serde::{Deserialize, Serialize}; | ||
|
||
/// rustdoc format-version. | ||
pub const FORMAT_VERSION: u32 = 16; | ||
pub const FORMAT_VERSION: u32 = 17; | ||
|
||
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information | ||
/// about the language items in the local crate, as well as info about external items to allow | ||
|
@@ -115,6 +115,35 @@ pub enum Visibility { | |
}, | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] | ||
pub struct DynTrait { | ||
/// All the traits implemented. One of them is the vtable, and the rest must be auto traits. | ||
pub traits: Vec<PolyTrait>, | ||
/// The lifetime of the whole dyn object | ||
/// ```text | ||
/// dyn Debug + 'static | ||
/// ^^^^^^^ | ||
/// | | ||
/// this part | ||
/// ``` | ||
pub lifetime: Option<String>, | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] | ||
/// A trait and potential HRTBs | ||
pub struct PolyTrait { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wasn't sure what the best name for this is. The compiler seems to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know what it means ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A Trait with possible HRTB params There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't hesitate to add doc comments to explain what it stands for. Always appreciated. |
||
#[serde(rename = "trait")] | ||
pub trait_: Type, | ||
camelid marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// Used for Higher-Rank Trait Bounds (HRTBs) | ||
/// ```text | ||
/// dyn for<'a> Fn() -> &'a i32" | ||
/// ^^^^^^^ | ||
/// | | ||
/// this part | ||
/// ``` | ||
pub generic_params: Vec<GenericParamDef>, | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] | ||
#[serde(rename_all = "snake_case")] | ||
pub enum GenericArgs { | ||
|
@@ -395,7 +424,7 @@ pub enum WherePredicate { | |
type_: Type, | ||
bounds: Vec<GenericBound>, | ||
/// Used for Higher-Rank Trait Bounds (HRTBs) | ||
/// ```plain | ||
/// ```text | ||
/// where for<'a> &'a T: Iterator," | ||
/// ^^^^^^^ | ||
/// | | ||
|
@@ -420,7 +449,7 @@ pub enum GenericBound { | |
#[serde(rename = "trait")] | ||
trait_: Type, | ||
/// Used for Higher-Rank Trait Bounds (HRTBs) | ||
/// ```plain | ||
/// ```text | ||
/// where F: for<'a, 'b> Fn(&'a u8, &'b u8) | ||
/// ^^^^^^^^^^^ | ||
/// | | ||
|
@@ -458,6 +487,7 @@ pub enum Type { | |
args: Option<Box<GenericArgs>>, | ||
param_names: Vec<GenericBound>, | ||
}, | ||
DynTrait(DynTrait), | ||
/// Parameterized types | ||
Generic(String), | ||
/// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples | ||
|
@@ -505,7 +535,7 @@ pub enum Type { | |
pub struct FunctionPointer { | ||
pub decl: FnDecl, | ||
/// Used for Higher-Rank Trait Bounds (HRTBs) | ||
/// ```plain | ||
/// ```text | ||
/// for<'c> fn(val: &'c i32) -> i32 | ||
/// ^^^^^^^ | ||
/// | | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems to be doing the same thing but instead of creating one vector, it creates two. Did I miss something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah no nevermind. But then I wonder why the
into_vec
is needed at all...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it’s not a Vec. It’s a boxed slice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably it could skip the
into_vec
because of the impl for IntoIterator right?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like @camelid said. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
args
is aBox<[GenericArg]>
, which doesn't implIntoIterator
, butVec
does and the conversion is zero cost. I guess you couldimpl <T, U: FromWithTcx<T>> FromWithTcx<Box<[T]>> for Vec<U>
, but I don't think thats worth it as it only comes up twice.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh strange. Well if it doesn't work don't worry about it then.