Skip to content

Commit eae2f29

Browse files
committed
rustdoc-search: fix rendering assoc types in results
1 parent 2556b4e commit eae2f29

File tree

4 files changed

+122
-22
lines changed

4 files changed

+122
-22
lines changed

src/librustdoc/html/static/js/search.js

+37-16
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,13 @@ function takeFromArray(array, count) {
2525
}
2626

2727
function onEachBtwn(arr, func, funcBtwn) {
28-
let i = 0;
28+
let skipped = true;
2929
for (const value of arr) {
30-
if (i !== 0) {
31-
funcBtwn(value, i);
30+
if (!skipped) {
31+
funcBtwn(value);
3232
}
33-
if (func(value, i)) {
34-
return true;
35-
}
36-
i += 1;
33+
skipped = func(value);
3734
}
38-
return false;
3935
}
4036

4137
(function() {
@@ -292,6 +288,13 @@ function initSearch(rawSearchIndex) {
292288
* @type {Map<string, {id: integer, assocOnly: boolean}>}
293289
*/
294290
const typeNameIdMap = new Map();
291+
/**
292+
* Map from type ID to associated type name. Used for display,
293+
* not for search.
294+
*
295+
* @type {Map<integer, string>}
296+
*/
297+
const assocTypeIdNameMap = new Map();
295298
const ALIASES = new Map();
296299

297300
/**
@@ -1680,14 +1683,28 @@ function initSearch(rawSearchIndex) {
16801683
return;
16811684
}
16821685
pushText(fnType, result);
1683-
if (fnType.bindings.size > 0 || fnType.generics.length > 0) {
1684-
pushText({ name: "<", highlighted: false }, result);
1685-
}
1686+
let hasBindings = false;
16861687
if (fnType.bindings.size > 0) {
16871688
onEachBtwn(
16881689
fnType.bindings,
16891690
([key, values]) => {
1690-
pushText(key, result);
1691+
const name = assocTypeIdNameMap.get(key);
1692+
if (values.length === 1 && values[0].id < 0 &&
1693+
`${fnType.name}::${name}` === fnParamNames[-1 - values[0].id]
1694+
) {
1695+
// the internal `Item=Iterator::Item` type variable should be
1696+
// shown in the where clause and name mapping output, but is
1697+
// redundant in this spot
1698+
for (const value of values) {
1699+
writeFn(value, []);
1700+
}
1701+
return true;
1702+
}
1703+
if (!hasBindings) {
1704+
hasBindings = true;
1705+
pushText({ name: "<", highlighted: false }, result);
1706+
}
1707+
pushText({ name, highlighted: false }, result);
16911708
pushText({
16921709
name: values.length > 1 ? "=(" : "=",
16931710
highlighted: false,
@@ -1704,15 +1721,15 @@ function initSearch(rawSearchIndex) {
17041721
() => pushText({ name: ", ", highlighted: false }, result),
17051722
);
17061723
}
1707-
if (fnType.bindings.size > 0 && fnType.generics.length > 0) {
1708-
pushText({ name: ", ", highlighted: false }, result);
1724+
if (fnType.generics.length > 0) {
1725+
pushText({ name: hasBindings ? ", " : "<", highlighted: false }, result);
17091726
}
17101727
onEachBtwn(
17111728
fnType.generics,
17121729
value => writeFn(value, result),
17131730
() => pushText({ name: ", ", highlighted: false }, result),
17141731
);
1715-
if (fnType.bindings.size > 0 || fnType.generics.length > 0) {
1732+
if (hasBindings || fnType.generics.length > 0) {
17161733
pushText({ name: ">", highlighted: false }, result);
17171734
}
17181735
}
@@ -3554,8 +3571,12 @@ ${item.displayPath}<span class="${type}">${name}</span>\
35543571
};
35553572
} else {
35563573
const item = lowercasePaths[pathIndex - 1];
3574+
const id = buildTypeMapIndex(item.name, isAssocType);
3575+
if (isAssocType) {
3576+
assocTypeIdNameMap.set(id, paths[pathIndex - 1].name);
3577+
}
35573578
result = {
3558-
id: buildTypeMapIndex(item.name, isAssocType),
3579+
id,
35593580
name: paths[pathIndex - 1].name,
35603581
ty: item.ty,
35613582
path: item.path,
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// exact-check
2+
3+
const EXPECTED = [
4+
// Trait-associated types (that is, associated types with no constraints)
5+
// are treated like type parameters, so that you can "pattern match"
6+
// them. We should avoid redundant output (no `Item=MyIter::Item` stuff)
7+
// and should give reasonable results
8+
{
9+
'query': 'MyIter<T> -> Option<T>',
10+
'correction': null,
11+
'others': [
12+
{
13+
'path': 'assoc_type_unbound::MyIter',
14+
'name': 'next',
15+
'displayType': '&mut `MyIter` -> `Option`<`MyIter::Item`>',
16+
'displayMappedNames': 'MyIter::Item = T',
17+
'displayWhereClause': '',
18+
},
19+
],
20+
},
21+
{
22+
'query': 'MyIter<Item=T> -> Option<T>',
23+
'correction': null,
24+
'others': [
25+
{
26+
'path': 'assoc_type_unbound::MyIter',
27+
'name': 'next',
28+
'displayType': '&mut `MyIter` -> `Option`<`MyIter::Item`>',
29+
'displayMappedNames': 'MyIter::Item = T',
30+
'displayWhereClause': '',
31+
},
32+
],
33+
},
34+
{
35+
'query': 'MyIter<T> -> Option<Item=T>',
36+
'correction': null,
37+
'others': [],
38+
},
39+
];
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub trait MyIter {
2+
type Item;
3+
fn next(&mut self) -> Option<Self::Item>;
4+
}

tests/rustdoc-js/assoc-type.js

+42-6
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,40 @@ const EXPECTED = [
77
'query': 'iterator<something> -> u32',
88
'correction': null,
99
'others': [
10-
{ 'path': 'assoc_type::my', 'name': 'other_fn' },
11-
{ 'path': 'assoc_type', 'name': 'my_fn' },
10+
{
11+
'path': 'assoc_type::my',
12+
'name': 'other_fn',
13+
'displayType': 'X -> `u32`',
14+
'displayMappedNames': '',
15+
'displayWhereClause': 'X: `Iterator`<`Something`>',
16+
},
17+
{
18+
'path': 'assoc_type',
19+
'name': 'my_fn',
20+
'displayType': 'X -> `u32`',
21+
'displayMappedNames': '',
22+
'displayWhereClause': 'X: `Iterator`<Item=`Something`>',
23+
},
1224
],
1325
},
1426
{
1527
'query': 'iterator<something>',
1628
'correction': null,
1729
'in_args': [
18-
{ 'path': 'assoc_type::my', 'name': 'other_fn' },
19-
{ 'path': 'assoc_type', 'name': 'my_fn' },
30+
{
31+
'path': 'assoc_type::my',
32+
'name': 'other_fn',
33+
'displayType': 'X -> u32',
34+
'displayMappedNames': '',
35+
'displayWhereClause': 'X: `Iterator`<`Something`>',
36+
},
37+
{
38+
'path': 'assoc_type',
39+
'name': 'my_fn',
40+
'displayType': 'X -> u32',
41+
'displayMappedNames': '',
42+
'displayWhereClause': 'X: `Iterator`<Item=`Something`>',
43+
},
2044
],
2145
},
2246
{
@@ -26,8 +50,20 @@ const EXPECTED = [
2650
{ 'path': 'assoc_type', 'name': 'Something' },
2751
],
2852
'in_args': [
29-
{ 'path': 'assoc_type::my', 'name': 'other_fn' },
30-
{ 'path': 'assoc_type', 'name': 'my_fn' },
53+
{
54+
'path': 'assoc_type::my',
55+
'name': 'other_fn',
56+
'displayType': '`X` -> u32',
57+
'displayMappedNames': '',
58+
'displayWhereClause': 'X: Iterator<`Something`>',
59+
},
60+
{
61+
'path': 'assoc_type',
62+
'name': 'my_fn',
63+
'displayType': '`X` -> u32',
64+
'displayMappedNames': '',
65+
'displayWhereClause': 'X: Iterator<Item=`Something`>',
66+
},
3167
],
3268
},
3369
// if I write an explicit binding, only it shows up

0 commit comments

Comments
 (0)