Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
107 changes: 90 additions & 17 deletions src/librustdoc/html/static/js/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -1318,7 +1318,7 @@ function initSearch(rawSearchIndex) {
* then this function will try with a different solution, or bail with false if it
* runs out of candidates.
*
* @param {Array<FunctionType>} fnTypes - The objects to check.
* @param {Array<FunctionType>} fnTypesIn - The objects to check.
* @param {Array<QueryElement>} queryElems - The elements from the parsed query.
* @param {[FunctionType]} whereClause - Trait bounds for generic items.
* @param {Map<number,number>|null} mgensIn
Expand All @@ -1329,9 +1329,9 @@ function initSearch(rawSearchIndex) {
*/
function unifyFunctionTypes(fnTypesIn, queryElems, whereClause, mgensIn, solutionCb) {
/**
* @type Map<integer, integer>
* @type Map<integer, integer>|null
*/
let mgens = new Map(mgensIn);
let mgens = mgensIn === null ? null : new Map(mgensIn);
if (queryElems.length === 0) {
return !solutionCb || solutionCb(mgens);
}
Expand All @@ -1340,6 +1340,63 @@ function initSearch(rawSearchIndex) {
}
const ql = queryElems.length;
let fl = fnTypesIn.length;

// Fast path
if (queryElems.length === 1 && queryElems[0].generics.length === 0) {
const queryElem = queryElems[0];
for (const fnType of fnTypesIn) {
if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, whereClause, mgens)) {
continue;
}
if (fnType.id < 0 && queryElem.id < 0) {
if (mgens && mgens.has(fnType.id) &&
mgens.get(fnType.id) !== queryElem.id) {
continue;
}
const mgensScratch = new Map(mgens);
mgensScratch.set(fnType.id, queryElem.id);
if (!solutionCb || solutionCb(mgensScratch)) {
return true;
}
} else if (!solutionCb || solutionCb(mgens ? new Map(mgens) : null)) {
// unifyFunctionTypeIsMatchCandidate already checks that ids match
return true;
}
}
for (const fnType of fnTypesIn) {
if (!unifyFunctionTypeIsUnboxCandidate(fnType, queryElem, whereClause, mgens)) {
continue;
}
if (fnType.id < 0) {
if (mgens && mgens.has(fnType.id) &&
mgens.get(fnType.id) !== 0) {
continue;
}
const mgensScratch = new Map(mgens);
mgensScratch.set(fnType.id, 0);
if (unifyFunctionTypes(
whereClause[(-fnType.id) - 1],
queryElems,
whereClause,
mgensScratch,
solutionCb
)) {
return true;
}
} else if (unifyFunctionTypes(
fnType.generics,
queryElems,
whereClause,
mgens ? new Map(mgens) : null,
solutionCb
)) {
return true;
}
}
return false;
}

// Slow path
/**
* @type Array<FunctionType>
*/
Expand Down Expand Up @@ -1382,12 +1439,14 @@ function initSearch(rawSearchIndex) {
fnTypesOffset,
unbox,
} = backtracking.pop();
mgens = new Map(mgensScratch);
mgens = mgensScratch !== null ? new Map(mgensScratch) : null;
const fnType = fnTypesScratch[fnTypesOffset];
const queryElem = queryElems[queryElemsOffset];
if (unbox) {
if (fnType.id < 0) {
if (mgens.has(fnType.id) && mgens.get(fnType.id) !== 0) {
if (mgens === null) {
mgens = new Map();
} else if (mgens.has(fnType.id) && mgens.get(fnType.id) !== 0) {
continue;
}
mgens.set(fnType.id, 0);
Expand All @@ -1401,7 +1460,10 @@ function initSearch(rawSearchIndex) {
i = queryElemsOffset - 1;
} else {
if (fnType.id < 0) {
if (mgens.has(fnType.id) && mgens.get(fnType.id) !== queryElem.id) {
if (mgens === null) {
mgens = new Map();
} else if (mgens.has(fnType.id) &&
mgens.get(fnType.id) !== queryElem.id) {
continue;
}
mgens.set(fnType.id, queryElem.id);
Expand Down Expand Up @@ -1456,7 +1518,7 @@ function initSearch(rawSearchIndex) {
if (!fnTypesScratch) {
fnTypesScratch = fnTypes.slice();
}
if (!mgensScratch) {
if (!mgensScratch && mgens !== null) {
mgensScratch = new Map(mgens);
}
backtracking.push({
Expand All @@ -1478,10 +1540,19 @@ function initSearch(rawSearchIndex) {
// use the current candidate
const {fnTypesOffset: candidate, mgensScratch: mgensNew} = matchCandidates.pop();
if (fnTypes[candidate].id < 0 && queryElems[i].id < 0) {
if (mgens === null) {
mgens = new Map();
}
mgens.set(fnTypes[candidate].id, queryElems[i].id);
}
for (const [fid, qid] of mgensNew) {
mgens.set(fid, qid);
if (mgensNew !== null) {
if (mgens === null) {
mgens = mgensNew;
} else {
for (const [fid, qid] of mgensNew) {
mgens.set(fid, qid);
}
}
}
// `i` and `j` are paired off
// `queryElems[i]` is left in place
Expand Down Expand Up @@ -1514,15 +1585,17 @@ function initSearch(rawSearchIndex) {
// or, if mgens[fnType.id] = 0, then we've matched this generic with a bare trait
// and should make that same decision everywhere it appears
if (fnType.id < 0 && queryElem.id < 0) {
if (mgens.has(fnType.id) && mgens.get(fnType.id) !== queryElem.id) {
return false;
}
for (const [fid, qid] of mgens.entries()) {
if (fnType.id !== fid && queryElem.id === qid) {
if (mgens !== null) {
if (mgens.has(fnType.id) && mgens.get(fnType.id) !== queryElem.id) {
return false;
}
if (fnType.id === fid && queryElem.id !== qid) {
return false;
for (const [fid, qid] of mgens.entries()) {
if (fnType.id !== fid && queryElem.id === qid) {
return false;
}
if (fnType.id === fid && queryElem.id !== qid) {
return false;
}
}
}
} else {
Expand Down Expand Up @@ -1575,7 +1648,7 @@ function initSearch(rawSearchIndex) {
}
// mgens[fnType.id] === 0 indicates that we committed to unboxing this generic
// mgens[fnType.id] === null indicates that we haven't decided yet
if (mgens.has(fnType.id) && mgens.get(fnType.id) !== 0) {
if (mgens !== null && mgens.has(fnType.id) && mgens.get(fnType.id) !== 0) {
return false;
}
// This is only a potential unbox if the search query appears in the where clause
Expand Down
22 changes: 22 additions & 0 deletions tests/rustdoc-js/generics2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// exact-check

const EXPECTED = [
{
'query': 'outside<U>, outside<V> -> outside<W>',
'others': [],
},
{
'query': 'outside<V>, outside<U> -> outside<W>',
'others': [],
},
{
'query': 'outside<U>, outside<U> -> outside<W>',
'others': [],
},
{
'query': 'outside<U>, outside<U> -> outside<U>',
'others': [
{"path": "generics2", "name": "should_match_3"}
],
},
];
13 changes: 13 additions & 0 deletions tests/rustdoc-js/generics2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pub struct Outside<T>(T);

pub fn no_match<U, V>(a: Outside<U>, b: Outside<V>) -> (Outside<U>, Outside<V>) {
unimplemented!();
}

pub fn no_match_2<U, V>(a: Outside<V>, b: Outside<U>) -> (Outside<U>, Outside<V>) {
unimplemented!();
}

pub fn should_match_3<U>(a: Outside<U>, b: Outside<U>) -> (Outside<U>, Outside<U>) {
unimplemented!();
}