Auto merge of #107989 - matthiaskrgr:rollup-jklrd5g, r=matthiaskrgr

Rollup of 6 pull requests

Successful merges:

 - #107340 (rustdoc: merge doctest tooltip with notable traits tooltip)
 - #107838 (Introduce `-Zterminal-urls` to use OSC8 for error codes)
 - #107922 (Print disk usage in PGO CI script)
 - #107931 (Intern span when length is MAX_LEN with parent.)
 - #107935 (rustc_ast: Merge impls and reorder methods for attributes and meta items)
 - #107986 (layout: deal with placeholders, ICE on bound types)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-02-13 13:37:22 +00:00
commit 0b439b119b
33 changed files with 713 additions and 651 deletions

View File

@ -40,310 +40,6 @@ impl MarkedAttrs {
}
}
impl NestedMetaItem {
/// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
pub fn meta_item(&self) -> Option<&MetaItem> {
match self {
NestedMetaItem::MetaItem(item) => Some(item),
_ => None,
}
}
/// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s.
pub fn lit(&self) -> Option<&MetaItemLit> {
match self {
NestedMetaItem::Lit(lit) => Some(lit),
_ => None,
}
}
/// Returns `true` if this list item is a MetaItem with a name of `name`.
pub fn has_name(&self, name: Symbol) -> bool {
self.meta_item().map_or(false, |meta_item| meta_item.has_name(name))
}
/// For a single-segment meta item, returns its name; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> {
self.meta_item().and_then(|meta_item| meta_item.ident())
}
pub fn name_or_empty(&self) -> Symbol {
self.ident().unwrap_or_else(Ident::empty).name
}
/// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
/// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
pub fn value_str(&self) -> Option<Symbol> {
self.meta_item().and_then(|meta_item| meta_item.value_str())
}
/// Returns a name and single literal value tuple of the `MetaItem`.
pub fn name_value_literal(&self) -> Option<(Symbol, &MetaItemLit)> {
self.meta_item().and_then(|meta_item| {
meta_item.meta_item_list().and_then(|meta_item_list| {
if meta_item_list.len() == 1
&& let Some(ident) = meta_item.ident()
&& let Some(lit) = meta_item_list[0].lit()
{
return Some((ident.name, lit));
}
None
})
})
}
/// Gets a list of inner meta items from a list `MetaItem` type.
pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
}
/// Returns `true` if the variant is `MetaItem`.
pub fn is_meta_item(&self) -> bool {
self.meta_item().is_some()
}
/// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
pub fn is_word(&self) -> bool {
self.meta_item().map_or(false, |meta_item| meta_item.is_word())
}
/// See [`MetaItem::name_value_literal_span`].
pub fn name_value_literal_span(&self) -> Option<Span> {
self.meta_item()?.name_value_literal_span()
}
}
impl Attribute {
#[inline]
pub fn has_name(&self, name: Symbol) -> bool {
match &self.kind {
AttrKind::Normal(normal) => normal.item.path == name,
AttrKind::DocComment(..) => false,
}
}
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> {
match &self.kind {
AttrKind::Normal(normal) => {
if let [ident] = &*normal.item.path.segments {
Some(ident.ident)
} else {
None
}
}
AttrKind::DocComment(..) => None,
}
}
pub fn name_or_empty(&self) -> Symbol {
self.ident().unwrap_or_else(Ident::empty).name
}
pub fn value_str(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.value_str(),
AttrKind::DocComment(..) => None,
}
}
pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.meta_item_list(),
AttrKind::DocComment(..) => None,
}
}
pub fn is_word(&self) -> bool {
if let AttrKind::Normal(normal) = &self.kind {
matches!(normal.item.args, AttrArgs::Empty)
} else {
false
}
}
}
impl MetaItem {
/// For a single-segment meta item, returns its name; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> {
if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
}
pub fn name_or_empty(&self) -> Symbol {
self.ident().unwrap_or_else(Ident::empty).name
}
/// ```text
/// Example:
/// #[attribute(name = "value")]
/// ^^^^^^^^^^^^^^
/// ```
pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
match &self.kind {
MetaItemKind::NameValue(v) => Some(v),
_ => None,
}
}
pub fn value_str(&self) -> Option<Symbol> {
self.kind.value_str()
}
pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
match &self.kind {
MetaItemKind::List(l) => Some(&**l),
_ => None,
}
}
pub fn is_word(&self) -> bool {
matches!(self.kind, MetaItemKind::Word)
}
pub fn has_name(&self, name: Symbol) -> bool {
self.path == name
}
/// This is used in case you want the value span instead of the whole attribute. Example:
///
/// ```text
/// #[doc(alias = "foo")]
/// ```
///
/// In here, it'll return a span for `"foo"`.
pub fn name_value_literal_span(&self) -> Option<Span> {
Some(self.name_value_literal()?.span)
}
}
impl AttrArgsEq {
fn value_str(&self) -> Option<Symbol> {
match self {
AttrArgsEq::Ast(expr) => match expr.kind {
ExprKind::Lit(token_lit) => {
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
}
_ => None,
},
AttrArgsEq::Hir(lit) => lit.kind.str(),
}
}
}
impl AttrItem {
pub fn span(&self) -> Span {
self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
}
pub fn meta(&self, span: Span) -> Option<MetaItem> {
Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span })
}
pub fn meta_kind(&self) -> Option<MetaItemKind> {
MetaItemKind::from_attr_args(&self.args)
}
fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
match &self.args {
AttrArgs::Delimited(args) if args.delim == MacDelimiter::Parenthesis => {
MetaItemKind::list_from_tokens(args.tokens.clone())
}
AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None,
}
}
fn value_str(&self) -> Option<Symbol> {
match &self.args {
AttrArgs::Eq(_, args) => args.value_str(),
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
}
}
}
impl Attribute {
/// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
/// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not
/// a doc comment) will return `false`.
pub fn is_doc_comment(&self) -> bool {
match self.kind {
AttrKind::Normal(..) => false,
AttrKind::DocComment(..) => true,
}
}
/// Returns the documentation and its kind if this is a doc comment or a sugared doc comment.
/// * `///doc` returns `Some(("doc", CommentKind::Line))`.
/// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
/// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
/// * `#[doc(...)]` returns `None`.
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
match &self.kind {
AttrKind::DocComment(kind, data) => Some((*data, *kind)),
AttrKind::Normal(normal) if normal.item.path == sym::doc => {
normal.item.value_str().map(|s| (s, CommentKind::Line))
}
_ => None,
}
}
/// Returns the documentation if this is a doc comment or a sugared doc comment.
/// * `///doc` returns `Some("doc")`.
/// * `#[doc = "doc"]` returns `Some("doc")`.
/// * `#[doc(...)]` returns `None`.
pub fn doc_str(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::DocComment(.., data) => Some(*data),
AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(),
_ => None,
}
}
pub fn may_have_doc_links(&self) -> bool {
self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
}
pub fn get_normal_item(&self) -> &AttrItem {
match &self.kind {
AttrKind::Normal(normal) => &normal.item,
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
pub fn unwrap_normal_item(self) -> AttrItem {
match self.kind {
AttrKind::Normal(normal) => normal.into_inner().item,
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
/// Extracts the MetaItem from inside this Attribute.
pub fn meta(&self) -> Option<MetaItem> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.meta(self.span),
AttrKind::DocComment(..) => None,
}
}
pub fn meta_kind(&self) -> Option<MetaItemKind> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.meta_kind(),
AttrKind::DocComment(..) => None,
}
}
pub fn tokens(&self) -> TokenStream {
match &self.kind {
AttrKind::Normal(normal) => normal
.tokens
.as_ref()
.unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
.to_attr_token_stream()
.to_tokenstream(),
&AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token(
Token::new(token::DocComment(comment_kind, self.style, data), self.span),
Spacing::Alone,
)]),
}
}
}
pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>);
#[cfg(debug_assertions)]
@ -381,93 +77,236 @@ impl AttrIdGenerator {
}
}
pub fn mk_attr(
g: &AttrIdGenerator,
style: AttrStyle,
path: Path,
args: AttrArgs,
span: Span,
) -> Attribute {
mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span)
}
impl Attribute {
pub fn get_normal_item(&self) -> &AttrItem {
match &self.kind {
AttrKind::Normal(normal) => &normal.item,
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
pub fn mk_attr_from_item(
g: &AttrIdGenerator,
item: AttrItem,
tokens: Option<LazyAttrTokenStream>,
style: AttrStyle,
span: Span,
) -> Attribute {
Attribute {
kind: AttrKind::Normal(P(NormalAttr { item, tokens })),
id: g.mk_attr_id(),
style,
span,
pub fn unwrap_normal_item(self) -> AttrItem {
match self.kind {
AttrKind::Normal(normal) => normal.into_inner().item,
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
/// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
/// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not
/// a doc comment) will return `false`.
pub fn is_doc_comment(&self) -> bool {
match self.kind {
AttrKind::Normal(..) => false,
AttrKind::DocComment(..) => true,
}
}
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> {
match &self.kind {
AttrKind::Normal(normal) => {
if let [ident] = &*normal.item.path.segments {
Some(ident.ident)
} else {
None
}
}
AttrKind::DocComment(..) => None,
}
}
pub fn name_or_empty(&self) -> Symbol {
self.ident().unwrap_or_else(Ident::empty).name
}
#[inline]
pub fn has_name(&self, name: Symbol) -> bool {
match &self.kind {
AttrKind::Normal(normal) => normal.item.path == name,
AttrKind::DocComment(..) => false,
}
}
pub fn is_word(&self) -> bool {
if let AttrKind::Normal(normal) = &self.kind {
matches!(normal.item.args, AttrArgs::Empty)
} else {
false
}
}
pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.meta_item_list(),
AttrKind::DocComment(..) => None,
}
}
pub fn value_str(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.value_str(),
AttrKind::DocComment(..) => None,
}
}
/// Returns the documentation and its kind if this is a doc comment or a sugared doc comment.
/// * `///doc` returns `Some(("doc", CommentKind::Line))`.
/// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
/// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
/// * `#[doc(...)]` returns `None`.
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
match &self.kind {
AttrKind::DocComment(kind, data) => Some((*data, *kind)),
AttrKind::Normal(normal) if normal.item.path == sym::doc => {
normal.item.value_str().map(|s| (s, CommentKind::Line))
}
_ => None,
}
}
/// Returns the documentation if this is a doc comment or a sugared doc comment.
/// * `///doc` returns `Some("doc")`.
/// * `#[doc = "doc"]` returns `Some("doc")`.
/// * `#[doc(...)]` returns `None`.
pub fn doc_str(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::DocComment(.., data) => Some(*data),
AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(),
_ => None,
}
}
pub fn may_have_doc_links(&self) -> bool {
self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
}
/// Extracts the MetaItem from inside this Attribute.
pub fn meta(&self) -> Option<MetaItem> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.meta(self.span),
AttrKind::DocComment(..) => None,
}
}
pub fn meta_kind(&self) -> Option<MetaItemKind> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.meta_kind(),
AttrKind::DocComment(..) => None,
}
}
pub fn tokens(&self) -> TokenStream {
match &self.kind {
AttrKind::Normal(normal) => normal
.tokens
.as_ref()
.unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
.to_attr_token_stream()
.to_tokenstream(),
&AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token(
Token::new(token::DocComment(comment_kind, self.style, data), self.span),
Spacing::Alone,
)]),
}
}
}
pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
let path = Path::from_ident(Ident::new(name, span));
let args = AttrArgs::Empty;
mk_attr(g, style, path, args, span)
impl AttrItem {
pub fn span(&self) -> Span {
self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
}
fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
match &self.args {
AttrArgs::Delimited(args) if args.delim == MacDelimiter::Parenthesis => {
MetaItemKind::list_from_tokens(args.tokens.clone())
}
AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None,
}
}
fn value_str(&self) -> Option<Symbol> {
match &self.args {
AttrArgs::Eq(_, args) => args.value_str(),
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
}
}
pub fn meta(&self, span: Span) -> Option<MetaItem> {
Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span })
}
pub fn meta_kind(&self) -> Option<MetaItemKind> {
MetaItemKind::from_attr_args(&self.args)
}
}
pub fn mk_attr_name_value_str(
g: &AttrIdGenerator,
style: AttrStyle,
name: Symbol,
val: Symbol,
span: Span,
) -> Attribute {
let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
let expr = P(Expr {
id: DUMMY_NODE_ID,
kind: ExprKind::Lit(lit),
span,
attrs: AttrVec::new(),
tokens: None,
});
let path = Path::from_ident(Ident::new(name, span));
let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr));
mk_attr(g, style, path, args, span)
}
pub fn mk_attr_nested_word(
g: &AttrIdGenerator,
style: AttrStyle,
outer: Symbol,
inner: Symbol,
span: Span,
) -> Attribute {
let inner_tokens = TokenStream::new(vec![TokenTree::Token(
Token::from_ast_ident(Ident::new(inner, span)),
Spacing::Alone,
)]);
let outer_ident = Ident::new(outer, span);
let path = Path::from_ident(outer_ident);
let attr_args = AttrArgs::Delimited(DelimArgs {
dspan: DelimSpan::from_single(span),
delim: MacDelimiter::Parenthesis,
tokens: inner_tokens,
});
mk_attr(g, style, path, attr_args, span)
}
pub fn mk_doc_comment(
g: &AttrIdGenerator,
comment_kind: CommentKind,
style: AttrStyle,
data: Symbol,
span: Span,
) -> Attribute {
Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
}
pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
items.iter().any(|item| item.has_name(name))
impl AttrArgsEq {
fn value_str(&self) -> Option<Symbol> {
match self {
AttrArgsEq::Ast(expr) => match expr.kind {
ExprKind::Lit(token_lit) => {
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
}
_ => None,
},
AttrArgsEq::Hir(lit) => lit.kind.str(),
}
}
}
impl MetaItem {
/// For a single-segment meta item, returns its name; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> {
if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
}
pub fn name_or_empty(&self) -> Symbol {
self.ident().unwrap_or_else(Ident::empty).name
}
pub fn has_name(&self, name: Symbol) -> bool {
self.path == name
}
pub fn is_word(&self) -> bool {
matches!(self.kind, MetaItemKind::Word)
}
pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
match &self.kind {
MetaItemKind::List(l) => Some(&**l),
_ => None,
}
}
/// ```text
/// Example:
/// #[attribute(name = "value")]
/// ^^^^^^^^^^^^^^
/// ```
pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
match &self.kind {
MetaItemKind::NameValue(v) => Some(v),
_ => None,
}
}
/// This is used in case you want the value span instead of the whole attribute. Example:
///
/// ```text
/// #[doc(alias = "foo")]
/// ```
///
/// In here, it'll return a span for `"foo"`.
pub fn name_value_literal_span(&self) -> Option<Span> {
Some(self.name_value_literal()?.span)
}
pub fn value_str(&self) -> Option<Symbol> {
self.kind.value_str()
}
fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
where
I: Iterator<Item = TokenTree>,
@ -564,6 +403,24 @@ impl MetaItemKind {
}
}
fn from_tokens(
tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
) -> Option<MetaItemKind> {
match tokens.peek() {
Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => {
let inner_tokens = inner_tokens.clone();
tokens.next();
MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
}
Some(TokenTree::Delimited(..)) => None,
Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
tokens.next();
MetaItemKind::name_value_from_tokens(tokens)
}
_ => Some(MetaItemKind::Word),
}
}
fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
match args {
AttrArgs::Empty => Some(MetaItemKind::Word),
@ -585,24 +442,6 @@ impl MetaItemKind {
AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())),
}
}
fn from_tokens(
tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
) -> Option<MetaItemKind> {
match tokens.peek() {
Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => {
let inner_tokens = inner_tokens.clone();
tokens.next();
MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
}
Some(TokenTree::Delimited(..)) => None,
Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
tokens.next();
MetaItemKind::name_value_from_tokens(tokens)
}
_ => Some(MetaItemKind::Word),
}
}
}
impl NestedMetaItem {
@ -613,6 +452,77 @@ impl NestedMetaItem {
}
}
/// For a single-segment meta item, returns its name; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> {
self.meta_item().and_then(|meta_item| meta_item.ident())
}
pub fn name_or_empty(&self) -> Symbol {
self.ident().unwrap_or_else(Ident::empty).name
}
/// Returns `true` if this list item is a MetaItem with a name of `name`.
pub fn has_name(&self, name: Symbol) -> bool {
self.meta_item().map_or(false, |meta_item| meta_item.has_name(name))
}
/// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
pub fn is_word(&self) -> bool {
self.meta_item().map_or(false, |meta_item| meta_item.is_word())
}
/// Gets a list of inner meta items from a list `MetaItem` type.
pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
}
/// Returns a name and single literal value tuple of the `MetaItem`.
pub fn name_value_literal(&self) -> Option<(Symbol, &MetaItemLit)> {
self.meta_item().and_then(|meta_item| {
meta_item.meta_item_list().and_then(|meta_item_list| {
if meta_item_list.len() == 1
&& let Some(ident) = meta_item.ident()
&& let Some(lit) = meta_item_list[0].lit()
{
return Some((ident.name, lit));
}
None
})
})
}
/// See [`MetaItem::name_value_literal_span`].
pub fn name_value_literal_span(&self) -> Option<Span> {
self.meta_item()?.name_value_literal_span()
}
/// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
/// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
pub fn value_str(&self) -> Option<Symbol> {
self.meta_item().and_then(|meta_item| meta_item.value_str())
}
/// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s.
pub fn lit(&self) -> Option<&MetaItemLit> {
match self {
NestedMetaItem::Lit(lit) => Some(lit),
_ => None,
}
}
/// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
pub fn meta_item(&self) -> Option<&MetaItem> {
match self {
NestedMetaItem::MetaItem(item) => Some(item),
_ => None,
}
}
/// Returns `true` if the variant is `MetaItem`.
pub fn is_meta_item(&self) -> bool {
self.meta_item().is_some()
}
fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
where
I: Iterator<Item = TokenTree>,
@ -634,3 +544,89 @@ impl NestedMetaItem {
MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
}
}
pub fn mk_doc_comment(
g: &AttrIdGenerator,
comment_kind: CommentKind,
style: AttrStyle,
data: Symbol,
span: Span,
) -> Attribute {
Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
}
pub fn mk_attr(
g: &AttrIdGenerator,
style: AttrStyle,
path: Path,
args: AttrArgs,
span: Span,
) -> Attribute {
mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span)
}
pub fn mk_attr_from_item(
g: &AttrIdGenerator,
item: AttrItem,
tokens: Option<LazyAttrTokenStream>,
style: AttrStyle,
span: Span,
) -> Attribute {
Attribute {
kind: AttrKind::Normal(P(NormalAttr { item, tokens })),
id: g.mk_attr_id(),
style,
span,
}
}
pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
let path = Path::from_ident(Ident::new(name, span));
let args = AttrArgs::Empty;
mk_attr(g, style, path, args, span)
}
pub fn mk_attr_nested_word(
g: &AttrIdGenerator,
style: AttrStyle,
outer: Symbol,
inner: Symbol,
span: Span,
) -> Attribute {
let inner_tokens = TokenStream::new(vec![TokenTree::Token(
Token::from_ast_ident(Ident::new(inner, span)),
Spacing::Alone,
)]);
let outer_ident = Ident::new(outer, span);
let path = Path::from_ident(outer_ident);
let attr_args = AttrArgs::Delimited(DelimArgs {
dspan: DelimSpan::from_single(span),
delim: MacDelimiter::Parenthesis,
tokens: inner_tokens,
});
mk_attr(g, style, path, attr_args, span)
}
pub fn mk_attr_name_value_str(
g: &AttrIdGenerator,
style: AttrStyle,
name: Symbol,
val: Symbol,
span: Span,
) -> Attribute {
let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
let expr = P(Expr {
id: DUMMY_NODE_ID,
kind: ExprKind::Lit(lit),
span,
attrs: AttrVec::new(),
tokens: None,
});
let path = Path::from_ident(Ident::new(name, span));
let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr));
mk_attr(g, style, path, args, span)
}
pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
items.iter().any(|item| item.has_name(name))
}

