Skip to content

Commit 9360e87

Browse files
authored
Rollup merge of rust-lang#75649 - jyn514:inherent-lang-impls, r=GuillaumeGomez
Fix intra-doc links for inherent impls that are both lang items and not the default impl I found in rust-lang#75464 (comment) that `str::to_uppercase()` doesn't resolve while `str::trim()` does. The only real difference is that `to_uppercase` is defined in `alloc`, while trim is defined in `core`. It turns out that rustdoc was ignoring `lang_items.str_alloc_impl()` - it saw them in `collect_trait_impls`, but not for intra-doc links. This uses the same `impls` for all parts of rustdoc, so that there can be no more inconsistency. It does have the slight downside that the matches are no longer exhaustive but it will be very clear if a new lang item is missed because it will panic when you try to document it (and if you don't document it, does rustdoc really need to know about it?). ~~This needs a test case (probably just `str::to_uppercase`).~~ Added. This is best reviewed commit-by-commit. r? @GuillaumeGomez
2 parents 7e09c7e + 7be824e commit 9360e87

File tree

8 files changed

+125
-97
lines changed

8 files changed

+125
-97
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4052,6 +4052,7 @@ dependencies = [
40524052
"rustc-rayon",
40534053
"serde",
40544054
"serde_json",
4055+
"smallvec 1.4.0",
40554056
"tempfile",
40564057
]
40574058

src/librustdoc/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ minifier = "0.0.33"
1414
rayon = { version = "0.3.0", package = "rustc-rayon" }
1515
serde = { version = "1.0", features = ["derive"] }
1616
serde_json = "1.0"
17+
smallvec = "1.0"
1718
tempfile = "3"
1819
itertools = "0.8"

src/librustdoc/clean/types.rs

+83
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::default::Default;
33
use std::fmt;
44
use std::hash::{Hash, Hasher};
55
use std::iter::FromIterator;
6+
use std::lazy::SyncOnceCell as OnceCell;
67
use std::num::NonZeroU32;
78
use std::rc::Rc;
89
use std::sync::Arc;
@@ -19,12 +20,14 @@ use rustc_hir::lang_items;
1920
use rustc_hir::Mutability;
2021
use rustc_index::vec::IndexVec;
2122
use rustc_middle::middle::stability;
23+
use rustc_middle::ty::TyCtxt;
2224
use rustc_span::hygiene::MacroKind;
2325
use rustc_span::source_map::DUMMY_SP;
2426
use rustc_span::symbol::{kw, sym, Ident, Symbol};
2527
use rustc_span::{self, FileName};
2628
use rustc_target::abi::VariantIdx;
2729
use rustc_target::spec::abi::Abi;
30+
use smallvec::{smallvec, SmallVec};
2831

2932
use crate::clean::cfg::Cfg;
3033
use crate::clean::external_path;
@@ -1264,6 +1267,86 @@ impl PrimitiveType {
12641267
}
12651268
}
12661269

1270+
pub fn impls(&self, tcx: TyCtxt<'_>) -> &'static SmallVec<[DefId; 4]> {
1271+
Self::all_impls(tcx).get(self).expect("missing impl for primitive type")
1272+
}
1273+
1274+
pub fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>> {
1275+
static CELL: OnceCell<FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>>> = OnceCell::new();
1276+
1277+
CELL.get_or_init(move || {
1278+
use self::PrimitiveType::*;
1279+
1280+
/// A macro to create a FxHashMap.
1281+
///
1282+
/// Example:
1283+
///
1284+
/// ```
1285+
/// let letters = map!{"a" => "b", "c" => "d"};
1286+
/// ```
1287+
///
1288+
/// Trailing commas are allowed.
1289+
/// Commas between elements are required (even if the expression is a block).
1290+
macro_rules! map {
1291+
($( $key: expr => $val: expr ),* $(,)*) => {{
1292+
let mut map = ::rustc_data_structures::fx::FxHashMap::default();
1293+
$( map.insert($key, $val); )*
1294+
map
1295+
}}
1296+
}
1297+
1298+
let single = |a: Option<DefId>| a.into_iter().collect();
1299+
let both = |a: Option<DefId>, b: Option<DefId>| -> SmallVec<_> {
1300+
a.into_iter().chain(b).collect()
1301+
};
1302+
1303+
let lang_items = tcx.lang_items();
1304+
map! {
1305+
Isize => single(lang_items.isize_impl()),
1306+
I8 => single(lang_items.i8_impl()),
1307+
I16 => single(lang_items.i16_impl()),
1308+
I32 => single(lang_items.i32_impl()),
1309+
I64 => single(lang_items.i64_impl()),
1310+
I128 => single(lang_items.i128_impl()),
1311+
Usize => single(lang_items.usize_impl()),
1312+
U8 => single(lang_items.u8_impl()),
1313+
U16 => single(lang_items.u16_impl()),
1314+
U32 => single(lang_items.u32_impl()),
1315+
U64 => single(lang_items.u64_impl()),
1316+
U128 => single(lang_items.u128_impl()),
1317+
F32 => both(lang_items.f32_impl(), lang_items.f32_runtime_impl()),
1318+
F64 => both(lang_items.f64_impl(), lang_items.f64_runtime_impl()),
1319+
Char => single(lang_items.char_impl()),
1320+
Bool => single(lang_items.bool_impl()),
1321+
Str => both(lang_items.str_impl(), lang_items.str_alloc_impl()),
1322+
Slice => {
1323+
lang_items
1324+
.slice_impl()
1325+
.into_iter()
1326+
.chain(lang_items.slice_u8_impl())
1327+
.chain(lang_items.slice_alloc_impl())
1328+
.chain(lang_items.slice_u8_alloc_impl())
1329+
.collect()
1330+
},
1331+
Array => single(lang_items.array_impl()),
1332+
Tuple => smallvec![],
1333+
Unit => smallvec![],
1334+
RawPointer => {
1335+
lang_items
1336+
.const_ptr_impl()
1337+
.into_iter()
1338+
.chain(lang_items.mut_ptr_impl())
1339+
.chain(lang_items.const_slice_ptr_impl())
1340+
.chain(lang_items.mut_slice_ptr_impl())
1341+
.collect()
1342+
},
1343+
Reference => smallvec![],
1344+
Fn => smallvec![],
1345+
Never => smallvec![],
1346+
}
1347+
})
1348+
}
1349+
12671350
pub fn to_url_str(&self) -> &'static str {
12681351
self.as_str()
12691352
}

