about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-28 17:54:35 +0000
committerbors <bors@rust-lang.org>2023-12-28 17:54:35 +0000
commit3ee671095499d83ba18d510683fa2a784d7d2ad2 (patch)
tree27c97142153699881c96f3c736b173501deef6dd
parentf4d794ea0b845413344621d89f6c945062748485 (diff)
parente8831b6df892887862505d356b436d0e1ff506b0 (diff)
downloadrust-3ee671095499d83ba18d510683fa2a784d7d2ad2.tar.gz
rust-3ee671095499d83ba18d510683fa2a784d7d2ad2.zip
Auto merge of #119384 - matthiaskrgr:rollup-hhz9ws0, r=matthiaskrgr
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
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs8
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs54
-rw-r--r--src/librustdoc/html/static/js/search.js47
-rw-r--r--tests/rustdoc-js-std/asrawfd.js1
-rw-r--r--tests/rustdoc-js-std/path-maxeditdistance.js42
-rw-r--r--tests/rustdoc-js-std/path-ordering.js31
-rw-r--r--tests/rustdoc-js/exact-match.js1
-rw-r--r--tests/rustdoc-js/module-substring.js22
-rw-r--r--tests/rustdoc-js/path-maxeditdistance.js35
-rw-r--r--tests/rustdoc-js/path-maxeditdistance.rs3
-rw-r--r--tests/rustdoc-js/path-ordering.js8
-rw-r--r--tests/rustdoc-js/path-ordering.rs6
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions1.rs2
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions1.stderr4
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions2.rs2
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions2.stderr4
-rw-r--r--tests/ui/impl-trait/not_general_enough_regression_106630.rs33
-rw-r--r--tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs6
-rw-r--r--tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr12
-rw-r--r--tests/ui/parser/issues/issue-24375.rs2
-rw-r--r--tests/ui/parser/issues/issue-24375.stderr4
-rw-r--r--tests/ui/parser/match-arm-without-body.stderr8
-rw-r--r--tests/ui/parser/pat-lt-bracket-1.rs2
-rw-r--r--tests/ui/parser/pat-lt-bracket-1.stderr4
24 files changed, 249 insertions, 92 deletions
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 73bd19f34c1..bf6151b64d3 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -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(
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 1598fd19f6d..19226f37abe 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -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,
 }
 
@@ -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.
@@ -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],
@@ -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;
@@ -965,7 +969,7 @@ 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>(
@@ -973,11 +977,11 @@ impl<'a> Parser<'a> {
         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>(
@@ -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>(
@@ -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),
@@ -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)
     }
 
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index e824a1fd4bd..e6263db3283 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -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) {
@@ -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) {
@@ -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;
                 }
             }
@@ -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;
             }
 