View File

@ -23,7 +23,7 @@ use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
use rustc_data_structures::sync::SeqCst;
use rustc_errors::registry::{InvalidErrorCode, Registry};
use rustc_errors::{ErrorGuaranteed, PResult};
use rustc_errors::{ErrorGuaranteed, PResult, TerminalUrl};
use rustc_feature::find_gated_cfg;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
@ -1191,6 +1191,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
None,
false,
false,
TerminalUrl::No,
));
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);

View File

@ -18,7 +18,7 @@ use crate::translation::{to_fluent_args, Translate};
use crate::{
diagnostic::DiagnosticLocation, CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage,
FluentBundle, Handler, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic,
SubstitutionHighlight, SuggestionStyle,
SubstitutionHighlight, SuggestionStyle, TerminalUrl,
};
use rustc_lint_defs::pluralize;
@ -66,6 +66,7 @@ impl HumanReadableErrorType {
diagnostic_width: Option<usize>,
macro_backtrace: bool,
track_diagnostics: bool,
terminal_url: TerminalUrl,
) -> EmitterWriter {
let (short, color_config) = self.unzip();
let color = color_config.suggests_using_colors();
@ -80,6 +81,7 @@ impl HumanReadableErrorType {
diagnostic_width,
macro_backtrace,
track_diagnostics,
terminal_url,
)
}
}
@ -652,6 +654,7 @@ pub struct EmitterWriter {
macro_backtrace: bool,
track_diagnostics: bool,
terminal_url: TerminalUrl,
}
#[derive(Debug)]
@ -672,6 +675,7 @@ impl EmitterWriter {
diagnostic_width: Option<usize>,
macro_backtrace: bool,
track_diagnostics: bool,
terminal_url: TerminalUrl,
) -> EmitterWriter {
let dst = Destination::from_stderr(color_config);
EmitterWriter {
@ -685,6 +689,7 @@ impl EmitterWriter {
diagnostic_width,
macro_backtrace,
track_diagnostics,
terminal_url,
}
}
@ -699,6 +704,7 @@ impl EmitterWriter {
diagnostic_width: Option<usize>,
macro_backtrace: bool,
track_diagnostics: bool,
terminal_url: TerminalUrl,
) -> EmitterWriter {
EmitterWriter {
dst: Raw(dst, colored),
@ -711,6 +717,7 @@ impl EmitterWriter {
diagnostic_width,
macro_backtrace,
track_diagnostics,
terminal_url,
}
}
@ -1378,7 +1385,13 @@ impl EmitterWriter {
// only render error codes, not lint codes
if let Some(DiagnosticId::Error(ref code)) = *code {
buffer.append(0, "[", Style::Level(*level));
buffer.append(0, code, Style::Level(*level));
let code = if let TerminalUrl::Yes = self.terminal_url {
let path = "https://doc.rust-lang.org/error_codes";
format!("\x1b]8;;{path}/{code}.html\x07{code}\x1b]8;;\x07")
} else {
code.clone()
};
buffer.append(0, &code, Style::Level(*level));
buffer.append(0, "]", Style::Level(*level));
label_width += 2 + code.len();
}

View File

@ -17,6 +17,7 @@ use crate::translation::{to_fluent_args, Translate};
use crate::DiagnosticId;
use crate::{
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
TerminalUrl,
};
use rustc_lint_defs::Applicability;
@ -47,6 +48,7 @@ pub struct JsonEmitter {
diagnostic_width: Option<usize>,
macro_backtrace: bool,
track_diagnostics: bool,
terminal_url: TerminalUrl,
}
impl JsonEmitter {
@ -60,6 +62,7 @@ impl JsonEmitter {
diagnostic_width: Option<usize>,
macro_backtrace: bool,
track_diagnostics: bool,
terminal_url: TerminalUrl,
) -> JsonEmitter {
JsonEmitter {
dst: Box::new(io::BufWriter::new(io::stderr())),
@ -73,6 +76,7 @@ impl JsonEmitter {
diagnostic_width,
macro_backtrace,
track_diagnostics,
terminal_url,
}
}
@ -84,6 +88,7 @@ impl JsonEmitter {
diagnostic_width: Option<usize>,
macro_backtrace: bool,
track_diagnostics: bool,
terminal_url: TerminalUrl,
) -> JsonEmitter {
let file_path_mapping = FilePathMapping::empty();
JsonEmitter::stderr(
@ -96,6 +101,7 @@ impl JsonEmitter {
diagnostic_width,
macro_backtrace,
track_diagnostics,
terminal_url,
)
}
@ -110,6 +116,7 @@ impl JsonEmitter {
diagnostic_width: Option<usize>,
macro_backtrace: bool,
track_diagnostics: bool,
terminal_url: TerminalUrl,
) -> JsonEmitter {
JsonEmitter {
dst,
@ -123,6 +130,7 @@ impl JsonEmitter {
diagnostic_width,
macro_backtrace,
track_diagnostics,
terminal_url,
}
}
@ -360,6 +368,7 @@ impl Diagnostic {
je.diagnostic_width,
je.macro_backtrace,
je.track_diagnostics,
je.terminal_url,
)
.ui_testing(je.ui_testing)
.emit_diagnostic(diag);

View File

@ -4,7 +4,7 @@ use crate::json::JsonEmitter;
use rustc_span::source_map::{FilePathMapping, SourceMap};
use crate::emitter::{ColorConfig, HumanReadableErrorType};
use crate::Handler;
use crate::{Handler, TerminalUrl};
use rustc_span::{BytePos, Span};
use std::str;
@ -60,6 +60,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
None,
false,
false,
TerminalUrl::No,
);
let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1));

View File

@ -573,6 +573,7 @@ impl Handler {
None,
flags.macro_backtrace,
flags.track_diagnostics,
TerminalUrl::No,
));
Self::with_emitter_and_flags(emitter, flags)
}
@ -1838,6 +1839,13 @@ pub fn add_elided_lifetime_in_path_suggestion(
);
}
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum TerminalUrl {
No,
Yes,
Auto,
}
/// Useful type to use with `Result<>` indicate that an error has already
/// been reported to the user, so no need to continue checking.
#[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq, PartialOrd, Ord)]

View File

@ -8,7 +8,7 @@ use rustc_span::{BytePos, Span};
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
use rustc_errors::{Handler, MultiSpan, PResult};
use rustc_errors::{Handler, MultiSpan, PResult, TerminalUrl};
use std::io;
use std::io::prelude::*;
@ -152,6 +152,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
None,
false,
false,
TerminalUrl::No,
);
let handler = Handler::with_emitter(true, None, Box::new(emitter));
#[allow(rustc::untranslatable_diagnostic)]

