Skip to content

Rollup of 5 pull requests #119384

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Dec 28, 2023
8 changes: 7 additions & 1 deletion compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2937,7 +2937,13 @@ impl<'a> Parser<'a> {
let is_almost_fat_arrow = TokenKind::FatArrow
.similar_tokens()
.is_some_and(|similar_tokens| similar_tokens.contains(&this.token.kind));
let mut result = if !is_fat_arrow && !is_almost_fat_arrow {

// this avoids the compiler saying that a `,` or `}` was expected even though
// the pattern isn't a never pattern (and thus an arm body is required)
let armless = (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern())
|| matches!(this.token.kind, token::Comma | token::CloseDelim(Delimiter::Brace));

let mut result = if armless {
// A pattern without a body, allowed for never patterns.
arm_body = None;
this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)]).map(
Expand Down
54 changes: 32 additions & 22 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,15 @@ impl TokenType {
}
}

/// Used by [`Parser::expect_any_with_type`].
#[derive(Copy, Clone, Debug)]
enum TokenExpectType {
/// Unencountered tokens are inserted into [`Parser::expected_tokens`].
/// See [`Parser::check`].
Expect,

/// Unencountered tokens are not inserted into [`Parser::expected_tokens`].
/// See [`Parser::check_noexpect`].
NoExpect,
}

Expand Down Expand Up @@ -504,18 +510,10 @@ impl<'a> Parser<'a> {
}

fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> {
let result = self.token.ident().ok_or_else(|| self.expected_ident_found(recover));

let (ident, is_raw) = match result {
Ok(ident) => ident,
Err(err) => match err {
// we recovered!
Ok(ident) => ident,
Err(err) => return Err(err),
},
};

Ok((ident, is_raw))
match self.token.ident() {
Some(ident) => Ok(ident),
None => self.expected_ident_found(recover),
}
}

/// Checks if the next token is `tok`, and returns `true` if so.
Expand Down Expand Up @@ -766,13 +764,17 @@ impl<'a> Parser<'a> {
}
}

/// Checks if the next token is contained within `kets`, and returns `true` if so.
fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool {
kets.iter().any(|k| match expect {
TokenExpectType::Expect => self.check(k),
TokenExpectType::NoExpect => self.token == **k,
TokenExpectType::NoExpect => self.check_noexpect(k),
})
}

