rustdoc-search: search never type with !
This feature extends rustdoc to support the syntax that most users will naturally attempt to use to search for diverging functions. Part of #60485 It's already possible to do this search with `primitive:never`, but that's not what the Rust language itself uses, so nobody will try it if they aren't told or helped along.
This commit is contained in:
parent
df77afbcaf
commit
db277f5284
@ -386,6 +386,35 @@ function initSearch(rawSearchIndex) {
|
|||||||
if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
|
if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
|
||||||
throw ["You cannot have more than one element if you use quotes"];
|
throw ["You cannot have more than one element if you use quotes"];
|
||||||
}
|
}
|
||||||
|
const typeFilter = parserState.typeFilter;
|
||||||
|
parserState.typeFilter = null;
|
||||||
|
if (name === "!") {
|
||||||
|
if (typeFilter !== null && typeFilter !== "primitive") {
|
||||||
|
throw [
|
||||||
|
"Invalid search type: primitive never type ",
|
||||||
|
"!",
|
||||||
|
" and ",
|
||||||
|
typeFilter,
|
||||||
|
" both specified",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (generics.length !== 0) {
|
||||||
|
throw [
|
||||||
|
"Never type ",
|
||||||
|
"!",
|
||||||
|
" does not accept generic parameters",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: "never",
|
||||||
|
id: -1,
|
||||||
|
fullPath: ["never"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "never",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: "primitive",
|
||||||
|
};
|
||||||
|
}
|
||||||
const pathSegments = name.split("::");
|
const pathSegments = name.split("::");
|
||||||
if (pathSegments.length > 1) {
|
if (pathSegments.length > 1) {
|
||||||
for (let i = 0, len = pathSegments.length; i < len; ++i) {
|
for (let i = 0, len = pathSegments.length; i < len; ++i) {
|
||||||
@ -399,6 +428,13 @@ function initSearch(rawSearchIndex) {
|
|||||||
}
|
}
|
||||||
throw ["Unexpected ", "::::"];
|
throw ["Unexpected ", "::::"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pathSegment === "!") {
|
||||||
|
pathSegments[i] = "never";
|
||||||
|
if (i !== 0) {
|
||||||
|
throw ["Never type ", "!", " is not associated item"];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// In case we only have something like `<p>`, there is no name.
|
// In case we only have something like `<p>`, there is no name.
|
||||||
@ -409,8 +445,6 @@ function initSearch(rawSearchIndex) {
|
|||||||
if (isInGenerics) {
|
if (isInGenerics) {
|
||||||
parserState.genericsElems += 1;
|
parserState.genericsElems += 1;
|
||||||
}
|
}
|
||||||
const typeFilter = parserState.typeFilter;
|
|
||||||
parserState.typeFilter = null;
|
|
||||||
return {
|
return {
|
||||||
name: name,
|
name: name,
|
||||||
id: -1,
|
id: -1,
|
||||||
@ -459,10 +493,11 @@ function initSearch(rawSearchIndex) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (foundExclamation !== -1) {
|
if (foundExclamation !== -1) {
|
||||||
if (start <= (end - 2)) {
|
if (foundExclamation !== start &&
|
||||||
|
isIdentCharacter(parserState.userQuery[foundExclamation - 1])
|
||||||
|
) {
|
||||||
throw ["Cannot have associated items in macros"];
|
throw ["Cannot have associated items in macros"];
|
||||||
} else {
|
} else {
|
||||||
// if start == end - 1, we got the never type
|
|
||||||
// while the never type has no associated macros, we still
|
// while the never type has no associated macros, we still
|
||||||
// can parse a path like that
|
// can parse a path like that
|
||||||
foundExclamation = -1;
|
foundExclamation = -1;
|
||||||
@ -478,7 +513,10 @@ function initSearch(rawSearchIndex) {
|
|||||||
end = parserState.pos;
|
end = parserState.pos;
|
||||||
}
|
}
|
||||||
// if start == end - 1, we got the never type
|
// if start == end - 1, we got the never type
|
||||||
if (foundExclamation !== -1 && start <= (end - 2)) {
|
if (foundExclamation !== -1 &&
|
||||||
|
foundExclamation !== start &&
|
||||||
|
isIdentCharacter(parserState.userQuery[foundExclamation - 1])
|
||||||
|
) {
|
||||||
if (parserState.typeFilter === null) {
|
if (parserState.typeFilter === null) {
|
||||||
parserState.typeFilter = "macro";
|
parserState.typeFilter = "macro";
|
||||||
} else if (parserState.typeFilter !== "macro") {
|
} else if (parserState.typeFilter !== "macro") {
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
const EXPECTED = {
|
const EXPECTED = [
|
||||||
'query': '!',
|
{
|
||||||
'others': [
|
'query': '!',
|
||||||
{ 'path': 'std', 'name': 'never' },
|
'others': [
|
||||||
],
|
{ 'path': 'std', 'name': 'never' },
|
||||||
};
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': '!::clone',
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'std::never', 'name': 'clone' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
@ -359,6 +359,15 @@ const PARSED = [
|
|||||||
userQuery: "mod:a!",
|
userQuery: "mod:a!",
|
||||||
error: 'Invalid search type: macro `!` and `mod` both specified',
|
error: 'Invalid search type: macro `!` and `mod` both specified',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
query: "mod:!",
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "mod:!",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "mod:!",
|
||||||
|
error: 'Invalid search type: primitive never type `!` and `mod` both specified',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
query: "a!::a",
|
query: "a!::a",
|
||||||
elems: [],
|
elems: [],
|
||||||
|
@ -8,11 +8,12 @@ const PARSED = [
|
|||||||
pathLast: "r",
|
pathLast: "r",
|
||||||
generics: [
|
generics: [
|
||||||
{
|
{
|
||||||
name: "!",
|
name: "never",
|
||||||
fullPath: ["!"],
|
fullPath: ["never"],
|
||||||
pathWithoutLast: [],
|
pathWithoutLast: [],
|
||||||
pathLast: "!",
|
pathLast: "never",
|
||||||
generics: [],
|
generics: [],
|
||||||
|
typeFilter: 15,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
typeFilter: -1,
|
typeFilter: -1,
|
||||||
@ -26,12 +27,12 @@ const PARSED = [
|
|||||||
{
|
{
|
||||||
query: "!",
|
query: "!",
|
||||||
elems: [{
|
elems: [{
|
||||||
name: "!",
|
name: "never",
|
||||||
fullPath: ["!"],
|
fullPath: ["never"],
|
||||||
pathWithoutLast: [],
|
pathWithoutLast: [],
|
||||||
pathLast: "!",
|
pathLast: "never",
|
||||||
generics: [],
|
generics: [],
|
||||||
typeFilter: -1,
|
typeFilter: 15,
|
||||||
}],
|
}],
|
||||||
foundElems: 1,
|
foundElems: 1,
|
||||||
original: "!",
|
original: "!",
|
||||||
@ -64,12 +65,21 @@ const PARSED = [
|
|||||||
userQuery: "a!::b",
|
userQuery: "a!::b",
|
||||||
error: "Cannot have associated items in macros",
|
error: "Cannot have associated items in macros",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
query: "!<T>",
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "!<T>",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "!<t>",
|
||||||
|
error: "Never type `!` does not accept generic parameters",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
query: "!::b",
|
query: "!::b",
|
||||||
elems: [{
|
elems: [{
|
||||||
name: "!::b",
|
name: "!::b",
|
||||||
fullPath: ["!", "b"],
|
fullPath: ["never", "b"],
|
||||||
pathWithoutLast: ["!"],
|
pathWithoutLast: ["never"],
|
||||||
pathLast: "b",
|
pathLast: "b",
|
||||||
generics: [],
|
generics: [],
|
||||||
typeFilter: -1,
|
typeFilter: -1,
|
||||||
@ -80,6 +90,58 @@ const PARSED = [
|
|||||||
userQuery: "!::b",
|
userQuery: "!::b",
|
||||||
error: null,
|
error: null,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
query: "b::!",
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "b::!",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "b::!",
|
||||||
|
error: "Never type `!` is not associated item",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: "!::!",
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "!::!",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "!::!",
|
||||||
|
error: "Never type `!` is not associated item",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: "b::!::c",
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "b::!::c",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "b::!::c",
|
||||||
|
error: "Never type `!` is not associated item",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: "!::b<T>",
|
||||||
|
elems: [{
|
||||||
|
name: "!::b",
|
||||||
|
fullPath: ["never", "b"],
|
||||||
|
pathWithoutLast: ["never"],
|
||||||
|
pathLast: "b",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "t",
|
||||||
|
fullPath: ["t"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "t",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
typeFilter: -1,
|
||||||
|
}],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "!::b<T>",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "!::b<t>",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
query: "a!::b!",
|
query: "a!::b!",
|
||||||
elems: [],
|
elems: [],
|
||||||
|
@ -84,12 +84,12 @@ const PARSED = [
|
|||||||
foundElems: 1,
|
foundElems: 1,
|
||||||
original: "-> !",
|
original: "-> !",
|
||||||
returned: [{
|
returned: [{
|
||||||
name: "!",
|
name: "never",
|
||||||
fullPath: ["!"],
|
fullPath: ["never"],
|
||||||
pathWithoutLast: [],
|
pathWithoutLast: [],
|
||||||
pathLast: "!",
|
pathLast: "never",
|
||||||
generics: [],
|
generics: [],
|
||||||
typeFilter: -1,
|
typeFilter: 15,
|
||||||
}],
|
}],
|
||||||
userQuery: "-> !",
|
userQuery: "-> !",
|
||||||
error: null,
|
error: null,
|
||||||
|
46
tests/rustdoc-js/never-search.js
Normal file
46
tests/rustdoc-js/never-search.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// exact-check
|
||||||
|
|
||||||
|
const EXPECTED = [
|
||||||
|
{
|
||||||
|
'query': '-> !',
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'never_search', 'name': 'loops' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': '-> never',
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'never_search', 'name': 'loops' },
|
||||||
|
{ 'path': 'never_search', 'name': 'returns' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': '!',
|
||||||
|
'in_args': [
|
||||||
|
{ 'path': 'never_search', 'name': 'impossible' },
|
||||||
|
{ 'path': 'never_search', 'name': 'box_impossible' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'never',
|
||||||
|
'in_args': [
|
||||||
|
{ 'path': 'never_search', 'name': 'impossible' },
|
||||||
|
{ 'path': 'never_search', 'name': 'uninteresting' },
|
||||||
|
{ 'path': 'never_search', 'name': 'box_impossible' },
|
||||||
|
{ 'path': 'never_search', 'name': 'box_uninteresting' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'box<!>',
|
||||||
|
'in_args': [
|
||||||
|
{ 'path': 'never_search', 'name': 'box_impossible' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'box<never>',
|
||||||
|
'in_args': [
|
||||||
|
{ 'path': 'never_search', 'name': 'box_impossible' },
|
||||||
|
{ 'path': 'never_search', 'name': 'box_uninteresting' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
13
tests/rustdoc-js/never-search.rs
Normal file
13
tests/rustdoc-js/never-search.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#![feature(never_type)]
|
||||||
|
|
||||||
|
#[allow(nonstandard_style)]
|
||||||
|
pub struct never;
|
||||||
|
|
||||||
|
pub fn loops() -> ! { loop {} }
|
||||||
|
pub fn returns() -> never { never }
|
||||||
|
|
||||||
|
pub fn impossible(x: !) { match x {} }
|
||||||
|
pub fn uninteresting(x: never) { match x { never => {} } }
|
||||||
|
|
||||||
|
pub fn box_impossible(x: Box<!>) { match *x {} }
|
||||||
|
pub fn box_uninteresting(x: Box<never>) { match *x { never => {} } }
|
Loading…
Reference in New Issue
Block a user