View File

@ -4,7 +4,7 @@ use crate::early_error;
use crate::lint;
use crate::search_paths::SearchPath;
use crate::utils::NativeLib;
use rustc_errors::LanguageIdentifier;
use rustc_errors::{LanguageIdentifier, TerminalUrl};
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
use rustc_target::spec::{
RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
@ -402,6 +402,8 @@ mod desc {
pub const parse_code_model: &str = "one of supported code models (`rustc --print code-models`)";
pub const parse_tls_model: &str = "one of supported TLS models (`rustc --print tls-models`)";
pub const parse_target_feature: &str = parse_string;
pub const parse_terminal_url: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), or `auto`";
pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
pub const parse_split_debuginfo: &str =
"one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
@ -1044,6 +1046,16 @@ mod parse {
true
}
pub(crate) fn parse_terminal_url(slot: &mut TerminalUrl, v: Option<&str>) -> bool {
*slot = match v {
Some("on" | "" | "yes" | "y") | None => TerminalUrl::Yes,
Some("off" | "no" | "n") => TerminalUrl::No,
Some("auto") => TerminalUrl::Auto,
_ => return false,
};
true
}
pub(crate) fn parse_symbol_mangling_version(
slot: &mut Option<SymbolManglingVersion>,
v: Option<&str>,
@ -1675,6 +1687,8 @@ options! {
"show extended diagnostic help (default: no)"),
temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
"the directory the intermediate files are written to"),
terminal_urls: TerminalUrl = (TerminalUrl::No, parse_terminal_url, [UNTRACKED],
"use the OSC 8 hyperlink terminal specification to print hyperlinks in the compiler output"),
#[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
"enable ThinLTO when possible"),