@@ -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);
 
             /**
diff --git a/tests/rustdoc-js-std/asrawfd.js b/tests/rustdoc-js-std/asrawfd.js
index 5b3cfeabbcd..5dbc4ba95d9 100644
--- a/tests/rustdoc-js-std/asrawfd.js
+++ b/tests/rustdoc-js-std/asrawfd.js
@@ -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' },
     ],
 };
diff --git a/tests/rustdoc-js-std/path-maxeditdistance.js b/tests/rustdoc-js-std/path-maxeditdistance.js
new file mode 100644
index 00000000000..822389aaa4f
--- /dev/null
+++ b/tests/rustdoc-js-std/path-maxeditdistance.js
@@ -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' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js-std/path-ordering.js b/tests/rustdoc-js-std/path-ordering.js
index c3d61d238cc..e6b7bfab1e5 100644
--- a/tests/rustdoc-js-std/path-ordering.js
+++ b/tests/rustdoc-js-std/path-ordering.js
@@ -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' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/exact-match.js b/tests/rustdoc-js/exact-match.js
index ce3a76f9b7d..9e47d27490b 100644
--- a/tests/rustdoc-js/exact-match.js
+++ b/tests/rustdoc-js/exact-match.js
@@ -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' },
     ],
 };
diff --git a/tests/rustdoc-js/module-substring.js b/tests/rustdoc-js/module-substring.js
index 7a10397ebc6..74c421d7f0b 100644
--- a/tests/rustdoc-js/module-substring.js
+++ b/tests/rustdoc-js/module-substring.js
@@ -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' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/path-maxeditdistance.js b/tests/rustdoc-js/path-maxeditdistance.js
new file mode 100644
index 00000000000..73b24a6dddf
--- /dev/null
+++ b/tests/rustdoc-js/path-maxeditdistance.js
@@ -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': [],
+    },
+];
diff --git a/tests/rustdoc-js/path-maxeditdistance.rs b/tests/rustdoc-js/path-maxeditdistance.rs
new file mode 100644
index 00000000000..3861280d59b
--- /dev/null
+++ b/tests/rustdoc-js/path-maxeditdistance.rs
@@ -0,0 +1,3 @@
+#![crate_name="abracadabra"]
+
+pub struct HocusPocusPrestidigitation;
diff --git a/tests/rustdoc-js/path-ordering.js b/tests/rustdoc-js/path-ordering.js
index f2e6fe2fa61..73d3f4b2755 100644
--- a/tests/rustdoc-js/path-ordering.js
+++ b/tests/rustdoc-js/path-ordering.js
@@ -1,13 +1,13 @@
 // exact-check
 
 const EXPECTED = {
-    'query': 'b::ccccccc',
+    'query': 'bbbbbb::ccccccc',
     'others': [
         // `ccccccc` is an exact match for all three of these.
         // However `b` is a closer match for `bb` than for any
         // of the others, so it ought to go first.
-        { 'path': 'path_ordering::bb', 'name': 'Ccccccc' },
-        { 'path': 'path_ordering::aa', 'name': 'Ccccccc' },
-        { 'path': 'path_ordering::dd', 'name': 'Ccccccc' },
+        { 'path': 'path_ordering::bbbbbb', 'name': 'Ccccccc' },
+        { 'path': 'path_ordering::abbbbb', 'name': 'Ccccccc' },
+        { 'path': 'path_ordering::dbbbbb', 'name': 'Ccccccc' },
     ],
 };
diff --git a/tests/rustdoc-js/path-ordering.rs b/tests/rustdoc-js/path-ordering.rs
index 7843cf7f9dc..71e24923ed1 100644
--- a/tests/rustdoc-js/path-ordering.rs
+++ b/tests/rustdoc-js/path-ordering.rs
@@ -1,9 +1,9 @@
-pub mod dd {
+pub mod dbbbbb {
     pub struct Ccccccc;
 }
-pub mod aa {
+pub mod abbbbb {
     pub struct Ccccccc;
 }
-pub mod bb {
+pub mod bbbbbb {
     pub struct Ccccccc;
 }
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs
index 9ffc2190d20..55353999b67 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs
@@ -17,7 +17,7 @@ fn main() {
         }
         match x as i32 {
             0..5+1 => errors_only.push(x),
-            //~^ error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `+`
+            //~^ error: expected one of `=>`, `if`, or `|`, found `+`
             1 | -3..0 => first_or.push(x),
             y @ (0..5 | 6) => or_two.push(y),
             y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
index 05235c9b922..19ebcaf0f36 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
@@ -1,8 +1,8 @@
-error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `+`
+error: expected one of `=>`, `if`, or `|`, found `+`
   --> $DIR/range_pat_interactions1.rs:19:17
    |
 LL |             0..5+1 => errors_only.push(x),
-   |                 ^ expected one of `,`, `=>`, `if`, `|`, or `}`
+   |                 ^ expected one of `=>`, `if`, or `|`
 
 error[E0408]: variable `n` is not bound in all patterns
   --> $DIR/range_pat_interactions1.rs:10:25
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs
index b212bfbe093..4615ebd688a 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs
@@ -9,7 +9,7 @@ fn main() {
         match x as i32 {
             0..=(5+1) => errors_only.push(x),
             //~^ error: inclusive range with no end
-            //~| error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `(`
+            //~| error: expected one of `=>`, `if`, or `|`, found `(`
             1 | -3..0 => first_or.push(x),
             y @ (0..5 | 6) => or_two.push(y),
             y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
index 0129f927e34..13a5542a474 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
@@ -6,11 +6,11 @@ LL |             0..=(5+1) => errors_only.push(x),
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `(`
+error: expected one of `=>`, `if`, or `|`, found `(`
   --> $DIR/range_pat_interactions2.rs:10:17
    |
 LL |             0..=(5+1) => errors_only.push(x),
-   |                 ^ expected one of `,`, `=>`, `if`, `|`, or `}`
+   |                 ^ expected one of `=>`, `if`, or `|`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/impl-trait/not_general_enough_regression_106630.rs b/tests/ui/impl-trait/not_general_enough_regression_106630.rs
new file mode 100644
index 00000000000..439973950f3
--- /dev/null
+++ b/tests/ui/impl-trait/not_general_enough_regression_106630.rs
@@ -0,0 +1,33 @@
+// edition:2018
+// run-pass
+
+use std::future::Future;
+
+trait AsyncCallback<'a> {
+    type Out;
+}
+
+impl<'a, Fut, T, F> AsyncCallback<'a> for F
+where
+    F: FnOnce(&'a mut ()) -> Fut,
+    Fut: Future<Output = T> + Send + 'a,
+{
+    type Out = T;
+}
+
+trait CallbackMarker {}
+
+impl<F, T> CallbackMarker for F
+where
+    T: 'static,
+    for<'a> F: AsyncCallback<'a, Out = T> + Send,
+{
+}
+
+fn do_sth<F: CallbackMarker>(_: F) {}
+
+async fn callback(_: &mut ()) -> impl Send {}
+
+fn main() {
+    do_sth(callback);
+}
diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs
index 2c402e4c65e..d1950087c4c 100644
--- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs
+++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs
@@ -84,15 +84,15 @@ fn main() {}
 
 #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
 //~^ ERROR inclusive range with no end
-//~| ERROR expected one of `,`, `=>`, `if`, `|`, or `}`, found `#`
+//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
 #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
 //~^ ERROR inclusive range with no end
-//~| ERROR expected one of `,`, `=>`, `if`, `|`, or `}`, found `#`
+//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
 #[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } }
 //~^ ERROR unexpected token: `#`
 #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
 //~^ ERROR inclusive range with no end
-//~| ERROR expected one of `,`, `=>`, `if`, `|`, or `}`, found `#`
+//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
 
 #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
 //~^ ERROR unexpected token: `#`
diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
index a0e95c5c1ed..e46c591080d 100644
--- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
+++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
@@ -365,11 +365,11 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `#`
+error: expected one of `=>`, `if`, or `|`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:85:38
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
-   |                                      ^ expected one of `,`, `=>`, `if`, `|`, or `}`
+   |                                      ^ expected one of `=>`, `if`, or `|`
 
 error[E0586]: inclusive range with no end
   --> $DIR/attr-stmt-expr-attr-bad.rs:88:35
@@ -379,11 +379,11 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `#`
+error: expected one of `=>`, `if`, or `|`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:88:38
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
-   |                                      ^ expected one of `,`, `=>`, `if`, `|`, or `}`
+   |                                      ^ expected one of `=>`, `if`, or `|`
 
 error: unexpected token: `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:91:39
@@ -399,11 +399,11 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `#`
+error: expected one of `=>`, `if`, or `|`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:93:38
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
-   |                                      ^ expected one of `,`, `=>`, `if`, `|`, or `}`
+   |                                      ^ expected one of `=>`, `if`, or `|`
 
 error: unexpected token: `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:97:34
diff --git a/tests/ui/parser/issues/issue-24375.rs b/tests/ui/parser/issues/issue-24375.rs
index 8d1bc579e7b..1d128d33e4f 100644
--- a/tests/ui/parser/issues/issue-24375.rs
+++ b/tests/ui/parser/issues/issue-24375.rs
@@ -3,7 +3,7 @@ static tmp : [&'static str; 2]  = ["hello", "he"];
 fn main() {
     let z = "hello";
     match z {
-        tmp[0] => {} //~ ERROR expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `[`
+        tmp[0] => {} //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `[`
         _ => {}
     }
 }
diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr
index 2b980a5520f..bb1e19e9e6d 100644
--- a/tests/ui/parser/issues/issue-24375.stderr
+++ b/tests/ui/parser/issues/issue-24375.stderr
@@ -1,8 +1,8 @@
-error: expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `[`
+error: expected one of `=>`, `@`, `if`, or `|`, found `[`
   --> $DIR/issue-24375.rs:6:12
    |
 LL |         tmp[0] => {}
-   |            ^ expected one of `,`, `=>`, `@`, `if`, `|`, or `}`
+   |            ^ expected one of `=>`, `@`, `if`, or `|`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/match-arm-without-body.stderr b/tests/ui/parser/match-arm-without-body.stderr
index d98c7ec2826..a3f7e32c177 100644
--- a/tests/ui/parser/match-arm-without-body.stderr
+++ b/tests/ui/parser/match-arm-without-body.stderr
@@ -1,8 +1,8 @@
-error: expected one of `,`, `=>`, `if`, `|`, or `}`, found reserved identifier `_`
+error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
   --> $DIR/match-arm-without-body.rs:13:9
    |
 LL |         Some(_)
-   |                - expected one of `,`, `=>`, `if`, `|`, or `}`
+   |                - expected one of `=>`, `if`, or `|`
 LL |         _ => {}
    |         ^ unexpected token
 
@@ -44,11 +44,11 @@ LL +
 LL ~         _ => {}
    |
 
-error: expected one of `,`, `.`, `=>`, `?`, `}`, or an operator, found reserved identifier `_`
+error: expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_`
   --> $DIR/match-arm-without-body.rs:36:9
    |
 LL |         Some(_) if true
-   |                        - expected one of `,`, `.`, `=>`, `?`, `}`, or an operator
+   |                        - expected one of `.`, `=>`, `?`, or an operator
 LL |         _ => {}
    |         ^ unexpected token
 
diff --git a/tests/ui/parser/pat-lt-bracket-1.rs b/tests/ui/parser/pat-lt-bracket-1.rs
index 33da15adb9e..2e2001434f2 100644
--- a/tests/ui/parser/pat-lt-bracket-1.rs
+++ b/tests/ui/parser/pat-lt-bracket-1.rs
@@ -1,7 +1,7 @@
 fn main() {
   match 42 {
     x < 7 => (),
-   //~^ error: expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `<`
+   //~^ error: expected one of `=>`, `@`, `if`, or `|`, found `<`
     _ => ()
   }
 }
diff --git a/tests/ui/parser/pat-lt-bracket-1.stderr b/tests/ui/parser/pat-lt-bracket-1.stderr
index f39487052ad..14e679bbee0 100644
--- a/tests/ui/parser/pat-lt-bracket-1.stderr
+++ b/tests/ui/parser/pat-lt-bracket-1.stderr
@@ -1,8 +1,8 @@
-error: expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `<`
+error: expected one of `=>`, `@`, `if`, or `|`, found `<`
   --> $DIR/pat-lt-bracket-1.rs:3:7
    |
 LL |     x < 7 => (),
-   |       ^ expected one of `,`, `=>`, `@`, `if`, `|`, or `}`
+   |       ^ expected one of `=>`, `@`, `if`, or `|`
 
 error: aborting due to 1 previous error