src/librustdoc/clean/utils.rs

+1-29
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,6 @@ pub fn qpath_to_string(p: &hir::QPath<'_>) -> String {
351351
}
352352

353353
pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut Vec<Item>) {
354-
use self::PrimitiveType::*;
355354
let tcx = cx.tcx;
356355

357356
for item in items {
@@ -370,34 +369,7 @@ pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut V
370369
None => continue,
371370
},
372371
};
373-
let did = match primitive {
374-
Isize => tcx.lang_items().isize_impl(),
375-
I8 => tcx.lang_items().i8_impl(),
376-
I16 => tcx.lang_items().i16_impl(),
377-
I32 => tcx.lang_items().i32_impl(),
378-
I64 => tcx.lang_items().i64_impl(),
379-
I128 => tcx.lang_items().i128_impl(),
380-
Usize => tcx.lang_items().usize_impl(),
381-
U8 => tcx.lang_items().u8_impl(),
382-
U16 => tcx.lang_items().u16_impl(),
383-
U32 => tcx.lang_items().u32_impl(),
384-
U64 => tcx.lang_items().u64_impl(),
385-
U128 => tcx.lang_items().u128_impl(),
386-
F32 => tcx.lang_items().f32_impl(),
387-
F64 => tcx.lang_items().f64_impl(),
388-
Char => tcx.lang_items().char_impl(),
389-
Bool => tcx.lang_items().bool_impl(),
390-
Str => tcx.lang_items().str_impl(),
391-
Slice => tcx.lang_items().slice_impl(),
392-
Array => tcx.lang_items().array_impl(),
393-
Tuple => None,
394-
Unit => None,
395-
RawPointer => tcx.lang_items().const_ptr_impl(),
396-
Reference => None,
397-
Fn => None,
398-
Never => None,
399-
};
400-
if let Some(did) = did {
372+
for &did in primitive.impls(tcx) {
401373
if !did.is_local() {
402374
inline::build_impl(cx, did, None, ret);
403375
}

src/librustdoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#![feature(ptr_offset_from)]
1313
#![feature(crate_visibility_modifier)]
1414
#![feature(never_type)]
15+
#![feature(once_cell)]
1516
#![recursion_limit = "256"]
1617

1718
#[macro_use]

src/librustdoc/passes/collect_intra_doc_links.rs

+23-34
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_span::hygiene::MacroKind;
1616
use rustc_span::symbol::Ident;
1717
use rustc_span::symbol::Symbol;
1818
use rustc_span::DUMMY_SP;
19+
use smallvec::SmallVec;
1920

2021
use std::cell::Cell;
2122
use std::ops::Range;
@@ -270,18 +271,26 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
270271
.ok_or(ErrorKind::ResolutionFailure)?;
271272

272273
if let Some(prim) = is_primitive(&path, TypeNS) {
273-
let did = primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)?;
274-
return cx
275-
.tcx
276-
.associated_items(did)
277-
.filter_by_name_unhygienic(item_name)
278-
.next()
279-
.and_then(|item| match item.kind {
280-
ty::AssocKind::Fn => Some("method"),
281-
_ => None,
282-
})
283-
.map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name))))
284-
.ok_or(ErrorKind::ResolutionFailure);
274+
for &impl_ in primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)? {
275+
let link = cx
276+
.tcx
277+
.associated_items(impl_)
278+
.find_by_name_and_namespace(
279+
cx.tcx,
280+
Ident::with_dummy_span(item_name),
281+
ns,
282+
impl_,
283+
)
284+
.and_then(|item| match item.kind {
285+
ty::AssocKind::Fn => Some("method"),
286+
_ => None,
287+
})
288+
.map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name))));
289+
if let Some(link) = link {
290+
return Ok(link);
291+
}
292+
}
293+
return Err(ErrorKind::ResolutionFailure);
285294
}
286295