View File

@ -24,6 +24,7 @@ use rustc_errors::registry::Registry;
use rustc_errors::{
error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
TerminalUrl,
};
use rustc_macros::HashStable_Generic;
pub use rustc_span::def_id::StableCrateId;
@ -1273,6 +1274,19 @@ fn default_emitter(
) -> Box<dyn Emitter + sync::Send> {
let macro_backtrace = sopts.unstable_opts.macro_backtrace;
let track_diagnostics = sopts.unstable_opts.track_diagnostics;
let terminal_url = match sopts.unstable_opts.terminal_urls {
TerminalUrl::Auto => {
match (std::env::var("COLORTERM").as_deref(), std::env::var("TERM").as_deref()) {
(Ok("truecolor"), Ok("xterm-256color"))
if sopts.unstable_features.is_nightly_build() =>
{
TerminalUrl::Yes
}
_ => TerminalUrl::No,
}
}
t => t,
};
match sopts.error_format {
config::ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip();
@ -1297,6 +1311,7 @@ fn default_emitter(
sopts.diagnostic_width,
macro_backtrace,
track_diagnostics,
terminal_url,
);
Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
}
@ -1312,6 +1327,7 @@ fn default_emitter(
sopts.diagnostic_width,
macro_backtrace,
track_diagnostics,
terminal_url,
)
.ui_testing(sopts.unstable_opts.ui_testing),
),
@ -1628,6 +1644,7 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler
None,
false,
false,
TerminalUrl::No,
))
}
config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(
@ -1638,6 +1655,7 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler
None,
false,
false,
TerminalUrl::No,
)),
};
rustc_errors::Handler::with_emitter(true, None, emitter)

View File

