Auto merge of #96263 - Dylan-DPC:rollup-0eofl13, r=Dylan-DPC

Rollup of 5 pull requests

Successful merges:

 - #90630 (Create real parser for search queries)
 - #96193 ([fuchsia] Add implementation for `current_exe`)
 - #96196 (Remove assertion that all paths in `ShouldRun` exist)
 - #96228 (Fix locations for intrinsics impls and change to links)
 - #96236 (Add an explicit `Span` field to `OutlivesConstraint`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors
2022-04-21 02:16:32 +00:00
40 changed files with 2390 additions and 532 deletions
@@ -156,6 +156,7 @@ fn next(&mut self) -> Option<Self::Item> {
sup: self.static_region,
sub: next_static_idx.into(),
locations: Locations::All(DUMMY_SP),
span: DUMMY_SP,
category: ConstraintCategory::Internal,
variance_info: VarianceDiagInfo::default(),
})
@@ -2,6 +2,7 @@
use rustc_index::vec::IndexVec;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
use rustc_span::Span;
use std::fmt;
use std::ops::Index;
@@ -87,6 +88,12 @@ pub struct OutlivesConstraint<'tcx> {
/// Where did this constraint arise?
pub locations: Locations,
/// The `Span` associated with the creation of this constraint.
/// This should be used in preference to obtaining the span from
/// `locations`, since the `locations` may give a poor span
/// in some cases (e.g. converting a constraint from a promoted).
pub span: Span,
/// What caused this constraint?
pub category: ConstraintCategory,
@@ -74,14 +74,18 @@ fn for_each_constraint(
let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
constraints.sort_by_key(|c| (c.sup, c.sub));
for constraint in &constraints {
let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
let OutlivesConstraint { sup, sub, locations, category, span, variance_info: _ } =
constraint;
let (name, arg) = match locations {
Locations::All(span) => {
("All", tcx.sess.source_map().span_to_embeddable_string(*span))
}
Locations::Single(loc) => ("Single", format!("{:?}", loc)),
};
with_msg(&format!("{:?}: {:?} due to {:?} at {}({})", sup, sub, category, name, arg))?;
with_msg(&format!(
"{:?}: {:?} due to {:?} at {}({}) ({:?}",
sup, sub, category, name, arg, span
))?;
}
Ok(())
@@ -1733,7 +1733,7 @@ fn check_member_constraints(
crate fn retrieve_closure_constraint_info(
&self,
body: &Body<'tcx>,
_body: &Body<'tcx>,
constraint: &OutlivesConstraint<'tcx>,
) -> BlameConstraint<'tcx> {
let loc = match constraint.locations {
@@ -1760,7 +1760,7 @@ fn check_member_constraints(
.unwrap_or(BlameConstraint {
category: constraint.category,
from_closure: false,
cause: ObligationCause::dummy_with_span(body.source_info(loc).span),
cause: ObligationCause::dummy_with_span(constraint.span),
variance_info: constraint.variance_info,
})
}
@@ -1869,6 +1869,7 @@ fn check_member_constraints(
sup: r,
sub: constraint.min_choice,
locations: Locations::All(p_c.definition_span),
span: p_c.definition_span,
category: ConstraintCategory::OpaqueType,
variance_info: ty::VarianceDiagInfo::default(),
};
@@ -2017,7 +2018,7 @@ fn check_member_constraints(
category: constraint.category,
from_closure: false,
cause: ObligationCause::new(
constraint.locations.span(body),
constraint.span,
CRATE_HIR_ID,
cause_code.clone(),
),
@@ -8,7 +8,7 @@
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::DUMMY_SP;
use rustc_span::{Span, DUMMY_SP};
use crate::{
constraints::OutlivesConstraint,
@@ -26,6 +26,7 @@
implicit_region_bound: Option<ty::Region<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
locations: Locations,
span: Span,
category: ConstraintCategory,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
}
@@ -38,6 +39,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
implicit_region_bound: Option<ty::Region<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
locations: Locations,
span: Span,
category: ConstraintCategory,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
) -> Self {
@@ -49,6 +51,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
implicit_region_bound,
param_env,
locations,
span,
category,
constraints,
}
@@ -153,6 +156,7 @@ fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
self.constraints.outlives_constraints.push(OutlivesConstraint {
locations: self.locations,
category: self.category,
span: self.span,
sub,
sup,
variance_info: ty::VarianceDiagInfo::default(),
@@ -316,6 +316,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
self.implicit_region_bound,
self.param_env,
Locations::All(DUMMY_SP),
DUMMY_SP,
ConstraintCategory::Internal,
&mut self.constraints,
)
@@ -235,6 +235,7 @@ pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<
Some(self.implicit_region_bound),
self.param_env,
Locations::All(DUMMY_SP),
DUMMY_SP,
ConstraintCategory::Internal,
&mut self.borrowck_context.constraints,
)
@@ -1141,6 +1141,7 @@ fn push_region_constraints(
Some(self.implicit_region_bound),
self.param_env,
locations,
locations.span(self.body),
category,
&mut self.borrowck_context.constraints,
)
@@ -2401,6 +2402,7 @@ fn add_reborrow_constraint(
sup: ref_region.to_region_vid(),
sub: borrow_region.to_region_vid(),
locations: location.to_locations(),
span: location.to_locations().span(body),
category,
variance_info: ty::VarianceDiagInfo::default(),
});
@@ -116,6 +116,7 @@ fn push_outlives(
sup,
sub,
locations: self.locations,
span: self.locations.span(self.type_checker.body),
category: self.category,
variance_info: info,
},
+4 -4
View File
@@ -1,7 +1,7 @@
//! Compiler intrinsics.
//!
//! The corresponding definitions are in `compiler/rustc_codegen_llvm/src/intrinsic.rs`.
//! The corresponding const implementations are in `compiler/rustc_mir/src/interpret/intrinsics.rs`
//! The corresponding definitions are in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_llvm/src/intrinsic.rs>.
//! The corresponding const implementations are in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs>.
//!
//! # Const intrinsics
//!
@@ -10,8 +10,8 @@
//!
//! In order to make an intrinsic usable at compile-time, one needs to copy the implementation
//! from <https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs> to
//! `compiler/rustc_mir/src/interpret/intrinsics.rs` and add a
//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic.
//! <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs> and add a
//! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration.
//!
//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
+21 -1
View File
@@ -427,7 +427,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
crate::fs::read_to_string("sys:exe").map(PathBuf::from)
}
#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
#[cfg(target_os = "l4re")]
pub fn current_exe() -> io::Result<PathBuf> {
use crate::io::ErrorKind;
Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!"))
@@ -451,6 +451,26 @@ pub fn current_exe() -> io::Result<PathBuf> {
super::unsupported::unsupported()
}
#[cfg(target_os = "fuchsia")]
pub fn current_exe() -> io::Result<PathBuf> {
use crate::io::ErrorKind;
#[cfg(test)]
use realstd::env;
#[cfg(not(test))]
use crate::env;
let exe_path = env::args().next().ok_or(io::const_io_error!(
ErrorKind::Uncategorized,
"an executable path was not found because no arguments were provided through argv"
))?;
let path = PathBuf::from(exe_path);
// Prepend the current working directory to the path if it's not absolute.
if !path.is_absolute() { getcwd().map(|cwd| cwd.join(path)) } else { Ok(path) }
}
pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
}
+7 -5
View File
@@ -388,11 +388,13 @@ pub fn paths(mut self, paths: &[&str]) -> Self {
paths
.iter()
.map(|p| {
assert!(
self.builder.src.join(p).exists(),
"`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}",
p
);
// FIXME(#96188): make sure this is actually a path.
// This currently breaks for paths within submodules.
//assert!(
// self.builder.src.join(p).exists(),
// "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}",
// p
//);
TaskPath { path: p.into(), kind: Some(self.kind) }
})
.collect(),
+55 -4
View File
@@ -8,10 +8,34 @@ function initSearch(searchIndex){}
/**
* @typedef {{
* raw: string,
* query: string,
* type: string,
* id: string,
* name: string,
* fullPath: Array<string>,
* pathWithoutLast: Array<string>,
* pathLast: string,
* generics: Array<QueryElement>,
* }}
*/
var QueryElement;
/**
* @typedef {{
* pos: number,
* totalElems: number,
* typeFilter: (null|string),
* userQuery: string,
* }}
*/
var ParserState;
/**
* @typedef {{
* original: string,
* userQuery: string,
* typeFilter: number,
* elems: Array<QueryElement>,
* args: Array<QueryElement>,
* returned: Array<QueryElement>,
* foundElems: number,
* }}
*/
var ParsedQuery;
@@ -30,3 +54,30 @@ var ParsedQuery;
* }}
*/
var Row;
/**
* @typedef {{
* in_args: Array<Object>,
* returned: Array<Object>,
* others: Array<Object>,
* query: ParsedQuery,
* }}
*/
var ResultsTable;
/**
* @typedef {{
* desc: string,
* displayPath: string,
* fullPath: string,
* href: string,
* id: number,
* lev: number,
* name: string,
* normalizedName: string,
* parent: (Object|undefined),
* path: string,
* ty: number,
* }}
*/
var Results;
+956 -422
View File
@@ -61,15 +61,6 @@ function printTab(nb) {
});
}
function removeEmptyStringsFromArray(x) {
for (var i = 0, len = x.length; i < len; ++i) {
if (x[i] === "") {
x.splice(i, 1);
i -= 1;
}
}
}
/**
* A function to compute the Levenshtein distance between two strings
* Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
@@ -133,11 +124,436 @@ window.initSearch = function(rawSearchIndex) {
searchState.input.value = params.search || "";
}
function isWhitespace(c) {
return " \t\n\r".indexOf(c) !== -1;
}
function isSpecialStartCharacter(c) {
return "<\"".indexOf(c) !== -1;
}
function isEndCharacter(c) {
return ",>-".indexOf(c) !== -1;
}
function isStopCharacter(c) {
return isWhitespace(c) || isEndCharacter(c);
}
function isErrorCharacter(c) {
return "()".indexOf(c) !== -1;
}
function itemTypeFromName(typename) {
for (var i = 0, len = itemTypes.length; i < len; ++i) {
if (itemTypes[i] === typename) {
return i;
}
}
throw new Error("Unknown type filter `" + typename + "`");
}
/**
* If we encounter a `"`, then we try to extract the string from it until we find another `"`.
*
* This function will throw an error in the following cases:
* * There is already another string element.
* * We are parsing a generic argument.
* * There is more than one element.
* * There is no closing `"`.
*
* @param {ParsedQuery} query
* @param {ParserState} parserState
* @param {boolean} isInGenerics
*/
function getStringElem(query, parserState, isInGenerics) {
if (isInGenerics) {
throw new Error("`\"` cannot be used in generics");
} else if (query.literalSearch) {
throw new Error("Cannot have more than one literal search element");
} else if (parserState.totalElems - parserState.genericsElems > 0) {
throw new Error("Cannot use literal search when there is more than one element");
}
parserState.pos += 1;
var start = parserState.pos;
var end = getIdentEndPosition(parserState);
if (parserState.pos >= parserState.length) {
throw new Error("Unclosed `\"`");
} else if (parserState.userQuery[end] !== "\"") {
throw new Error(`Unexpected \`${parserState.userQuery[end]}\` in a string element`);
} else if (start === end) {
throw new Error("Cannot have empty string element");
}
// To skip the quote at the end.
parserState.pos += 1;
query.literalSearch = true;
}
/**
* Returns `true` if the current parser position is starting with "::".
*
* @param {ParserState} parserState
*
* @return {boolean}
*/
function isPathStart(parserState) {
return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '::';
}
/**
* Returns `true` if the current parser position is starting with "->".
*
* @param {ParserState} parserState
*
* @return {boolean}
*/
function isReturnArrow(parserState) {
return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '->';
}
/**
* Returns `true` if the given `c` character is valid for an ident.
*
* @param {string} c
*
* @return {boolean}
*/
function isIdentCharacter(c) {
return (
c === '_' ||
(c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z'));
}
/**
* Returns `true` if the given `c` character is a separator.
*
* @param {string} c
*
* @return {boolean}
*/
function isSeparatorCharacter(c) {
return c === "," || isWhitespaceCharacter(c);
}
/**
* Returns `true` if the given `c` character is a whitespace.
*
* @param {string} c
*
* @return {boolean}
*/
function isWhitespaceCharacter(c) {
return c === " " || c === "\t";
}
/**
* @param {ParsedQuery} query
* @param {ParserState} parserState
* @param {string} name - Name of the query element.
* @param {Array<QueryElement>} generics - List of generics of this query element.
*
* @return {QueryElement} - The newly created `QueryElement`.
*/
function createQueryElement(query, parserState, name, generics, isInGenerics) {
if (name === '*' || (name.length === 0 && generics.length === 0)) {
return;
}
if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
throw new Error("You cannot have more than one element if you use quotes");
}
var pathSegments = name.split("::");
if (pathSegments.length > 1) {
for (var i = 0, len = pathSegments.length; i < len; ++i) {
var pathSegment = pathSegments[i];
if (pathSegment.length === 0) {
if (i === 0) {
throw new Error("Paths cannot start with `::`");
} else if (i + 1 === len) {
throw new Error("Paths cannot end with `::`");
}
throw new Error("Unexpected `::::`");
}
}
}
// In case we only have something like `<p>`, there is no name.
if (pathSegments.length === 0 || (pathSegments.length === 1 && pathSegments[0] === "")) {
throw new Error("Found generics without a path");
}
parserState.totalElems += 1;
if (isInGenerics) {
parserState.genericsElems += 1;
}
return {
name: name,
fullPath: pathSegments,
pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1),
pathLast: pathSegments[pathSegments.length - 1],
generics: generics,
};
}
/**
* This function goes through all characters until it reaches an invalid ident character or the
* end of the query. It returns the position of the last character of the ident.
*
* @param {ParserState} parserState
*
* @return {integer}
*/
function getIdentEndPosition(parserState) {
var end = parserState.pos;
while (parserState.pos < parserState.length) {
var c = parserState.userQuery[parserState.pos];
if (!isIdentCharacter(c)) {
if (isErrorCharacter(c)) {
throw new Error(`Unexpected \`${c}\``);
} else if (
isStopCharacter(c) ||
isSpecialStartCharacter(c) ||
isSeparatorCharacter(c))
{
break;
}
// If we allow paths ("str::string" for example).
else if (c === ":") {
if (!isPathStart(parserState)) {
break;
}
// Skip current ":".
parserState.pos += 1;
} else {
throw new Error(`Unexpected \`${c}\``);
}
}
parserState.pos += 1;
end = parserState.pos;
}
return end;
}
/**
* @param {ParsedQuery} query
* @param {ParserState} parserState
* @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
* @param {boolean} isInGenerics
*/
function getNextElem(query, parserState, elems, isInGenerics) {
var generics = [];
var start = parserState.pos;
var end;
// We handle the strings on their own mostly to make code easier to follow.
if (parserState.userQuery[parserState.pos] === "\"") {
start += 1;
getStringElem(query, parserState, isInGenerics);
end = parserState.pos - 1;
} else {
end = getIdentEndPosition(parserState);
}
if (parserState.pos < parserState.length &&
parserState.userQuery[parserState.pos] === "<")
{
if (isInGenerics) {
throw new Error("Unexpected `<` after `<`");
} else if (start >= end) {
throw new Error("Found generics without a path");
}
parserState.pos += 1;
getItemsBefore(query, parserState, generics, ">");
}
if (start >= end && generics.length === 0) {
return;
}
elems.push(
createQueryElement(
query,
parserState,
parserState.userQuery.slice(start, end),
generics,
isInGenerics
)
);
}
/**
* This function parses the next query element until it finds `endChar`, calling `getNextElem`
* to collect each element.
*
* If there is no `endChar`, this function will implicitly stop at the end without raising an
* error.
*
* @param {ParsedQuery} query
* @param {ParserState} parserState
* @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
* @param {string} endChar - This function will stop when it'll encounter this
* character.
*/
function getItemsBefore(query, parserState, elems, endChar) {
var foundStopChar = true;
while (parserState.pos < parserState.length) {
var c = parserState.userQuery[parserState.pos];
if (c === endChar) {
break;
} else if (isSeparatorCharacter(c)) {
parserState.pos += 1;
foundStopChar = true;
continue;
} else if (c === ":" && isPathStart(parserState)) {
throw new Error("Unexpected `::`: paths cannot start with `::`");
} else if (c === ":" || isEndCharacter(c)) {
var extra = "";
if (endChar === ">") {
extra = "`<`";
} else if (endChar === "") {
extra = "`->`";
}
throw new Error("Unexpected `" + c + "` after " + extra);
}
if (!foundStopChar) {
if (endChar !== "") {
throw new Error(`Expected \`,\`, \` \` or \`${endChar}\`, found \`${c}\``);
}
throw new Error(`Expected \`,\` or \` \`, found \`${c}\``);
}
var posBefore = parserState.pos;
getNextElem(query, parserState, elems, endChar === ">");
// This case can be encountered if `getNextElem` encounted a "stop character" right from
// the start. For example if you have `,,` or `<>`. In this case, we simply move up the
// current position to continue the parsing.
if (posBefore === parserState.pos) {
parserState.pos += 1;
}
foundStopChar = false;
}
// We are either at the end of the string or on the `endChar`` character, let's move forward
// in any case.
parserState.pos += 1;
}
/**
* Checks that the type filter doesn't have unwanted characters like `<>` (which are ignored
* if empty).
*
* @param {ParserState} parserState
*/
function checkExtraTypeFilterCharacters(parserState) {
var query = parserState.userQuery;
for (var pos = 0; pos < parserState.pos; ++pos) {
if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) {
throw new Error(`Unexpected \`${query[pos]}\` in type filter`);
}
}
}
/**
* Parses the provided `query` input to fill `parserState`. If it encounters an error while
* parsing `query`, it'll throw an error.
*
* @param {ParsedQuery} query
* @param {ParserState} parserState
*/
function parseInput(query, parserState) {
var c, before;
var foundStopChar = true;
while (parserState.pos < parserState.length) {
c = parserState.userQuery[parserState.pos];
if (isStopCharacter(c)) {
foundStopChar = true;
if (isSeparatorCharacter(c)) {
parserState.pos += 1;
continue;
} else if (c === "-" || c === ">") {
if (isReturnArrow(parserState)) {
break;
}
throw new Error(`Unexpected \`${c}\` (did you mean \`->\`?)`);
}
throw new Error(`Unexpected \`${c}\``);
} else if (c === ":" && !isPathStart(parserState)) {
if (parserState.typeFilter !== null) {
throw new Error("Unexpected `:`");
}
if (query.elems.length === 0) {
throw new Error("Expected type filter before `:`");
} else if (query.elems.length !== 1 || parserState.totalElems !== 1) {
throw new Error("Unexpected `:`");
} else if (query.literalSearch) {
throw new Error("You cannot use quotes on type filter");
}
checkExtraTypeFilterCharacters(parserState);
// The type filter doesn't count as an element since it's a modifier.
parserState.typeFilter = query.elems.pop().name;
parserState.pos += 1;
parserState.totalElems = 0;
query.literalSearch = false;
foundStopChar = true;
continue;
}
if (!foundStopChar) {
if (parserState.typeFilter !== null) {
throw new Error(`Expected \`,\`, \` \` or \`->\`, found \`${c}\``);
}
throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``);
}
before = query.elems.length;
getNextElem(query, parserState, query.elems, false);
if (query.elems.length === before) {
// Nothing was added, weird... Let's increase the position to not remain stuck.
parserState.pos += 1;
}
foundStopChar = false;
}
while (parserState.pos < parserState.length) {
c = parserState.userQuery[parserState.pos];
if (isReturnArrow(parserState)) {
parserState.pos += 2;
// Get returned elements.
getItemsBefore(query, parserState, query.returned, "");
// Nothing can come afterward!
if (query.returned.length === 0) {
throw new Error("Expected at least one item after `->`");
}
break;
} else {
parserState.pos += 1;
}
}
}
/**
* Takes the user search input and returns an empty `ParsedQuery`.
*
* @param {string} userQuery
*
* @return {ParsedQuery}
*/
function newParsedQuery(userQuery) {
return {
original: userQuery,
userQuery: userQuery.toLowerCase(),
typeFilter: NO_TYPE_FILTER,
elems: [],
returned: [],
// Total number of "top" elements (does not include generics).
foundElems: 0,
literalSearch: false,
error: null,
};
}
/**
* Build an URL with search parameters.
*
* @param {string} search - The current search being performed.
* @param {string|null} filterCrates - The current filtering crate (if any).
*
* @return {string}
*/
function buildUrl(search, filterCrates) {
@@ -167,33 +583,139 @@ window.initSearch = function(rawSearchIndex) {
}
/**
* Executes the query and returns a list of results for each results tab.
* @param {Object} query - The user query
* @param {Array<string>} searchWords - The list of search words to query against
* @param {string} [filterCrates] - Crate to search in
* @return {{
* in_args: Array<?>,
* returned: Array<?>,
* others: Array<?>
* }}
* Parses the query.
*
* The supported syntax by this parser is as follow:
*
* ident = *(ALPHA / DIGIT / "_")
* path = ident *(DOUBLE-COLON ident)
* arg = path [generics]
* arg-without-generic = path
* type-sep = COMMA/WS *(COMMA/WS)
* nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
* nonempty-arg-list-without-generics = *(type-sep) arg-without-generic
* *(type-sep arg-without-generic) *(type-sep)
* generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list-without-generics ] *(type-sep)
* CLOSE-ANGLE-BRACKET/EOF
* return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
*
* exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
* type-search = [type-filter *WS COLON] [ nonempty-arg-list ] [ return-args ]
*
* query = *WS (exact-search / type-search) *WS
*
* type-filter = (
* "mod" /
* "externcrate" /
* "import" /
* "struct" /
* "enum" /
* "fn" /
* "type" /
* "static" /
* "trait" /
* "impl" /
* "tymethod" /
* "method" /
* "structfield" /
* "variant" /
* "macro" /
* "primitive" /
* "associatedtype" /
* "constant" /
* "associatedconstant" /
* "union" /
* "foreigntype" /
* "keyword" /
* "existential" /
* "attr" /
* "derive" /
* "traitalias")
*
* OPEN-ANGLE-BRACKET = "<"
* CLOSE-ANGLE-BRACKET = ">"
* COLON = ":"
* DOUBLE-COLON = "::"
* QUOTE = %x22
* COMMA = ","
* RETURN-ARROW = "->"
*
* ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
* DIGIT = %x30-39
* WS = %x09 / " "
*
* @param {string} val - The user query
*
* @return {ParsedQuery} - The parsed query
*/
function execQuery(query, searchWords, filterCrates) {
function itemTypeFromName(typename) {
for (var i = 0, len = itemTypes.length; i < len; ++i) {
if (itemTypes[i] === typename) {
return i;
function parseQuery(userQuery) {
userQuery = userQuery.trim();
var parserState = {
length: userQuery.length,
pos: 0,
// Total number of elements (includes generics).
totalElems: 0,
genericsElems: 0,
typeFilter: null,
userQuery: userQuery.toLowerCase(),
};
var query = newParsedQuery(userQuery);
try {
parseInput(query, parserState);
if (parserState.typeFilter !== null) {
var typeFilter = parserState.typeFilter;
if (typeFilter === "const") {
typeFilter = "constant";
}
query.typeFilter = itemTypeFromName(typeFilter);
}
return NO_TYPE_FILTER;
} catch (err) {
query = newParsedQuery(userQuery);
query.error = err.message;
query.typeFilter = -1;
return query;
}
var valLower = query.query.toLowerCase(),
val = valLower,
typeFilter = itemTypeFromName(query.type),
results = {}, results_in_args = {}, results_returned = {},
split = valLower.split("::");
if (!query.literalSearch) {
// If there is more than one element in the query, we switch to literalSearch in any
// case.
query.literalSearch = parserState.totalElems > 1;
}
query.foundElems = query.elems.length + query.returned.length;
return query;
}
removeEmptyStringsFromArray(split);
/**
* Creates the query results.
*
* @param {Array<Result>} results_in_args
* @param {Array<Result>} results_returned
* @param {Array<Result>} results_in_args
* @param {ParsedQuery} parsedQuery
*
* @return {ResultsTable}
*/
function createQueryResults(results_in_args, results_returned, results_others, parsedQuery) {
return {
"in_args": results_in_args,
"returned": results_returned,
"others": results_others,
"query": parsedQuery,
};
}
/**
* Executes the parsed query and builds a {ResultsTable}.
*
* @param {ParsedQuery} parsedQuery - The parsed user query
* @param {Object} searchWords - The list of search words to query against
* @param {Object} [filterCrates] - Crate to search in if defined
*
* @return {ResultsTable}
*/
function execQuery(parsedQuery, searchWords, filterCrates) {
var results_others = {}, results_in_args = {}, results_returned = {};
function transformResults(results) {
var duplicates = {};
@@ -227,6 +749,7 @@ window.initSearch = function(rawSearchIndex) {
}
function sortResults(results, isType) {
var userQuery = parsedQuery.userQuery;
var ar = [];
for (var entry in results) {
if (hasOwnPropertyRustdoc(results, entry)) {
@@ -246,8 +769,8 @@ window.initSearch = function(rawSearchIndex) {
var a, b;
// sort by exact match with regard to the last word (mismatch goes later)
a = (aaa.word !== val);
b = (bbb.word !== val);
a = (aaa.word !== userQuery);
b = (bbb.word !== userQuery);
if (a !== b) { return a - b; }
// Sort by non levenshtein results and then levenshtein results by the distance
@@ -309,6 +832,12 @@ window.initSearch = function(rawSearchIndex) {
return 0;
});
var nameSplit = null;
if (parsedQuery.elems.length === 1) {
var hasPath = typeof parsedQuery.elems[0].path === "undefined";
nameSplit = hasPath ? null : parsedQuery.elems[0].path;
}
for (var i = 0, len = results.length; i < len; ++i) {
result = results[i];
@@ -320,215 +849,222 @@ window.initSearch = function(rawSearchIndex) {
path = result.item.path.toLowerCase(),
parent = result.item.parent;
if (!isType && !validateResult(name, path, split, parent)) {
if (!isType && !validateResult(name, path, nameSplit, parent)) {
result.id = -1;
}
}
return transformResults(results);
}
function extractGenerics(val) {
val = val.toLowerCase();
if (val.indexOf("<") !== -1) {
var values = val.substring(val.indexOf("<") + 1, val.lastIndexOf(">"));
return {
name: val.substring(0, val.indexOf("<")),
generics: values.split(/\s*,\s*/),
};
/**
* This function checks if the object (`row`) generics match the given type (`elem`)
* generics. If there are no generics on `row`, `defaultLev` is returned.
*
* @param {Row} row - The object to check.
* @param {QueryElement} elem - The element from the parsed query.
* @param {integer} defaultLev - This is the value to return in case there are no generics.
*
* @return {integer} - Returns the best match (if any) or `MAX_LEV_DISTANCE + 1`.
*/
function checkGenerics(row, elem, defaultLev) {
if (row.length <= GENERICS_DATA || row[GENERICS_DATA].length === 0) {
return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
} else if (row[GENERICS_DATA].length > 0 && row[GENERICS_DATA][0][NAME] === "") {
if (row.length > GENERICS_DATA) {
return checkGenerics(row[GENERICS_DATA][0], elem, defaultLev);
}
return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
}
return {
name: val,
generics: [],
};
}
function checkGenerics(obj, val) {
// The names match, but we need to be sure that all generics kinda
// match as well.
var tmp_lev, elem_name;
if (val.generics.length > 0) {
if (obj.length > GENERICS_DATA &&
obj[GENERICS_DATA].length >= val.generics.length) {
var elems = Object.create(null);
var elength = obj[GENERICS_DATA].length;
for (var x = 0; x < elength; ++x) {
if (!elems[obj[GENERICS_DATA][x][NAME]]) {
elems[obj[GENERICS_DATA][x][NAME]] = 0;
}
elems[obj[GENERICS_DATA][x][NAME]] += 1;
}
var total = 0;
var done = 0;
// We need to find the type that matches the most to remove it in order
// to move forward.
var vlength = val.generics.length;
for (x = 0; x < vlength; ++x) {
var lev = MAX_LEV_DISTANCE + 1;
var firstGeneric = val.generics[x];
var match = null;
if (elems[firstGeneric]) {
match = firstGeneric;
lev = 0;
} else {
for (elem_name in elems) {
tmp_lev = levenshtein(elem_name, firstGeneric);
if (tmp_lev < lev) {
lev = tmp_lev;
match = elem_name;
}
}
}
if (match !== null) {
elems[match] -= 1;
if (elems[match] == 0) {
delete elems[match];
}
total += lev;
done += 1;
} else {
var elem_name;
if (elem.generics.length > 0 && row[GENERICS_DATA].length >= elem.generics.length) {
var elems = Object.create(null);
for (var x = 0, length = row[GENERICS_DATA].length; x < length; ++x) {
elem_name = row[GENERICS_DATA][x][NAME];
if (elem_name === "") {
// Pure generic, needs to check into it.
if (checkGenerics(
row[GENERICS_DATA][x], elem, MAX_LEV_DISTANCE + 1) !== 0) {
return MAX_LEV_DISTANCE + 1;
}
continue;
}
return Math.ceil(total / done);
if (elems[elem_name] === undefined) {
elems[elem_name] = 0;
}
elems[elem_name] += 1;
}
// We need to find the type that matches the most to remove it in order
// to move forward.
for (x = 0, length = elem.generics.length; x < length; ++x) {
var generic = elem.generics[x];
var match = null;
if (elems[generic.name]) {
match = generic.name;
} else {
for (elem_name in elems) {
if (!hasOwnPropertyRustdoc(elems, elem_name)) {
continue;
}
if (elem_name === generic) {
match = elem_name;
break;
}
}
}
if (match === null) {
return MAX_LEV_DISTANCE + 1;
}
elems[match] -= 1;
if (elems[match] === 0) {
delete elems[match];
}
}
return 0;
}
return MAX_LEV_DISTANCE + 1;
}
/**
* This function checks if the object (`obj`) matches the given type (`val`) and its
* This function checks if the object (`row`) matches the given type (`elem`) and its
* generics (if any).
*
* @param {Object} obj
* @param {string} val
* @param {Row} row
* @param {QueryElement} elem - The element from the parsed query.
*
* @return {integer} - Returns a Levenshtein distance to the best match.
*/
function checkIfInGenerics(row, elem) {
var lev = MAX_LEV_DISTANCE + 1;
for (var x = 0, length = row[GENERICS_DATA].length; x < length && lev !== 0; ++x) {
lev = Math.min(
checkType(row[GENERICS_DATA][x], elem, true),
lev
);
}
return lev;
}
/**
* This function checks if the object (`row`) matches the given type (`elem`) and its
* generics (if any).
*
* @param {Row} row
* @param {QueryElement} elem - The element from the parsed query.
* @param {boolean} literalSearch
*
* @return {integer} - Returns a Levenshtein distance to the best match. If there is
* no match, returns `MAX_LEV_DISTANCE + 1`.
*/
function checkType(obj, val, literalSearch) {
var lev_distance = MAX_LEV_DISTANCE + 1;
var tmp_lev = MAX_LEV_DISTANCE + 1;
var len, x, firstGeneric;
if (obj[NAME] === val.name) {
if (literalSearch) {
if (val.generics && val.generics.length !== 0) {
if (obj.length > GENERICS_DATA &&
obj[GENERICS_DATA].length > 0) {
var elems = Object.create(null);
len = obj[GENERICS_DATA].length;
for (x = 0; x < len; ++x) {
if (!elems[obj[GENERICS_DATA][x][NAME]]) {
elems[obj[GENERICS_DATA][x][NAME]] = 0;
}
elems[obj[GENERICS_DATA][x][NAME]] += 1;
}
function checkType(row, elem, literalSearch) {
if (row[NAME].length === 0) {
// This is a pure "generic" search, no need to run other checks.
if (row.length > GENERICS_DATA) {
return checkIfInGenerics(row, elem);
}
return MAX_LEV_DISTANCE + 1;
}
len = val.generics.length;
for (x = 0; x < len; ++x) {
firstGeneric = val.generics[x];
if (elems[firstGeneric]) {
elems[firstGeneric] -= 1;
} else {
// Something wasn't found and this is a literal search so
// abort and return a "failing" distance.
return MAX_LEV_DISTANCE + 1;
}
}
// Everything was found, success!
var lev = levenshtein(row[NAME], elem.name);
if (literalSearch) {
if (lev !== 0) {
// The name didn't match, let's try to check if the generics do.
if (elem.generics.length === 0) {
var checkGeneric = (row.length > GENERICS_DATA &&
row[GENERICS_DATA].length > 0);
if (checkGeneric && row[GENERICS_DATA].findIndex(function(tmp_elem) {
return tmp_elem[NAME] === elem.name;
}) !== -1) {
return 0;
}
}
return MAX_LEV_DISTANCE + 1;
} else if (elem.generics.length > 0) {
return checkGenerics(row, elem, MAX_LEV_DISTANCE + 1);
}
return 0;
} else if (row.length > GENERICS_DATA) {
if (elem.generics.length === 0) {
if (lev === 0) {
return 0;
}
// The name didn't match so we now check if the type we're looking for is inside
// the generics!
lev = checkIfInGenerics(row, elem);
// Now whatever happens, the returned distance is "less good" so we should mark
// it as such, and so we add 0.5 to the distance to make it "less good".
return lev + 0.5;
} else if (lev > MAX_LEV_DISTANCE) {
// So our item's name doesn't match at all and has generics.
//
// Maybe it's present in a sub generic? For example "f<A<B<C>>>()", if we're
// looking for "B<C>", we'll need to go down.
return checkIfInGenerics(row, elem);
} else {
// At this point, the name kinda match and we have generics to check, so
// let's go!
var tmp_lev = checkGenerics(row, elem, lev);
if (tmp_lev > MAX_LEV_DISTANCE) {
return MAX_LEV_DISTANCE + 1;
}
return 0;
} else {
// If the type has generics but don't match, then it won't return at this point.
// Otherwise, `checkGenerics` will return 0 and it'll return.
if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
tmp_lev = checkGenerics(obj, val);
if (tmp_lev <= MAX_LEV_DISTANCE) {
return tmp_lev;
}
}
// We compute the median value of both checks and return it.
return (tmp_lev + lev) / 2;
}
} else if (literalSearch) {
var found = false;
if ((!val.generics || val.generics.length === 0) &&
obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
found = obj[GENERICS_DATA].some(
function(gen) {
return gen[NAME] === val.name;
});
}
return found ? 0 : MAX_LEV_DISTANCE + 1;
} else if (elem.generics.length > 0) {
// In this case, we were expecting generics but there isn't so we simply reject this
// one.
return MAX_LEV_DISTANCE + 1;
}
lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance);
if (lev_distance <= MAX_LEV_DISTANCE) {
// The generics didn't match but the name kinda did so we give it
// a levenshtein distance value that isn't *this* good so it goes
// into the search results but not too high.
lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
}
if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
// We can check if the type we're looking for is inside the generics!
var olength = obj[GENERICS_DATA].length;
for (x = 0; x < olength; ++x) {
tmp_lev = Math.min(levenshtein(obj[GENERICS_DATA][x][NAME], val.name), tmp_lev);
}
if (tmp_lev !== 0) {
// If we didn't find a good enough result, we go check inside the generics of
// the generics.
for (x = 0; x < olength && tmp_lev !== 0; ++x) {
tmp_lev = Math.min(
checkType(obj[GENERICS_DATA][x], val, literalSearch),
tmp_lev
);
}
}
}
// Now whatever happens, the returned distance is "less good" so we should mark it
// as such, and so we add 1 to the distance to make it "less good".
return Math.min(lev_distance, tmp_lev) + 1;
// No generics on our query or on the target type so we can return without doing
// anything else.
return lev;
}
/**
* This function checks if the object (`obj`) has an argument with the given type (`val`).
* This function checks if the object (`row`) has an argument with the given type (`elem`).
*
* @param {Object} obj
* @param {string} val
* @param {boolean} literalSearch
* @param {Row} row
* @param {QueryElement} elem - The element from the parsed query.
* @param {integer} typeFilter
*
* @return {integer} - Returns a Levenshtein distance to the best match. If there is no
* match, returns `MAX_LEV_DISTANCE + 1`.
*/
function findArg(obj, val, literalSearch, typeFilter) {
var lev_distance = MAX_LEV_DISTANCE + 1;
function findArg(row, elem, typeFilter) {
var lev = MAX_LEV_DISTANCE + 1;
if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
var length = obj.type[INPUTS_DATA].length;
if (row && row.type && row.type[INPUTS_DATA] && row.type[INPUTS_DATA].length > 0) {
var length = row.type[INPUTS_DATA].length;
for (var i = 0; i < length; i++) {
var tmp = obj.type[INPUTS_DATA][i];
var tmp = row.type[INPUTS_DATA][i];
if (!typePassesFilter(typeFilter, tmp[1])) {
continue;
}
tmp = checkType(tmp, val, literalSearch);
if (tmp === 0) {
lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
if (lev === 0) {
return 0;
} else if (literalSearch) {
continue;
}
lev_distance = Math.min(tmp, lev_distance);
}
}
return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
}
function checkReturned(obj, val, literalSearch, typeFilter) {
var lev_distance = MAX_LEV_DISTANCE + 1;
/**
* This function checks if the object (`row`) returns the given type (`elem`).
*
* @param {Row} row
* @param {QueryElement} elem - The element from the parsed query.
* @param {integer} typeFilter
*
* @return {integer} - Returns a Levenshtein distance to the best match. If there is no
* match, returns `MAX_LEV_DISTANCE + 1`.
*/
function checkReturned(row, elem, typeFilter) {
var lev = MAX_LEV_DISTANCE + 1;
if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
var ret = obj.type[OUTPUT_DATA];
if (row && row.type && row.type.length > OUTPUT_DATA) {
var ret = row.type[OUTPUT_DATA];
if (typeof ret[0] === "string") {
ret = [ret];
}
@@ -537,16 +1073,13 @@ window.initSearch = function(rawSearchIndex) {
if (!typePassesFilter(typeFilter, tmp[1])) {
continue;
}
tmp = checkType(tmp, val, literalSearch);
if (tmp === 0) {
lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
if (lev === 0) {
return 0;
} else if (literalSearch) {
continue;
}
lev_distance = Math.min(tmp, lev_distance);
}
}
return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
}
function checkPath(contains, lastElem, ty) {
@@ -621,13 +1154,14 @@ window.initSearch = function(rawSearchIndex) {
}
function handleAliases(ret, query, filterCrates) {
var lowerQuery = query.toLowerCase();
// We separate aliases and crate aliases because we want to have current crate
// aliases to be before the others in the displayed results.
var aliases = [];
var crateAliases = [];
if (filterCrates !== null) {
if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
var query_aliases = ALIASES[filterCrates][query.search];
if (ALIASES[filterCrates] && ALIASES[filterCrates][lowerQuery]) {
var query_aliases = ALIASES[filterCrates][lowerQuery];
var len = query_aliases.length;
for (var i = 0; i < len; ++i) {
aliases.push(createAliasFromItem(searchIndex[query_aliases[i]]));
@@ -635,9 +1169,9 @@ window.initSearch = function(rawSearchIndex) {
}
} else {
Object.keys(ALIASES).forEach(function(crate) {
if (ALIASES[crate][query.search]) {
if (ALIASES[crate][lowerQuery]) {
var pushTo = crate === window.currentCrate ? crateAliases : aliases;
var query_aliases = ALIASES[crate][query.search];
var query_aliases = ALIASES[crate][lowerQuery];
var len = query_aliases.length;
for (var i = 0; i < len; ++i) {
pushTo.push(createAliasFromItem(searchIndex[query_aliases[i]]));
@@ -658,7 +1192,7 @@ window.initSearch = function(rawSearchIndex) {
aliases.sort(sortFunc);
var pushFunc = function(alias) {
alias.alias = query.raw;
alias.alias = query;
var res = buildHrefAndPath(alias);
alias.displayPath = pathSplitter(res[0]);
alias.fullPath = alias.displayPath + alias.name;
@@ -674,208 +1208,237 @@ window.initSearch = function(rawSearchIndex) {
}
/**
* This function adds the given result into the provided `res` map if it matches the
* This function adds the given result into the provided `results` map if it matches the
* following condition:
*
* * If it is a "literal search" (`isExact`), then `lev` must be 0.
* * If it is a "literal search" (`parsedQuery.literalSearch`), then `lev` must be 0.
* * If it is not a "literal search", `lev` must be <= `MAX_LEV_DISTANCE`.
*
* The `res` map contains information which will be used to sort the search results:
* The `results` map contains information which will be used to sort the search results:
*
* * `fullId` is a `string`` used as the key of the object we use for the `res` map.
* * `fullId` is a `string`` used as the key of the object we use for the `results` map.
* * `id` is the index in both `searchWords` and `searchIndex` arrays for this element.
* * `index` is an `integer`` used to sort by the position of the word in the item's name.
* * `lev` is the main metric used to sort the search results.
*
* @param {boolean} isExact
* @param {Object} res
* @param {Results} results
* @param {string} fullId
* @param {integer} id
* @param {integer} index
* @param {integer} lev
*/
function addIntoResults(isExact, res, fullId, id, index, lev) {
if (lev === 0 || (!isExact && lev <= MAX_LEV_DISTANCE)) {
if (res[fullId] !== undefined) {
var result = res[fullId];
function addIntoResults(results, fullId, id, index, lev) {
if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) {
if (results[fullId] !== undefined) {
var result = results[fullId];
if (result.dontValidate || result.lev <= lev) {
return;
}
}
res[fullId] = {
results[fullId] = {
id: id,
index: index,
dontValidate: isExact,
dontValidate: parsedQuery.literalSearch,
lev: lev,
};
}
}
// quoted values mean literal search
var nSearchWords = searchWords.length;
var i, it;
var ty;
var fullId;
var returned;
var in_args;
var len;
if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
val.charAt(val.length - 1) === val.charAt(0))
{
val = extractGenerics(val.substr(1, val.length - 2));
for (i = 0; i < nSearchWords; ++i) {
if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
continue;
}
in_args = findArg(searchIndex[i], val, true, typeFilter);
returned = checkReturned(searchIndex[i], val, true, typeFilter);
ty = searchIndex[i];
fullId = ty.id;
if (searchWords[i] === val.name
&& typePassesFilter(typeFilter, searchIndex[i].ty)) {
addIntoResults(true, results, fullId, i, -1, 0);
}
addIntoResults(true, results_in_args, fullId, i, -1, in_args);
addIntoResults(true, results_returned, fullId, i, -1, returned);
/**
* This function is called in case the query is only one element (with or without generics).
* This element will be compared to arguments' and returned values' items and also to items.
*
* Other important thing to note: since there is only one element, we use levenshtein
* distance for name comparisons.
*
* @param {Row} row
* @param {integer} pos - Position in the `searchIndex`.
* @param {QueryElement} elem - The element from the parsed query.
* @param {Results} results_others - Unqualified results (not in arguments nor in
* returned values).
* @param {Results} results_in_args - Matching arguments results.
* @param {Results} results_returned - Matching returned arguments results.
*/
function handleSingleArg(
row,
pos,
elem,
results_others,
results_in_args,
results_returned
) {
if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
return;
}
query.inputs = [val];
query.output = val;
query.search = val;
// searching by type
} else if (val.search("->") > -1) {
var trimmer = function(s) { return s.trim(); };
var parts = val.split("->").map(trimmer);
var input = parts[0];
// sort inputs so that order does not matter
var inputs = input.split(",").map(trimmer).sort();
for (i = 0, len = inputs.length; i < len; ++i) {
inputs[i] = extractGenerics(inputs[i]);
var lev, lev_add = 0, index = -1;
var fullId = row.id;
var in_args = findArg(row, elem, parsedQuery.typeFilter);
var returned = checkReturned(row, elem, parsedQuery.typeFilter);
addIntoResults(results_in_args, fullId, pos, index, in_args);
addIntoResults(results_returned, fullId, pos, index, returned);
if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
return;
}
var output = extractGenerics(parts[1]);
var searchWord = searchWords[pos];
for (i = 0; i < nSearchWords; ++i) {
if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
continue;
if (parsedQuery.literalSearch) {
if (searchWord === elem.name) {
addIntoResults(results_others, fullId, pos, -1, 0);
}
var type = searchIndex[i].type;
ty = searchIndex[i];
if (!type) {
continue;
return;
}
// No need to check anything else if it's a "pure" generics search.
if (elem.name.length === 0) {
if (row.type !== null) {
lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1);
addIntoResults(results_others, fullId, pos, index, lev);
}
fullId = ty.id;
return;
}
returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
if (output.name === "*" || returned === 0) {
in_args = false;
var is_module = false;
if (input === "*") {
is_module = true;
} else {
var firstNonZeroDistance = 0;
for (it = 0, len = inputs.length; it < len; it++) {
var distance = checkType(type, inputs[it], true);
if (distance > 0) {
firstNonZeroDistance = distance;
break;
}
}
in_args = firstNonZeroDistance;
}
addIntoResults(true, results_in_args, fullId, i, -1, in_args);
addIntoResults(true, results_returned, fullId, i, -1, returned);
if (is_module) {
addIntoResults(true, results, fullId, i, -1, 0);
}
if (elem.fullPath.length > 1) {
lev = checkPath(elem.pathWithoutLast, elem.pathLast, row);
if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
return;
} else if (lev > 0) {
lev_add = lev / 10;
}
}
query.inputs = inputs.map(function(input) {
return input.name;
});
query.output = output.name;
} else {
query.inputs = [val];
query.output = val;
query.search = val;
// gather matching search results up to a certain maximum
val = val.replace(/_/g, "");
var valGenerics = extractGenerics(val);
var paths = valLower.split("::");
removeEmptyStringsFromArray(paths);
val = paths[paths.length - 1];
var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
var lev, j;
for (j = 0; j < nSearchWords; ++j) {
ty = searchIndex[j];
if (!ty || (filterCrates !== null && ty.crate !== filterCrates)) {
continue;
if (searchWord.indexOf(elem.pathLast) > -1 ||
row.normalizedName.indexOf(elem.pathLast) > -1)
{
// filter type: ... queries
if (!results_others[fullId] !== undefined) {
index = row.normalizedName.indexOf(elem.pathLast);
}
var lev_add = 0;
if (paths.length > 1) {
lev = checkPath(contains, paths[paths.length - 1], ty);
if (lev > MAX_LEV_DISTANCE) {
continue;
} else if (lev > 0) {
lev_add = lev / 10;
}
}
lev = levenshtein(searchWord, elem.pathLast);
lev += lev_add;
if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1)
{
if (elem.pathLast.length < 6) {
lev = 1;
} else {
lev = 0;
}
}
if (lev > MAX_LEV_DISTANCE) {
return;
} else if (index !== -1 && elem.fullPath.length < 2) {
lev -= 1;
}
if (lev < 0) {
lev = 0;
}
addIntoResults(results_others, fullId, pos, index, lev);
}
returned = MAX_LEV_DISTANCE + 1;
in_args = MAX_LEV_DISTANCE + 1;
var index = -1;
// we want lev results to go lower than others
lev = MAX_LEV_DISTANCE + 1;
fullId = ty.id;
/**
* This function is called in case the query has more than one element. In this case, it'll
* try to match the items which validates all the elements. For `aa -> bb` will look for
* functions which have a parameter `aa` and has `bb` in its returned values.
*
* @param {Row} row
* @param {integer} pos - Position in the `searchIndex`.
* @param {Object} results
*/
function handleArgs(row, pos, results) {
if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
return;
}
if (searchWords[j].indexOf(split[i]) > -1 ||
searchWords[j].indexOf(val) > -1 ||
ty.normalizedName.indexOf(val) > -1)
{
// filter type: ... queries
if (typePassesFilter(typeFilter, ty.ty) && results[fullId] === undefined) {
index = ty.normalizedName.indexOf(val);
}
}
if ((lev = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) {
if (typePassesFilter(typeFilter, ty.ty)) {
lev += 1;
var totalLev = 0;
var nbLev = 0;
var lev;
// If the result is too "bad", we return false and it ends this search.
function checkArgs(elems, callback) {
for (var i = 0, len = elems.length; i < len; ++i) {
var elem = elems[i];
// There is more than one parameter to the query so all checks should be "exact"
lev = callback(row, elem, NO_TYPE_FILTER);
if (lev <= 1) {
nbLev += 1;
totalLev += lev;
} else {
lev = MAX_LEV_DISTANCE + 1;
return false;
}
}
in_args = findArg(ty, valGenerics, false, typeFilter);
returned = checkReturned(ty, valGenerics, false, typeFilter);
return true;
}
if (!checkArgs(parsedQuery.elems, findArg)) {
return;
}
if (!checkArgs(parsedQuery.returned, checkReturned)) {
return;
}
lev += lev_add;
if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) {
if (val.length < 6) {
lev -= 1;
} else {
lev = 0;
if (nbLev === 0) {
return;
}
lev = Math.round(totalLev / nbLev);
addIntoResults(results, row.id, pos, 0, lev);
}
function innerRunQuery() {
var elem, i, nSearchWords, in_returned, row;
if (parsedQuery.foundElems === 1) {
if (parsedQuery.elems.length === 1) {
elem = parsedQuery.elems[0];
for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
// It means we want to check for this element everywhere (in names, args and
// returned).
handleSingleArg(
searchIndex[i],
i,
elem,
results_others,
results_in_args,
results_returned
);
}
} else if (parsedQuery.returned.length === 1) {
// We received one returned argument to check, so looking into returned values.
elem = parsedQuery.returned[0];
for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
row = searchIndex[i];
in_returned = checkReturned(row, elem, parsedQuery.typeFilter);
addIntoResults(results_returned, row.id, i, -1, in_returned);
}
}
addIntoResults(false, results_in_args, fullId, j, index, in_args);
addIntoResults(false, results_returned, fullId, j, index, returned);
if (typePassesFilter(typeFilter, ty.ty) &&
(index !== -1 || lev <= MAX_LEV_DISTANCE)) {
if (index !== -1 && paths.length < 2) {
lev = 0;
}
addIntoResults(false, results, fullId, j, index, lev);
} else if (parsedQuery.foundElems > 0) {
var container = results_others;
// In the special case where only a "returned" information is available, we want to
// put the information into the "results_returned" dict.
if (parsedQuery.returned.length !== 0 && parsedQuery.elems.length === 0) {
container = results_returned;
}
for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
handleArgs(searchIndex[i], i, container);
}
}
}
var ret = {
"in_args": sortResults(results_in_args, true),
"returned": sortResults(results_returned, true),
"others": sortResults(results, false),
};
handleAliases(ret, query, filterCrates);
if (parsedQuery.error === null) {
innerRunQuery();
}
var ret = createQueryResults(
sortResults(results_in_args, true),
sortResults(results_returned, true),
sortResults(results_others, false),
parsedQuery);
handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates);
if (parsedQuery.error !== null && ret.others.length !== 0) {
// It means some doc aliases were found so let's "remove" the error!
ret.query.error = null;
}
return ret;
}
@@ -892,9 +1455,13 @@ window.initSearch = function(rawSearchIndex) {
* @param {string} path - The path of the result
* @param {string} keys - The keys to be used (["file", "open"])
* @param {Object} parent - The parent of the result
*
* @return {boolean} - Whether the result is valid or not
*/
function validateResult(name, path, keys, parent) {
if (!keys || !keys.length) {
return true;
}
for (var i = 0, len = keys.length; i < len; ++i) {
// each check is for validation so we negate the conditions and invalidate
if (!(
@@ -913,30 +1480,6 @@ window.initSearch = function(rawSearchIndex) {
return true;
}
/**
* Parse a string into a query object.
*
* @param {string} raw - The text that the user typed.
* @returns {ParsedQuery}
*/
function getQuery(raw) {
var matches, type = "", query;
query = raw;
matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
if (matches) {
type = matches[1].replace(/^const$/, "constant");
query = query.substring(matches[0].length);
}
return {
raw: raw,
query: query,
type: type,
id: query + type
};
}
function nextTab(direction) {
var next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
searchState.focusedByTab[searchState.currentTab] = document.activeElement;
@@ -1088,11 +1631,11 @@ window.initSearch = function(rawSearchIndex) {
link.appendChild(wrapper);
output.appendChild(link);
});
} else {
} else if (query.error === null) {
output.className = "search-failed" + extraClass;
output.innerHTML = "No results :(<br/>" +
"Try on <a href=\"https://duckduckgo.com/?q=" +
encodeURIComponent("rust " + query.query) +
encodeURIComponent("rust " + query.userQuery) +
"\">DuckDuckGo</a>?<br/><br/>" +
"Or try looking in one of these:<ul><li>The <a " +
"href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
@@ -1115,6 +1658,11 @@ window.initSearch = function(rawSearchIndex) {
return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
}
/**
* @param {ResultsTable} results
* @param {boolean} go_to_first
* @param {string} filterCrates
*/
function showResults(results, go_to_first, filterCrates) {
var search = searchState.outputElement();
if (go_to_first || (results.others.length === 1
@@ -1132,13 +1680,15 @@ window.initSearch = function(rawSearchIndex) {
elem.click();
return;
}
var query = getQuery(searchState.input.value);
if (results.query === undefined) {
results.query = parseQuery(searchState.input.value);
}
currentResults = query.id;
currentResults = results.query.userQuery;
var ret_others = addTab(results.others, query, true);
var ret_in_args = addTab(results.in_args, query, false);
var ret_returned = addTab(results.returned, query, false);
var ret_others = addTab(results.others, results.query, true);
var ret_in_args = addTab(results.in_args, results.query, false);
var ret_returned = addTab(results.returned, results.query, false);
// Navigate to the relevant tab if the current tab is empty, like in case users search
// for "-> String". If they had selected another tab previously, they have to click on
@@ -1164,11 +1714,19 @@ window.initSearch = function(rawSearchIndex) {
}
crates += `</select>`;
}
var output = `<div id="search-settings">
<h1 class="search-results-title">Results for ${escape(query.query)} ` +
(query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
crates +
`</div><div id="titles">` +
var typeFilter = "";
if (results.query.typeFilter !== NO_TYPE_FILTER) {
typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
}
var output = `<div id="search-settings">` +
`<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
`${typeFilter}</h1> in ${crates} </div>`;
if (results.query.error !== null) {
output += `<h3>Query parser error: "${results.query.error}".</h3>`;
}
output += `<div id="titles">` +
makeTabHeader(0, "In Names", ret_others[1]) +
makeTabHeader(1, "In Parameters", ret_in_args[1]) +
makeTabHeader(2, "In Return Types", ret_returned[1]) +
@@ -1196,28 +1754,6 @@ window.initSearch = function(rawSearchIndex) {
printTab(currentTab);
}
function execSearch(query, searchWords, filterCrates) {
query = query.raw.trim();
var results = {
"in_args": [],
"returned": [],
"others": [],
};
if (query.length !== 0) {
var tmp = execQuery(getQuery(query), searchWords, filterCrates);
results.in_args.push(tmp.in_args);
results.returned.push(tmp.returned);
results.others.push(tmp.others);
}
return {
"in_args": results.in_args[0],
"returned": results.returned[0],
"others": results.others[0],
};
}
/**
* Perform a search based on the current state of the search input element
* and display the results.
@@ -1226,17 +1762,14 @@ window.initSearch = function(rawSearchIndex) {
*/
function search(e, forced) {
var params = searchState.getQueryStringParams();
var query = getQuery(searchState.input.value.trim());
var query = parseQuery(searchState.input.value.trim());
if (e) {
e.preventDefault();
}
if (query.query.length === 0) {
return;
}
if (!forced && query.id === currentResults) {
if (query.query.length > 0) {
if (!forced && query.userQuery === currentResults) {
if (query.userQuery.length > 0) {
putBackSearch();
}
return;
@@ -1251,13 +1784,12 @@ window.initSearch = function(rawSearchIndex) {
}
// Update document title to maintain a meaningful browser history
searchState.title = "Results for " + query.query + " - Rust";
searchState.title = "Results for " + query.original + " - Rust";
// Because searching is incremental by character, only the most
// recent search query is added to the browser history.
if (searchState.browserSupportsHistoryApi()) {
var newURL = buildUrl(query.raw, filterCrates);
var newURL = buildUrl(query.original, filterCrates);
if (!history.state && !params.search) {
history.pushState(null, "", newURL);
} else {
@@ -1265,8 +1797,10 @@ window.initSearch = function(rawSearchIndex) {
}
}
showResults(execSearch(query, searchWords, filterCrates),
params["go_to_first"], filterCrates);
showResults(
execQuery(query, searchWords, filterCrates),
params.go_to_first,
filterCrates);
}
function buildIndex(rawSearchIndex) {
@@ -25,14 +25,14 @@
| '_#2r live at {bb0[0..=1]}
| '_#3r live at {bb0[0..=1]}
| '_#4r live at {bb0[0..=1]}
| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27)
| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55)
| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43)
| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67)
| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27)
| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43)
| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55)
| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67)
| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
|
fn use_x(_1: &'_#6r mut i32, _2: &'_#7r u32, _3: &'_#8r u32, _4: &'_#9r u32) -> bool {
debug w => _1; // in scope 0 at $DIR/named-lifetimes-basic.rs:12:26: 12:27
@@ -18,8 +18,8 @@
| '_#3r live at {bb1[0]}
| '_#4r live at {bb1[1..=3]}
| '_#5r live at {bb1[4..=7], bb2[0..=2]}
| '_#3r: '_#4r due to Assignment at Single(bb1[0])
| '_#4r: '_#5r due to Assignment at Single(bb1[3])
| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
|
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
@@ -18,8 +18,8 @@
| '_#3r live at {bb1[0]}
| '_#4r live at {bb1[1..=3]}
| '_#5r live at {bb1[4..=7], bb2[0..=2]}
| '_#3r: '_#4r due to Assignment at Single(bb1[0])
| '_#4r: '_#5r due to Assignment at Single(bb1[3])
| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
|
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
@@ -16,7 +16,7 @@
| '_#1r live at {bb0[0..=22]}
| '_#3r live at {bb0[10]}
| '_#4r live at {bb0[11]}
| '_#3r: '_#4r due to Assignment at Single(bb0[10])
| '_#3r: '_#4r due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0)
|
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/storage_ranges.rs:3:11: 3:11
+1 -1
View File
@@ -1,6 +1,6 @@
// exact-check
const QUERY = 'hashmap';
const QUERY = '"hashmap"';
const FILTER_CRATE = 'core';
const EXPECTED = {
+365
View File
@@ -0,0 +1,365 @@
const QUERY = [
'<P>',
'-> <P>',
'a<"P">',
'"P" "P"',
'P "P"',
'"p" p',
'"const": p',
"a<:a>",
"a<::a>",
"((a))",
"(p -> p",
"::a::b",
"a::::b",
"a::b::",
":a",
"a b:",
"a (b:",
"_:",
"a-bb",
"a>bb",
"ab'",
"a->",
'"p" <a>',
'"p" a<a>',
"a,<",
"aaaaa<>b",
"fn:aaaaa<>b",
"->a<>b",
"a<->",
"a:: a",
"a ::a",
"a<a>:",
"a<>:",
"a,:",
" a<> :",
"mod : :",
];
const PARSED = [
{
elems: [],
foundElems: 0,
original: "<P>",
returned: [],
typeFilter: -1,
userQuery: "<p>",
error: "Found generics without a path",
},
{
elems: [],
foundElems: 0,
original: "-> <P>",
returned: [],
typeFilter: -1,
userQuery: "-> <p>",
error: "Found generics without a path",
},
{
elems: [],
foundElems: 0,
original: "a<\"P\">",
returned: [],
typeFilter: -1,
userQuery: "a<\"p\">",
error: "`\"` cannot be used in generics",
},
{
elems: [],
foundElems: 0,
original: "\"P\" \"P\"",
returned: [],
typeFilter: -1,
userQuery: "\"p\" \"p\"",
error: "Cannot have more than one literal search element",
},
{
elems: [],
foundElems: 0,
original: "P \"P\"",
returned: [],
typeFilter: -1,
userQuery: "p \"p\"",
error: "Cannot use literal search when there is more than one element",
},
{
elems: [],
foundElems: 0,
original: "\"p\" p",
returned: [],
typeFilter: -1,
userQuery: "\"p\" p",
error: "You cannot have more than one element if you use quotes",
},
{
elems: [],
foundElems: 0,
original: "\"const\": p",
returned: [],
typeFilter: -1,
userQuery: "\"const\": p",
error: "You cannot use quotes on type filter",
},
{
elems: [],
foundElems: 0,
original: "a<:a>",
returned: [],
typeFilter: -1,
userQuery: "a<:a>",
error: "Unexpected `:` after `<`",
},
{
elems: [],
foundElems: 0,
original: "a<::a>",
returned: [],
typeFilter: -1,
userQuery: "a<::a>",
error: "Unexpected `::`: paths cannot start with `::`",
},
{
elems: [],
foundElems: 0,
original: "((a))",
returned: [],
typeFilter: -1,
userQuery: "((a))",
error: "Unexpected `(`",
},
{
elems: [],
foundElems: 0,
original: "(p -> p",
returned: [],
typeFilter: -1,
userQuery: "(p -> p",
error: "Unexpected `(`",
},
{
elems: [],
foundElems: 0,
original: "::a::b",
returned: [],
typeFilter: -1,
userQuery: "::a::b",
error: "Paths cannot start with `::`",
},
{
elems: [],
foundElems: 0,
original: "a::::b",
returned: [],
typeFilter: -1,
userQuery: "a::::b",
error: "Unexpected `::::`",
},
{
elems: [],
foundElems: 0,
original: "a::b::",
returned: [],
typeFilter: -1,
userQuery: "a::b::",
error: "Paths cannot end with `::`",
},
{
elems: [],
foundElems: 0,
original: ":a",
returned: [],
typeFilter: -1,
userQuery: ":a",
error: "Expected type filter before `:`",
},
{
elems: [],
foundElems: 0,
original: "a b:",
returned: [],
typeFilter: -1,
userQuery: "a b:",
error: "Unexpected `:`",
},
{
elems: [],
foundElems: 0,
original: "a (b:",
returned: [],
typeFilter: -1,
userQuery: "a (b:",
error: "Unexpected `(`",
},
{
elems: [],
foundElems: 0,
original: "_:",
returned: [],
typeFilter: -1,
userQuery: "_:",
error: "Unknown type filter `_`",
},
{
elems: [],
foundElems: 0,
original: "a-bb",
returned: [],
typeFilter: -1,
userQuery: "a-bb",
error: "Unexpected `-` (did you mean `->`?)",
},
{
elems: [],
foundElems: 0,
original: "a>bb",
returned: [],
typeFilter: -1,
userQuery: "a>bb",
error: "Unexpected `>` (did you mean `->`?)",
},
{
elems: [],
foundElems: 0,
original: "ab'",
returned: [],
typeFilter: -1,
userQuery: "ab'",
error: "Unexpected `'`",
},
{
elems: [],
foundElems: 0,
original: "a->",
returned: [],
typeFilter: -1,
userQuery: "a->",
error: "Expected at least one item after `->`",
},
{
elems: [],
foundElems: 0,
original: '"p" <a>',
returned: [],
typeFilter: -1,
userQuery: '"p" <a>',
error: "Found generics without a path",
},
{
elems: [],
foundElems: 0,
original: '"p" a<a>',
returned: [],
typeFilter: -1,
userQuery: '"p" a<a>',
error: "You cannot have more than one element if you use quotes",
},
{
elems: [],
foundElems: 0,
original: 'a,<',
returned: [],
typeFilter: -1,
userQuery: 'a,<',
error: 'Found generics without a path',
},
{
elems: [],
foundElems: 0,
original: 'aaaaa<>b',
returned: [],
typeFilter: -1,
userQuery: 'aaaaa<>b',
error: 'Expected `,`, ` `, `:` or `->`, found `b`',
},
{
elems: [],
foundElems: 0,
original: 'fn:aaaaa<>b',
returned: [],
typeFilter: -1,
userQuery: 'fn:aaaaa<>b',
error: 'Expected `,`, ` ` or `->`, found `b`',
},
{
elems: [],
foundElems: 0,
original: '->a<>b',
returned: [],
typeFilter: -1,
userQuery: '->a<>b',
error: 'Expected `,` or ` `, found `b`',
},
{
elems: [],
foundElems: 0,
original: 'a<->',
returned: [],
typeFilter: -1,
userQuery: 'a<->',
error: 'Unexpected `-` after `<`',
},
{
elems: [],
foundElems: 0,
original: 'a:: a',
returned: [],
typeFilter: -1,
userQuery: 'a:: a',
error: 'Paths cannot end with `::`',
},
{
elems: [],
foundElems: 0,
original: 'a ::a',
returned: [],
typeFilter: -1,
userQuery: 'a ::a',
error: 'Paths cannot start with `::`',
},
{
elems: [],
foundElems: 0,
original: "a<a>:",
returned: [],
typeFilter: -1,
userQuery: "a<a>:",
error: 'Unexpected `:`',
},
{
elems: [],
foundElems: 0,
original: "a<>:",
returned: [],
typeFilter: -1,
userQuery: "a<>:",
error: 'Unexpected `<` in type filter',
},
{
elems: [],
foundElems: 0,
original: "a,:",
returned: [],
typeFilter: -1,
userQuery: "a,:",
error: 'Unexpected `,` in type filter',
},
{
elems: [],
foundElems: 0,
original: "a<> :",
returned: [],
typeFilter: -1,
userQuery: "a<> :",
error: 'Unexpected `<` in type filter',
},
{
elems: [],
foundElems: 0,
original: "mod : :",
returned: [],
typeFilter: -1,
userQuery: "mod : :",
error: 'Unexpected `:`',
},
];
+43
View File
@@ -0,0 +1,43 @@
const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo'];
const PARSED = [
{
elems: [{
name: "foo",
fullPath: ["foo"],
pathWithoutLast: [],
pathLast: "foo",
generics: [],
}],
foundElems: 1,
original: "fn:foo",
returned: [],
typeFilter: 5,
userQuery: "fn:foo",
error: null,
},
{
elems: [{
name: "foo",
fullPath: ["foo"],
pathWithoutLast: [],
pathLast: "foo",
generics: [],
}],
foundElems: 1,
original: "enum : foo",
returned: [],
typeFilter: 4,
userQuery: "enum : foo",
error: null,
},
{
elems: [],
foundElems: 0,
original: "macro<f>:foo",
returned: [],
typeFilter: -1,
userQuery: "macro<f>:foo",
error: "Unexpected `:`",
},
];
@@ -0,0 +1,62 @@
const QUERY = ['A<B<C<D>, E>', 'p<> u8', '"p"<a>'];
const PARSED = [
{
elems: [],
foundElems: 0,
original: 'A<B<C<D>, E>',
returned: [],
typeFilter: -1,
userQuery: 'a<b<c<d>, e>',
error: 'Unexpected `<` after `<`',
},
{
elems: [
{
name: "p",
fullPath: ["p"],
pathWithoutLast: [],
pathLast: "p",
generics: [],
},
{
name: "u8",
fullPath: ["u8"],
pathWithoutLast: [],
pathLast: "u8",
generics: [],
},
],
foundElems: 2,
original: "p<> u8",
returned: [],
typeFilter: -1,
userQuery: "p<> u8",
error: null,
},
{
elems: [
{
name: "p",
fullPath: ["p"],
pathWithoutLast: [],
pathLast: "p",
generics: [
{
name: "a",
fullPath: ["a"],
pathWithoutLast: [],
pathLast: "a",
generics: [],
},
],
},
],
foundElems: 1,
original: '"p"<a>',
returned: [],
typeFilter: -1,
userQuery: '"p"<a>',
error: null,
},
];
+27
View File
@@ -0,0 +1,27 @@
const QUERY = ['R<P>'];
const PARSED = [
{
elems: [{
name: "r",
fullPath: ["r"],
pathWithoutLast: [],
pathLast: "r",
generics: [
{
name: "p",
fullPath: ["p"],
pathWithoutLast: [],
pathLast: "p",
generics: [],
},
],
}],
foundElems: 1,
original: "R<P>",
returned: [],
typeFilter: -1,
userQuery: "r<p>",
error: null,
}
];
+90
View File
@@ -0,0 +1,90 @@
const QUERY = ['A::B', 'A::B,C', 'A::B<f>,C', 'mod::a'];
const PARSED = [
{
elems: [{
name: "a::b",
fullPath: ["a", "b"],
pathWithoutLast: ["a"],
pathLast: "b",
generics: [],
}],
foundElems: 1,
original: "A::B",
returned: [],
typeFilter: -1,
userQuery: "a::b",
error: null,
},
{
elems: [
{
name: "a::b",
fullPath: ["a", "b"],
pathWithoutLast: ["a"],
pathLast: "b",
generics: [],
},
{
name: "c",
fullPath: ["c"],
pathWithoutLast: [],
pathLast: "c",
generics: [],
},
],
foundElems: 2,
original: 'A::B,C',
returned: [],
typeFilter: -1,
userQuery: 'a::b,c',
error: null,
},
{
elems: [
{
name: "a::b",
fullPath: ["a", "b"],
pathWithoutLast: ["a"],
pathLast: "b",
generics: [
{
name: "f",
fullPath: ["f"],
pathWithoutLast: [],
pathLast: "f",
generics: [],
},
],
},
{
name: "c",
fullPath: ["c"],
pathWithoutLast: [],
pathLast: "c",
generics: [],
},
],
foundElems: 2,
original: 'A::B<f>,C',
returned: [],
typeFilter: -1,
userQuery: 'a::b<f>,c',
error: null,
},
{
elems: [{
name: "mod::a",
fullPath: ["mod", "a"],
pathWithoutLast: ["mod"],
pathLast: "a",
generics: [],
}],
foundElems: 1,
original: "mod::a",
returned: [],
typeFilter: -1,
userQuery: "mod::a",
error: null,
},
];
+87
View File
@@ -0,0 +1,87 @@
const QUERY = [
'-> "p"',
'"p",',
'"p" -> a',
'"a" -> "p"',
'->"-"',
'"a',
'""',
];
const PARSED = [
{
elems: [],
foundElems: 1,
original: '-> "p"',
returned: [{
name: "p",
fullPath: ["p"],
pathWithoutLast: [],
pathLast: "p",
generics: [],
}],
typeFilter: -1,
userQuery: '-> "p"',
error: null,
},
{
elems: [{
name: "p",
fullPath: ["p"],
pathWithoutLast: [],
pathLast: "p",
generics: [],
}],
foundElems: 1,
original: '"p",',
returned: [],
typeFilter: -1,
userQuery: '"p",',
error: null,
},
{
elems: [],
foundElems: 0,
original: '"p" -> a',
returned: [],
typeFilter: -1,
userQuery: '"p" -> a',
error: "You cannot have more than one element if you use quotes",
},
{
elems: [],
foundElems: 0,
original: '"a" -> "p"',
returned: [],
typeFilter: -1,
userQuery: '"a" -> "p"',
error: "Cannot have more than one literal search element",
},
{
elems: [],
foundElems: 0,
original: '->"-"',
returned: [],
typeFilter: -1,
userQuery: '->"-"',
error: 'Unexpected `-` in a string element',
},
{
elems: [],
foundElems: 0,
original: '"a',
returned: [],
typeFilter: -1,
userQuery: '"a',
error: 'Unclosed `"`',
},
{
elems: [],
foundElems: 0,
original: '""',
returned: [],
typeFilter: -1,
userQuery: '""',
error: 'Cannot have empty string element',
},
];
@@ -0,0 +1,78 @@
const QUERY = ['-> F<P>', '-> P', '->,a', 'aaaaa->a'];
const PARSED = [
{
elems: [],
foundElems: 1,
original: "-> F<P>",
returned: [{
name: "f",
fullPath: ["f"],
pathWithoutLast: [],
pathLast: "f",
generics: [
{
name: "p",
fullPath: ["p"],
pathWithoutLast: [],
pathLast: "p",
generics: [],
},
],
}],
typeFilter: -1,
userQuery: "-> f<p>",
error: null,
},
{
elems: [],
foundElems: 1,
original: "-> P",
returned: [{
name: "p",
fullPath: ["p"],
pathWithoutLast: [],
pathLast: "p",
generics: [],
}],
typeFilter: -1,
userQuery: "-> p",
error: null,
},
{
elems: [],
foundElems: 1,
original: "->,a",
returned: [{
name: "a",
fullPath: ["a"],
pathWithoutLast: [],
pathLast: "a",
generics: [],
}],
typeFilter: -1,
userQuery: "->,a",
error: null,
},
{
elems: [{
name: "aaaaa",
fullPath: ["aaaaa"],
pathWithoutLast: [],
pathLast: "aaaaa",
generics: [],
}],
foundElems: 2,
original: "aaaaa->a",
returned: [{
name: "a",
fullPath: ["a"],
pathWithoutLast: [],
pathLast: "a",
generics: [],
}],
typeFilter: -1,
userQuery: "aaaaa->a",
error: null,
},
];
@@ -0,0 +1,206 @@
// ignore-tidy-tab
const QUERY = [
'aaaaaa b',
'a b',
'a,b',
'a\tb',
'a<b c>',
'a<b,c>',
'a<b\tc>',
];
const PARSED = [
{
elems: [
{
name: 'aaaaaa',
fullPath: ['aaaaaa'],
pathWithoutLast: [],
pathLast: 'aaaaaa',
generics: [],
},
{
name: 'b',
fullPath: ['b'],
pathWithoutLast: [],
pathLast: 'b',
generics: [],
},
],
foundElems: 2,
original: "aaaaaa b",
returned: [],
typeFilter: -1,
userQuery: "aaaaaa b",
error: null,
},
{
elems: [
{
name: 'a',
fullPath: ['a'],
pathWithoutLast: [],
pathLast: 'a',
generics: [],
},
{
name: 'b',
fullPath: ['b'],
pathWithoutLast: [],
pathLast: 'b',
generics: [],
},
],
foundElems: 2,
original: "a b",
returned: [],
typeFilter: -1,
userQuery: "a b",
error: null,
},
{
elems: [
{
name: 'a',
fullPath: ['a'],
pathWithoutLast: [],
pathLast: 'a',
generics: [],
},
{
name: 'b',
fullPath: ['b'],
pathWithoutLast: [],
pathLast: 'b',
generics: [],
},
],
foundElems: 2,
original: "a,b",
returned: [],
typeFilter: -1,
userQuery: "a,b",
error: null,
},
{
elems: [
{
name: 'a',
fullPath: ['a'],
pathWithoutLast: [],
pathLast: 'a',
generics: [],
},
{
name: 'b',
fullPath: ['b'],
pathWithoutLast: [],
pathLast: 'b',
generics: [],
},
],
foundElems: 2,
original: "a\tb",
returned: [],
typeFilter: -1,
userQuery: "a\tb",
error: null,
},
{
elems: [
{
name: 'a',
fullPath: ['a'],
pathWithoutLast: [],
pathLast: 'a',
generics: [
{
name: 'b',
fullPath: ['b'],
pathWithoutLast: [],
pathLast: 'b',
generics: [],
},
{
name: 'c',
fullPath: ['c'],
pathWithoutLast: [],
pathLast: 'c',
generics: [],
},
],
},
],
foundElems: 1,
original: "a<b c>",
returned: [],
typeFilter: -1,
userQuery: "a<b c>",
error: null,
},
{
elems: [
{
name: 'a',
fullPath: ['a'],
pathWithoutLast: [],
pathLast: 'a',
generics: [
{
name: 'b',
fullPath: ['b'],
pathWithoutLast: [],
pathLast: 'b',
generics: [],
},
{
name: 'c',
fullPath: ['c'],
pathWithoutLast: [],
pathLast: 'c',
generics: [],
},
],
},
],
foundElems: 1,
original: "a<b,c>",
returned: [],
typeFilter: -1,
userQuery: "a<b,c>",
error: null,
},
{
elems: [
{
name: 'a',
fullPath: ['a'],
pathWithoutLast: [],
pathLast: 'a',
generics: [
{
name: 'b',
fullPath: ['b'],
pathWithoutLast: [],
pathLast: 'b',
generics: [],
},
{
name: 'c',
fullPath: ['c'],
pathWithoutLast: [],
pathLast: 'c',
generics: [],
},
],
},
],
foundElems: 1,
original: "a<b\tc>",
returned: [],
typeFilter: -1,
userQuery: "a<b\tc>",
error: null,
},
];
@@ -0,0 +1,123 @@
// This test is mostly to check that the parser still kinda outputs something
// (and doesn't enter an infinite loop!) even though the query is completely
// invalid.
const QUERY = [
'a b',
'a b',
'a,b(c)',
'aaa,a',
',,,,',
'mod :',
'mod\t:',
];
const PARSED = [
{
elems: [
{
name: "a",
fullPath: ["a"],
pathWithoutLast: [],
pathLast: "a",
generics: [],
},
{
name: "b",
fullPath: ["b"],
pathWithoutLast: [],
pathLast: "b",
generics: [],
},
],
foundElems: 2,
original: "a b",
returned: [],
typeFilter: -1,
userQuery: "a b",
error: null,
},
{
elems: [
{
name: "a",
fullPath: ["a"],
pathWithoutLast: [],
pathLast: "a",
generics: [],
},
{
name: "b",
fullPath: ["b"],
pathWithoutLast: [],
pathLast: "b",
generics: [],
},
],
foundElems: 2,
original: "a b",
returned: [],
typeFilter: -1,
userQuery: "a b",
error: null,
},
{
elems: [],
foundElems: 0,
original: "a,b(c)",
returned: [],
typeFilter: -1,
userQuery: "a,b(c)",
error: "Unexpected `(`",
},
{
elems: [
{
name: "aaa",
fullPath: ["aaa"],
pathWithoutLast: [],
pathLast: "aaa",
generics: [],
},
{
name: "a",
fullPath: ["a"],
pathWithoutLast: [],
pathLast: "a",
generics: [],
},
],
foundElems: 2,
original: "aaa,a",
returned: [],
typeFilter: -1,
userQuery: "aaa,a",
error: null,
},
{
elems: [],
foundElems: 0,
original: ",,,,",
returned: [],
typeFilter: -1,
userQuery: ",,,,",
error: null,
},
{
elems: [],
foundElems: 0,
original: 'mod :',
returned: [],
typeFilter: 0,
userQuery: 'mod :',
error: null,
},
{
elems: [],
foundElems: 0,
original: 'mod\t:',
returned: [],
typeFilter: 0,
userQuery: 'mod\t:',
error: null,
},
];
+9 -1
View File
@@ -1,4 +1,7 @@
// ignore-order
const QUERY = '"error"';
const FILTER_CRATE = 'std';
const EXPECTED = {
'others': [
@@ -6,7 +9,12 @@ const EXPECTED = {
{ 'path': 'std::fmt', 'name': 'Error' },
{ 'path': 'std::io', 'name': 'Error' },
],
'in_args': [],
'in_args': [
{ 'path': 'std::fmt::Error', 'name': 'eq' },
{ 'path': 'std::fmt::Error', 'name': 'cmp' },
{ 'path': 'std::fmt::Error', 'name': 'partial_cmp' },
],
'returned': [
{ 'path': 'std::fmt::LowerExp', 'name': 'fmt' },
],
+2 -2
View File
@@ -1,8 +1,8 @@
const QUERY = 'struct:Vec';
const QUERY = 'struct:VecD';
const EXPECTED = {
'others': [
{ 'path': 'std::vec', 'name': 'Vec' },
{ 'path': 'std::collections', 'name': 'VecDeque' },
{ 'path': 'std::vec', 'name': 'Vec' },
],
};
+4 -1
View File
@@ -1,6 +1,7 @@
// exact-check
const QUERY = 'macro:print';
const FILTER_CRATE = 'std';
const EXPECTED = {
'others': [
@@ -9,6 +10,8 @@ const EXPECTED = {
{ 'path': 'std', 'name': 'println' },
{ 'path': 'std', 'name': 'eprintln' },
{ 'path': 'std::pin', 'name': 'pin' },
{ 'path': 'core::pin', 'name': 'pin' },
{ 'path': 'std::future', 'name': 'join' },
{ 'path': 'std', 'name': 'line' },
{ 'path': 'std', 'name': 'write' },
],
};
+1 -1
View File
@@ -4,6 +4,6 @@ const EXPECTED = {
'others': [
{ 'path': 'std::vec::Vec', 'name': 'new' },
{ 'path': 'std::vec::Vec', 'name': 'ne' },
{ 'path': 'std::rc::Rc', 'name': 'ne' },
{ 'path': 'alloc::vec::Vec', 'name': 'ne' },
],
};
+1 -1
View File
@@ -1,6 +1,6 @@
// exact-check
const QUERY = 'true';
const QUERY = '"true"';
const FILTER_CRATE = 'doc_alias_filter';
+20
View File
@@ -27,6 +27,7 @@ const QUERY = [
const EXPECTED = [
{
// StructItem
'others': [
{
'path': 'doc_alias',
@@ -38,6 +39,7 @@ const EXPECTED = [
],
},
{
// StructFieldItem
'others': [
{
'path': 'doc_alias::Struct',
@@ -49,6 +51,7 @@ const EXPECTED = [
],
},
{
// StructMethodItem
'others': [
{
'path': 'doc_alias::Struct',
@@ -76,6 +79,7 @@ const EXPECTED = [
],
},
{
// ImplTraitFunction
'others': [
{
'path': 'doc_alias::Struct',
@@ -87,6 +91,7 @@ const EXPECTED = [
],
},
{
// EnumItem
'others': [
{
'path': 'doc_alias',
@@ -98,6 +103,7 @@ const EXPECTED = [
],
},
{
// VariantItem
'others': [
{
'path': 'doc_alias::Enum',
@@ -109,6 +115,7 @@ const EXPECTED = [
],
},
{
// EnumMethodItem
'others': [
{
'path': 'doc_alias::Enum',
@@ -120,6 +127,7 @@ const EXPECTED = [
],
},
{
// TypedefItem
'others': [
{
'path': 'doc_alias',
@@ -131,6 +139,7 @@ const EXPECTED = [
],
},
{
// TraitItem
'others': [
{
'path': 'doc_alias',
@@ -142,6 +151,7 @@ const EXPECTED = [
],
},
{
// TraitTypeItem
'others': [
{
'path': 'doc_alias::Trait',
@@ -153,6 +163,7 @@ const EXPECTED = [
],
},
{
// AssociatedConstItem
'others': [
{
'path': 'doc_alias::Trait',
@@ -164,6 +175,7 @@ const EXPECTED = [
],
},
{
// TraitFunctionItem
'others': [
{
'path': 'doc_alias::Trait',
@@ -175,6 +187,7 @@ const EXPECTED = [
],
},
{
// FunctionItem
'others': [
{
'path': 'doc_alias',
@@ -186,6 +199,7 @@ const EXPECTED = [
],
},
{
// ModuleItem
'others': [
{
'path': 'doc_alias',
@@ -197,6 +211,7 @@ const EXPECTED = [
],
},
{
// ConstItem
'others': [
{
'path': 'doc_alias',
@@ -212,6 +227,7 @@ const EXPECTED = [
],
},
{
// StaticItem
'others': [
{
'path': 'doc_alias',
@@ -223,6 +239,7 @@ const EXPECTED = [
],
},
{
// UnionItem
'others': [
{
'path': 'doc_alias',
@@ -240,6 +257,7 @@ const EXPECTED = [
],
},
{
// UnionFieldItem
'others': [
{
'path': 'doc_alias::Union',
@@ -251,6 +269,7 @@ const EXPECTED = [
],
},
{
// UnionMethodItem
'others': [
{
'path': 'doc_alias::Union',
@@ -262,6 +281,7 @@ const EXPECTED = [
],
},
{
// MacroItem
'others': [
{
'path': 'doc_alias',
+19 -4
View File
@@ -1,16 +1,18 @@
// exact-check
const QUERY = [
'"R<P>"',
'R<P>',
'"P"',
'P',
'"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
'ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>',
'TraitCat',
'TraitDog',
'Result<String>',
];
const EXPECTED = [
{
// R<P>
'returned': [
{ 'path': 'generics', 'name': 'alef' },
],
@@ -19,6 +21,7 @@ const EXPECTED = [
],
},
{
// "P"
'others': [
{ 'path': 'generics', 'name': 'P' },
],
@@ -30,29 +33,41 @@ const EXPECTED = [
],
},
{
// P
'returned': [
{ 'path': 'generics', 'name': 'alef' },
{ 'path': 'generics', 'name': 'bet' },
],
'in_args': [
{ 'path': 'generics', 'name': 'alpha' },
{ 'path': 'generics', 'name': 'beta' },
],
},
{
// "ExtraCreditStructMulti"<ExtraCreditInnerMulti, ExtraCreditInnerMulti>
'in_args': [
{ 'path': 'generics', 'name': 'extracreditlabhomework' },
],
'returned': [],
},
{
// TraitCat
'in_args': [
{ 'path': 'generics', 'name': 'gamma' },
],
},
{
// TraitDog
'in_args': [
{ 'path': 'generics', 'name': 'gamma' },
],
},
{
// Result<String>
'others': [],
'returned': [
{ 'path': 'generics', 'name': 'super_soup' },
],
'in_args': [
{ 'path': 'generics', 'name': 'super_soup' },
],
},
];
+2
View File
@@ -24,3 +24,5 @@ pub trait TraitCat {}
pub trait TraitDog {}
pub fn gamma<T: TraitCat + TraitDog>(t: T) {}
pub fn super_soup(s: Result<String, i32>) -> Result<String, i32> { s }
+1 -1
View File
@@ -1,5 +1,5 @@
error: implementation of `FnOnce` is not general enough
--> $DIR/rfc1623.rs:36:8
--> $DIR/rfc1623.rs:32:8
|
LL | f: &id,
| ^^^ implementation of `FnOnce` is not general enough
+12 -40
View File
@@ -1,63 +1,35 @@
error[E0308]: mismatched types
--> $DIR/rfc1623.rs:29:35
--> $DIR/rfc1623.rs:32:8
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
LL | |
LL | |
LL | |
... |
LL | |
LL | | };
| |_^ one type is more general than the other
LL | f: &id,
| ^^^ one type is more general than the other
|
= note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
found type `Fn<(&Foo<'_>,)>`
error[E0308]: mismatched types
--> $DIR/rfc1623.rs:29:35
--> $DIR/rfc1623.rs:32:8
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
LL | |
LL | |
LL | |
... |
LL | |
LL | | };
| |_^ one type is more general than the other
LL | f: &id,
| ^^^ one type is more general than the other
|
= note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
found type `Fn<(&Foo<'_>,)>`
error: implementation of `FnOnce` is not general enough
--> $DIR/rfc1623.rs:29:35
--> $DIR/rfc1623.rs:32:8
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
LL | |
LL | |
LL | |
... |
LL | |
LL | | };
| |_^ implementation of `FnOnce` is not general enough
LL | f: &id,
| ^^^ implementation of `FnOnce` is not general enough
|
= note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
error: implementation of `FnOnce` is not general enough
--> $DIR/rfc1623.rs:29:35
--> $DIR/rfc1623.rs:32:8
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
LL | |
LL | |
LL | |
... |
LL | |
LL | | };
| |_^ implementation of `FnOnce` is not general enough
LL | f: &id,
| ^^^ implementation of `FnOnce` is not general enough
|
= note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
+4 -4
View File
@@ -27,14 +27,14 @@ fn id<T>(t: T) -> T {
}
static SOME_STRUCT: &SomeStruct = &SomeStruct {
//[nll]~^ ERROR mismatched types
//[nll]~| ERROR mismatched types
//[nll]~| ERROR implementation of `FnOnce` is not general enough
//[nll]~| ERROR implementation of `FnOnce` is not general enough
foo: &Foo { bools: &[false, true] },
bar: &Bar { bools: &[true, true] },
f: &id,
//[base]~^ ERROR implementation of `FnOnce` is not general enough
//[nll]~^^ ERROR mismatched types
//[nll]~| ERROR mismatched types
//[nll]~| ERROR implementation of `FnOnce` is not general enough
//[nll]~| ERROR implementation of `FnOnce` is not general enough
};
// very simple test for a 'static static with default lifetime
+149 -21
View File
@@ -58,7 +58,8 @@ function extractFunction(content, functionName) {
} while (pos < content.length && content[pos] !== '/' && content[pos - 1] !== '*');
// Eat quoted strings
} else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") {
} else if ((content[pos] === '"' || content[pos] === "'" || content[pos] === "`") &&
(pos === 0 || content[pos - 1] !== '/')) {
stop = content[pos];
do {
if (content[pos] === '\\') {
@@ -269,8 +270,13 @@ function loadSearchJsAndIndex(searchJs, searchIndex, storageJs, crate) {
// execQuery last parameter is built in buildIndex.
// buildIndex requires the hashmap from search-index.
var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
"handleAliases", "getQuery", "buildIndex", "execQuery", "execSearch",
"removeEmptyStringsFromArray"];
"buildIndex", "execQuery", "parseQuery", "createQueryResults",
"isWhitespace", "isSpecialStartCharacter", "isStopCharacter",
"parseInput", "getItemsBefore", "getNextElem", "createQueryElement",
"isReturnArrow", "isPathStart", "getStringElem", "newParsedQuery",
"itemTypeFromName", "isEndCharacter", "isErrorCharacter",
"isIdentCharacter", "isSeparatorCharacter", "getIdentEndPosition",
"checkExtraTypeFilterCharacters", "isWhitespaceCharacter"];
const functions = ["hasOwnPropertyRustdoc", "onEach"];
ALIASES = {};
@@ -286,12 +292,99 @@ function loadSearchJsAndIndex(searchJs, searchIndex, storageJs, crate) {
return [loaded, index];
}
// This function checks if `expected` has all the required fields needed for the checks.
function checkNeededFields(fullPath, expected, error_text, queryName, position) {
let fieldsToCheck;
if (fullPath.length === 0) {
fieldsToCheck = [
"foundElems",
"original",
"returned",
"typeFilter",
"userQuery",
"error",
];
} else if (fullPath.endsWith("elems") || fullPath.endsWith("generics")) {
fieldsToCheck = [
"name",
"fullPath",
"pathWithoutLast",
"pathLast",
"generics",
];
} else {
fieldsToCheck = [];
}
for (var i = 0; i < fieldsToCheck.length; ++i) {
const field = fieldsToCheck[i];
if (!expected.hasOwnProperty(field)) {
let text = `${queryName}==> Mandatory key \`${field}\` is not present`;
if (fullPath.length > 0) {
text += ` in field \`${fullPath}\``;
if (position != null) {
text += ` (position ${position})`;
}
}
error_text.push(text);
}
}
}
function valueCheck(fullPath, expected, result, error_text, queryName) {
if (Array.isArray(expected)) {
for (var i = 0; i < expected.length; ++i) {
checkNeededFields(fullPath, expected[i], error_text, queryName, i);
if (i >= result.length) {
error_text.push(`${queryName}==> EXPECTED has extra value in array from field ` +
`\`${fullPath}\` (position ${i}): \`${JSON.stringify(expected[i])}\``);
} else {
valueCheck(fullPath + '[' + i + ']', expected[i], result[i], error_text, queryName);
}
}
for (; i < result.length; ++i) {
error_text.push(`${queryName}==> RESULT has extra value in array from field ` +
`\`${fullPath}\` (position ${i}): \`${JSON.stringify(result[i])}\` ` +
'compared to EXPECTED');
}
} else if (expected !== null && typeof expected !== "undefined" &&
expected.constructor == Object)
{
for (const key in expected) {
if (!expected.hasOwnProperty(key)) {
continue;
}
if (!result.hasOwnProperty(key)) {
error_text.push('==> Unknown key "' + key + '"');
break;
}
const obj_path = fullPath + (fullPath.length > 0 ? '.' : '') + key;
valueCheck(obj_path, expected[key], result[key], error_text, queryName);
}
} else {
expectedValue = JSON.stringify(expected);
resultValue = JSON.stringify(result);
if (expectedValue != resultValue) {
error_text.push(`${queryName}==> Different values for field \`${fullPath}\`:\n` +
`EXPECTED: \`${expectedValue}\`\nRESULT: \`${resultValue}\``);
}
}
}
function runParser(query, expected, loaded, loadedFile, queryName) {
var error_text = [];
checkNeededFields("", expected, error_text, queryName, null);
if (error_text.length === 0) {
valueCheck('', expected, loaded.parseQuery(query), error_text, queryName);
}
return error_text;
}
function runSearch(query, expected, index, loaded, loadedFile, queryName) {
const filter_crate = loadedFile.FILTER_CRATE;
const ignore_order = loadedFile.ignore_order;
const exact_check = loadedFile.exact_check;
var results = loaded.execSearch(loaded.getQuery(query), index, filter_crate);
var results = loaded.execQuery(loaded.parseQuery(query), index, filter_crate);
var error_text = [];
for (var key in expected) {
@@ -353,40 +446,75 @@ function checkResult(error_text, loadedFile, displaySuccess) {
return 1;
}
function runChecks(testFile, loaded, index) {
var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;';
if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
} else {
testFileContent += "exports.FILTER_CRATE = null;";
}
var loadedFile = loadContent(testFileContent);
const expected = loadedFile.EXPECTED;
function runCheck(loadedFile, key, callback) {
const expected = loadedFile[key];
const query = loadedFile.QUERY;
if (Array.isArray(query)) {
if (!Array.isArray(expected)) {
console.log("FAILED");
console.log("==> If QUERY variable is an array, EXPECTED should be an array too");
console.log(`==> If QUERY variable is an array, ${key} should be an array too`);
return 1;
} else if (query.length !== expected.length) {
console.log("FAILED");
console.log("==> QUERY variable should have the same length as EXPECTED");
console.log(`==> QUERY variable should have the same length as ${key}`);
return 1;
}
for (var i = 0; i < query.length; ++i) {
var error_text = runSearch(query[i], expected[i], index, loaded, loadedFile,
"[ query `" + query[i] + "`]");
var error_text = callback(query[i], expected[i], "[ query `" + query[i] + "`]");
if (checkResult(error_text, loadedFile, false) !== 0) {
return 1;
}
}
console.log("OK");
return 0;
} else {
var error_text = callback(query, expected, "");
if (checkResult(error_text, loadedFile, true) !== 0) {
return 1;
}
}
var error_text = runSearch(query, expected, index, loaded, loadedFile, "");
return checkResult(error_text, loadedFile, true);
return 0;
}
function runChecks(testFile, loaded, index) {
var checkExpected = false;
var checkParsed = false;
var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;';
if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
} else {
testFileContent += "exports.FILTER_CRATE = null;";
}
if (testFileContent.indexOf("\nconst EXPECTED") !== -1) {
testFileContent += 'exports.EXPECTED = EXPECTED;';
checkExpected = true;
}
if (testFileContent.indexOf("\nconst PARSED") !== -1) {
testFileContent += 'exports.PARSED = PARSED;';
checkParsed = true;
}
if (!checkParsed && !checkExpected) {
console.log("FAILED");
console.log("==> At least `PARSED` or `EXPECTED` is needed!");
return 1;
}
const loadedFile = loadContent(testFileContent);
var res = 0;
if (checkExpected) {
res += runCheck(loadedFile, "EXPECTED", (query, expected, text) => {
return runSearch(query, expected, index, loaded, loadedFile, text);
});
}
if (checkParsed) {
res += runCheck(loadedFile, "PARSED", (query, expected, text) => {
return runParser(query, expected, loaded, loadedFile, text);
});
}
return res;
}
function load_files(doc_folder, resource_suffix, crate) {