Skip to content

Commit

Permalink
Avoid collisions between traits and their derive macros
Browse files Browse the repository at this point in the history
  • Loading branch information
Manishearth committed Jun 10, 2020
1 parent e003c3e commit 27dcb4a
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 4 deletions.
29 changes: 26 additions & 3 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Expand Up @@ -12,6 +12,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty;
use rustc_resolve::ParentScope;
use rustc_session::lint;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::Ident;
use rustc_span::symbol::Symbol;
use rustc_span::DUMMY_SP;
Expand Down Expand Up @@ -407,6 +408,22 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
}
}

/// Check for resolve collisions between a trait and its derive
///
/// These are common and we should just resolve to the trait in that case
fn is_derive_trait_collision<T>(ns: &PerNS<Option<(Res, T)>>) -> bool {
if let PerNS {
type_ns: Some((Res::Def(DefKind::Trait, _), _)),
macro_ns: Some((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)),
..
} = *ns
{
true
} else {
false
}
}

impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
fn fold_item(&mut self, mut item: Item) -> Option<Item> {
let item_hir_id = if item.is_mod() {
Expand Down Expand Up @@ -650,7 +667,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
}
None => {
// Try everything!
let candidates = PerNS {
let mut candidates = PerNS {
macro_ns: self
.macro_resolve(path_str, base_node)
.map(|res| (res, extra_fragment.clone())),
Expand Down Expand Up @@ -705,10 +722,16 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
continue;
}

let is_unambiguous = candidates.clone().present_items().count() == 1;
if is_unambiguous {
let len = candidates.clone().present_items().count();

if len == 1 {
candidates.present_items().next().unwrap()
} else if len == 2 && is_derive_trait_collision(&candidates) {
candidates.type_ns.unwrap()
} else {
if is_derive_trait_collision(&candidates) {
candidates.macro_ns = None;
}
ambiguity_error(
cx,
&item,
Expand Down
5 changes: 5 additions & 0 deletions src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs
Expand Up @@ -19,6 +19,11 @@ pub fn b_derive(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(DeriveTrait)]
pub fn trait_derive(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_attribute]
pub fn attr_a(input: TokenStream, _args: TokenStream) -> TokenStream {
input
Expand Down
6 changes: 5 additions & 1 deletion src/test/rustdoc/intra-link-proc-macro.rs
Expand Up @@ -11,7 +11,11 @@ use intra_link_proc_macro_macro::{DeriveB, attr_b};

// @has - '//a/@href' '../intra_link_proc_macro/derive.DeriveA.html'
// @has - '//a/@href' '../intra_link_proc_macro/attr.attr_a.html'
// @has - '//a/@href' '../intra_link_proc_macro/trait.DeriveTrait.html'
// @has - '//a/@href' '../intra_link_proc_macro_macro/derive.DeriveB.html'
// @has - '//a/@href' '../intra_link_proc_macro_macro/attr.attr_b.html'
/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b]
/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b], [DeriveTrait]
pub struct Foo;

// this should not cause ambiguity errors
pub trait DeriveTrait {}

0 comments on commit 27dcb4a

Please sign in to comment.