Skip to content

Commit

Permalink
Rollup merge of rust-lang#118812 - notriddle:notriddle/assoc-name-int…
Browse files Browse the repository at this point in the history
…ern, r=GuillaumeGomez

rustdoc-search: do not treat associated type names as types

[Before](http://notriddle.com/rustdoc-html-demo-6/tor-before/tor_config/list_builder/trait.DirectDefaultEmptyListBuilderAccessors.html?search=DirectDefaultEmptyListBuilderAccessors%3CT%3DT%3E%20-%3E%20Vec%3CT%3E#associatedtype.T)

[After](http://notriddle.com/rustdoc-html-demo-6/tor-after/tor_config/list_builder/trait.DirectDefaultEmptyListBuilderAccessors.html?search=DirectDefaultEmptyListBuilderAccessors%3CT%3DT%3E%20-%3E%20Vec%3CT%3E#associatedtype.T)

[Profile](http://notriddle.com/rustdoc-html-demo-6/tor-profile/index.html)

As a bit of background information: in type-based queries, a type name that does not exist gets treated as a generic type variable.

This causes a counterintuitive behavior in the `tor_config` crate, which has a trait with an associated type variable called `T`.

This isn't a searchable concrete type, but its name still gets stored in the typeNameIdMap, as a convenient way to intern its name.

(The second commit is a mostly unrelated bugfix.)
  • Loading branch information
GuillaumeGomez authored Dec 11, 2023
2 parents ec59ea8 + 7162cb9 commit df7d23c
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 14 deletions.
35 changes: 21 additions & 14 deletions src/librustdoc/html/static/js/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ function initSearch(rawSearchIndex) {
* Map from normalized type names to integers. Used to make type search
* more efficient.
*
* @type {Map<string, integer>}
* @type {Map<string, {id: integer, assocOnly: boolean}>}
*/
let typeNameIdMap;
const ALIASES = new Map();
Expand All @@ -270,19 +270,22 @@ function initSearch(rawSearchIndex) {
* get the same ID.
*
* @param {string} name
* @param {boolean} isAssocType - True if this is an assoc type
*
* @returns {integer}
*/
function buildTypeMapIndex(name) {
function buildTypeMapIndex(name, isAssocType) {
if (name === "" || name === null) {
return null;
}

if (typeNameIdMap.has(name)) {
return typeNameIdMap.get(name);
const obj = typeNameIdMap.get(name);
obj.assocOnly = isAssocType && obj.assocOnly;
return obj.id;
} else {
const id = typeNameIdMap.size;
typeNameIdMap.set(name, id);
typeNameIdMap.set(name, {id, assocOnly: isAssocType});
return id;
}
}
Expand Down Expand Up @@ -1430,7 +1433,7 @@ function initSearch(rawSearchIndex) {
return true;
}
} else if (unifyFunctionTypes(
fnType.generics,
[...fnType.generics, ...Array.from(fnType.bindings.values()).flat() ],
queryElems,
whereClause,
mgens ? new Map(mgens) : null,
Expand Down Expand Up @@ -2129,17 +2132,20 @@ function initSearch(rawSearchIndex) {
* See `buildTypeMapIndex` for more information.
*
* @param {QueryElement} elem
* @param {boolean} isAssocType
*/
function convertNameToId(elem) {
if (typeNameIdMap.has(elem.pathLast)) {
elem.id = typeNameIdMap.get(elem.pathLast);
function convertNameToId(elem, isAssocType) {
if (typeNameIdMap.has(elem.pathLast) &&
(isAssocType || !typeNameIdMap.get(elem.pathLast).assocOnly)) {
elem.id = typeNameIdMap.get(elem.pathLast).id;
} else if (!parsedQuery.literalSearch) {
let match = null;
let matchDist = maxEditDistance + 1;
let matchName = "";
for (const [name, id] of typeNameIdMap) {
for (const [name, {id, assocOnly}] of typeNameIdMap) {
const dist = editDistance(name, elem.pathLast, maxEditDistance);
if (dist <= matchDist && dist <= maxEditDistance) {
if (dist <= matchDist && dist <= maxEditDistance &&
(isAssocType || !assocOnly)) {
if (dist === matchDist && matchName > name) {
continue;
}
Expand Down Expand Up @@ -2206,12 +2212,13 @@ function initSearch(rawSearchIndex) {
name,
" does not exist",
];
return [null, []];
}
for (const elem2 of constraints) {
convertNameToId(elem2);
}

return [typeNameIdMap.get(name), constraints];
return [typeNameIdMap.get(name).id, constraints];
})
);
}
Expand Down Expand Up @@ -2720,7 +2727,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
*
* @param {RawFunctionType} type
*/
function buildItemSearchType(type, lowercasePaths) {
function buildItemSearchType(type, lowercasePaths, isAssocType) {
const PATH_INDEX_DATA = 0;
const GENERICS_DATA = 1;
const BINDINGS_DATA = 2;
Expand Down Expand Up @@ -2749,7 +2756,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
//
// As a result, the key should never have generics on it.
return [
buildItemSearchType(assocType, lowercasePaths).id,
buildItemSearchType(assocType, lowercasePaths, true).id,
buildItemSearchTypeAll(constraints, lowercasePaths),
];
}));
Expand Down Expand Up @@ -2780,7 +2787,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
}
const item = lowercasePaths[pathIndex - 1];
return {
id: buildTypeMapIndex(item.name),
id: buildTypeMapIndex(item.name, isAssocType),
ty: item.ty,
path: item.path,
generics,
Expand Down
11 changes: 11 additions & 0 deletions tests/rustdoc-js/assoc-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ const EXPECTED = [
{ 'path': 'assoc_type::my', 'name': 'other_fn' },
],
},
{
'query': 'something',
'correction': null,
'others': [
{ 'path': 'assoc_type', 'name': 'Something' },
],
'in_args': [
{ 'path': 'assoc_type', 'name': 'my_fn' },
{ 'path': 'assoc_type::my', 'name': 'other_fn' },
],
},
// if I write an explicit binding, only it shows up
{
'query': 'iterator<item=something> -> u32',
Expand Down
70 changes: 70 additions & 0 deletions tests/rustdoc-js/enum-variant-not-type.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const EXPECTED = [
{
'query': 'T -> T',
'correction': null,
'others': [
{
'path': 'enum_variant_not_type',
'name': 'my_fn',
},
{
'path': 'enum_variant_not_type::AutoCorrectConfounder',
'name': 'assoc_type_acts_like_generic',
},
],
},
{
'query': 'InsertUnnecessarilyLongTypeNameHere -> InsertUnnecessarilyLongTypeNameHere',
'correction': null,
'others': [
{
'path': 'enum_variant_not_type',
'name': 'my_fn',
},
{
'path': 'enum_variant_not_type::AutoCorrectConfounder',
'name': 'assoc_type_acts_like_generic',
},
],
},
{
'query': 'InsertUnnecessarilyLongTypeNameHere',
'correction': null,
'others': [
{
'path': 'enum_variant_not_type::AutoCorrectConfounder',
'name': 'InsertUnnecessarilyLongTypeNameHere',
},
],
},
{
'query': 'InsertUnnecessarilyLongTypeNameHereX',
'correction': null,
'others': [
{
'path': 'enum_variant_not_type::AutoCorrectConfounder',
'name': 'InsertUnnecessarilyLongTypeNameHere',
},
],
},
{
'query': 'T',
'correction': null,
'others': [
{
'path': 'enum_variant_not_type::MyTrait',
'name': 'T',
},
],
},
{
'query': 'T',
'correction': null,
'others': [
{
'path': 'enum_variant_not_type::MyTrait',
'name': 'T',
},
],
},
];
14 changes: 14 additions & 0 deletions tests/rustdoc-js/enum-variant-not-type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
pub trait MyTrait {
// Reduced from `arti` crate.
// https://tpo.pages.torproject.net/core/doc/rust/tor_config/list_builder/trait.DirectDefaultEmptyListBuilderAccessors.html#associatedtype.T
type T;
fn not_appearing(&self) -> Option<&Self::T>;
}

pub fn my_fn<X>(t: X) -> X { t }

pub trait AutoCorrectConfounder {
type InsertUnnecessarilyLongTypeNameHere;
fn assoc_type_acts_like_generic(&self, x: &Self::InsertUnnecessarilyLongTypeNameHere)
-> Option<&Self::InsertUnnecessarilyLongTypeNameHere>;
}

0 comments on commit df7d23c

Please sign in to comment.