mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 06:51:58 +00:00
Auto merge of #90422 - GuillaumeGomez:rollup-s1mdag0, r=GuillaumeGomez
Rollup of 5 pull requests Successful merges: - #90156 (Remove underlines from non-top docblocks.) - #90183 (Show all Deref implementations recursively) - #90202 (Improve and test cross-crate hygiene) - #90375 (Use `is_global` in `candidate_should_be_dropped_in_favor_of`) - #90399 (Skipping verbose diagnostic suggestions when calling .as_ref() on type not implementing AsRef) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e249ce6b23
@ -1198,8 +1198,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if let EntryKind::Mod(data) = kind {
|
||||
for exp in data.decode((self, sess)).reexports.decode((self, sess)) {
|
||||
if let EntryKind::Mod(exports) = kind {
|
||||
for exp in exports.decode((self, sess)) {
|
||||
match exp.res {
|
||||
Res::Def(DefKind::Macro(..), _) => {}
|
||||
_ if macros_only => continue,
|
||||
@ -1219,10 +1219,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||
}
|
||||
|
||||
fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
|
||||
if let EntryKind::Mod(m) = self.kind(id) {
|
||||
m.decode((self, sess)).expansion
|
||||
} else {
|
||||
panic!("Expected module, found {:?}", self.local_def_id(id))
|
||||
match self.kind(id) {
|
||||
EntryKind::Mod(_) | EntryKind::Enum(_) | EntryKind::Trait(_) => {
|
||||
self.get_expn_that_defined(id, sess)
|
||||
}
|
||||
_ => panic!("Expected module, found {:?}", self.local_def_id(id)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1086,11 +1086,11 @@ impl EncodeContext<'a, 'tcx> {
|
||||
Lazy::empty()
|
||||
};
|
||||
|
||||
let data = ModData { reexports, expansion: tcx.expn_that_defined(local_def_id) };
|
||||
|
||||
record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
|
||||
record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports));
|
||||
if self.is_proc_macro {
|
||||
record!(self.tables.children[def_id] <- &[]);
|
||||
// Encode this here because we don't do it in encode_def_ids.
|
||||
record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
|
||||
} else {
|
||||
record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| {
|
||||
item_id.def_id.local_def_index
|
||||
|
@ -346,7 +346,7 @@ enum EntryKind {
|
||||
Union(Lazy<VariantData>, ReprOptions),
|
||||
Fn(Lazy<FnData>),
|
||||
ForeignFn(Lazy<FnData>),
|
||||
Mod(Lazy<ModData>),
|
||||
Mod(Lazy<[Export]>),
|
||||
MacroDef(Lazy<MacroDef>),
|
||||
ProcMacro(MacroKind),
|
||||
Closure,
|
||||
@ -364,12 +364,6 @@ enum EntryKind {
|
||||
#[derive(Encodable, Decodable)]
|
||||
struct RenderedConst(String);
|
||||
|
||||
#[derive(MetadataEncodable, MetadataDecodable)]
|
||||
struct ModData {
|
||||
reexports: Lazy<[Export]>,
|
||||
expansion: ExpnId,
|
||||
}
|
||||
|
||||
#[derive(MetadataEncodable, MetadataDecodable)]
|
||||
struct FnData {
|
||||
asyncness: hir::IsAsync,
|
||||
|
@ -145,17 +145,11 @@ impl<'a> Resolver<'a> {
|
||||
} else {
|
||||
def_key.disambiguated_data.data.get_opt_name().expect("module without name")
|
||||
};
|
||||
let expn_id = if def_kind == DefKind::Mod {
|
||||
self.cstore().module_expansion_untracked(def_id, &self.session)
|
||||
} else {
|
||||
// FIXME: Parent expansions for enums and traits are not kept in metadata.
|
||||
ExpnId::root()
|
||||
};
|
||||
|
||||
Some(self.new_module(
|
||||
parent,
|
||||
ModuleKind::Def(def_kind, def_id, name),
|
||||
expn_id,
|
||||
self.cstore().module_expansion_untracked(def_id, &self.session),
|
||||
self.cstore().get_span_untracked(def_id, &self.session),
|
||||
// FIXME: Account for `#[no_implicit_prelude]` attributes.
|
||||
parent.map_or(false, |module| module.no_implicit_prelude),
|
||||
|
@ -842,9 +842,11 @@ impl<'a> Resolver<'a> {
|
||||
|
||||
// collect results based on the filter function
|
||||
// avoid suggesting anything from the same module in which we are resolving
|
||||
// avoid suggesting anything with a hygienic name
|
||||
if ident.name == lookup_ident.name
|
||||
&& ns == namespace
|
||||
&& !ptr::eq(in_module, parent_scope.module)
|
||||
&& !ident.span.normalize_to_macros_2_0().from_expansion()
|
||||
{
|
||||
let res = name_binding.res();
|
||||
if filter_fn(res) {
|
||||
|
@ -709,7 +709,7 @@ impl SyntaxContext {
|
||||
/// pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`.
|
||||
/// pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
|
||||
/// }
|
||||
/// n(f);
|
||||
/// n!(f);
|
||||
/// macro n($j:ident) {
|
||||
/// use foo::*;
|
||||
/// f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
|
||||
|
@ -1547,8 +1547,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// Check if a bound would previously have been removed when normalizing
|
||||
// the param_env so that it can be given the lowest priority. See
|
||||
// #50825 for the motivation for this.
|
||||
let is_global =
|
||||
|cand: &ty::PolyTraitRef<'_>| cand.is_known_global() && !cand.has_late_bound_regions();
|
||||
let is_global = |cand: &ty::PolyTraitRef<'tcx>| {
|
||||
cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
|
||||
};
|
||||
|
||||
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
|
||||
// and `DiscriminantKindCandidate` to anything else.
|
||||
|
@ -15,7 +15,7 @@ use rustc_middle::ty::print::with_crate_prefix;
|
||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||
use rustc_span::lev_distance;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{source_map, FileName, MultiSpan, Span};
|
||||
use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{FulfillmentError, Obligation};
|
||||
|
||||
@ -1251,6 +1251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.tcx.lang_items().deref_trait(),
|
||||
self.tcx.lang_items().deref_mut_trait(),
|
||||
self.tcx.lang_items().drop_trait(),
|
||||
self.tcx.get_diagnostic_item(sym::AsRef),
|
||||
];
|
||||
// Try alternative arbitrary self types that could fulfill this call.
|
||||
// FIXME: probe for all types that *could* be arbitrary self-types, not
|
||||
@ -1300,7 +1301,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// We don't want to suggest a container type when the missing
|
||||
// method is `.clone()` or `.deref()` otherwise we'd suggest
|
||||
// `Arc::new(foo).clone()`, which is far from what the user wants.
|
||||
let skip = skippable.contains(&did);
|
||||
// Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
|
||||
// implement the `AsRef` trait.
|
||||
let skip = skippable.contains(&did)
|
||||
|| (("Pin::new" == *pre)
|
||||
&& (Symbol::intern("as_ref") == item_name.name));
|
||||
// Make sure the method is defined for the *actual* receiver: we don't
|
||||
// want to treat `Box<Self>` as a receiver if it only works because of
|
||||
// an autoderef to `&self`
|
||||
|
@ -6,7 +6,7 @@ use std::rc::Rc;
|
||||
use std::sync::mpsc::{channel, Receiver};
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edition::Edition;
|
||||
@ -54,6 +54,9 @@ crate struct Context<'tcx> {
|
||||
/// real location of an item. This is used to allow external links to
|
||||
/// publicly reused items to redirect to the right location.
|
||||
pub(super) render_redirect_pages: bool,
|
||||
/// Tracks section IDs for `Deref` targets so they match in both the main
|
||||
/// body and the sidebar.
|
||||
pub(super) deref_id_map: RefCell<FxHashMap<DefId, String>>,
|
||||
/// The map used to ensure all generated 'id=' attributes are unique.
|
||||
pub(super) id_map: RefCell<IdMap>,
|
||||
/// Shared mutable state.
|
||||
@ -70,7 +73,7 @@ crate struct Context<'tcx> {
|
||||
|
||||
// `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
rustc_data_structures::static_assert_size!(Context<'_>, 104);
|
||||
rustc_data_structures::static_assert_size!(Context<'_>, 144);
|
||||
|
||||
/// Shared mutable state used in [`Context`] and elsewhere.
|
||||
crate struct SharedContext<'tcx> {
|
||||
@ -513,6 +516,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
||||
dst,
|
||||
render_redirect_pages: false,
|
||||
id_map: RefCell::new(id_map),
|
||||
deref_id_map: RefCell::new(FxHashMap::default()),
|
||||
shared: Rc::new(scx),
|
||||
include_sources,
|
||||
};
|
||||
@ -536,6 +540,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
|
||||
current: self.current.clone(),
|
||||
dst: self.dst.clone(),
|
||||
render_redirect_pages: self.render_redirect_pages,
|
||||
deref_id_map: RefCell::new(FxHashMap::default()),
|
||||
id_map: RefCell::new(IdMap::new()),
|
||||
shared: Rc::clone(&self.shared),
|
||||
include_sources: self.include_sources,
|
||||
|
@ -1054,6 +1054,19 @@ fn render_assoc_items(
|
||||
containing_item: &clean::Item,
|
||||
it: DefId,
|
||||
what: AssocItemRender<'_>,
|
||||
) {
|
||||
let mut derefs = FxHashSet::default();
|
||||
derefs.insert(it);
|
||||
render_assoc_items_inner(w, cx, containing_item, it, what, &mut derefs)
|
||||
}
|
||||
|
||||
fn render_assoc_items_inner(
|
||||
w: &mut Buffer,
|
||||
cx: &Context<'_>,
|
||||
containing_item: &clean::Item,
|
||||
it: DefId,
|
||||
what: AssocItemRender<'_>,
|
||||
derefs: &mut FxHashSet<DefId>,
|
||||
) {
|
||||
info!("Documenting associated items of {:?}", containing_item.name);
|
||||
let cache = cx.cache();
|
||||
@ -1063,9 +1076,10 @@ fn render_assoc_items(
|
||||
};
|
||||
let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
|
||||
if !non_trait.is_empty() {
|
||||
let mut tmp_buf = Buffer::empty_from(w);
|
||||
let render_mode = match what {
|
||||
AssocItemRender::All => {
|
||||
w.write_str(
|
||||
tmp_buf.write_str(
|
||||
"<h2 id=\"implementations\" class=\"small-section-header\">\
|
||||
Implementations<a href=\"#implementations\" class=\"anchor\"></a>\
|
||||
</h2>",
|
||||
@ -1073,21 +1087,28 @@ fn render_assoc_items(
|
||||
RenderMode::Normal
|
||||
}
|
||||
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
|
||||
let id =
|
||||
cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
|
||||
if let Some(def_id) = type_.def_id(cx.cache()) {
|
||||
cx.deref_id_map.borrow_mut().insert(def_id, id.clone());
|
||||
}
|
||||
write!(
|
||||
w,
|
||||
"<h2 id=\"deref-methods\" class=\"small-section-header\">\
|
||||
tmp_buf,
|
||||
"<h2 id=\"{id}\" class=\"small-section-header\">\
|
||||
<span>Methods from {trait_}<Target = {type_}></span>\
|
||||
<a href=\"#deref-methods\" class=\"anchor\"></a>\
|
||||
<a href=\"#{id}\" class=\"anchor\"></a>\
|
||||
</h2>",
|
||||
id = id,
|
||||
trait_ = trait_.print(cx),
|
||||
type_ = type_.print(cx),
|
||||
);
|
||||
RenderMode::ForDeref { mut_: deref_mut_ }
|
||||
}
|
||||
};
|
||||
let mut impls_buf = Buffer::empty_from(w);
|
||||
for i in &non_trait {
|
||||
render_impl(
|
||||
w,
|
||||
&mut impls_buf,
|
||||
cx,
|
||||
i,
|
||||
containing_item,
|
||||
@ -1104,18 +1125,27 @@ fn render_assoc_items(
|
||||
},
|
||||
);
|
||||
}
|
||||
if !impls_buf.is_empty() {
|
||||
w.push_buffer(tmp_buf);
|
||||
w.push_buffer(impls_buf);
|
||||
}
|
||||
}
|
||||
if let AssocItemRender::DerefFor { .. } = what {
|
||||
return;
|
||||
}
|
||||
|
||||
if !traits.is_empty() {
|
||||
let deref_impl =
|
||||
traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait());
|
||||
if let Some(impl_) = deref_impl {
|
||||
let has_deref_mut =
|
||||
traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait());
|
||||
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
|
||||
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut, derefs);
|
||||
}
|
||||
|
||||
// If we were already one level into rendering deref methods, we don't want to render
|
||||
// anything after recursing into any further deref methods above.
|
||||
if let AssocItemRender::DerefFor { .. } = what {
|
||||
return;
|
||||
}
|
||||
|
||||
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
|
||||
traits.iter().partition(|t| t.inner_impl().synthetic);
|
||||
let (blanket_impl, concrete): (Vec<&&Impl>, _) =
|
||||
@ -1167,6 +1197,7 @@ fn render_deref_methods(
|
||||
impl_: &Impl,
|
||||
container_item: &clean::Item,
|
||||
deref_mut: bool,
|
||||
derefs: &mut FxHashSet<DefId>,
|
||||
) {
|
||||
let cache = cx.cache();
|
||||
let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
|
||||
@ -1188,16 +1219,16 @@ fn render_deref_methods(
|
||||
if let Some(did) = target.def_id(cache) {
|
||||
if let Some(type_did) = impl_.inner_impl().for_.def_id(cache) {
|
||||
// `impl Deref<Target = S> for S`
|
||||
if did == type_did {
|
||||
if did == type_did || !derefs.insert(did) {
|
||||
// Avoid infinite cycles
|
||||
return;
|
||||
}
|
||||
}
|
||||
render_assoc_items(w, cx, container_item, did, what);
|
||||
render_assoc_items_inner(w, cx, container_item, did, what, derefs);
|
||||
} else {
|
||||
if let Some(prim) = target.primitive_type() {
|
||||
if let Some(&did) = cache.primitive_locations.get(&prim) {
|
||||
render_assoc_items(w, cx, container_item, did, what);
|
||||
render_assoc_items_inner(w, cx, container_item, did, what, derefs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1987,7 +2018,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
|
||||
if let Some(impl_) =
|
||||
v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait())
|
||||
{
|
||||
sidebar_deref_methods(cx, out, impl_, v);
|
||||
let mut derefs = FxHashSet::default();
|
||||
derefs.insert(did);
|
||||
sidebar_deref_methods(cx, out, impl_, v, &mut derefs);
|
||||
}
|
||||
|
||||
let format_impls = |impls: Vec<&Impl>| {
|
||||
@ -2061,7 +2094,13 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
|
||||
}
|
||||
}
|
||||
|
||||
fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &[Impl]) {
|
||||
fn sidebar_deref_methods(
|
||||
cx: &Context<'_>,
|
||||
out: &mut Buffer,
|
||||
impl_: &Impl,
|
||||
v: &[Impl],
|
||||
derefs: &mut FxHashSet<DefId>,
|
||||
) {
|
||||
let c = cx.cache();
|
||||
|
||||
debug!("found Deref: {:?}", impl_);
|
||||
@ -2078,7 +2117,7 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &[
|
||||
if let Some(did) = target.def_id(c) {
|
||||
if let Some(type_did) = impl_.inner_impl().for_.def_id(c) {
|
||||
// `impl Deref<Target = S> for S`
|
||||
if did == type_did {
|
||||
if did == type_did || !derefs.insert(did) {
|
||||
// Avoid infinite cycles
|
||||
return;
|
||||
}
|
||||
@ -2102,9 +2141,17 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &[
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if !ret.is_empty() {
|
||||
let map;
|
||||
let id = if let Some(target_def_id) = real_target.def_id(c) {
|
||||
map = cx.deref_id_map.borrow();
|
||||
map.get(&target_def_id).expect("Deref section without derived id")
|
||||
} else {
|
||||
"deref-methods"
|
||||
};
|
||||
write!(
|
||||
out,
|
||||
"<h3 class=\"sidebar-title\"><a href=\"#deref-methods\">Methods from {}<Target={}></a></h3>",
|
||||
"<h3 class=\"sidebar-title\"><a href=\"#{}\">Methods from {}<Target={}></a></h3>",
|
||||
id,
|
||||
Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
|
||||
Escape(&format!("{:#}", real_target.print(cx))),
|
||||
);
|
||||
@ -2117,6 +2164,21 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &[
|
||||
out.push_str("</div>");
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse into any further impls that might exist for `target`
|
||||
if let Some(target_did) = target.def_id_no_primitives() {
|
||||
if let Some(target_impls) = c.impls.get(&target_did) {
|
||||
if let Some(target_deref_impl) = target_impls.iter().find(|i| {
|
||||
i.inner_impl()
|
||||
.trait_
|
||||
.as_ref()
|
||||
.map(|t| Some(t.def_id()) == cx.tcx().lang_items().deref_trait())
|
||||
.unwrap_or(false)
|
||||
}) {
|
||||
sidebar_deref_methods(cx, out, target_deref_impl, target_impls, derefs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ h1, h2, h3, h4 {
|
||||
margin: 20px 0 15px 0;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
h5, h6 {
|
||||
.docblock h3, .docblock h4, h5, h6 {
|
||||
margin: 15px 0 5px 0;
|
||||
}
|
||||
h1.fqn {
|
||||
@ -149,7 +149,14 @@ h1.fqn {
|
||||
h1.fqn > .in-band > a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
h2, h3, h4 {
|
||||
/* The only headings that get underlines are:
|
||||
Markdown-generated headings within the top-doc
|
||||
Rustdoc-generated h2 section headings (e.g. "Implementations", "Required Methods", etc)
|
||||
Underlines elsewhere in the documentation break up visual flow and tend to invert
|
||||
section hierarchies. */
|
||||
h2,
|
||||
.top-doc h3,
|
||||
.top-doc h4 {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
h3.code-header {
|
||||
|
@ -3,7 +3,8 @@ use crate::clean::*;
|
||||
use crate::core::DocContext;
|
||||
use crate::fold::DocFolder;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::DefIdTree;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
@ -51,12 +52,35 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
|
||||
}
|
||||
|
||||
let mut cleaner = BadImplStripper { prims, items: crate_items };
|
||||
let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
|
||||
|
||||
// Follow all `Deref` targets of included items and recursively add them as valid
|
||||
fn add_deref_target(
|
||||
map: &FxHashMap<DefId, &Type>,
|
||||
cleaner: &mut BadImplStripper,
|
||||
type_did: DefId,
|
||||
) {
|
||||
if let Some(target) = map.get(&type_did) {
|
||||
debug!("add_deref_target: type {:?}, target {:?}", type_did, target);
|
||||
if let Some(target_prim) = target.primitive_type() {
|
||||
cleaner.prims.insert(target_prim);
|
||||
} else if let Some(target_did) = target.def_id_no_primitives() {
|
||||
// `impl Deref<Target = S> for S`
|
||||
if target_did == type_did {
|
||||
// Avoid infinite cycles
|
||||
return;
|
||||
}
|
||||
cleaner.items.insert(target_did.into());
|
||||
add_deref_target(map, cleaner, target_did);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// scan through included items ahead of time to splice in Deref targets to the "valid" sets
|
||||
for it in &new_items {
|
||||
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
|
||||
if cleaner.keep_impl(for_)
|
||||
&& trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
|
||||
if trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
|
||||
&& cleaner.keep_impl(for_, true)
|
||||
{
|
||||
let target = items
|
||||
.iter()
|
||||
@ -71,16 +95,26 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
|
||||
} else if let Some(did) = target.def_id(&cx.cache) {
|
||||
cleaner.items.insert(did.into());
|
||||
}
|
||||
if let Some(for_did) = for_.def_id_no_primitives() {
|
||||
if type_did_to_deref_target.insert(for_did, target).is_none() {
|
||||
// Since only the `DefId` portion of the `Type` instances is known to be same for both the
|
||||
// `Deref` target type and the impl for type positions, this map of types is keyed by
|
||||
// `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
|
||||
if cleaner.keep_impl_with_def_id(for_did.into()) {
|
||||
add_deref_target(&type_did_to_deref_target, &mut cleaner, for_did);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_items.retain(|it| {
|
||||
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
|
||||
cleaner.keep_impl(for_)
|
||||
|| trait_
|
||||
.as_ref()
|
||||
.map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into()))
|
||||
cleaner.keep_impl(
|
||||
for_,
|
||||
trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait(),
|
||||
) || trait_.as_ref().map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into()))
|
||||
|| blanket_impl.is_some()
|
||||
} else {
|
||||
true
|
||||
@ -179,14 +213,14 @@ struct BadImplStripper {
|
||||
}
|
||||
|
||||
impl BadImplStripper {
|
||||
fn keep_impl(&self, ty: &Type) -> bool {
|
||||
fn keep_impl(&self, ty: &Type, is_deref: bool) -> bool {
|
||||
if let Generic(_) = ty {
|
||||
// keep impls made on generics
|
||||
true
|
||||
} else if let Some(prim) = ty.primitive_type() {
|
||||
self.prims.contains(&prim)
|
||||
} else if let Some(did) = ty.def_id_no_primitives() {
|
||||
self.keep_impl_with_def_id(did.into())
|
||||
is_deref || self.keep_impl_with_def_id(did.into())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
// This test check that headers (a) have the correct heading level, and (b) are the right size.
|
||||
// This test check that headers (a) have the correct heading level, (b) are the right size,
|
||||
// and (c) have the correct underlining (or absence of underlining).
|
||||
// The sizes may change as design changes, but try to make sure a lower header is never bigger than
|
||||
// its parent headers.
|
||||
// its parent headers. Also make sure lower headers don't have underlines when their parents lack
|
||||
// an underline.
|
||||
// Most of these sizes are set in CSS in `em` units, so here's a conversion chart based on our
|
||||
// default 16px font size:
|
||||
// 24px 1.5em
|
||||
@ -13,87 +15,139 @@
|
||||
goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
|
||||
|
||||
assert-css: ("h1.fqn", {"font-size": "24px"})
|
||||
assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
|
||||
|
||||
assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
|
||||
assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
|
||||
assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
|
||||
assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
|
||||
assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "17.6px"})
|
||||
assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"})
|
||||
|
||||
assert-css: ("h2#fields", {"font-size": "22.4px"})
|
||||
assert-css: ("h2#fields", {"border-bottom-width": "1px"})
|
||||
assert-css: ("h3#title-for-field", {"font-size": "20.8px"})
|
||||
assert-css: ("h3#title-for-field", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h4#sub-heading-for-field", {"font-size": "16px"})
|
||||
assert-css: ("h4#sub-heading-for-field", {"border-bottom-width": "0px"})
|
||||
|
||||
assert-css: ("h2#implementations", {"font-size": "22.4px"})
|
||||
assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
|
||||
|
||||
assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
|
||||
assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
|
||||
assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
|
||||
assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
|
||||
|
||||
assert-css: ("h4#title-for-struct-impl-doc", {"font-size": "16px"})
|
||||
assert-css: ("h4#title-for-struct-impl-doc", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h5#sub-heading-for-struct-impl-doc", {"font-size": "16px"})
|
||||
assert-css: ("h5#sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"font-size": "15.2px"})
|
||||
assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"})
|
||||
|
||||
assert-css: ("h5#title-for-struct-impl-item-doc", {"font-size": "16px"})
|
||||
assert-css: ("h5#title-for-struct-impl-item-doc", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"font-size": "15.2px"})
|
||||
assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "15.2px"})
|
||||
|
||||
goto: file://|DOC_PATH|/test_docs/enum.HeavilyDocumentedEnum.html
|
||||
|
||||
assert-css: ("h1.fqn", {"font-size": "24px"})
|
||||
assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
|
||||
|
||||
assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
|
||||
assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
|
||||
assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
|
||||
assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
|
||||
assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "17.6px"})
|
||||
assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"})
|
||||
|
||||
assert-css: ("h2#variants", {"font-size": "22.4px"})
|
||||
assert-css: ("h2#variants", {"border-bottom-width": "1px"})
|
||||
|
||||
assert-css: ("h3#none-prose-title", {"font-size": "20.8px"})
|
||||
assert-css: ("h3#none-prose-title", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h4#none-prose-sub-heading", {"font-size": "16px"})
|
||||
assert-css: ("h4#none-prose-sub-heading", {"border-bottom-width": "0px"})
|
||||
|
||||
assert-css: ("h3#wrapped-prose-title", {"font-size": "20.8px"})
|
||||
assert-css: ("h3#wrapped-prose-title", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h4#wrapped-prose-sub-heading", {"font-size": "16px"})
|
||||
assert-css: ("h4#wrapped-prose-sub-heading", {"border-bottom-width": "0px"})
|
||||
|
||||
assert-css: ("h4#wrapped0-prose-title", {"font-size": "16px"})
|
||||
assert-css: ("h4#wrapped0-prose-title", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h5#wrapped0-prose-sub-heading", {"font-size": "16px"})
|
||||
assert-css: ("h5#wrapped0-prose-sub-heading", {"border-bottom-width": "0px"})
|
||||
|
||||
assert-css: ("h4#structy-prose-title", {"font-size": "16px"})
|
||||
assert-css: ("h4#structy-prose-title", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h5#structy-prose-sub-heading", {"font-size": "16px"})
|
||||
assert-css: ("h5#structy-prose-sub-heading", {"border-bottom-width": "0px"})
|
||||
|
||||
assert-css: ("h2#implementations", {"font-size": "22.4px"})
|
||||
assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
|
||||
|
||||
assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
|
||||
assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
|
||||
assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
|
||||
assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
|
||||
|
||||
assert-css: ("h4#title-for-enum-impl-doc", {"font-size": "16px"})
|
||||
assert-css: ("h4#title-for-enum-impl-doc", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h5#sub-heading-for-enum-impl-doc", {"font-size": "16px"})
|
||||
assert-css: ("h5#sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"font-size": "15.2px"})
|
||||
assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"})
|
||||
|
||||
assert-css: ("h5#title-for-enum-impl-item-doc", {"font-size": "16px"})
|
||||
assert-css: ("h5#title-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"})
|
||||
assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"})
|
||||
assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
|
||||
|
||||
goto: file://|DOC_PATH|/test_docs/union.HeavilyDocumentedUnion.html
|
||||
|
||||
assert-css: ("h1.fqn", {"font-size": "24px"})
|
||||
assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
|
||||
|
||||
assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
|
||||
assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
|
||||
assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
|
||||
assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
|
||||
|
||||
assert-css: ("h2#fields", {"font-size": "22.4px"})
|
||||
assert-css: ("h2#fields", {"border-bottom-width": "1px"})
|
||||
|
||||
assert-css: ("h3#title-for-union-variant", {"font-size": "20.8px"})
|
||||
assert-css: ("h3#title-for-union-variant", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h4#sub-heading-for-union-variant", {"font-size": "16px"})
|
||||
assert-css: ("h4#sub-heading-for-union-variant", {"border-bottom-width": "0px"})
|
||||
|
||||
assert-css: ("h2#implementations", {"font-size": "22.4px"})
|
||||
assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
|
||||
|
||||
assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
|
||||
assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h4#title-for-union-impl-doc", {"font-size": "16px"})
|
||||
assert-css: ("h4#title-for-union-impl-doc", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h5#sub-heading-for-union-impl-doc", {"font-size": "16px"})
|
||||
assert-css: ("h5#sub-heading-for-union-impl-doc", {"border-bottom-width": "0px"})
|
||||
|
||||
assert-css: ("h5#title-for-union-impl-item-doc", {"font-size": "16px"})
|
||||
assert-css: ("h5#title-for-union-impl-item-doc", {"border-bottom-width": "0px"})
|
||||
assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"font-size": "15.2px"})
|
||||
assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"border-bottom-width": "0px"})
|
||||
|
||||
goto: file://|DOC_PATH|/test_docs/macro.heavily_documented_macro.html
|
||||
|
||||
assert-css: ("h1.fqn", {"font-size": "24px"})
|
||||
assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
|
||||
|
||||
assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
|
||||
assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
|
||||
assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
|
||||
assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
|
19
src/test/rustdoc-ui/recursive-deref-ice.rs
Normal file
19
src/test/rustdoc-ui/recursive-deref-ice.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// check-pass
|
||||
|
||||
// ICE found in https://github.com/rust-lang/rust/issues/83123
|
||||
|
||||
pub struct Attribute;
|
||||
|
||||
pub struct Map<'hir> {}
|
||||
impl<'hir> Map<'hir> {
|
||||
pub fn attrs(&self) -> &'hir [Attribute] { &[] }
|
||||
}
|
||||
|
||||
pub struct List<T>(T);
|
||||
|
||||
impl<T> std::ops::Deref for List<T> {
|
||||
type Target = [T];
|
||||
fn deref(&self) -> &[T] {
|
||||
&[]
|
||||
}
|
||||
}
|
25
src/test/rustdoc/deref-recursive-pathbuf.rs
Normal file
25
src/test/rustdoc/deref-recursive-pathbuf.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
|
||||
// levels and across multiple crates.
|
||||
// For `Deref` on non-foreign types, look at `deref-recursive.rs`.
|
||||
|
||||
// @has 'foo/struct.Foo.html'
|
||||
// @has '-' '//*[@id="deref-methods-PathBuf"]' 'Methods from Deref<Target = PathBuf>'
|
||||
// @has '-' '//*[@class="impl-items"]//*[@id="method.as_path"]' 'pub fn as_path(&self)'
|
||||
// @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>'
|
||||
// @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)'
|
||||
// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
|
||||
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.as_path"]' 'as_path'
|
||||
// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
|
||||
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.exists"]' 'exists'
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct Foo(PathBuf);
|
||||
|
||||
impl Deref for Foo {
|
||||
type Target = PathBuf;
|
||||
fn deref(&self) -> &PathBuf { &self.0 }
|
||||
}
|
41
src/test/rustdoc/deref-recursive.rs
Normal file
41
src/test/rustdoc/deref-recursive.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
|
||||
// levels if needed.
|
||||
// For `Deref` on foreign types, look at `deref-recursive-pathbuf.rs`.
|
||||
|
||||
// @has 'foo/struct.Foo.html'
|
||||
// @has '-' '//*[@id="deref-methods-Bar"]' 'Methods from Deref<Target = Bar>'
|
||||
// @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)'
|
||||
// @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>'
|
||||
// @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
|
||||
// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
|
||||
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar'
|
||||
// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
|
||||
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.baz"]' 'baz'
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
pub struct Foo(Bar);
|
||||
pub struct Bar(Baz);
|
||||
pub struct Baz;
|
||||
|
||||
impl Deref for Foo {
|
||||
type Target = Bar;
|
||||
fn deref(&self) -> &Bar { &self.0 }
|
||||
}
|
||||
|
||||
impl Deref for Bar {
|
||||
type Target = Baz;
|
||||
fn deref(&self) -> &Baz { &self.0 }
|
||||
}
|
||||
|
||||
impl Bar {
|
||||
/// This appears under `Foo` methods
|
||||
pub fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl Baz {
|
||||
/// This should also appear in `Foo` methods when recursing
|
||||
pub fn baz(&self) {}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
#![crate_name = "foo"]
|
||||
|
||||
// @has 'foo/struct.Bar.html'
|
||||
// @has '-' '//*[@id="deref-methods"]' 'Methods from Deref<Target = FooJ>'
|
||||
// @has '-' '//*[@id="deref-methods-FooJ"]' 'Methods from Deref<Target = FooJ>'
|
||||
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)'
|
||||
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
|
||||
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
|
||||
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
|
||||
// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods"]' 'Methods from Deref<Target=FooJ>'
|
||||
// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
|
||||
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a'
|
||||
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b'
|
||||
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c'
|
||||
|
@ -15,7 +15,7 @@ impl Deref for A {
|
||||
fn deref(&self) -> &B { todo!() }
|
||||
}
|
||||
|
||||
// @!has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c'
|
||||
// @has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c'
|
||||
impl Deref for B {
|
||||
type Target = C;
|
||||
fn deref(&self) -> &C { todo!() }
|
||||
|
@ -1,9 +1,16 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
// Cyclic deref with the parent (which is not the top parent).
|
||||
pub struct A;
|
||||
pub struct B;
|
||||
pub struct C;
|
||||
|
||||
impl C {
|
||||
pub fn c(&self) {}
|
||||
}
|
||||
|
||||
// @has recursive_deref/struct.A.html '//h3[@class="code-header in-band"]' 'impl Deref for A'
|
||||
// @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)'
|
||||
impl Deref for A {
|
||||
type Target = B;
|
||||
|
||||
@ -13,8 +20,99 @@ impl Deref for A {
|
||||
}
|
||||
|
||||
// @has recursive_deref/struct.B.html '//h3[@class="code-header in-band"]' 'impl Deref for B'
|
||||
// @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)'
|
||||
impl Deref for B {
|
||||
type Target = A;
|
||||
type Target = C;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
// @has recursive_deref/struct.C.html '//h3[@class="code-header in-band"]' 'impl Deref for C'
|
||||
impl Deref for C {
|
||||
type Target = B;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
// Cyclic deref with the grand-parent (which is not the top parent).
|
||||
pub struct D;
|
||||
pub struct E;
|
||||
pub struct F;
|
||||
pub struct G;
|
||||
|
||||
impl G {
|
||||
// There is no "self" parameter so it shouldn't be listed!
|
||||
pub fn g() {}
|
||||
}
|
||||
|
||||
// @has recursive_deref/struct.D.html '//h3[@class="code-header in-band"]' 'impl Deref for D'
|
||||
// We also check that `G::g` method isn't rendered because there is no `self` argument.
|
||||
// @!has '-' '//*[@id="deref-methods-G"]'
|
||||
impl Deref for D {
|
||||
type Target = E;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
// @has recursive_deref/struct.E.html '//h3[@class="code-header in-band"]' 'impl Deref for E'
|
||||
// We also check that `G::g` method isn't rendered because there is no `self` argument.
|
||||
// @!has '-' '//*[@id="deref-methods-G"]'
|
||||
impl Deref for E {
|
||||
type Target = F;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
// @has recursive_deref/struct.F.html '//h3[@class="code-header in-band"]' 'impl Deref for F'
|
||||
// We also check that `G::g` method isn't rendered because there is no `self` argument.
|
||||
// @!has '-' '//*[@id="deref-methods-G"]'
|
||||
impl Deref for F {
|
||||
type Target = G;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
// @has recursive_deref/struct.G.html '//h3[@class="code-header in-band"]' 'impl Deref for G'
|
||||
impl Deref for G {
|
||||
type Target = E;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
// Cyclic deref with top parent.
|
||||
pub struct H;
|
||||
pub struct I;
|
||||
|
||||
impl I {
|
||||
// There is no "self" parameter so it shouldn't be listed!
|
||||
pub fn i() {}
|
||||
}
|
||||
|
||||
// @has recursive_deref/struct.H.html '//h3[@class="code-header in-band"]' 'impl Deref for H'
|
||||
// @!has '-' '//*[@id="deref-methods-I"]'
|
||||
impl Deref for H {
|
||||
type Target = I;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
// @has recursive_deref/struct.I.html '//h3[@class="code-header in-band"]' 'impl Deref for I'
|
||||
impl Deref for I {
|
||||
type Target = H;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
panic!()
|
||||
|
73
src/test/ui/hygiene/auxiliary/fields.rs
Normal file
73
src/test/ui/hygiene/auxiliary/fields.rs
Normal file
@ -0,0 +1,73 @@
|
||||
#![feature(decl_macro)]
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum Field {
|
||||
RootCtxt,
|
||||
MacroCtxt,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
macro x(
|
||||
$macro_name:ident,
|
||||
$macro2_name:ident,
|
||||
$type_name:ident,
|
||||
$field_name:ident,
|
||||
$const_name:ident
|
||||
) {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct $type_name {
|
||||
pub field: Field,
|
||||
pub $field_name: Field,
|
||||
}
|
||||
|
||||
pub const $const_name: $type_name =
|
||||
$type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt };
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! $macro_name {
|
||||
(check_fields_of $e:expr) => {{
|
||||
let e = $e;
|
||||
assert_eq!(e.field, Field::MacroCtxt);
|
||||
assert_eq!(e.$field_name, Field::RootCtxt);
|
||||
}};
|
||||
(check_fields) => {{
|
||||
assert_eq!($const_name.field, Field::MacroCtxt);
|
||||
assert_eq!($const_name.$field_name, Field::RootCtxt);
|
||||
}};
|
||||
(construct) => {
|
||||
$type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt }
|
||||
};
|
||||
}
|
||||
|
||||
pub macro $macro2_name {
|
||||
(check_fields_of $e:expr) => {{
|
||||
let e = $e;
|
||||
assert_eq!(e.field, Field::MacroCtxt);
|
||||
assert_eq!(e.$field_name, Field::RootCtxt);
|
||||
}},
|
||||
(check_fields) => {{
|
||||
assert_eq!($const_name.field, Field::MacroCtxt);
|
||||
assert_eq!($const_name.$field_name, Field::RootCtxt);
|
||||
}},
|
||||
(construct) => {
|
||||
$type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x!(test_fields, test_fields2, MyStruct, field, MY_CONST);
|
||||
|
||||
pub fn check_fields(s: MyStruct) {
|
||||
test_fields!(check_fields_of s);
|
||||
}
|
||||
|
||||
pub fn check_fields_local() {
|
||||
test_fields!(check_fields);
|
||||
test_fields2!(check_fields);
|
||||
|
||||
let s1 = test_fields!(construct);
|
||||
test_fields!(check_fields_of s1);
|
||||
|
||||
let s2 = test_fields2!(construct);
|
||||
test_fields2!(check_fields_of s2);
|
||||
}
|
160
src/test/ui/hygiene/auxiliary/methods.rs
Normal file
160
src/test/ui/hygiene/auxiliary/methods.rs
Normal file
@ -0,0 +1,160 @@
|
||||
#![feature(decl_macro)]
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum Method {
|
||||
DefaultMacroCtxt,
|
||||
DefaultRootCtxt,
|
||||
OverrideMacroCtxt,
|
||||
OverrideRootCtxt,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
macro x($macro_name:ident, $macro2_name:ident, $trait_name:ident, $method_name:ident) {
|
||||
pub trait $trait_name {
|
||||
fn method(&self) -> Method {
|
||||
Method::DefaultMacroCtxt
|
||||
}
|
||||
|
||||
fn $method_name(&self) -> Method {
|
||||
Method::DefaultRootCtxt
|
||||
}
|
||||
}
|
||||
|
||||
impl $trait_name for () {}
|
||||
impl $trait_name for bool {
|
||||
fn method(&self) -> Method {
|
||||
Method::OverrideMacroCtxt
|
||||
}
|
||||
|
||||
fn $method_name(&self) -> Method {
|
||||
Method::OverrideRootCtxt
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! $macro_name {
|
||||
(check_resolutions) => {
|
||||
assert_eq!(().method(), Method::DefaultMacroCtxt);
|
||||
assert_eq!($trait_name::method(&()), Method::DefaultMacroCtxt);
|
||||
assert_eq!(().$method_name(), Method::DefaultRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&()), Method::DefaultRootCtxt);
|
||||
|
||||
assert_eq!(false.method(), Method::OverrideMacroCtxt);
|
||||
assert_eq!($trait_name::method(&false), Method::OverrideMacroCtxt);
|
||||
assert_eq!(false.$method_name(), Method::OverrideRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&false), Method::OverrideRootCtxt);
|
||||
|
||||
assert_eq!('a'.method(), Method::DefaultMacroCtxt);
|
||||
assert_eq!($trait_name::method(&'a'), Method::DefaultMacroCtxt);
|
||||
assert_eq!('a'.$method_name(), Method::DefaultRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&'a'), Method::DefaultRootCtxt);
|
||||
|
||||
assert_eq!(1i32.method(), Method::OverrideMacroCtxt);
|
||||
assert_eq!($trait_name::method(&1i32), Method::OverrideMacroCtxt);
|
||||
assert_eq!(1i32.$method_name(), Method::OverrideRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&1i32), Method::OverrideRootCtxt);
|
||||
|
||||
assert_eq!(1i64.method(), Method::OverrideMacroCtxt);
|
||||
assert_eq!($trait_name::method(&1i64), Method::OverrideMacroCtxt);
|
||||
assert_eq!(1i64.$method_name(), Method::OverrideRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&1i64), Method::OverrideRootCtxt);
|
||||
};
|
||||
(assert_no_override $v:expr) => {
|
||||
assert_eq!($v.method(), Method::DefaultMacroCtxt);
|
||||
assert_eq!($trait_name::method(&$v), Method::DefaultMacroCtxt);
|
||||
assert_eq!($v.$method_name(), Method::DefaultRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&$v), Method::DefaultRootCtxt);
|
||||
};
|
||||
(assert_override $v:expr) => {
|
||||
assert_eq!($v.method(), Method::OverrideMacroCtxt);
|
||||
assert_eq!($trait_name::method(&$v), Method::OverrideMacroCtxt);
|
||||
assert_eq!($v.$method_name(), Method::OverrideRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&$v), Method::OverrideRootCtxt);
|
||||
};
|
||||
(impl for $t:ty) => {
|
||||
impl $trait_name for $t {
|
||||
fn method(&self) -> Method {
|
||||
Method::OverrideMacroCtxt
|
||||
}
|
||||
|
||||
fn $method_name(&self) -> Method {
|
||||
Method::OverrideRootCtxt
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub macro $macro2_name {
|
||||
(check_resolutions) => {
|
||||
assert_eq!(().method(), Method::DefaultMacroCtxt);
|
||||
assert_eq!($trait_name::method(&()), Method::DefaultMacroCtxt);
|
||||
assert_eq!(().$method_name(), Method::DefaultRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&()), Method::DefaultRootCtxt);
|
||||
|
||||
assert_eq!(false.method(), Method::OverrideMacroCtxt);
|
||||
assert_eq!($trait_name::method(&false), Method::OverrideMacroCtxt);
|
||||
assert_eq!(false.$method_name(), Method::OverrideRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&false), Method::OverrideRootCtxt);
|
||||
|
||||
assert_eq!('a'.method(), Method::DefaultMacroCtxt);
|
||||
assert_eq!($trait_name::method(&'a'), Method::DefaultMacroCtxt);
|
||||
assert_eq!('a'.$method_name(), Method::DefaultRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&'a'), Method::DefaultRootCtxt);
|
||||
|
||||
assert_eq!(1i32.method(), Method::OverrideMacroCtxt);
|
||||
assert_eq!($trait_name::method(&1i32), Method::OverrideMacroCtxt);
|
||||
assert_eq!(1i32.$method_name(), Method::OverrideRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&1i32), Method::OverrideRootCtxt);
|
||||
|
||||
assert_eq!(1i64.method(), Method::OverrideMacroCtxt);
|
||||
assert_eq!($trait_name::method(&1i64), Method::OverrideMacroCtxt);
|
||||
assert_eq!(1i64.$method_name(), Method::OverrideRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&1i64), Method::OverrideRootCtxt);
|
||||
},
|
||||
(assert_no_override $v:expr) => {
|
||||
assert_eq!($v.method(), Method::DefaultMacroCtxt);
|
||||
assert_eq!($trait_name::method(&$v), Method::DefaultMacroCtxt);
|
||||
assert_eq!($v.$method_name(), Method::DefaultRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&$v), Method::DefaultRootCtxt);
|
||||
},
|
||||
(assert_override $v:expr) => {
|
||||
assert_eq!($v.method(), Method::OverrideMacroCtxt);
|
||||
assert_eq!($trait_name::method(&$v), Method::OverrideMacroCtxt);
|
||||
assert_eq!($v.$method_name(), Method::OverrideRootCtxt);
|
||||
assert_eq!($trait_name::$method_name(&$v), Method::OverrideRootCtxt);
|
||||
},
|
||||
(impl for $t:ty) => {
|
||||
impl $trait_name for $t {
|
||||
fn method(&self) -> Method {
|
||||
Method::OverrideMacroCtxt
|
||||
}
|
||||
|
||||
fn $method_name(&self) -> Method {
|
||||
Method::OverrideRootCtxt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x!(test_trait, test_trait2, MyTrait, method);
|
||||
|
||||
impl MyTrait for char {}
|
||||
test_trait!(impl for i32);
|
||||
test_trait2!(impl for i64);
|
||||
|
||||
pub fn check_crate_local() {
|
||||
test_trait!(check_resolutions);
|
||||
test_trait2!(check_resolutions);
|
||||
}
|
||||
|
||||
// Check that any comparison of idents at monomorphization time is correct
|
||||
pub fn check_crate_local_generic<T: MyTrait, U: MyTrait>(t: T, u: U) {
|
||||
test_trait!(check_resolutions);
|
||||
test_trait2!(check_resolutions);
|
||||
|
||||
test_trait!(assert_no_override t);
|
||||
test_trait2!(assert_no_override t);
|
||||
test_trait!(assert_override u);
|
||||
test_trait2!(assert_override u);
|
||||
}
|
7
src/test/ui/hygiene/auxiliary/pub_hygiene.rs
Normal file
7
src/test/ui/hygiene/auxiliary/pub_hygiene.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#![feature(decl_macro)]
|
||||
|
||||
macro x() {
|
||||
pub struct MyStruct;
|
||||
}
|
||||
|
||||
x!();
|
15
src/test/ui/hygiene/auxiliary/use_by_macro.rs
Normal file
15
src/test/ui/hygiene/auxiliary/use_by_macro.rs
Normal file
@ -0,0 +1,15 @@
|
||||
#![feature(decl_macro)]
|
||||
|
||||
macro x($macro_name:ident) {
|
||||
#[macro_export]
|
||||
macro_rules! $macro_name {
|
||||
(define) => {
|
||||
pub struct MyStruct;
|
||||
};
|
||||
(create) => {
|
||||
MyStruct {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
x!(my_struct);
|
36
src/test/ui/hygiene/auxiliary/variants.rs
Normal file
36
src/test/ui/hygiene/auxiliary/variants.rs
Normal file
@ -0,0 +1,36 @@
|
||||
#![feature(decl_macro)]
|
||||
|
||||
#[rustfmt::skip]
|
||||
macro x($macro_name:ident, $macro2_name:ident, $type_name:ident, $variant_name:ident) {
|
||||
#[repr(u8)]
|
||||
pub enum $type_name {
|
||||
Variant = 0,
|
||||
$variant_name = 1,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! $macro_name {
|
||||
() => {{
|
||||
assert_eq!($type_name::Variant as u8, 0);
|
||||
assert_eq!($type_name::$variant_name as u8, 1);
|
||||
assert_eq!(<$type_name>::Variant as u8, 0);
|
||||
assert_eq!(<$type_name>::$variant_name as u8, 1);
|
||||
}};
|
||||
}
|
||||
|
||||
pub macro $macro2_name {
|
||||
() => {{
|
||||
assert_eq!($type_name::Variant as u8, 0);
|
||||
assert_eq!($type_name::$variant_name as u8, 1);
|
||||
assert_eq!(<$type_name>::Variant as u8, 0);
|
||||
assert_eq!(<$type_name>::$variant_name as u8, 1);
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
x!(test_variants, test_variants2, MyEnum, Variant);
|
||||
|
||||
pub fn check_variants() {
|
||||
test_variants!();
|
||||
test_variants2!();
|
||||
}
|
19
src/test/ui/hygiene/cross-crate-define-and-use.rs
Normal file
19
src/test/ui/hygiene/cross-crate-define-and-use.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Check that a marco from another crate can define an item in one expansion
|
||||
// and use it from another, without it being visible to everyone.
|
||||
// This requires that the definition of `my_struct` preserves the hygiene
|
||||
// information for the tokens in its definition.
|
||||
|
||||
// check-pass
|
||||
// aux-build:use_by_macro.rs
|
||||
|
||||
#![feature(type_name_of_val)]
|
||||
extern crate use_by_macro;
|
||||
|
||||
use use_by_macro::*;
|
||||
|
||||
enum MyStruct {}
|
||||
my_struct!(define);
|
||||
|
||||
fn main() {
|
||||
let x = my_struct!(create);
|
||||
}
|
24
src/test/ui/hygiene/cross-crate-fields.rs
Normal file
24
src/test/ui/hygiene/cross-crate-fields.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Test that fields on a struct defined in another crate are resolved correctly
|
||||
// their names differ only in `SyntaxContext`.
|
||||
|
||||
// run-pass
|
||||
// aux-build:fields.rs
|
||||
|
||||
extern crate fields;
|
||||
|
||||
use fields::*;
|
||||
|
||||
fn main() {
|
||||
check_fields_local();
|
||||
|
||||
test_fields!(check_fields);
|
||||
test_fields2!(check_fields);
|
||||
|
||||
let s1 = test_fields!(construct);
|
||||
check_fields(s1);
|
||||
test_fields!(check_fields_of s1);
|
||||
|
||||
let s2 = test_fields2!(construct);
|
||||
check_fields(s2);
|
||||
test_fields2!(check_fields_of s2);
|
||||
}
|
23
src/test/ui/hygiene/cross-crate-glob-hygiene.rs
Normal file
23
src/test/ui/hygiene/cross-crate-glob-hygiene.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Check that globs cannot import hygienic identifiers from a macro expansion
|
||||
// in another crate. `my_struct` is a `macro_rules` macro, so the struct it
|
||||
// defines is only not imported because `my_struct` is defined by a macros 2.0
|
||||
// macro.
|
||||
|
||||
// aux-build:use_by_macro.rs
|
||||
|
||||
extern crate use_by_macro;
|
||||
|
||||
use use_by_macro::*;
|
||||
|
||||
mod m {
|
||||
use use_by_macro::*;
|
||||
|
||||
my_struct!(define);
|
||||
}
|
||||
|
||||
use m::*;
|
||||
|
||||
fn main() {
|
||||
let x = my_struct!(create);
|
||||
//~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
|
||||
}
|
11
src/test/ui/hygiene/cross-crate-glob-hygiene.stderr
Normal file
11
src/test/ui/hygiene/cross-crate-glob-hygiene.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
|
||||
--> $DIR/cross-crate-glob-hygiene.rs:21:13
|
||||
|
|
||||
LL | let x = my_struct!(create);
|
||||
| ^^^^^^^^^^^^^^^^^^ not found in this scope
|
||||
|
|
||||
= note: this error originates in the macro `my_struct` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0422`.
|
33
src/test/ui/hygiene/cross-crate-methods.rs
Normal file
33
src/test/ui/hygiene/cross-crate-methods.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// Test that methods defined in another crate are resolved correctly their
|
||||
// names differ only in `SyntaxContext`. This also checks that any name
|
||||
// resolution done when monomorphizing is correct.
|
||||
|
||||
// run-pass
|
||||
// aux-build:methods.rs
|
||||
|
||||
extern crate methods;
|
||||
|
||||
use methods::*;
|
||||
|
||||
struct A;
|
||||
struct B;
|
||||
struct C;
|
||||
|
||||
impl MyTrait for A {}
|
||||
test_trait!(impl for B);
|
||||
test_trait2!(impl for C);
|
||||
|
||||
fn main() {
|
||||
check_crate_local();
|
||||
check_crate_local_generic(A, B);
|
||||
check_crate_local_generic(A, C);
|
||||
|
||||
test_trait!(check_resolutions);
|
||||
test_trait2!(check_resolutions);
|
||||
test_trait!(assert_no_override A);
|
||||
test_trait2!(assert_no_override A);
|
||||
test_trait!(assert_override B);
|
||||
test_trait2!(assert_override B);
|
||||
test_trait!(assert_override C);
|
||||
test_trait2!(assert_override C);
|
||||
}
|
12
src/test/ui/hygiene/cross-crate-name-collision.rs
Normal file
12
src/test/ui/hygiene/cross-crate-name-collision.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// Check that two items defined in another crate that have identifiers that
|
||||
// only differ by `SyntaxContext` do not cause name collisions when imported
|
||||
// in another crate.
|
||||
|
||||
// check-pass
|
||||
// aux-build:needs_hygiene.rs
|
||||
|
||||
extern crate needs_hygiene;
|
||||
|
||||
use needs_hygiene::*;
|
||||
|
||||
fn main() {}
|
15
src/test/ui/hygiene/cross-crate-name-hiding-2.rs
Normal file
15
src/test/ui/hygiene/cross-crate-name-hiding-2.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Check that an identifier from a 2.0 macro in another crate cannot be
|
||||
// resolved with an identifier that's not from a macro expansion.
|
||||
|
||||
// aux-build:use_by_macro.rs
|
||||
|
||||
extern crate use_by_macro;
|
||||
|
||||
use use_by_macro::*;
|
||||
|
||||
my_struct!(define);
|
||||
|
||||
fn main() {
|
||||
let x = MyStruct {};
|
||||
//~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
|
||||
}
|
9
src/test/ui/hygiene/cross-crate-name-hiding-2.stderr
Normal file
9
src/test/ui/hygiene/cross-crate-name-hiding-2.stderr
Normal file
@ -0,0 +1,9 @@
|
||||
error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
|
||||
--> $DIR/cross-crate-name-hiding-2.rs:13:13
|
||||
|
|
||||
LL | let x = MyStruct {};
|
||||
| ^^^^^^^^ not found in this scope
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0422`.
|
13
src/test/ui/hygiene/cross-crate-name-hiding.rs
Normal file
13
src/test/ui/hygiene/cross-crate-name-hiding.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// Check that an item defined by a 2.0 macro in another crate cannot be used in
|
||||
// another crate.
|
||||
|
||||
// aux-build:pub_hygiene.rs
|
||||
|
||||
extern crate pub_hygiene;
|
||||
|
||||
use pub_hygiene::*;
|
||||
|
||||
fn main() {
|
||||
let x = MyStruct {};
|
||||
//~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
|
||||
}
|
9
src/test/ui/hygiene/cross-crate-name-hiding.stderr
Normal file
9
src/test/ui/hygiene/cross-crate-name-hiding.stderr
Normal file
@ -0,0 +1,9 @@
|
||||
error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
|
||||
--> $DIR/cross-crate-name-hiding.rs:11:13
|
||||
|
|
||||
LL | let x = MyStruct {};
|
||||
| ^^^^^^^^ not found in this scope
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0422`.
|
14
src/test/ui/hygiene/cross-crate-redefine.rs
Normal file
14
src/test/ui/hygiene/cross-crate-redefine.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Check that items with identical `SyntaxContext` conflict even when that
|
||||
// context involves a mark from another crate.
|
||||
|
||||
// aux-build:use_by_macro.rs
|
||||
|
||||
extern crate use_by_macro;
|
||||
|
||||
use use_by_macro::*;
|
||||
|
||||
my_struct!(define);
|
||||
//~^ ERROR the name `MyStruct` is defined multiple times
|
||||
my_struct!(define);
|
||||
|
||||
fn main() {}
|
15
src/test/ui/hygiene/cross-crate-redefine.stderr
Normal file
15
src/test/ui/hygiene/cross-crate-redefine.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error[E0428]: the name `MyStruct` is defined multiple times
|
||||
--> $DIR/cross-crate-redefine.rs:10:1
|
||||
|
|
||||
LL | my_struct!(define);
|
||||
| ^^^^^^^^^^^^^^^^^^ `MyStruct` redefined here
|
||||
LL |
|
||||
LL | my_struct!(define);
|
||||
| ------------------ previous definition of the type `MyStruct` here
|
||||
|
|
||||
= note: `MyStruct` must be defined only once in the type namespace of this module
|
||||
= note: this error originates in the macro `my_struct` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0428`.
|
18
src/test/ui/hygiene/cross-crate-variants.rs
Normal file
18
src/test/ui/hygiene/cross-crate-variants.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// Test that variants of an enum defined in another crate are resolved
|
||||
// correctly when their names differ only in `SyntaxContext`.
|
||||
|
||||
// run-pass
|
||||
// aux-build:variants.rs
|
||||
|
||||
extern crate variants;
|
||||
|
||||
use variants::*;
|
||||
|
||||
fn main() {
|
||||
check_variants();
|
||||
|
||||
test_variants!();
|
||||
test_variants2!();
|
||||
|
||||
assert_eq!(MyEnum::Variant as u8, 1);
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
// check-pass
|
||||
// aux-build:needs_hygiene.rs
|
||||
|
||||
extern crate needs_hygiene;
|
||||
|
||||
use needs_hygiene::*;
|
||||
|
||||
fn main() {}
|
@ -49,6 +49,8 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt:
|
||||
crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it")
|
||||
crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site")
|
||||
crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy")
|
||||
crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
|
||||
crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
|
||||
crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
|
||||
crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
|
||||
|
||||
|
@ -73,6 +73,8 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt:
|
||||
crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer")
|
||||
crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner")
|
||||
crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang")
|
||||
crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
|
||||
crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
|
||||
crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
|
||||
crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
|
||||
|
||||
|
20
src/test/ui/traits/issue-90195-2.rs
Normal file
20
src/test/ui/traits/issue-90195-2.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// check-pass
|
||||
pub trait Archive {
|
||||
type Archived;
|
||||
}
|
||||
|
||||
impl<T> Archive for Option<T> {
|
||||
type Archived = ();
|
||||
}
|
||||
pub type Archived<T> = <T as Archive>::Archived;
|
||||
|
||||
pub trait Deserialize<D> {}
|
||||
|
||||
const ARRAY_SIZE: usize = 32;
|
||||
impl<__D> Deserialize<__D> for ()
|
||||
where
|
||||
Option<[u8; ARRAY_SIZE]>: Archive,
|
||||
Archived<Option<[u8; ARRAY_SIZE]>>: Deserialize<__D>,
|
||||
{
|
||||
}
|
||||
fn main() {}
|
21
src/test/ui/traits/issue-90195.rs
Normal file
21
src/test/ui/traits/issue-90195.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// check-pass
|
||||
pub trait Archive {
|
||||
type Archived;
|
||||
}
|
||||
|
||||
impl<T> Archive for Option<T> {
|
||||
type Archived = ();
|
||||
}
|
||||
pub type Archived<T> = <T as Archive>::Archived;
|
||||
|
||||
pub trait Deserialize<D> {}
|
||||
|
||||
const ARRAY_SIZE: usize = 32;
|
||||
impl<__D> Deserialize<__D> for ()
|
||||
where
|
||||
Option<[u8; ARRAY_SIZE]>: Archive,
|
||||
Option<[u8; ARRAY_SIZE]>: Archive,
|
||||
Archived<Option<[u8; ARRAY_SIZE]>>: Deserialize<__D>,
|
||||
{
|
||||
}
|
||||
fn main() {}
|
3
src/test/ui/typeck/issue-89806.rs
Normal file
3
src/test/ui/typeck/issue-89806.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
0u8.as_ref(); //~ ERROR no method named `as_ref` found for type `u8` in the current scope
|
||||
}
|
9
src/test/ui/typeck/issue-89806.stderr
Normal file
9
src/test/ui/typeck/issue-89806.stderr
Normal file
@ -0,0 +1,9 @@
|
||||
error[E0599]: no method named `as_ref` found for type `u8` in the current scope
|
||||
--> $DIR/issue-89806.rs:2:9
|
||||
|
|
||||
LL | 0u8.as_ref();
|
||||
| ^^^^^^ method not found in `u8`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
Loading…
Reference in New Issue
Block a user