Skip to content

Commit

Permalink
Auto merge of #119384 - matthiaskrgr:rollup-hhz9ws0, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 5 pull requests

Successful merges:

 - #119331 (rustdoc-search: count path edits with separate edit limit)
 - #119359 (Simplify Parser::ident_or_error)
 - #119376 (Add regression test for #106630)
 - #119379 (Update `parse_seq` doc)
 - #119380 (Don't suggest writing a bodyless arm if the pattern can never be a never pattern)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Dec 28, 2023
2 parents f4d794e + e8831b6 commit 3ee6710
Show file tree
Hide file tree
Showing 24 changed files with 249 additions and 92 deletions.
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

0 comments on commit 3ee6710

Please sign in to comment.