From 92b84f849a63af6454845452ee8a5567d6956302 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 10 Dec 2023 16:05:18 -0700 Subject: [PATCH] rustdoc-search: do not treat associated type names as types Before: http://notriddle.com/rustdoc-html-demo-6/tor-before/tor_config/ After: http://notriddle.com/rustdoc-html-demo-6/tor-after/tor_config/ Profile: http://notriddle.com/rustdoc-html-demo-6/tor-profile/ 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. --- src/librustdoc/html/static/js/search.js | 33 ++++++----- tests/rustdoc-js/enum-variant-not-type.js | 70 +++++++++++++++++++++++ tests/rustdoc-js/enum-variant-not-type.rs | 14 +++++ 3 files changed, 104 insertions(+), 13 deletions(-) create mode 100644 tests/rustdoc-js/enum-variant-not-type.js create mode 100644 tests/rustdoc-js/enum-variant-not-type.rs diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 8f68796ad26..832ac427112 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -243,7 +243,7 @@ function initSearch(rawSearchIndex) { * Map from normalized type names to integers. Used to make type search * more efficient. * - * @type {Map} + * @type {Map} */ let typeNameIdMap; const ALIASES = new Map(); @@ -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; } } @@ -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; } @@ -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]; }) ); } @@ -2720,7 +2727,7 @@ ${item.displayPath}${name}\ * * @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; @@ -2749,7 +2756,7 @@ ${item.displayPath}${name}\ // // As a result, the key should never have generics on it. return [ - buildItemSearchType(assocType, lowercasePaths).id, + buildItemSearchType(assocType, lowercasePaths, true).id, buildItemSearchTypeAll(constraints, lowercasePaths), ]; })); @@ -2780,7 +2787,7 @@ ${item.displayPath}${name}\ } const item = lowercasePaths[pathIndex - 1]; return { - id: buildTypeMapIndex(item.name), + id: buildTypeMapIndex(item.name, isAssocType), ty: item.ty, path: item.path, generics, diff --git a/tests/rustdoc-js/enum-variant-not-type.js b/tests/rustdoc-js/enum-variant-not-type.js new file mode 100644 index 00000000000..b0f1ec66658 --- /dev/null +++ b/tests/rustdoc-js/enum-variant-not-type.js @@ -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', + }, + ], + }, +]; diff --git a/tests/rustdoc-js/enum-variant-not-type.rs b/tests/rustdoc-js/enum-variant-not-type.rs new file mode 100644 index 00000000000..421bddf6289 --- /dev/null +++ b/tests/rustdoc-js/enum-variant-not-type.rs @@ -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(t: X) -> X { t } + +pub trait AutoCorrectConfounder { + type InsertUnnecessarilyLongTypeNameHere; + fn assoc_type_acts_like_generic(&self, x: &Self::InsertUnnecessarilyLongTypeNameHere) + -> Option<&Self::InsertUnnecessarilyLongTypeNameHere>; +}