/// Parses a sequence until the specified delimiters. The function
/// `f` must consume tokens until reaching the next separator or
/// closing bracket.
fn parse_seq_to_before_tokens<T>(
&mut self,
kets: &[&TokenKind],
Expand All @@ -791,13 +793,15 @@ impl<'a> Parser<'a> {
}
if let Some(t) = &sep.sep {
if first {
// no separator for the first element
first = false;
} else {
// check for separator
match self.expect(t) {
Ok(false) => {
Ok(false) /* not recovered */ => {
self.current_closure.take();
}
Ok(true) => {
Ok(true) /* recovered */ => {
self.current_closure.take();
recovered = true;
break;
Expand Down Expand Up @@ -965,19 +969,19 @@ impl<'a> Parser<'a> {
Ok(())
}

/// Parses a sequence, not including the closing delimiter. The function
/// Parses a sequence, not including the delimiters. The function
/// `f` must consume tokens until reaching the next separator or
/// closing bracket.
fn parse_seq_to_before_end<T>(
&mut self,
ket: &TokenKind,
sep: SeqSep,
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (ThinVec<T>, bool, bool)> {
) -> PResult<'a, (ThinVec<T>, bool /* trailing */, bool /* recovered */)> {
self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
}

/// Parses a sequence, including the closing delimiter. The function
/// Parses a sequence, including only the closing delimiter. The function
/// `f` must consume tokens until reaching the next separator or
/// closing bracket.
fn parse_seq_to_end<T>(
Expand All @@ -993,7 +997,7 @@ impl<'a> Parser<'a> {
Ok((val, trailing))
}

/// Parses a sequence, including the closing delimiter. The function
/// Parses a sequence, including both delimiters. The function
/// `f` must consume tokens until reaching the next separator or
/// closing bracket.
fn parse_unspanned_seq<T>(
Expand All @@ -1002,16 +1006,19 @@ impl<'a> Parser<'a> {
ket: &TokenKind,
sep: SeqSep,
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (ThinVec<T>, bool)> {
) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> {
self.expect(bra)?;
self.parse_seq_to_end(ket, sep, f)
}

/// Parses a comma-separated sequence, including both delimiters.
/// The function `f` must consume tokens until reaching the next separator or
/// closing bracket.
fn parse_delim_comma_seq<T>(
&mut self,
delim: Delimiter,
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (ThinVec<T>, bool)> {
) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> {
self.parse_unspanned_seq(
&token::OpenDelim(delim),
&token::CloseDelim(delim),
Expand All @@ -1020,10 +1027,13 @@ impl<'a> Parser<'a> {
)
}

/// Parses a comma-separated sequence delimited by parentheses (e.g. `(x, y)`).
/// The function `f` must consume tokens until reaching the next separator or
/// closing bracket.
fn parse_paren_comma_seq<T>(
&mut self,
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (ThinVec<T>, bool)> {
) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> {
self.parse_delim_comma_seq(Delimiter::Parenthesis, f)
}

Expand Down
47 changes: 30 additions & 17 deletions src/librustdoc/html/static/js/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -1805,11 +1805,20 @@ function initSearch(rawSearchIndex) {
return unifyFunctionTypes([row], [elem], whereClause, mgens);
}

function checkPath(contains, ty, maxEditDistance) {
/**
* Compute an "edit distance" that ignores missing path elements.
* @param {string[]} contains search query path
* @param {Row} ty indexed item
* @returns {null|number} edit distance
*/
function checkPath(contains, ty) {
if (contains.length === 0) {
return 0;
}
let ret_dist = maxEditDistance + 1;
const maxPathEditDistance = Math.floor(
contains.reduce((acc, next) => acc + next.length, 0) / 3
);
let ret_dist = maxPathEditDistance + 1;
const path = ty.path.split("::");

if (ty.parent && ty.parent.name) {
Expand All @@ -1821,15 +1830,23 @@ function initSearch(rawSearchIndex) {
pathiter: for (let i = length - clength; i >= 0; i -= 1) {
let dist_total = 0;
for (let x = 0; x < clength; ++x) {
const dist = editDistance(path[i + x], contains[x], maxEditDistance);
if (dist > maxEditDistance) {
continue pathiter;
const [p, c] = [path[i + x], contains[x]];
if (Math.floor((p.length - c.length) / 3) <= maxPathEditDistance &&
p.indexOf(c) !== -1
) {
// discount distance on substring match
dist_total += Math.floor((p.length - c.length) / 3);
} else {
const dist = editDistance(p, c, maxPathEditDistance);
if (dist > maxPathEditDistance) {
continue pathiter;
}
dist_total += dist;
}
dist_total += dist;
}
ret_dist = Math.min(ret_dist, Math.round(dist_total / clength));
}
return ret_dist;
return ret_dist > maxPathEditDistance ? null : ret_dist;
}

function typePassesFilter(filter, type) {
Expand Down Expand Up @@ -2030,8 +2047,8 @@ function initSearch(rawSearchIndex) {
}

if (elem.fullPath.length > 1) {
path_dist = checkPath(elem.pathWithoutLast, row, maxEditDistance);
if (path_dist > maxEditDistance) {
path_dist = checkPath(elem.pathWithoutLast, row);
if (path_dist === null) {
return;
}
}
Expand All @@ -2045,7 +2062,7 @@ function initSearch(rawSearchIndex) {

const dist = editDistance(row.normalizedName, elem.normalizedPathLast, maxEditDistance);

if (index === -1 && dist + path_dist > maxEditDistance) {
if (index === -1 && dist > maxEditDistance) {
return;
}

Expand Down Expand Up @@ -2100,13 +2117,9 @@ function initSearch(rawSearchIndex) {
}

function innerRunQuery() {
let queryLen = 0;
for (const elem of parsedQuery.elems) {
queryLen += elem.name.length;
}
for (const elem of parsedQuery.returned) {
queryLen += elem.name.length;
}
const queryLen =
parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) +
parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0);
const maxEditDistance = Math.floor(queryLen / 3);

/**
Expand Down
1 change: 0 additions & 1 deletion tests/rustdoc-js-std/asrawfd.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const EXPECTED = {
// Validate that type alias methods get the correct path.
{ 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' },
{ 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' },
{ 'path': 'std::os::linux::process::PidFd', 'name': 'as_raw_fd' },
{ 'path': 'std::os::fd::RawFd', 'name': 'as_raw_fd' },
],
};
42 changes: 42 additions & 0 deletions tests/rustdoc-js-std/path-maxeditdistance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// exact-check
const FILTER_CRATE = "std";
const EXPECTED = [
{
query: 'vec::intoiterator',
others: [
// trait std::iter::IntoIterator is not the first result
{ 'path': 'std::vec', 'name': 'IntoIter' },
{ 'path': 'std::vec::Vec', 'name': 'into_iter' },
{ 'path': 'std::vec::Drain', 'name': 'into_iter' },
{ 'path': 'std::vec::IntoIter', 'name': 'into_iter' },
{ 'path': 'std::vec::ExtractIf', 'name': 'into_iter' },
{ 'path': 'std::vec::Splice', 'name': 'into_iter' },
{ 'path': 'std::collections::VecDeque', 'name': 'into_iter' },
],
},
{
query: 'vec::iter',
others: [
// std::net::ToSocketAttrs::iter should not show up here
{ 'path': 'std::vec', 'name': 'IntoIter' },
{ 'path': 'std::vec::Vec', 'name': 'from_iter' },
{ 'path': 'std::vec::Vec', 'name': 'into_iter' },
{ 'path': 'std::vec::Drain', 'name': 'into_iter' },
{ 'path': 'std::vec::IntoIter', 'name': 'into_iter' },
{ 'path': 'std::vec::ExtractIf', 'name': 'into_iter' },
{ 'path': 'std::vec::Splice', 'name': 'into_iter' },
{ 'path': 'std::collections::VecDeque', 'name': 'iter' },
{ 'path': 'std::collections::VecDeque', 'name': 'iter_mut' },
{ 'path': 'std::collections::VecDeque', 'name': 'from_iter' },
{ 'path': 'std::collections::VecDeque', 'name': 'into_iter' },
],
},
{
query: 'slice::itermut',
others: [
// std::collections::btree_map::itermut should not show up here
{ 'path': 'std::slice', 'name': 'IterMut' },
{ 'path': 'std::slice', 'name': 'iter_mut' },
],
},
];
31 changes: 20 additions & 11 deletions tests/rustdoc-js-std/path-ordering.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
const EXPECTED = {
query: 'hashset::insert',
others: [
// ensure hashset::insert comes first
{ 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' },
{ 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert' },
{ 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_with' },
{ 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_owned' },
{ 'path': 'std::collections::hash_map::HashMap', 'name': 'insert' },
],
};
const EXPECTED = [
{
query: 'hashset::insert',
others: [
// ensure hashset::insert comes first
{ 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' },
{ 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert' },
{ 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_with' },
{ 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_owned' },
],
},
{
query: 'hash::insert',
others: [
// ensure hashset/hashmap::insert come first
{ 'path': 'std::collections::hash_map::HashMap', 'name': 'insert' },
{ 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' },
],
},
];
1 change: 0 additions & 1 deletion tests/rustdoc-js/exact-match.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ const EXPECTED = {
'others': [
{ 'path': 'exact_match::Si', 'name': 'pc' },
{ 'path': 'exact_match::Psi', 'name': 'pc' },
{ 'path': 'exact_match::Si', 'name': 'pa' },
],
};
22 changes: 15 additions & 7 deletions tests/rustdoc-js/module-substring.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
const EXPECTED = {
'query': 'ig::pc',
'others': [
{ 'path': 'module_substring::Sig', 'name': 'pc' },
{ 'path': 'module_substring::Si', 'name': 'pc' },
],
};
const EXPECTED = [
{
'query': 'ig::pc',
'others': [
{ 'path': 'module_substring::Sig', 'name': 'pc' },
],
},
{
'query': 'si::pc',
'others': [
{ 'path': 'module_substring::Si', 'name': 'pc' },
{ 'path': 'module_substring::Sig', 'name': 'pc' },
],
},
];
35 changes: 35 additions & 0 deletions tests/rustdoc-js/path-maxeditdistance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// exact-check

const EXPECTED = [
{
'query': 'xxxxxxxxxxx::hocuspocusprestidigitation',
// do not match abracadabra::hocuspocusprestidigitation
'others': [],
},
{
// exact match
'query': 'abracadabra::hocuspocusprestidigitation',
'others': [
{ 'path': 'abracadabra', 'name': 'HocusPocusPrestidigitation' },
],
},
{
// swap br/rb; that's edit distance 2, where maxPathEditDistance = 3 (11 / 3)
'query': 'arbacadarba::hocuspocusprestidigitation',
'others': [
{ 'path': 'abracadabra', 'name': 'HocusPocusPrestidigitation' },
],
},
{
// truncate 5 chars, where maxEditDistance = 7 (21 / 3)
'query': 'abracadarba::hocusprestidigitation',
'others': [
{ 'path': 'abracadabra', 'name': 'HocusPocusPrestidigitation' },
],
},
{
// truncate 9 chars, where maxEditDistance = 5 (17 / 3)
'query': 'abracadarba::hprestidigitation',
'others': [],
},
];
Loading