Skip to content

rustdoc search: increase strictness of typechecking #137981

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 12 additions & 5 deletions src/librustdoc/html/static/js/rustdoc.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,24 @@ declare namespace rustdoc {
* Same as QueryElement, but bindings and typeFilter support strings
*/
interface ParserQueryElement {
name: string,
name: string|null,
id: number|null,
fullPath: Array<string>,
pathWithoutLast: Array<string>,
pathLast: string,
normalizedPathLast: string,
generics: Array<ParserQueryElement>,
bindings: Map<string, Array<ParserQueryElement>>,
bindingName: {name: string, generics: ParserQueryElement[]}|null,
typeFilter: string|null,
bindingName: {name: string|null, generics: ParserQueryElement[]}|null,
typeFilter: number|string|null,
}

/**
* Same as ParserQueryElement, but all fields are optional.
*/
type ParserQueryElementFields = {
[K in keyof ParserQueryElement]?: ParserQueryElement[T]
}
/**
* Intermediate parser state. Discarded when parsing is done.
*/
Expand Down Expand Up @@ -176,10 +182,11 @@ declare namespace rustdoc {
name: string,
normalizedName: string,
word: string,
paramNames: string[],
parent: ({ty: number, name: string, path: string, exactPath: string}|null|undefined),
path: string,
ty: number,
type?: FunctionSearchType
type: FunctionSearchType | null,
}

/**
Expand Down Expand Up @@ -390,7 +397,7 @@ declare namespace rustdoc {
*/
type RawSearchIndexCrate = {
doc: string,
a: Object,
a: { [key: string]: number[] },
n: Array<string>,
t: string,
D: string,
Expand Down
69 changes: 29 additions & 40 deletions src/librustdoc/html/static/js/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,6 @@ function getNextElem(query, parserState, elems, isInGenerics) {
getFilteredNextElem(query, parserState, generics, isInGenerics);
generics[generics.length - 1].bindingName = makePrimitiveElement("output");
} else {
// @ts-expect-error
generics.push(makePrimitiveElement(null, {
bindingName: makePrimitiveElement("output"),
typeFilter: null,
Expand Down Expand Up @@ -791,7 +790,7 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {
generics: generics.filter(gen => {
// Syntactically, bindings are parsed as generics,
// but the query engine treats them differently.
if (gen.bindingName !== null) {
if (gen.bindingName !== null && gen.bindingName.name !== null) {
if (gen.name !== null) {
gen.bindingName.generics.unshift(gen);
}
Expand All @@ -811,8 +810,8 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {

/**
*
* @param {string} name
* @param {Object=} extra
* @param {string|null} name
* @param {rustdoc.ParserQueryElementFields=} extra
* @returns {rustdoc.ParserQueryElement}
*/
function makePrimitiveElement(name, extra) {
Expand Down Expand Up @@ -1478,73 +1477,61 @@ class DocSearch {
* Special type name IDs for searching by array.
* @type {number}
*/
// @ts-expect-error
this.typeNameIdOfArray = this.buildTypeMapIndex("array");
/**
* Special type name IDs for searching by slice.
* @type {number}
*/
// @ts-expect-error
this.typeNameIdOfSlice = this.buildTypeMapIndex("slice");
/**
* Special type name IDs for searching by both array and slice (`[]` syntax).
* @type {number}
*/
// @ts-expect-error
this.typeNameIdOfArrayOrSlice = this.buildTypeMapIndex("[]");
/**
* Special type name IDs for searching by tuple.
* @type {number}
*/
// @ts-expect-error
this.typeNameIdOfTuple = this.buildTypeMapIndex("tuple");
/**
* Special type name IDs for searching by unit.
* @type {number}
*/
// @ts-expect-error
this.typeNameIdOfUnit = this.buildTypeMapIndex("unit");
/**
* Special type name IDs for searching by both tuple and unit (`()` syntax).
* @type {number}
*/
// @ts-expect-error
this.typeNameIdOfTupleOrUnit = this.buildTypeMapIndex("()");
/**
* Special type name IDs for searching `fn`.
* @type {number}
*/
// @ts-expect-error
this.typeNameIdOfFn = this.buildTypeMapIndex("fn");
/**
* Special type name IDs for searching `fnmut`.
* @type {number}
*/
// @ts-expect-error
this.typeNameIdOfFnMut = this.buildTypeMapIndex("fnmut");
/**
* Special type name IDs for searching `fnonce`.
* @type {number}
*/
// @ts-expect-error
this.typeNameIdOfFnOnce = this.buildTypeMapIndex("fnonce");
/**
* Special type name IDs for searching higher order functions (`->` syntax).
* @type {number}
*/
// @ts-expect-error
this.typeNameIdOfHof = this.buildTypeMapIndex("->");
/**
* Special type name IDs the output assoc type.
* @type {number}
*/
// @ts-expect-error
this.typeNameIdOfOutput = this.buildTypeMapIndex("output", true);
/**
* Special type name IDs for searching by reference.
* @type {number}
*/
// @ts-expect-error
this.typeNameIdOfReference = this.buildTypeMapIndex("reference");

/**
Expand Down Expand Up @@ -1586,7 +1573,6 @@ class DocSearch {
/**
* @type {Array<rustdoc.Row>}
*/
// @ts-expect-error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for helping clean all this stuff up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, hopefully this should make things easier to maintain going forward.

I always planned on working on the migration if typescript got the ok, you just went and implemented half of it before I could do anything :p

I was a bit worried you were going to be put off by some of the conditional type wizardry, since it's doing things that the rust type system can't.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rust doesn't have literal types, conditional types, or overloading.

But TypeScript can't do this, because type parameters are erased.

my_function(my_iterator.collect())
                     // ^^^^^^^ magically uses the correct `FromIterator`

I don't want to hammer that square peg into Rust's round hole. Writing in JS means giving up some power while accepting power elsewhere.

this.searchIndex = this.buildIndex(rawSearchIndex);
}

Expand All @@ -1598,10 +1584,16 @@ class DocSearch {
* done more quickly. Two types with the same name but different item kinds
* get the same ID.
*
* @param {string} name
* @template T extends string
* @overload
* @param {T} name
* @param {boolean=} isAssocType - True if this is an assoc type
* @returns {T extends "" ? null : number}
*
* @param {string} name
* @param {boolean=} isAssocType
* @returns {number | null}
*
* @returns {number?}
*/
buildTypeMapIndex(name, isAssocType) {
if (name === "" || name === null) {
Expand Down Expand Up @@ -1909,6 +1901,7 @@ class DocSearch {
* Convert raw search index into in-memory search index.
*
* @param {Map<string, rustdoc.RawSearchIndexCrate>} rawSearchIndex
* @returns {rustdoc.Row[]}
*/
buildIndex(rawSearchIndex) {
/**
Expand Down Expand Up @@ -2008,6 +2001,7 @@ class DocSearch {
return cb;
};

/** @type {rustdoc.Row[]} */
const searchIndex = [];
let currentIndex = 0;
let id = 0;
Expand Down Expand Up @@ -2108,8 +2102,6 @@ class DocSearch {
// an array of [(Number) item type,
// (String) name]
const rawPaths = crateCorpus.p;
// an array of [(String) alias name
// [Number] index to items]
const aliases = crateCorpus.a;
// an array of [(Number) item index,
// (String) comma-separated list of function generic param names]
Expand Down Expand Up @@ -2232,6 +2224,7 @@ class DocSearch {
// object defined above.
const itemParentIdx = itemParentIdxDecoder.next();
normalizedName = word.indexOf("_") === -1 ? word : word.replace(/_/g, "");
/** @type {rustdoc.Row} */
const row = {
crate,
ty: itemTypes.charCodeAt(i) - 65, // 65 = "A"
Expand Down Expand Up @@ -2274,16 +2267,14 @@ class DocSearch {
continue;
}

// @ts-expect-error
/** @type{number[]} */
let currentNameAliases;
if (currentCrateAliases.has(alias_name)) {
currentNameAliases = currentCrateAliases.get(alias_name);
} else {
currentNameAliases = [];
// @ts-expect-error
currentCrateAliases.set(alias_name, currentNameAliases);
}
// @ts-expect-error
for (const local_alias of aliases[alias_name]) {
currentNameAliases.push(local_alias + currentIndex);
}
Expand Down Expand Up @@ -2326,15 +2317,13 @@ class DocSearch {
* @param {rustdoc.ParserQueryElement} elem
*/
function convertTypeFilterOnElem(elem) {
if (elem.typeFilter !== null) {
if (typeof elem.typeFilter === "string") {
let typeFilter = elem.typeFilter;
if (typeFilter === "const") {
typeFilter = "constant";
}
// @ts-expect-error
elem.typeFilter = itemTypeFromName(typeFilter);
} else {
// @ts-expect-error
elem.typeFilter = NO_TYPE_FILTER;
}
for (const elem2 of elem.generics) {
Expand Down Expand Up @@ -2407,9 +2396,9 @@ class DocSearch {
continue;
}
if (!foundStopChar) {
let extra = "";
/** @type String[] */
let extra = [];
if (isLastElemGeneric(query.elems, parserState)) {
// @ts-expect-error
extra = [" after ", ">"];
} else if (prevIs(parserState, "\"")) {
throw ["Cannot have more than one element if you use quotes"];
Expand Down Expand Up @@ -2547,7 +2536,7 @@ class DocSearch {
* See `buildTypeMapIndex` for more information.
*
* @param {rustdoc.QueryElement} elem
* @param {boolean} isAssocType
* @param {boolean=} isAssocType
*/
const convertNameToId = (elem, isAssocType) => {
const loweredName = elem.pathLast.toLowerCase();
Expand Down Expand Up @@ -2627,7 +2616,6 @@ class DocSearch {
];
}
for (const elem2 of elem.generics) {
// @ts-expect-error
convertNameToId(elem2);
}
elem.bindings = new Map(Array.from(elem.bindings.entries())
Expand Down Expand Up @@ -2750,7 +2738,11 @@ class DocSearch {
return [displayPath, href, `${exactPath}::${name}`];
};

// @ts-expect-error
/**
*
* @param {string} path
* @returns {string}
*/
function pathSplitter(path) {
const tmp = "<span>" + path.replace(/::/g, "::</span><span>");
if (tmp.endsWith("<span>")) {
Expand All @@ -2763,9 +2755,9 @@ class DocSearch {
* Add extra data to result objects, and filter items that have been
* marked for removal.
*
* @param {[rustdoc.ResultObject]} results
* @param {rustdoc.ResultObject[]} results
* @param {"sig"|"elems"|"returned"|null} typeInfo
* @returns {[rustdoc.ResultObject]}
* @returns {rustdoc.ResultObject[]}
*/
const transformResults = (results, typeInfo) => {
const duplicates = new Set();
Expand Down Expand Up @@ -2840,7 +2832,7 @@ class DocSearch {
}
let fnInputs = null;
let fnOutput = null;
// @ts-expect-error
/** @type {Map<number, number> | null} */
let mgens = null;
if (typeInfo !== "elems" && typeInfo !== "returned") {
fnInputs = unifyFunctionTypes(
Expand Down Expand Up @@ -3053,7 +3045,6 @@ class DocSearch {
writeFn(nested, result);
}
return;
// @ts-expect-error
} else if (mgens) {
for (const [queryId, fnId] of mgens) {
if (fnId === fnType.id) {
Expand All @@ -3069,7 +3060,7 @@ class DocSearch {
name: fnParamNames[-1 - fnType.id],
highlighted: !!fnType.highlighted,
}, result);
// @ts-expect-error
/** @type{string[]} */
const where = [];
onEachBtwn(
fnType.generics,
Expand All @@ -3079,7 +3070,6 @@ class DocSearch {
() => pushText({ name: " + ", highlighted: false }, where),
);
if (where.length > 0) {
// @ts-expect-error
whereClause.set(fnParamNames[-1 - fnType.id], where);
}
} else {
Expand Down Expand Up @@ -3181,7 +3171,7 @@ class DocSearch {
* @param {rustdoc.Results} results
* @param {"sig"|"elems"|"returned"|null} typeInfo
* @param {string} preferredCrate
* @returns {Promise<[rustdoc.ResultObject]>}
* @returns {Promise<rustdoc.ResultObject[]>}
*/
const sortResults = async(results, typeInfo, preferredCrate) => {
const userQuery = parsedQuery.userQuery;
Expand Down Expand Up @@ -3337,7 +3327,6 @@ class DocSearch {
return 0;
});

// @ts-expect-error
return transformResults(result_list, typeInfo);
};

Expand Down
Loading