Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
3f20a5d
Optimize copying large ranges of undefmask blocks
oli-obk Feb 18, 2019
1e3d1b6
No magic numbers
oli-obk Feb 18, 2019
aa8c48a
Don't try to copy relocations if there are none
oli-obk Feb 19, 2019
d32b7e5
Test the `UndefMask` type
oli-obk Feb 19, 2019
4ded592
Use a more general approach for setting large definedness ranges
oli-obk Feb 19, 2019
60fde17
Use bit operations for setting large ranges of bits in a u64
oli-obk Feb 20, 2019
876258b
Default to integrated `rust-lld` linker for UEFI targets
phil-opp Mar 6, 2019
94a6936
Track embedded-book in the toolstate
kennytm Mar 9, 2019
bd2e126
Revert "Revert "Add clamp functions""
EdorianDark Mar 9, 2019
6041ec3
add feature clamp
EdorianDark Mar 9, 2019
135b686
Update src/tools/publish_toolstate.py
jamesmunns Mar 10, 2019
d6f5100
Fix tidy
kennytm Mar 10, 2019
8371377
CI: Set job names.
ehuss Mar 9, 2019
4888b1f
we can now skip should_panic tests with the libtest harness
RalfJung Mar 10, 2019
52d9fa8
enabled too many tests
RalfJung Mar 10, 2019
537d4dd
overhaul intra-doc-link ambiguity warning
euclio Feb 28, 2019
d70d79f
replace ad-hoc namespace enums
euclio Mar 9, 2019
3bb2275
use `!` in macro disambiguation suggestion
euclio Mar 9, 2019
e25df32
consistent naming for duration_float methods and additional f32 methods
newpavlov Mar 11, 2019
35c19c5
move MAX_NANOS_F64/32 to methods
newpavlov Mar 11, 2019
980871a
fix tests
newpavlov Mar 11, 2019
197efb0
fix test
newpavlov Mar 11, 2019
b9d12ed
Be more discerning on when to attempt suggesting a comma in a macro i…
estebank Mar 11, 2019
78b248d
fix typo
newpavlov Mar 12, 2019
1ae1312
Explain the bits of `UndefMask`
oli-obk Mar 12, 2019
2a1eb1c
Document the precomputation algorithm's purpose
oli-obk Mar 12, 2019
795d307
Suggest return lifetime when there's only one named lifetime
estebank Mar 12, 2019
f923476
review comments
estebank Mar 12, 2019
adbd0a6
Make std time tests more robust for platform differences
Mar 12, 2019
0ea9b58
Suggest adding lifetime to struct field
estebank Mar 13, 2019
266ca31
Stabilize Range*::contains.
smmalis37 Mar 13, 2019
27abd52
Fix operator precedence
estebank Mar 13, 2019
9d938f6
Add test for #55809.
davidtwco Mar 13, 2019
311025e
Fix generic argument lookup for Self
Mar 7, 2019
4e5692d
test that wildcard type `_` is not duplicated by `type Foo<X> = (X, X…
pnkfelix Jan 18, 2019
88d43a0
Don't run test launching `echo` since that doesn't exist on Windows
Zoxc Mar 14, 2019
41cdf07
Run RustdocUi earlier
Zoxc Mar 14, 2019
69582e2
Rollup merge of #57729 - pnkfelix:issue-55748-pat-types-are-constrain…
Mark-Simulacrum Mar 14, 2019
ef70ca2
Rollup merge of #58556 - oli-obk:imperative_recursion, r=pnkfelix
Mark-Simulacrum Mar 14, 2019
b656841
Rollup merge of #58710 - EdorianDark:master, r=sfackler
Mark-Simulacrum Mar 14, 2019
2d2a3f2
Rollup merge of #58824 - euclio:intra-link-ambiguity, r=petrochenkov
Mark-Simulacrum Mar 14, 2019
3fca1de
Rollup merge of #58976 - phil-opp:patch-2, r=alexcrichton
Mark-Simulacrum Mar 14, 2019
d30cf00
Rollup merge of #59025 - aoikonomopoulos:issue-57924, r=varkor
Mark-Simulacrum Mar 14, 2019
0aec050
Rollup merge of #59038 - kennytm:track-embedded-book, r=oli-obk
Mark-Simulacrum Mar 14, 2019
027b203
Rollup merge of #59055 - ehuss:ci-job-name, r=alexcrichton
Mark-Simulacrum Mar 14, 2019
75980d1
Rollup merge of #59072 - RalfJung:miri-alloc-tests, r=kennytm
Mark-Simulacrum Mar 14, 2019
e113402
Rollup merge of #59102 - newpavlov:duration_float, r=alexcrichton
Mark-Simulacrum Mar 14, 2019
58f26bb
Rollup merge of #59116 - estebank:comma-sugg, r=petrochenkov
Mark-Simulacrum Mar 14, 2019
6d1c519
Rollup merge of #59146 - estebank:suggest-return-lt, r=varkor
Mark-Simulacrum Mar 14, 2019
935a9cf
Rollup merge of #59147 - jethrogb:jb/time-tests, r=sfackler
Mark-Simulacrum Mar 14, 2019
511c3de
Rollup merge of #59152 - smmalis37:range_contains, r=SimonSapin
Mark-Simulacrum Mar 14, 2019
52dc1d9
Rollup merge of #59156 - davidtwco:issue-55809, r=nikomatsakis
Mark-Simulacrum Mar 14, 2019
fa9ccc7
Rollup merge of #59175 - Zoxc:fix-process-test, r=alexcrichton
Mark-Simulacrum Mar 14, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
replace ad-hoc namespace enums
  • Loading branch information
euclio committed Mar 10, 2019
commit d70d79ffb4bc60fb98e45aaf9442ea8e6cb15d01
165 changes: 67 additions & 98 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use errors::Applicability;
use rustc::hir::def::Def;
use rustc::hir::def::{Def, Namespace::{self, *}, PerNS};
use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::lint as lint;
Expand Down Expand Up @@ -36,46 +36,24 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
}
}

#[derive(Debug)]
enum PathKind {
/// Either a value or type, but not a macro
Unknown,
/// Macro
Macro,
/// Values, functions, consts, statics (everything in the value namespace)
Value,
/// Types, traits (everything in the type namespace)
Type,
}

struct LinkCollector<'a, 'tcx> {
cx: &'a DocContext<'tcx>,
mod_ids: Vec<ast::NodeId>,
is_nightly_build: bool,
}

#[derive(Debug, Copy, Clone)]
enum Namespace {
Type,
Value,
Macro,
}

impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
fn new(cx: &'a DocContext<'tcx>) -> Self {
LinkCollector {
cx,
mod_ids: Vec::new(),
is_nightly_build: UnstableFeatures::from_environment().is_nightly_build(),
}
}

/// Resolves a given string as a path, along with whether or not it is
/// in the value namespace. Also returns an optional URL fragment in the case
/// of variants and methods.
/// Resolves a string as a path within a particular namespace. Also returns an optional
/// URL fragment in the case of variants and methods.
fn resolve(&self,
path_str: &str,
is_val: bool,
ns: Namespace,
current_item: &Option<String>,
parent_id: Option<ast::NodeId>)
-> Result<(Def, Option<String>), ()>
Expand All @@ -86,11 +64,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
// path.
if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) {
// FIXME: `with_scope` requires the `NodeId` of a module.
let result = cx.enter_resolver(|resolver| resolver.with_scope(id,
|resolver| {
resolver.resolve_str_path_error(DUMMY_SP,
&path_str, is_val)
}));
let result = cx.enter_resolver(|resolver| {
resolver.with_scope(id, |resolver| {
resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns == ValueNS)
})
});

if let Ok(result) = result {
// In case this is a trait item, skip the
Expand All @@ -103,16 +81,16 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
_ => return Ok((result.def, None))
};

if value != is_val {
if value != (ns == ValueNS) {
return Err(())
}
} else if let Some(prim) = is_primitive(path_str, is_val) {
} else if let Some(prim) = is_primitive(path_str, ns) {
return Ok((prim, Some(path_str.to_owned())))
} else {
// If resolution failed, it may still be a method
// because methods are not handled by the resolver
// If so, bail when we're not looking for a value.
if !is_val {
if ns != ValueNS {
return Err(())
}
}
Expand All @@ -136,7 +114,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
path = name.clone();
}
}
if let Some(prim) = is_primitive(&path, false) {
if let Some(prim) = is_primitive(&path, TypeNS) {
let did = primitive_impl(cx, &path).ok_or(())?;
return cx.tcx.associated_items(did)
.find(|item| item.ident.name == item_name)
Expand All @@ -160,8 +138,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
.find(|item| item.ident.name == item_name);
if let Some(item) = item {
let out = match item.kind {
ty::AssociatedKind::Method if is_val => "method",
ty::AssociatedKind::Const if is_val => "associatedconstant",
ty::AssociatedKind::Method if ns == ValueNS => "method",
ty::AssociatedKind::Const if ns == ValueNS => "associatedconstant",
_ => return Err(())
};
Ok((ty.def, Some(format!("{}.{}", out, item_name))))
Expand Down Expand Up @@ -198,9 +176,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
.find(|item| item.ident.name == item_name);
if let Some(item) = item {
let kind = match item.kind {
ty::AssociatedKind::Const if is_val => "associatedconstant",
ty::AssociatedKind::Type if !is_val => "associatedtype",
ty::AssociatedKind::Method if is_val => {
ty::AssociatedKind::Const if ns == ValueNS => "associatedconstant",
ty::AssociatedKind::Type if ns == TypeNS => "associatedtype",
ty::AssociatedKind::Method if ns == ValueNS => {
if item.defaultness.has_value() {
"method"
} else {
Expand Down Expand Up @@ -287,39 +265,35 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {

look_for_tests(&cx, &dox, &item, true);

if !self.is_nightly_build {
return None;
}

for (ori_link, link_range) in markdown_links(&dox) {
// Bail early for real links.
if ori_link.contains('/') {
continue;
}
let link = ori_link.replace("`", "");
let (def, fragment) = {
let mut kind = PathKind::Unknown;
let mut kind = None;
let path_str = if let Some(prefix) =
["struct@", "enum@", "type@",
"trait@", "union@"].iter()
.find(|p| link.starts_with(**p)) {
kind = PathKind::Type;
kind = Some(TypeNS);
link.trim_start_matches(prefix)
} else if let Some(prefix) =
["const@", "static@",
"value@", "function@", "mod@",
"fn@", "module@", "method@"]
.iter().find(|p| link.starts_with(**p)) {
kind = PathKind::Value;
kind = Some(ValueNS);
link.trim_start_matches(prefix)
} else if link.ends_with("()") {
kind = PathKind::Value;
kind = Some(ValueNS);
link.trim_end_matches("()")
} else if link.starts_with("macro@") {
kind = PathKind::Macro;
kind = Some(MacroNS);
link.trim_start_matches("macro@")
} else if link.ends_with('!') {
kind = PathKind::Macro;
kind = Some(MacroNS);
link.trim_end_matches('!')
} else {
&link[..]
Expand All @@ -331,8 +305,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
}

match kind {
PathKind::Value => {
if let Ok(def) = self.resolve(path_str, true, &current_item, parent_node) {
Some(ns @ ValueNS) => {
if let Ok(def) = self.resolve(path_str, ns, &current_item, parent_node) {
def
} else {
resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
Expand All @@ -342,66 +316,58 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
continue;
}
}
PathKind::Type => {
if let Ok(def) = self.resolve(path_str, false, &current_item, parent_node) {
Some(ns @ TypeNS) => {
if let Ok(def) = self.resolve(path_str, ns, &current_item, parent_node) {
def
} else {
resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
// This could just be a normal link.
continue;
}
}
PathKind::Unknown => {
None => {
// Try everything!
let mut candidates = vec![];

if let Some(macro_def) = macro_resolve(cx, path_str) {
candidates.push(((macro_def, None), Namespace::Macro));
}

if let Ok(type_def) =
self.resolve(path_str, false, &current_item, parent_node)
{
candidates.push((type_def, Namespace::Type));
}

if let Ok(value_def) =
self.resolve(path_str, true, &current_item, parent_node)
{
// Structs, variants, and mods exist in both namespaces, skip them.
match value_def.0 {
Def::StructCtor(..)
| Def::Mod(..)
| Def::Variant(..)
| Def::VariantCtor(..)
| Def::SelfCtor(..) => (),
_ => candidates.push((value_def, Namespace::Value)),
}
}
let candidates = PerNS {
macro_ns: macro_resolve(cx, path_str).map(|def| (def, None)),
type_ns: self
.resolve(path_str, TypeNS, &current_item, parent_node)
.ok(),
value_ns: self
.resolve(path_str, ValueNS, &current_item, parent_node)
.ok()
.and_then(|(def, fragment)| {
// Constructors are picked up in the type namespace.
match def {
Def::StructCtor(..)
| Def::VariantCtor(..)
| Def::SelfCtor(..) => None,
_ => Some((def, fragment))
}
}),
};

if candidates.len() == 1 {
candidates.remove(0).0
} else if candidates.is_empty() {
if candidates.is_empty() {
resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
// this could just be a normal link
continue;
} else {
let candidates = candidates.into_iter().map(|((def, _), ns)| {
(def, ns)
}).collect::<Vec<_>>();
}

let is_unambiguous = candidates.clone().present_items().count() == 1;
if is_unambiguous {
candidates.present_items().next().unwrap()
} else {
ambiguity_error(
cx,
&item.attrs,
path_str,
&dox,
link_range,
&candidates,
candidates.map(|candidate| candidate.map(|(def, _)| def)),
);
continue;
}
}
PathKind::Macro => {
Some(MacroNS) => {
if let Some(def) = macro_resolve(cx, path_str) {
(def, None)
} else {
Expand Down Expand Up @@ -514,13 +480,16 @@ fn ambiguity_error(
path_str: &str,
dox: &str,
link_range: Option<Range<usize>>,
candidates: &[(Def, Namespace)],
candidates: PerNS<Option<Def>>,
) {
let sp = span_of_attrs(attrs);

let mut msg = format!("`{}` is ", path_str);

match candidates {
let candidates = [TypeNS, ValueNS, MacroNS].iter().filter_map(|&ns| {
candidates[ns].map(|def| (def, ns))
}).collect::<Vec<_>>();
match candidates.as_slice() {
[(first_def, _), (second_def, _)] => {
msg += &format!(
"both {} {} and {} {}",
Expand Down Expand Up @@ -568,9 +537,9 @@ fn ambiguity_error(
(Def::Union(..), _) => "union",
(Def::Trait(..), _) => "trait",
(Def::Mod(..), _) => "module",
(_, Namespace::Type) => "type",
(_, Namespace::Value) => "value",
(_, Namespace::Macro) => "macro",
(_, TypeNS) => "type",
(_, ValueNS) => "value",
(_, MacroNS) => "macro",
};

// FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
Expand Down Expand Up @@ -646,11 +615,11 @@ const PRIMITIVES: &[(&str, Def)] = &[
("char", Def::PrimTy(hir::PrimTy::Char)),
];

fn is_primitive(path_str: &str, is_val: bool) -> Option<Def> {
if is_val {
None
} else {
fn is_primitive(path_str: &str, ns: Namespace) -> Option<Def> {
if ns == TypeNS {
PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1)
} else {
None
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/test/rustdoc-ui/intra-links-ambiguity.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,11 @@ help: to link to the function, add parentheses
LL | /// [ambiguous()] is ambiguous. //~ERROR ambiguous
| ^^^^^^^^^^^

error: `multi_conflict` is a macro, a struct, and a function
error: `multi_conflict` is a struct, a function, and a macro
--> $DIR/intra-links-ambiguity.rs:31:6
|
LL | /// [`multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
| ^^^^^^^^^^^^^^^^ ambiguous link
help: to link to the macro, prefix with the item type
|
LL | /// [`macro@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
| ^^^^^^^^^^^^^^^^^^^^^^
help: to link to the struct, prefix with the item type
|
LL | /// [`struct@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
Expand All @@ -49,6 +45,10 @@ help: to link to the function, add parentheses
|
LL | /// [`multi_conflict()`] is a three-way conflict. //~ERROR `multi_conflict`
| ^^^^^^^^^^^^^^^^^^
help: to link to the macro, prefix with the item type
|
LL | /// [`macro@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
| ^^^^^^^^^^^^^^^^^^^^^^

error: `type_and_value` is both a module and a constant
--> $DIR/intra-links-ambiguity.rs:33:16
Expand Down