287296
let (_, ty_res) = cx
@@ -1227,26 +1236,6 @@ fn is_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
12271236
if ns == TypeNS { PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1) } else { None }
12281237
}
12291238

1230-
fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option<DefId> {
1231-
let tcx = cx.tcx;
1232-
match path_str {
1233-
"u8" => tcx.lang_items().u8_impl(),
1234-
"u16" => tcx.lang_items().u16_impl(),
1235-
"u32" => tcx.lang_items().u32_impl(),
1236-
"u64" => tcx.lang_items().u64_impl(),
1237-
"u128" => tcx.lang_items().u128_impl(),
1238-
"usize" => tcx.lang_items().usize_impl(),
1239-
"i8" => tcx.lang_items().i8_impl(),
1240-
"i16" => tcx.lang_items().i16_impl(),
1241-
"i32" => tcx.lang_items().i32_impl(),
1242-
"i64" => tcx.lang_items().i64_impl(),
1243-
"i128" => tcx.lang_items().i128_impl(),
1244-
"isize" => tcx.lang_items().isize_impl(),
1245-
"f32" => tcx.lang_items().f32_impl(),
1246-
"f64" => tcx.lang_items().f64_impl(),
1247-
"str" => tcx.lang_items().str_impl(),
1248-
"bool" => tcx.lang_items().bool_impl(),
1249-
"char" => tcx.lang_items().char_impl(),
1250-
_ => None,
1251-
}
1239+
fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option<&'static SmallVec<[DefId; 4]>> {
1240+
Some(PrimitiveType::from_symbol(Symbol::intern(path_str))?.impls(cx.tcx))
12521241
}

src/librustdoc/passes/collect_trait_impls.rs

+1-34
Original file line numberDiff line numberDiff line change
@@ -34,40 +34,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
3434
}
3535

3636
// Also try to inline primitive impls from other crates.
37-
let lang_items = cx.tcx.lang_items();
38-
let primitive_impls = [
39-
lang_items.isize_impl(),
40-
lang_items.i8_impl(),
41-
lang_items.i16_impl(),
42-
lang_items.i32_impl(),
43-
lang_items.i64_impl(),
44-
lang_items.i128_impl(),
45-
lang_items.usize_impl(),
46-
lang_items.u8_impl(),
47-
lang_items.u16_impl(),
48-
lang_items.u32_impl(),
49-
lang_items.u64_impl(),
50-
lang_items.u128_impl(),
51-
lang_items.f32_impl(),
52-
lang_items.f64_impl(),
53-
lang_items.f32_runtime_impl(),
54-
lang_items.f64_runtime_impl(),
55-
lang_items.bool_impl(),
56-
lang_items.char_impl(),
57-
lang_items.str_impl(),
58-
lang_items.array_impl(),
59-
lang_items.slice_impl(),
60-
lang_items.slice_u8_impl(),
61-
lang_items.str_alloc_impl(),
62-
lang_items.slice_alloc_impl(),
63-
lang_items.slice_u8_alloc_impl(),
64-
lang_items.const_ptr_impl(),
65-
lang_items.mut_ptr_impl(),
66-
lang_items.const_slice_ptr_impl(),
67-
lang_items.mut_slice_ptr_impl(),
68-
];
69-
70-
for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
37+
for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
7138
if !def_id.is_local() {
7239
inline::build_impl(cx, def_id, None, &mut new_items);
7340

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![deny(broken_intra_doc_links)]
2+
3+
// ignore-tidy-linelength
4+
5+
// @has intra_link_primitive_non_default_impl/fn.f.html
6+
/// [`str::trim`]
7+
// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim"]' 'str::trim'
8+
/// [`str::to_lowercase`]
9+
// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
10+
/// [`str::into_boxed_bytes`]
11+
// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
12+
/// [`str::replace`]
13+
// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.replace"]' 'str::replace'
14+
pub fn f() {}

0 commit comments

Comments
 (0)