Skip to content

Commit

Permalink
Rollup merge of #74078 - jyn514:lut, r=Manishearth
Browse files Browse the repository at this point in the history
Always resolve type@primitive as a primitive, not a module

Previously, if there were a module in scope with the same name as the
primitive, that would take precedence. Coupled with
#58699, this made it impossible
to link to the primitive when that module was in scope.

This approach could be extended so that `struct@foo` would no longer resolve
to any type, etc. However, it could not be used for glob imports:

```rust
pub mod foo {
  pub struct Bar;
}

pub enum Bar {}
use foo::*;

// This is expected to link to `inner::Bar`, but instead it will link to the enum.
/// Link to [struct@Bar]
pub struct MyDocs;
```

The reason for this is that this change does not affect the resolution
algorithm of rustc_resolve at all. The only reason we could special-case
primitives is because we have a list of all possible primitives ahead of time.

Closes #74063

r? @Manishearth
  • Loading branch information
Manishearth authored Jul 7, 2020
2 parents 86f8c53 + e46c187 commit ecc6f56
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 5 deletions.
33 changes: 28 additions & 5 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
fn resolve(
&self,
path_str: &str,
disambiguator: Option<&str>,
ns: Namespace,
current_item: &Option<String>,
parent_id: Option<hir::HirId>,
Expand Down Expand Up @@ -203,11 +204,22 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
}
return Ok((res, Some(path_str.to_owned())));
}
other => {
debug!(
"failed to resolve {} in namespace {:?} (got {:?})",
path_str, ns, other
);
Res::Def(DefKind::Mod, _) => {
// This resolved to a module, but if we were passed `type@`,
// we want primitive types to take precedence instead.
if disambiguator == Some("type") {
if let Some(prim) = is_primitive(path_str, ns) {
if extra_fragment.is_some() {
return Err(ErrorKind::AnchorFailure(
"primitive types cannot be followed by anchors",
));
}
return Ok((prim, Some(path_str.to_owned())));
}
}
return Ok((res, extra_fragment.clone()));
}
_ => {
return Ok((res, extra_fragment.clone()));
}
};
Expand Down Expand Up @@ -566,11 +578,13 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
let mut path_str;
let (res, fragment) = {
let mut kind = None;
let mut disambiguator = None;
path_str = if let Some(prefix) = ["struct@", "enum@", "type@", "trait@", "union@"]
.iter()
.find(|p| link.starts_with(**p))
{
kind = Some(TypeNS);
disambiguator = Some(&prefix[..prefix.len() - 1]);
link.trim_start_matches(prefix)
} else if let Some(prefix) = [
"const@",
Expand All @@ -586,18 +600,23 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
.find(|p| link.starts_with(**p))
{
kind = Some(ValueNS);
disambiguator = Some(&prefix[..prefix.len() - 1]);
link.trim_start_matches(prefix)
} else if link.ends_with("()") {
kind = Some(ValueNS);
disambiguator = Some("fn");
link.trim_end_matches("()")
} else if link.starts_with("macro@") {
kind = Some(MacroNS);
disambiguator = Some("macro");
link.trim_start_matches("macro@")
} else if link.starts_with("derive@") {
kind = Some(MacroNS);
disambiguator = Some("derive");
link.trim_start_matches("derive@")
} else if link.ends_with('!') {
kind = Some(MacroNS);
disambiguator = Some("macro");
link.trim_end_matches('!')
} else {
&link[..]
Expand Down Expand Up @@ -634,6 +653,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
Some(ns @ ValueNS) => {
match self.resolve(
path_str,
disambiguator,
ns,
&current_item,
base_node,
Expand All @@ -657,6 +677,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
Some(ns @ TypeNS) => {
match self.resolve(
path_str,
disambiguator,
ns,
&current_item,
base_node,
Expand All @@ -683,6 +704,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
.map(|res| (res, extra_fragment.clone())),
type_ns: match self.resolve(
path_str,
disambiguator,
TypeNS,
&current_item,
base_node,
Expand All @@ -697,6 +719,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
},
value_ns: match self.resolve(
path_str,
disambiguator,
ValueNS,
&current_item,
base_node,
Expand Down
12 changes: 12 additions & 0 deletions src/test/rustdoc/intra-link-prim-precedence.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// ignore-tidy-linelength
#![deny(intra_doc_resolution_failure)]

pub mod char {}

/// See also [type@char]
// @has intra_link_prim_precedence/struct.MyString.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
pub struct MyString;

/// See also [char]
// @has intra_link_prim_precedence/struct.MyString2.html '//a/@href' 'intra_link_prim_precedence/char/index.html'
pub struct MyString2;

0 comments on commit ecc6f56

Please sign in to comment.