@ -110,11 +110,16 @@ impl Span {
// Inline format with parent.
let len_or_tag = len_or_tag | PARENT_MASK;
let parent2 = parent.local_def_index.as_u32();
if ctxt2 == SyntaxContext::root().as_u32() && parent2 <= MAX_CTXT {
if ctxt2 == SyntaxContext::root().as_u32()
&& parent2 <= MAX_CTXT
&& len_or_tag < LEN_TAG
{
debug_assert_ne!(len_or_tag, LEN_TAG);
return Span { base_or_index: base, len_or_tag, ctxt_or_tag: parent2 as u16 };
}
} else {
// Inline format with ctxt.
debug_assert_ne!(len_or_tag, LEN_TAG);
return Span {
base_or_index: base,
len_or_tag: len as u16,

View File

@ -470,14 +470,11 @@ fn layout_of_uncached<'tcx>(
return Err(LayoutError::Unknown(ty));
}
ty::Placeholder(..)
| ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..)
| ty::Infer(_) => {
ty::Bound(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) | ty::Infer(_) => {
bug!("Layout::compute: unexpected type `{}`", ty)
}
ty::Bound(..) | ty::Param(_) | ty::Error(_) => {
ty::Placeholder(..) | ty::Param(_) | ty::Error(_) => {
return Err(LayoutError::Unknown(ty));
}
})

View File

@ -211,7 +211,8 @@ Duration = float
TimerSection = Union[Duration, "Timer"]
def iterate_sections(section: TimerSection, name: str, level: int = 0) -> Iterator[Tuple[int, str, Duration]]:
def iterate_sections(section: TimerSection, name: str, level: int = 0) -> Iterator[
Tuple[int, str, Duration]]:
"""
Hierarchically iterate the sections of a timer, in a depth-first order.
"""
@ -239,7 +240,7 @@ class Timer:
start = get_timestamp()
exc = None
child_timer = Timer(parent_names=self.parent_names + (name, ))
child_timer = Timer(parent_names=self.parent_names + (name,))
full_name = " > ".join(child_timer.parent_names)
try:
LOGGER.info(f"Section `{full_name}` starts")
@ -648,6 +649,16 @@ def print_binary_sizes(pipeline: Pipeline):
LOGGER.info(f"Rustc binary size\n{output.getvalue()}")
def print_free_disk_space(pipeline: Pipeline):
usage = shutil.disk_usage(pipeline.opt_artifacts())
total = usage.total
used = usage.used
free = usage.free
logging.info(
f"Free disk space: {format_bytes(free)} out of total {format_bytes(total)} ({(used / total) * 100:.2f}% used)")
def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: List[str]):
# Clear and prepare tmp directory
shutil.rmtree(pipeline.opt_artifacts(), ignore_errors=True)
@ -666,6 +677,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L
with stage1.section("Gather profiles"):
gather_llvm_profiles(pipeline)
print_free_disk_space(pipeline)
clear_llvm_files(pipeline)
final_build_args += [
@ -683,6 +695,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L
with stage2.section("Gather profiles"):
gather_rustc_profiles(pipeline)
print_free_disk_space(pipeline)
clear_llvm_files(pipeline)
final_build_args += [
@ -702,6 +715,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L
with stage3.section("Gather profiles"):
gather_llvm_bolt_profiles(pipeline)
print_free_disk_space(pipeline)
clear_llvm_files(pipeline)
final_build_args += [
"--llvm-bolt-profile-use",
@ -733,5 +747,6 @@ if __name__ == "__main__":
raise e
finally:
timer.print_stats()
print_free_disk_space(pipeline)
print_binary_sizes(pipeline)

View File

@ -4,6 +4,7 @@ use rustc_data_structures::sync::{self, Lrc};
use rustc_data_structures::unord::UnordSet;
use rustc_errors::emitter::{Emitter, EmitterWriter};
use rustc_errors::json::JsonEmitter;
use rustc_errors::TerminalUrl;
use rustc_feature::UnstableFeatures;
use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
@ -144,6 +145,7 @@ pub(crate) fn new_handler(
diagnostic_width,
false,
unstable_opts.track_diagnostics,
TerminalUrl::No,
)
.ui_testing(unstable_opts.ui_testing),
)
@ -163,6 +165,7 @@ pub(crate) fn new_handler(
diagnostic_width,
false,
unstable_opts.track_diagnostics,
TerminalUrl::No,
)
.ui_testing(unstable_opts.ui_testing),
)

View File

@ -1,7 +1,7 @@
use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError};
use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError, TerminalUrl};
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{self as hir, intravisit, CRATE_HIR_ID};
use rustc_interface::interface;
@ -557,6 +557,7 @@ pub(crate) fn make_test(
Some(80),
false,
false,
TerminalUrl::No,
)
.supports_color();
@ -571,6 +572,7 @@ pub(crate) fn make_test(
None,
false,
false,
TerminalUrl::No,
);
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
@ -756,6 +758,7 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
None,
false,
false,
TerminalUrl::No,
);
let handler = Handler::with_emitter(false, None, Box::new(emitter));

View File

@ -96,13 +96,19 @@ fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, to
);
if tooltip != Tooltip::None {
let edition_code;
write!(
out,
"<div class='tooltip'{}>ⓘ</div>",
if let Tooltip::Edition(edition_info) = tooltip {
format!(" data-edition=\"{}\"", edition_info)
} else {
String::new()
"<a href=\"#\" class=\"tooltip\" title=\"{}\">ⓘ</a>",
match tooltip {
Tooltip::Ignore => "This example is not tested",
Tooltip::CompileFail => "This example deliberately fails to compile",
Tooltip::ShouldPanic => "This example panics",
Tooltip::Edition(edition) => {
edition_code = format!("This example runs with edition {edition}");
&edition_code
}
Tooltip::None => unreachable!(),
},
);
}

View File

@ -1310,7 +1310,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O
if has_notable_trait {
cx.types_with_notable_traits.insert(ty.clone());
Some(format!(
" <a href=\"#\" class=\"notable-traits\" data-ty=\"{ty}\">ⓘ</a>",
" <a href=\"#\" class=\"tooltip\" data-notable-ty=\"{ty}\">ⓘ</a>",
ty = Escape(&format!("{:#}", ty.print(cx))),
))
} else {

View File

@ -715,8 +715,8 @@ h2.small-section-header > .anchor {
.main-heading a:hover,
.example-wrap > pre.rust a:hover,
.all-items a:hover,
.docblock a:not(.test-arrow):not(.scrape-help):hover,
.docblock-short a:not(.test-arrow):not(.scrape-help):hover,
.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,
.docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,
.item-info a {
text-decoration: underline;
}
@ -1109,44 +1109,8 @@ pre.rust .doccomment {
display: block;
left: -25px;
top: 5px;
}
.example-wrap .tooltip:hover::after {
padding: 5px 3px 3px 3px;
border-radius: 6px;
margin-left: 5px;
font-size: 1rem;
border: 1px solid var(--border-color);
position: absolute;
width: max-content;
top: -2px;
z-index: 1;
background-color: var(--tooltip-background-color);
color: var(--tooltip-color);
}
.example-wrap .tooltip:hover::before {
content: " ";
position: absolute;
top: 50%;
left: 16px;
margin-top: -5px;
z-index: 1;
border: 5px solid transparent;
border-right-color: var(--tooltip-background-color);
}
.example-wrap.ignore .tooltip:hover::after {
content: "This example is not tested";
}
.example-wrap.compile_fail .tooltip:hover::after {
content: "This example deliberately fails to compile";
}
.example-wrap.should_panic .tooltip:hover::after {
content: "This example panics";
}
.example-wrap.edition .tooltip:hover::after {
content: "This code runs with edition " attr(data-edition);
margin: 0;
line-height: 1;
}
.example-wrap.compile_fail .tooltip,
@ -1213,7 +1177,7 @@ a.test-arrow:hover {
border-right: 3px solid var(--target-border-color);
}
.notable-traits {
.code-header a.tooltip {
color: inherit;
margin-right: 15px;
position: relative;
@ -1222,7 +1186,7 @@ a.test-arrow:hover {
/* placeholder thunk so that the mouse can easily travel from "(i)" to popover
the resulting "hover tunnel" is a stepped triangle, approximating
https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown */
.notable-traits:hover::after {
a.tooltip:hover::after {
position: absolute;
top: calc(100% - 10px);
left: -15px;
@ -1231,11 +1195,11 @@ a.test-arrow:hover {
content: "\00a0";
}
.notable .content {
.popover.tooltip .content {
margin: 0.25em 0.5em;
}
.notable .content pre, .notable .content code {
.popover.tooltip .content pre, .popover.tooltip .content code {
background: transparent;
margin: 0;
padding: 0;
@ -1243,7 +1207,7 @@ a.test-arrow:hover {
white-space: pre-wrap;
}
.notable .content > h3:first-child {
.popover.tooltip .content > h3:first-child {
margin: 0 0 5px 0;
}

View File

@ -74,8 +74,6 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
--target-background-color: rgba(255, 236, 164, 0.06);
--target-border-color: rgba(255, 180, 76, 0.85);
--tooltip-background-color: #314559;
--tooltip-color: #c5c5c5;
--kbd-color: #c5c5c5;
--kbd-background: #314559;
--kbd-box-shadow-color: #5c6773;

View File

@ -69,8 +69,6 @@
--test-arrow-hover-background-color: #4e8bca;
--target-background-color: #494a3d;
--target-border-color: #bb7410;
--tooltip-background-color: #000;
--tooltip-color: #fff;
--kbd-color: #000;
--kbd-background: #fafbfc;
--kbd-box-shadow-color: #c6cbd1;

View File

@ -69,8 +69,6 @@
--test-arrow-hover-background-color: #4e8bca;
--target-background-color: #fdffd3;
--target-border-color: #ad7c37;
--tooltip-background-color: #000;
--tooltip-color: #fff;
--kbd-color: #000;
--kbd-background: #fafbfc;
--kbd-box-shadow-color: #c6cbd1;

View File

@ -378,7 +378,7 @@ function loadCss(cssUrl) {
}
ev.preventDefault();
searchState.defocus();
window.hideAllModals(true); // true = reset focus for notable traits
window.hideAllModals(true); // true = reset focus for tooltips
}
function handleShortcut(ev) {
@ -784,17 +784,17 @@ function loadCss(cssUrl) {
// we need to switch away from mobile mode and make the main content area scrollable.
hideSidebar();
}
if (window.CURRENT_NOTABLE_ELEMENT) {
// As a workaround to the behavior of `contains: layout` used in doc togglers, the
// notable traits popup is positioned using javascript.
if (window.CURRENT_TOOLTIP_ELEMENT) {
// As a workaround to the behavior of `contains: layout` used in doc togglers,
// tooltip popovers are positioned using javascript.
//
// This means when the window is resized, we need to redo the layout.
const base = window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE;
const force_visible = base.NOTABLE_FORCE_VISIBLE;
hideNotable(false);
const base = window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE;
const force_visible = base.TOOLTIP_FORCE_VISIBLE;
hideTooltip(false);
if (force_visible) {
showNotable(base);
base.NOTABLE_FORCE_VISIBLE = true;
showTooltip(base);
base.TOOLTIP_FORCE_VISIBLE = true;
}
}
});
@ -822,27 +822,35 @@ function loadCss(cssUrl) {
});
});
function showNotable(e) {
if (!window.NOTABLE_TRAITS) {
function showTooltip(e) {
const notable_ty = e.getAttribute("data-notable-ty");
if (!window.NOTABLE_TRAITS && notable_ty) {
const data = document.getElementById("notable-traits-data");
if (data) {
window.NOTABLE_TRAITS = JSON.parse(data.innerText);
} else {
throw new Error("showNotable() called on page without any notable traits!");
throw new Error("showTooltip() called with notable without any notable traits!");
}
}
if (window.CURRENT_NOTABLE_ELEMENT && window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE === e) {
if (window.CURRENT_TOOLTIP_ELEMENT && window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE === e) {
// Make this function idempotent.
return;
}
window.hideAllModals(false);
const ty = e.getAttribute("data-ty");
const wrapper = document.createElement("div");
wrapper.innerHTML = "<div class=\"content\">" + window.NOTABLE_TRAITS[ty] + "</div>";
wrapper.className = "notable popover";
if (notable_ty) {
wrapper.innerHTML = "<div class=\"content\">" +
window.NOTABLE_TRAITS[notable_ty] + "</div>";
} else if (e.getAttribute("title") !== undefined) {
const titleContent = document.createElement("div");
titleContent.className = "content";
titleContent.appendChild(document.createTextNode(e.getAttribute("title")));
wrapper.appendChild(titleContent);
}
wrapper.className = "tooltip popover";
const focusCatcher = document.createElement("div");
focusCatcher.setAttribute("tabindex", "0");
focusCatcher.onfocus = hideNotable;
focusCatcher.onfocus = hideTooltip;
wrapper.appendChild(focusCatcher);
const pos = e.getBoundingClientRect();
// 5px overlap so that the mouse can easily travel from place to place
@ -864,62 +872,62 @@ function loadCss(cssUrl) {
);
}
wrapper.style.visibility = "";
window.CURRENT_NOTABLE_ELEMENT = wrapper;
window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE = e;
window.CURRENT_TOOLTIP_ELEMENT = wrapper;
window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e;
wrapper.onpointerleave = function(ev) {
// If this is a synthetic touch event, ignore it. A click event will be along shortly.
if (ev.pointerType !== "mouse") {
return;
}
if (!e.NOTABLE_FORCE_VISIBLE && !elemIsInParent(event.relatedTarget, e)) {
hideNotable(true);
if (!e.TOOLTIP_FORCE_VISIBLE && !elemIsInParent(event.relatedTarget, e)) {
hideTooltip(true);
}
};
}
function notableBlurHandler(event) {
if (window.CURRENT_NOTABLE_ELEMENT &&
!elemIsInParent(document.activeElement, window.CURRENT_NOTABLE_ELEMENT) &&
!elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT) &&
!elemIsInParent(document.activeElement, window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE) &&
!elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE)
function tooltipBlurHandler(event) {
if (window.CURRENT_TOOLTIP_ELEMENT &&
!elemIsInParent(document.activeElement, window.CURRENT_TOOLTIP_ELEMENT) &&
!elemIsInParent(event.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT) &&
!elemIsInParent(document.activeElement, window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE) &&
!elemIsInParent(event.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE)
) {
// Work around a difference in the focus behaviour between Firefox, Chrome, and Safari.
// When I click the button on an already-opened notable trait popover, Safari
// When I click the button on an already-opened tooltip popover, Safari
// hides the popover and then immediately shows it again, while everyone else hides it
// and it stays hidden.
//
// To work around this, make sure the click finishes being dispatched before
// hiding the popover. Since `hideNotable()` is idempotent, this makes Safari behave
// hiding the popover. Since `hideTooltip()` is idempotent, this makes Safari behave
// consistently with the other two.
setTimeout(() => hideNotable(false), 0);
setTimeout(() => hideTooltip(false), 0);
}
}
function hideNotable(focus) {
if (window.CURRENT_NOTABLE_ELEMENT) {
if (window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.NOTABLE_FORCE_VISIBLE) {
function hideTooltip(focus) {
if (window.CURRENT_TOOLTIP_ELEMENT) {
if (window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE) {
if (focus) {
window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.focus();
window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus();
}
window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.NOTABLE_FORCE_VISIBLE = false;
window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE = false;
}
const body = document.getElementsByTagName("body")[0];
body.removeChild(window.CURRENT_NOTABLE_ELEMENT);
window.CURRENT_NOTABLE_ELEMENT = null;
body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);
window.CURRENT_TOOLTIP_ELEMENT = null;
}
}
onEachLazy(document.getElementsByClassName("notable-traits"), e => {
onEachLazy(document.getElementsByClassName("tooltip"), e => {
e.onclick = function() {
this.NOTABLE_FORCE_VISIBLE = this.NOTABLE_FORCE_VISIBLE ? false : true;
if (window.CURRENT_NOTABLE_ELEMENT && !this.NOTABLE_FORCE_VISIBLE) {
hideNotable(true);
this.TOOLTIP_FORCE_VISIBLE = this.TOOLTIP_FORCE_VISIBLE ? false : true;
if (window.CURRENT_TOOLTIP_ELEMENT && !this.TOOLTIP_FORCE_VISIBLE) {
hideTooltip(true);
} else {
showNotable(this);
window.CURRENT_NOTABLE_ELEMENT.setAttribute("tabindex", "0");
window.CURRENT_NOTABLE_ELEMENT.focus();
window.CURRENT_NOTABLE_ELEMENT.onblur = notableBlurHandler;
showTooltip(this);
window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex", "0");
window.CURRENT_TOOLTIP_ELEMENT.focus();
window.CURRENT_TOOLTIP_ELEMENT.onblur = tooltipBlurHandler;
}
return false;
};
@ -928,16 +936,16 @@ function loadCss(cssUrl) {
if (ev.pointerType !== "mouse") {
return;
}
showNotable(this);
showTooltip(this);
};
e.onpointerleave = function(ev) {
// If this is a synthetic touch event, ignore it. A click event will be along shortly.
if (ev.pointerType !== "mouse") {
return;
}
if (!this.NOTABLE_FORCE_VISIBLE &&
!elemIsInParent(ev.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) {
hideNotable(true);
if (!this.TOOLTIP_FORCE_VISIBLE &&
!elemIsInParent(ev.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT)) {
hideTooltip(true);
}
};
});
@ -1039,14 +1047,14 @@ function loadCss(cssUrl) {
}
/**
* Hide popover menus, notable trait tooltips, and the sidebar (if applicable).
* Hide popover menus, clickable tooltips, and the sidebar (if applicable).
*
* Pass "true" to reset focus for notable traits.
* Pass "true" to reset focus for tooltip popovers.
*/
window.hideAllModals = function(switchFocus) {
hideSidebar();
window.hidePopoverMenus();
hideNotable(switchFocus);
hideTooltip(switchFocus);
};
/**

View File

@ -11,7 +11,7 @@ use rustc_ast::token::CommentKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
use rustc_errors::{Applicability, Handler, SuggestionStyle};
use rustc_errors::{Applicability, Handler, SuggestionStyle, TerminalUrl};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AnonConst, Expr};
@ -717,6 +717,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
None,
false,
false,
TerminalUrl::No,
);
let handler = Handler::with_emitter(false, None, Box::new(emitter));
let sess = ParseSess::with_span_handler(handler, sm);

View File

@ -220,6 +220,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
None,
false,
false,
rustc_errors::TerminalUrl::No,
));
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);

View File

@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
use rustc_data_structures::sync::{Lrc, Send};
use rustc_errors::emitter::{Emitter, EmitterWriter};
use rustc_errors::translation::Translate;
use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel};
use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel, TerminalUrl};
use rustc_session::parse::ParseSess as RawParseSess;
use rustc_span::{
source_map::{FilePathMapping, SourceMap},
@ -135,6 +135,7 @@ fn default_handler(
None,
false,
false,
TerminalUrl::No,
))
};
Handler::with_emitter(

View File

@ -30,24 +30,16 @@ define-function: (
".docblock .example-wrap.compile_fail",
{"border-left": "2px solid rgb(255, 0, 0)"},
)
assert-css: (
".docblock .example-wrap.compile_fail .tooltip::after",
{
"content": '"This example deliberately fails to compile"',
"padding": "5px 3px 3px",
"background-color": |background|,
"color": |color|,
"border": "1px solid " + |border|,
},
)
assert-css: (
".docblock .example-wrap.compile_fail .tooltip::before",
{
"border-width": "5px",
"border-style": "solid",
"border-color": "rgba(0, 0, 0, 0) " + |background| + " rgba(0, 0, 0, 0) rgba(0, 0, 0, 0)",
},
click: ".docblock .example-wrap.compile_fail .tooltip"
assert-text: (
".popover.tooltip",
"This example deliberately fails to compile"
)
assert-css: (".popover.tooltip", {
"color": |color|,
"background-color": |background|,
"border-color": |border|,
})
// should_panic block
assert-css: (
@ -69,24 +61,16 @@ define-function: (
".docblock .example-wrap.should_panic",
{"border-left": "2px solid rgb(255, 0, 0)"},
)
assert-css: (
".docblock .example-wrap.should_panic .tooltip::after",
{
"content": '"This example panics"',
"padding": "5px 3px 3px",
"background-color": |background|,
"color": |color|,
"border": "1px solid " + |border|,
},
)
assert-css: (
".docblock .example-wrap.should_panic .tooltip::before",
{
"border-width": "5px",
"border-style": "solid",
"border-color": "rgba(0, 0, 0, 0) " + |background| + " rgba(0, 0, 0, 0) rgba(0, 0, 0, 0)",
},
click: ".docblock .example-wrap.should_panic .tooltip"
assert-text: (
".popover.tooltip",
"This example panics"
)
assert-css: (".popover.tooltip", {
"color": |color|,
"background-color": |background|,
"border-color": |border|,
})
// ignore block
assert-css: (
@ -108,42 +92,36 @@ define-function: (
".docblock .example-wrap.ignore",
{"border-left": "2px solid rgb(255, 142, 0)"},
)
assert-css: (
".docblock .example-wrap.ignore .tooltip::after",
{
"content": '"This example is not tested"',
"padding": "5px 3px 3px",
"background-color": |background|,
"color": |color|,
"border": "1px solid " + |border|,
},
)
assert-css: (
".docblock .example-wrap.ignore .tooltip::before",
{
"border-width": "5px",
"border-style": "solid",
"border-color": "rgba(0, 0, 0, 0) " + |background| + " rgba(0, 0, 0, 0) rgba(0, 0, 0, 0)",
},
click: ".docblock .example-wrap.ignore .tooltip"
assert-text: (
".popover.tooltip",
"This example is not tested"
)
assert-css: (".popover.tooltip", {
"color": |color|,
"background-color": |background|,
"border-color": |border|,
})
click: ".docblock .example-wrap.ignore .tooltip"
assert-false: ".popover.tooltip"
},
)
call-function: ("check-colors", {
"theme": "ayu",
"background": "rgb(49, 69, 89)",
"background": "rgb(15, 20, 25)",
"color": "rgb(197, 197, 197)",
"border": "rgb(92, 103, 115)",
})
call-function: ("check-colors", {
"theme": "dark",
"background": "rgb(0, 0, 0)",
"color": "rgb(255, 255, 255)",
"background": "rgb(53, 53, 53)",
"color": "rgb(221, 221, 221)",
"border": "rgb(224, 224, 224)",
})
call-function: ("check-colors", {
"theme": "light",
"background": "rgb(0, 0, 0)",
"color": "rgb(255, 255, 255)",
"background": "rgb(255, 255, 255)",
"color": "rgb(0, 0, 0)",
"border": "rgb(224, 224, 224)",
})

View File

@ -6,13 +6,13 @@ size: (1100, 600)
// Checking they have the same y position.
compare-elements-position: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("y"),
)
// Checking they don't have the same x position.
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("x"),
)
// The `i` should be *after* the type.
@ -21,33 +21,33 @@ assert-position: (
{"x": 677},
)
assert-position: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
{"x": 955},
)
// The tooltip should be below the `i`
// Also, clicking the tooltip should bring its text into the DOM
assert-count: ("//*[@class='notable popover']", 0)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
assert-count: ("//*[@class='notable popover']", 1)
assert-count: ("//*[@class='tooltip popover']", 0)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: ("//*[@class='tooltip popover']", 1)
compare-elements-position-near: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@class='notable popover']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
"//*[@class='tooltip popover']",
{"y": 30}
)
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@class='notable popover']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
"//*[@class='tooltip popover']",
("x")
)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
move-cursor-to: "//h1"
assert-count: ("//*[@class='notable popover']", 0)
assert-count: ("//*[@class='tooltip popover']", 0)
// Now only the `i` should be on the next line.
size: (1055, 600)
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("y", "x"),
)
@ -56,13 +56,13 @@ size: (980, 600)
// Checking they have the same y position.
compare-elements-position: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("y"),
)
// Checking they don't have the same x position.
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("x"),
)
// The `i` should be *after* the type.
@ -71,7 +71,7 @@ assert-position: (
{"x": 245},
)
assert-position: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
{"x": 523},
)
@ -80,13 +80,13 @@ size: (650, 600)
// Checking they have the same y position.
compare-elements-position: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("y"),
)
// Checking they don't have the same x position.
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("x"),
)
// The `i` should be *after* the type.
@ -95,29 +95,29 @@ assert-position: (
{"x": 15},
)
assert-position: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
{"x": 293},
)
// The tooltip should STILL be below `i`
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
assert-count: ("//*[@class='notable popover']", 1)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: ("//*[@class='tooltip popover']", 1)
compare-elements-position-near: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@class='notable popover']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
"//*[@class='tooltip popover']",
{"y": 30}
)
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@class='notable popover']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
"//*[@class='tooltip popover']",
("x")
)
assert-position: (
"//*[@class='notable popover']",
"//*[@class='tooltip popover']",
{"x": 0}
)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
move-cursor-to: "//h1"
assert-count: ("//*[@class='notable popover']", 0)
assert-count: ("//*[@class='tooltip popover']", 0)
// Now check the colors.
define-function: (
@ -133,26 +133,26 @@ define-function: (
// We reload the page so the local storage settings are being used.
reload:
move-cursor-to: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
assert-count: (".notable.popover", 1)
move-cursor-to: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: (".tooltip.popover", 1)
assert-css: (
".notable.popover h3",
".tooltip.popover h3",
{"color": |header_color|},
ALL,
)
assert-css: (
".notable.popover pre",
".tooltip.popover pre",
{"color": |content_color|},
ALL,
)
assert-css: (
".notable.popover pre a.struct",
".tooltip.popover pre a.struct",
{"color": |type_color|},
ALL,
)
assert-css: (
".notable.popover pre a.trait",
".tooltip.popover pre a.trait",
{"color": |trait_color|},
ALL,
)
@ -195,24 +195,24 @@ call-function: (
reload:
// Check that pressing escape works
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
move-cursor-to: "//*[@class='notable popover']"
assert-count: ("//*[@class='notable popover']", 1)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
move-cursor-to: "//*[@class='tooltip popover']"
assert-count: ("//*[@class='tooltip popover']", 1)
press-key: "Escape"
assert-count: ("//*[@class='notable popover']", 0)
assert: "#method\.create_an_iterator_from_read .notable-traits:focus"
assert-count: ("//*[@class='tooltip popover']", 0)
assert: "#method\.create_an_iterator_from_read .tooltip:focus"
// Check that clicking outside works.
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
assert-count: ("//*[@class='notable popover']", 1)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: ("//*[@class='tooltip popover']", 1)
click: ".search-input"
assert-count: ("//*[@class='notable popover']", 0)
assert-false: "#method\.create_an_iterator_from_read .notable-traits:focus"
assert-count: ("//*[@class='tooltip popover']", 0)
assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"
// Check that pressing tab over and over works.
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
move-cursor-to: "//*[@class='notable popover']"
assert-count: ("//*[@class='notable popover']", 1)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
move-cursor-to: "//*[@class='tooltip popover']"
assert-count: ("//*[@class='tooltip popover']", 1)
press-key: "Tab"
press-key: "Tab"
press-key: "Tab"
@ -220,8 +220,8 @@ press-key: "Tab"
press-key: "Tab"
press-key: "Tab"
press-key: "Tab"
assert-count: ("//*[@class='notable popover']", 0)
assert: "#method\.create_an_iterator_from_read .notable-traits:focus"
assert-count: ("//*[@class='tooltip popover']", 0)
assert: "#method\.create_an_iterator_from_read .tooltip:focus"
// Now we check that the focus isn't given back to the wrong item when opening
// another popover.
@ -231,8 +231,8 @@ click: "#method\.create_an_iterator_from_read .fn"
assert-window-property-false: {"scrollY": |scroll|}
// Store the new position.
store-window-property: (scroll, "scrollY")
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
wait-for: "//*[@class='notable popover']"
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
wait-for: "//*[@class='tooltip popover']"
click: "#settings-menu a"
click: ".search-input"
// We ensure we didn't come back to the previous focused item.
@ -245,8 +245,8 @@ click: "#method\.create_an_iterator_from_read .fn"
assert-window-property-false: {"scrollY": |scroll|}
// Store the new position.
store-window-property: (scroll, "scrollY")
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
wait-for: "//*[@class='notable popover']"
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
wait-for: "//*[@class='tooltip popover']"
click: "#settings-menu a"
press-key: "Escape"
// We ensure we didn't come back to the previous focused item.
@ -254,23 +254,23 @@ assert-window-property-false: {"scrollY": |scroll|}
// Opening the mobile sidebar should close the popover.
size: (650, 600)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
assert-count: ("//*[@class='notable popover']", 1)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: ("//*[@class='tooltip popover']", 1)
click: ".sidebar-menu-toggle"
assert: "//*[@class='sidebar shown']"
assert-count: ("//*[@class='notable popover']", 0)
assert-false: "#method\.create_an_iterator_from_read .notable-traits:focus"
// Clicking a notable popover should close the sidebar.
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
assert-count: ("//*[@class='notable popover']", 1)
assert-count: ("//*[@class='tooltip popover']", 0)
assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"
// Clicking a notable trait tooltip popover should close the sidebar.
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: ("//*[@class='tooltip popover']", 1)
assert-false: "//*[@class='sidebar shown']"
// Also check the focus handling for the help button.
size: (1100, 600)
reload:
assert-count: ("//*[@class='notable popover']", 0)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
assert-count: ("//*[@class='notable popover']", 1)
assert-count: ("//*[@class='tooltip popover']", 0)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: ("//*[@class='tooltip popover']", 1)
click: "#help-button a"
assert-count: ("//*[@class='notable popover']", 0)
assert-false: "#method\.create_an_iterator_from_read .notable-traits:focus"
assert-count: ("//*[@class='tooltip popover']", 0)
assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"

View File

@ -176,6 +176,7 @@
-Z symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0')
-Z teach=val -- show extended diagnostic help (default: no)
-Z temps-dir=val -- the directory the intermediate files are written to
-Z terminal-urls=val -- use the OSC 8 hyperlink terminal specification to print hyperlinks in the compiler output
-Z thinlto=val -- enable ThinLTO when possible
-Z thir-unsafeck=val -- use the THIR unsafety checker (default: no)
-Z threads=val -- use a thread pool with N threads

View File

@ -3,7 +3,7 @@
// @has foo/fn.bar.html '//*[@class="example-wrap compile_fail"]/*[@class="tooltip"]' "ⓘ"
// @has foo/fn.bar.html '//*[@class="example-wrap ignore"]/*[@class="tooltip"]' "ⓘ"
// @has foo/fn.bar.html '//*[@class="example-wrap should_panic"]/*[@class="tooltip"]' "ⓘ"
// @has foo/fn.bar.html '//*[@data-edition="2018"]' "ⓘ"
// @has foo/fn.bar.html '//*[@title="This example runs with edition 2018"]' "ⓘ"
/// foo
///

View File

@ -9,7 +9,7 @@ impl<T: SomeTrait> SomeTrait for Wrapper<T> {}
#[doc(notable_trait)]
pub trait SomeTrait {
// @has doc_notable_trait/trait.SomeTrait.html
// @has - '//a[@class="notable-traits"]/@data-ty' 'Wrapper<Self>'
// @has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<Self>'
// @snapshot wrap-me - '//script[@id="notable-traits-data"]'
fn wrap_me(self) -> Wrapper<Self> where Self: Sized {
Wrapper {
@ -23,7 +23,7 @@ impl SomeTrait for SomeStruct {}
impl SomeStruct {
// @has doc_notable_trait/struct.SomeStruct.html
// @has - '//a[@class="notable-traits"]/@data-ty' 'SomeStruct'
// @has - '//a[@class="tooltip"]/@data-notable-ty' 'SomeStruct'
// @snapshot some-struct-new - '//script[@id="notable-traits-data"]'
pub fn new() -> SomeStruct {
SomeStruct
@ -31,7 +31,7 @@ impl SomeStruct {
}
// @has doc_notable_trait/fn.bare_fn.html
// @has - '//a[@class="notable-traits"]/@data-ty' 'SomeStruct'
// @has - '//a[@class="tooltip"]/@data-notable-ty' 'SomeStruct'
// @snapshot bare-fn - '//script[@id="notable-traits-data"]'
pub fn bare_fn() -> SomeStruct {
SomeStruct

View File

@ -3,7 +3,7 @@
use std::iter::Iterator;
// @has foo/struct.Odd.html
// @has - '//*[@id="method.new"]//a[@class="notable-traits"]/@data-ty' 'Odd'
// @has - '//*[@id="method.new"]//a[@class="tooltip"]/@data-notable-ty' 'Odd'
// @snapshot odd - '//script[@id="notable-traits-data"]'
pub struct Odd {
current: usize,

View File

@ -0,0 +1,4 @@
// compile-flags: -Zterminal-urls=yes
fn main() {
let () = 4; //~ ERROR
}

View File

@ -0,0 +1,11 @@
error[]8;;https://doc.rust-lang.org/error_codes/E0308.htmlE0308]8;;]: mismatched types
--> $DIR/terminal_urls.rs:3:9
|
LL | let () = 4;
| ^^ - this expression has type `{integer}`
| |
| expected integer, found `()`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

File diff suppressed because one or more lines are too long