Repository: rust-lang/rust-analyzer
Pull request #18371 (2024-10-22 11:35:02)

fix: Fix incorrect parsing of use bounds
Fixes https://github.com/rust-lang/rust-analyzer/issues/18357


Patch:
diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs
index b74cd90f69..5fba206693 100644
--- a/crates/hir-def/src/hir/type_ref.rs
+++ b/crates/hir-def/src/hir/type_ref.rs
@@ -157,9 +157,19 @@ pub enum TypeBound {
     Path(Path, TraitBoundModifier),
     ForLifetime(Box<[Name]>, Path),
     Lifetime(LifetimeRef),
+    Use(Box<[UseArgRef]>),
     Error,
 }
 
+#[cfg(target_pointer_width = "64")]
+const _: [(); 56] = [(); ::std::mem::size_of::<TypeBound>()];
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub enum UseArgRef {
+    Name(Name),
+    Lifetime(LifetimeRef),
+}
+
 /// A modifier on a bound, currently this is only used for `?Sized`, where the
 /// modifier is `Maybe`.
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
@@ -295,7 +305,7 @@ impl TypeRef {
                             TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
                                 go_path(path, f)
                             }
-                            TypeBound::Lifetime(_) | TypeBound::Error => (),
+                            TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
                         }
                     }
                 }
@@ -328,7 +338,7 @@ impl TypeRef {
                                 TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
                                     go_path(path, f)
                                 }
-                                TypeBound::Lifetime(_) | TypeBound::Error => (),
+                                TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
                             }
                         }
                     }
@@ -380,7 +390,16 @@ impl TypeBound {
                     None => TypeBound::Error,
                 }
             }
-            ast::TypeBoundKind::Use(_) => TypeBound::Error,
+            ast::TypeBoundKind::Use(gal) => TypeBound::Use(
+                gal.use_bound_generic_args()
+                    .map(|p| match p {
+                        ast::UseBoundGenericArg::Lifetime(l) => {
+                            UseArgRef::Lifetime(LifetimeRef::new(&l))
+                        }
+                        ast::UseBoundGenericArg::NameRef(n) => UseArgRef::Name(n.as_name()),
+                    })
+                    .collect(),
+            ),
             ast::TypeBoundKind::Lifetime(lifetime) => {
                 TypeBound::Lifetime(LifetimeRef::new(&lifetime))
             }
@@ -391,7 +410,7 @@ impl TypeBound {
         match self {
             TypeBound::Path(p, m) => Some((p, m)),
             TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)),
-            TypeBound::Lifetime(_) | TypeBound::Error => None,
+            TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None,
         }
     }
 }
diff --git a/crates/hir-def/src/lower.rs b/crates/hir-def/src/lower.rs
index 8e521460c3..e4786a1dd4 100644
--- a/crates/hir-def/src/lower.rs
+++ b/crates/hir-def/src/lower.rs
@@ -34,7 +34,7 @@ impl<'a> OuterImplTraitGuard<'a> {
     }
 }
 
-impl Drop for OuterImplTraitGuard<'_> {
+impl<'a> Drop for OuterImplTraitGuard<'a> {
     fn drop(&mut self) {
         self.ctx.outer_impl_trait.replace(self.old);
     }
diff --git a/crates/hir-def/src/pretty.rs b/crates/hir-def/src/pretty.rs
index d5ef17a91f..49c0ad4124 100644
--- a/crates/hir-def/src/pretty.rs
+++ b/crates/hir-def/src/pretty.rs
@@ -1,6 +1,9 @@
 //! Display and pretty printing routines.
 
-use std::fmt::{self, Write};
+use std::{
+    fmt::{self, Write},
+    mem,
+};
 
 use hir_expand::mod_path::PathKind;
 use intern::Interned;
@@ -11,7 +14,7 @@ use crate::{
     db::DefDatabase,
     lang_item::LangItemTarget,
     path::{GenericArg, GenericArgs, Path},
-    type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
+    type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef, UseArgRef},
 };
 
 pub(crate) fn print_path(
@@ -273,6 +276,22 @@ pub(crate) fn print_type_bounds(
                 print_path(db, path, buf, edition)?;
             }
             TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?,
+            TypeBound::Use(args) => {
+                write!(buf, "use<")?;
+                let mut first = true;
+                for arg in args {
+                    if !mem::take(&mut first) {
+                        write!(buf, ", ")?;
+                    }
+                    match arg {
+                        UseArgRef::Name(it) => write!(buf, "{}", it.display(db.upcast(), edition))?,
+                        UseArgRef::Lifetime(it) => {
+                            write!(buf, "{}", it.name.display(db.upcast(), edition))?
+                        }
+                    }
+                }
+                write!(buf, ">")?
+            }
             TypeBound::Error => write!(buf, "{{unknown}}")?,
         }
     }
diff --git a/crates/hir-expand/src/hygiene.rs b/crates/hir-expand/src/hygiene.rs
index f48de807c2..a819118915 100644
--- a/crates/hir-expand/src/hygiene.rs
+++ b/crates/hir-expand/src/hygiene.rs
@@ -227,7 +227,7 @@ pub(crate) fn dump_syntax_contexts(db: &dyn ExpandDatabase) -> String {
             &'a SyntaxContextData,
         );
 
-        impl std::fmt::Debug for SyntaxContextDebug<'_> {
+        impl<'a> std::fmt::Debug for SyntaxContextDebug<'a> {
             fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                 fancy_debug(self.2, self.1, self.0, f)
             }
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index 2b5342314a..7a3846df40 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -114,7 +114,7 @@ impl<'table, 'db> Autoderef<'table, 'db, usize> {
 }
 
 #[allow(private_bounds)]
-impl<T: TrackAutoderefSteps> Autoderef<'_, '_, T> {
+impl<'table, 'db, T: TrackAutoderefSteps> Autoderef<'table, 'db, T> {
     pub(crate) fn step_count(&self) -> usize {
         self.steps.len()
     }
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index 8a616956de..f7bacbd49b 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -521,7 +521,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
     }
 }
 
-impl ChalkContext<'_> {
+impl<'a> ChalkContext<'a> {
     fn edition(&self) -> Edition {
         self.db.crate_graph()[self.krate].edition
     }
diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 58de19ba81..1066a28c3f 100644
--- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -519,7 +519,7 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
     }
 }
 
-impl fmt::Debug for MatchCheckCtx<'_> {
+impl<'db> fmt::Debug for MatchCheckCtx<'db> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("MatchCheckCtx").finish()
     }
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 10f5bcdad8..79861345b8 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -19,7 +19,7 @@ use hir_def::{
     lang_item::{LangItem, LangItemTarget},
     nameres::DefMap,
     path::{Path, PathKind},
-    type_ref::{TraitBoundModifier, TypeBound, TypeRef},
+    type_ref::{TraitBoundModifier, TypeBound, TypeRef, UseArgRef},
     visibility::Visibility,
     GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId,
     ModuleId, TraitId,
@@ -2025,6 +2025,19 @@ impl HirDisplay for TypeBound {
                 )?;
                 path.hir_fmt(f)
             }
+            TypeBound::Use(args) => {
+                let edition = f.edition();
+                write!(
+                    f,
+                    "use<{}> ",
+                    args.iter()
+                        .map(|it| match it {
+                            UseArgRef::Lifetime(lt) => lt.name.display(f.db.upcast(), edition),
+                            UseArgRef::Name(n) => n.display(f.db.upcast(), edition),
+                        })
+                        .format(", ")
+                )
+            }
             TypeBound::Error => write!(f, "{{error}}"),
         }
     }
diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs
index 3d21785a70..e0d1758210 100644
--- a/crates/hir-ty/src/dyn_compatibility.rs
+++ b/crates/hir-ty/src/dyn_compatibility.rs
@@ -266,7 +266,7 @@ fn contains_illegal_self_type_reference<T: TypeVisitable<Interner>>(
         trait_self_param_idx: usize,
         allow_self_projection: AllowSelfProjection,
     }
-    impl TypeVisitor<Interner> for IllegalSelfTypeVisitor<'_> {
+    impl<'a> TypeVisitor<Interner> for IllegalSelfTypeVisitor<'a> {
         type BreakTy = ();
 
         fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 4f41af0b4e..88334b492d 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -1022,7 +1022,7 @@ impl<'a> InferenceContext<'a> {
             non_assocs: FxHashMap<OpaqueTyId, Ty>,
         }
 
-        impl TypeVisitor<Interner> for TypeAliasImplTraitCollector<'_, '_> {
+        impl<'a, 'b> TypeVisitor<Interner> for TypeAliasImplTraitCollector<'a, 'b> {
             type BreakTy = ();
 
             fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index c7ed68448b..f7db948998 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -1067,7 +1067,7 @@ impl<'a> TyLoweringContext<'a> {
                     lifetime,
                 })))
             }
-            TypeBound::Error => None,
+            TypeBound::Use(_) | TypeBound::Error => None,
         };
         clause.into_iter().chain(
             trait_ref
@@ -1087,6 +1087,7 @@ impl<'a> TyLoweringContext<'a> {
                 path.segments().last()
             }
             TypeBound::Path(_, TraitBoundModifier::Maybe)
+            | TypeBound::Use(_)
             | TypeBound::Error
             | TypeBound::Lifetime(_) => None,
         };
@@ -1571,7 +1572,7 @@ pub(crate) fn generic_predicates_for_param_query(
                         })
                     })
                 }
-                TypeBound::Lifetime(_) | TypeBound::Error => false,
+                TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
             }
         }
         WherePredicate::Lifetime { .. } => false,
diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs
index 59c583afb2..8e815aabf2 100644
--- a/crates/hir-ty/src/mir.rs
+++ b/crates/hir-ty/src/mir.rs
@@ -879,8 +879,7 @@ pub enum Rvalue {
     ///
     /// **Needs clarification**: Are there weird additional semantics here related to the runtime
     /// nature of this operation?
-    // ThreadLocalRef(DefId),
-    ThreadLocalRef(std::convert::Infallible),
+    //ThreadLocalRef(DefId),
 
     /// Creates a pointer with the indicated mutability to the place.
     ///
@@ -889,8 +888,7 @@ pub enum Rvalue {
     ///
     /// Like with references, the semantics of this operation are heavily dependent on the aliasing
     /// model.
-    // AddressOf(Mutability, Place),
-    AddressOf(std::convert::Infallible),
+    //AddressOf(Mutability, Place),
 
     /// Yields the length of the place, as a `usize`.
     ///
@@ -908,21 +906,19 @@ pub enum Rvalue {
     Cast(CastKind, Operand, Ty),
 
     // FIXME link to `pointer::offset` when it hits stable.
-    /// * `Offset` has the same semantics as `pointer::offset`, except that the second
-    ///   parameter may be a `usize` as well.
-    /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
-    ///   raw pointers, or function pointers and return a `bool`. The types of the operands must be
-    ///   matching, up to the usual caveat of the lifetimes in function pointers.
-    /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
-    ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
-    ///   truncated as needed.
-    /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
-    ///   types and return a value of that type.
-    /// * The remaining operations accept signed integers, unsigned integers, or floats with
-    ///   matching types and return a value of that type.
+    // /// * `Offset` has the same semantics as `pointer::offset`, except that the second
+    // ///   parameter may be a `usize` as well.
+    // /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
+    // ///   raw pointers, or function pointers and return a `bool`. The types of the operands must be
+    // ///   matching, up to the usual caveat of the lifetimes in function pointers.
+    // /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
+    // ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
+    // ///   truncated as needed.
+    // /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
+    // ///   types and return a value of that type.
+    // /// * The remaining operations accept signed integers, unsigned integers, or floats with
+    // ///   matching types and return a value of that type.
     //BinaryOp(BinOp, Box<(Operand, Operand)>),
-    BinaryOp(std::convert::Infallible),
-
     /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
     ///
     /// When overflow checking is disabled and we are generating run-time code, the error condition
@@ -941,7 +937,6 @@ pub enum Rvalue {
 
     /// Computes a value as described by the operation.
     //NullaryOp(NullOp, Ty),
-    NullaryOp(std::convert::Infallible),
 
     /// Exactly like `BinaryOp`, but less operands.
     ///
@@ -1100,10 +1095,6 @@ impl MirBody {
                                     for_operand(op, &mut f, &mut self.projection_store);
                                 }
                             }
-                            Rvalue::ThreadLocalRef(n)
-                            | Rvalue::AddressOf(n)
-                            | Rvalue::BinaryOp(n)
-                            | Rvalue::NullaryOp(n) => match *n {},
                         }
                     }
                     StatementKind::FakeRead(p) | StatementKind::Deinit(p) => {
diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs
index 9c86d3b59f..9830fa1ca7 100644
--- a/crates/hir-ty/src/mir/borrowck.rs
+++ b/crates/hir-ty/src/mir/borrowck.rs
@@ -167,10 +167,6 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
                             for_operand(op, statement.span);
                         }
                     }
-                    Rvalue::ThreadLocalRef(n)
-                    | Rvalue::AddressOf(n)
-                    | Rvalue::BinaryOp(n)
-                    | Rvalue::NullaryOp(n) => match *n {},
                 },
                 StatementKind::FakeRead(_)
                 | StatementKind::Deinit(_)
@@ -257,10 +253,6 @@ fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec<PartiallyMoved>
                             for_operand(op, statement.span);
                         }
                     }
-                    Rvalue::ThreadLocalRef(n)
-                    | Rvalue::AddressOf(n)
-                    | Rvalue::BinaryOp(n)
-                    | Rvalue::NullaryOp(n) => match *n {},
                 },
                 StatementKind::FakeRead(_)
                 | StatementKind::Deinit(_)
@@ -556,10 +548,6 @@ fn mutability_of_locals(
                             }
                         }
                         Rvalue::ShallowInitBox(_, _) | Rvalue::ShallowInitBoxWithAlloc(_) => (),
-                        Rvalue::ThreadLocalRef(n)
-                        | Rvalue::AddressOf(n)
-                        | Rvalue::BinaryOp(n)
-                        | Rvalue::NullaryOp(n) => match *n {},
                     }
                     if let Rvalue::Ref(
                         BorrowKind::Mut {
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 7580f042ad..0d42617d18 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -1628,10 +1628,6 @@ impl Evaluator<'_> {
                 }
                 CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"),
             },
-            Rvalue::ThreadLocalRef(n)
-            | Rvalue::AddressOf(n)
-            | Rvalue::BinaryOp(n)
-            | Rvalue::NullaryOp(n) => match *n {},
         })
     }
 
@@ -2707,15 +2703,17 @@ impl Evaluator<'_> {
             TyKind::Function(_) => {
                 self.exec_fn_pointer(func_data, destination, &args[1..], locals, target_bb, span)
             }
-            TyKind::Closure(closure, subst) => self.exec_closure(
-                *closure,
-                func_data,
-                &Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()),
-                destination,
-                &args[1..],
-                locals,
-                span,
-            ),
+            TyKind::Closure(closure, subst) => {
+                return self.exec_closure(
+                    *closure,
+                    func_data,
+                    &Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()),
+                    destination,
+                    &args[1..],
+                    locals,
+                    span,
+                );
+            }
             _ => {
                 // try to execute the manual impl of `FnTrait` for structs (nightly feature used in std)
                 let arg0 = func;
diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs
index 92132fa047..4c6bc376e2 100644
--- a/crates/hir-ty/src/mir/monomorphization.rs
+++ b/crates/hir-ty/src/mir/monomorphization.rs
@@ -258,10 +258,6 @@ impl Filler<'_> {
                         | Rvalue::UnaryOp(_, _)
                         | Rvalue::Discriminant(_)
                         | Rvalue::CopyForDeref(_) => (),
-                        Rvalue::ThreadLocalRef(n)
-                        | Rvalue::AddressOf(n)
-                        | Rvalue::BinaryOp(n)
-                        | Rvalue::NullaryOp(n) => match *n {},
                     },
                     StatementKind::Deinit(_)
                     | StatementKind::FakeRead(_)
diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs
index 06765a104c..df56071aa9 100644
--- a/crates/hir-ty/src/mir/pretty.rs
+++ b/crates/hir-ty/src/mir/pretty.rs
@@ -459,10 +459,6 @@ impl<'a> MirPrettyCtx<'a> {
                 self.place(p);
                 w!(self, ")");
             }
-            Rvalue::ThreadLocalRef(n)
-            | Rvalue::AddressOf(n)
-            | Rvalue::BinaryOp(n)
-            | Rvalue::NullaryOp(n) => match *n {},
         }
     }
 
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index 98e8feceb0..620bba2d75 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -123,7 +123,7 @@ pub(super) struct ClauseElaborator<'a> {
     seen: FxHashSet<WhereClause>,
 }
 
-impl ClauseElaborator<'_> {
+impl<'a> ClauseElaborator<'a> {
     fn extend_deduped(&mut self, clauses: impl IntoIterator<Item = WhereClause>) {
         self.stack.extend(clauses.into_iter().filter(|c| self.seen.insert(c.clone())))
     }
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 2716a10343..80908dac5d 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -154,7 +154,7 @@ impl<'db, DB> ops::Deref for Semantics<'db, DB> {
     }
 }
 
-impl<DB: HirDatabase> Semantics<'_, DB> {
+impl<'db, DB: HirDatabase> Semantics<'db, DB> {
     pub fn new(db: &DB) -> Semantics<'_, DB> {
         let impl_ = SemanticsImpl::new(db);
         Semantics { db, imp: impl_ }
diff --git a/crates/parser/src/grammar/generic_params.rs b/crates/parser/src/grammar/generic_params.rs
index ecfabca092..92311238c2 100644
--- a/crates/parser/src/grammar/generic_params.rs
+++ b/crates/parser/src/grammar/generic_params.rs
@@ -144,10 +144,31 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
         LIFETIME_IDENT => lifetime(p),
         T![for] => types::for_type(p, false),
         // test precise_capturing
-        // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T> {}
+        // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}
         T![use] if p.nth_at(1, T![<]) => {
             p.bump_any();
-            generic_param_list(p)
+            let m = p.start();
+            delimited(
+                p,
+                T![<],
+                T![>],
+                T![,],
+                || "expected identifier or lifetime".into(),
+                TokenSet::new(&[T![Self], IDENT, LIFETIME_IDENT]),
+                |p| {
+                    if p.at(T![Self]) {
+                        let m = p.start();
+                        p.bump(T![Self]);
+                        m.complete(p, NAME_REF);
+                    } else if p.at(LIFETIME_IDENT) {
+                        lifetime(p);
+                    } else {
+                        name_ref(p);
+                    }
+                    true
+                },
+            );
+            m.complete(p, USE_BOUND_GENERIC_ARGS);
         }
         T![?] if p.nth_at(1, T![for]) => {
             // test question_for_type_trait_bound
diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs
index 3db1a10ca5..882c243b0c 100644
--- a/crates/parser/src/grammar/patterns.rs
+++ b/crates/parser/src/grammar/patterns.rs
@@ -40,6 +40,9 @@ pub(super) fn pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
     pattern_r(p, recovery_set);
 }
 
+/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
+/// given `recovery_set`.
+
 // test or_pattern
 // fn main() {
 //     match () {
@@ -49,8 +52,6 @@ pub(super) fn pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
 //         [_ | _,] => (),
 //     }
 // }
-/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
-/// given `recovery_set`.
 fn pattern_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
     let m = p.start();
     pattern_single_r(p, recovery_set);
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs
index 8da338c0a2..21730244a3 100644
--- a/crates/parser/src/syntax_kind/generated.rs
+++ b/crates/parser/src/syntax_kind/generated.rs
@@ -312,6 +312,8 @@ pub enum SyntaxKind {
     UNDERSCORE_EXPR,
     UNION,
     USE,
+    USE_BOUND_GENERIC_ARG,
+    USE_BOUND_GENERIC_ARGS,
     USE_TREE,
     USE_TREE_LIST,
     VARIANT,
diff --git a/crates/proc-macro-api/src/msg/flat.rs b/crates/proc-macro-api/src/msg/flat.rs
index 5443a9bd67..88256e98b5 100644
--- a/crates/proc-macro-api/src/msg/flat.rs
+++ b/crates/proc-macro-api/src/msg/flat.rs
@@ -401,7 +401,7 @@ struct Writer<'a, 'span, S: InternableSpan> {
     text: Vec<String>,
 }
 
-impl<'a, S: InternableSpan> Writer<'a, '_, S> {
+impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> {
     fn write(&mut self, root: &'a tt::Subtree<S>) {
         self.enqueue(root);
         while let Some((idx, subtree)) = self.work.pop_front() {
@@ -524,7 +524,7 @@ struct Reader<'span, S: InternableSpan> {
     span_data_table: &'span S::Table,
 }
 
-impl<S: InternableSpan> Reader<'_, S> {
+impl<'span, S: InternableSpan> Reader<'span, S> {
     pub(crate) fn read(self) -> tt::Subtree<S> {
         let mut res: Vec<Option<tt::Subtree<S>>> = vec![None; self.subtree.len()];
         let read_span = |id| S::span_for_token_id(self.span_data_table, id);
diff --git a/crates/ra-salsa/src/derived/slot.rs b/crates/ra-salsa/src/derived/slot.rs
index 6c5ccba173..de7a397607 100644
--- a/crates/ra-salsa/src/derived/slot.rs
+++ b/crates/ra-salsa/src/derived/slot.rs
@@ -616,7 +616,7 @@ Please report this bug to https://github.com/salsa-rs/salsa/issues."
     }
 }
 
-impl<Q> Drop for PanicGuard<'_, Q>
+impl<'me, Q> Drop for PanicGuard<'me, Q>
 where
     Q: QueryFunction,
     Q::Value: Eq,
diff --git a/crates/ra-salsa/src/derived_lru/slot.rs b/crates/ra-salsa/src/derived_lru/slot.rs
index ff9cc4eade..d0e4b5422b 100644
--- a/crates/ra-salsa/src/derived_lru/slot.rs
+++ b/crates/ra-salsa/src/derived_lru/slot.rs
@@ -666,7 +666,7 @@ Please report this bug to https://github.com/salsa-rs/salsa/issues."
     }
 }
 
-impl<Q, MP> Drop for PanicGuard<'_, Q, MP>
+impl<'me, Q, MP> Drop for PanicGuard<'me, Q, MP>
 where
     Q: QueryFunction,
     MP: MemoizationPolicy<Q>,
diff --git a/crates/ra-salsa/src/interned.rs b/crates/ra-salsa/src/interned.rs
index 42c398d697..359662ec6b 100644
--- a/crates/ra-salsa/src/interned.rs
+++ b/crates/ra-salsa/src/interned.rs
@@ -493,7 +493,7 @@ where
     is_static::<Slot<K>>();
 }
 
-impl<Q> QueryTable<'_, Q>
+impl<'me, Q> QueryTable<'me, Q>
 where
     Q: Query<Storage = InternedStorage<Q>>,
     Q::Key: InternValue,
diff --git a/crates/ra-salsa/src/lib.rs b/crates/ra-salsa/src/lib.rs
index bd1ab6971c..1b327773ec 100644
--- a/crates/ra-salsa/src/lib.rs
+++ b/crates/ra-salsa/src/lib.rs
@@ -149,7 +149,7 @@ where
     db: &'me D,
 }
 
-impl<D: ?Sized> fmt::Debug for EventDebug<'_, D>
+impl<'me, D: ?Sized> fmt::Debug for EventDebug<'me, D>
 where
     D: plumbing::DatabaseOps,
 {
@@ -242,7 +242,7 @@ where
     db: &'me D,
 }
 
-impl<D: ?Sized> fmt::Debug for EventKindDebug<'_, D>
+impl<'me, D: ?Sized> fmt::Debug for EventKindDebug<'me, D>
 where
     D: plumbing::DatabaseOps,
 {
@@ -729,7 +729,7 @@ impl Cycle {
             db: &'me dyn Database,
         }
 
-        impl std::fmt::Debug for UnexpectedCycleDebug<'_> {
+        impl<'me> std::fmt::Debug for UnexpectedCycleDebug<'me> {
             fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                 fmt.debug_struct("UnexpectedCycle")
                     .field("all_participants", &self.c.all_participants(self.db))
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index b4e6e4c293..a9f8ac3a80 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -539,11 +539,18 @@ pub(crate) fn handle_document_symbol(
         url: &Url,
         res: &mut Vec<SymbolInformation>,
     ) {
+        let mut tags = Vec::new();
+
+        #[allow(deprecated)]
+        if let Some(true) = symbol.deprecated {
+            tags.push(SymbolTag::DEPRECATED)
+        }
+
         #[allow(deprecated)]
         res.push(SymbolInformation {
             name: symbol.name.clone(),
             kind: symbol.kind,
-            tags: symbol.tags.clone(),
+            tags: Some(tags),
             deprecated: symbol.deprecated,
             location: Location::new(url.clone(), symbol.range),
             container_name,
diff --git a/crates/rust-analyzer/src/tracing/hprof.rs b/crates/rust-analyzer/src/tracing/hprof.rs
index d466acef01..cad92962f3 100644
--- a/crates/rust-analyzer/src/tracing/hprof.rs
+++ b/crates/rust-analyzer/src/tracing/hprof.rs
@@ -120,7 +120,7 @@ pub struct DataVisitor<'a> {
     string: &'a mut String,
 }
 
-impl Visit for DataVisitor<'_> {
+impl<'a> Visit for DataVisitor<'a> {
     fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) {
         write!(self.string, "{} = {:?} ", field.name(), value).unwrap();
     }
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
index 90441c27f6..3609da0bb2 100644
--- a/crates/syntax/rust.ungram
+++ b/crates/syntax/rust.ungram
@@ -657,7 +657,14 @@ TypeBoundList =
 TypeBound =
   Lifetime
 | ('~' 'const' | 'const')? 'async'? '?'? Type
-| 'use' GenericParamList
+| 'use' UseBoundGenericArgs
+
+UseBoundGenericArgs =
+ '<' (UseBoundGenericArg (',' UseBoundGenericArg)* ','?)? '>'
+
+UseBoundGenericArg =
+  Lifetime
+| NameRef
 
 //************************//
 //        Patterns        //
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 4f8bff489c..b9eb1abb11 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -1993,13 +1993,15 @@ pub struct TypeBound {
     pub(crate) syntax: SyntaxNode,
 }
 impl TypeBound {
-    #[inline]
-    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
     #[inline]
     pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
     #[inline]
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
     #[inline]
+    pub fn use_bound_generic_args(&self) -> Option<UseBoundGenericArgs> {
+        support::child(&self.syntax)
+    }
+    #[inline]
     pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
     #[inline]
     pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
@@ -2076,6 +2078,21 @@ impl Use {
     pub fn use_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![use]) }
 }
 
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct UseBoundGenericArgs {
+    pub(crate) syntax: SyntaxNode,
+}
+impl UseBoundGenericArgs {
+    #[inline]
+    pub fn use_bound_generic_args(&self) -> AstChildren<UseBoundGenericArg> {
+        support::children(&self.syntax)
+    }
+    #[inline]
+    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
+    #[inline]
+    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct UseTree {
     pub(crate) syntax: SyntaxNode,
@@ -2402,6 +2419,12 @@ pub enum Type {
     TupleType(TupleType),
 }
 
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum UseBoundGenericArg {
+    Lifetime(Lifetime),
+    NameRef(NameRef),
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct AnyHasArgList {
     pub(crate) syntax: SyntaxNode,
@@ -4435,6 +4458,20 @@ impl AstNode for Use {
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for UseBoundGenericArgs {
+    #[inline]
+    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_BOUND_GENERIC_ARGS }
+    #[inline]
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
 impl AstNode for UseTree {
     #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
@@ -5560,6 +5597,34 @@ impl AstNode for Type {
         }
     }
 }
+impl From<Lifetime> for UseBoundGenericArg {
+    #[inline]
+    fn from(node: Lifetime) -> UseBoundGenericArg { UseBoundGenericArg::Lifetime(node) }
+}
+impl From<NameRef> for UseBoundGenericArg {
+    #[inline]
+    fn from(node: NameRef) -> UseBoundGenericArg { UseBoundGenericArg::NameRef(node) }
+}
+impl AstNode for UseBoundGenericArg {
+    #[inline]
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, LIFETIME | NAME_REF) }
+    #[inline]
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        let res = match syntax.kind() {
+            LIFETIME => UseBoundGenericArg::Lifetime(Lifetime { syntax }),
+            NAME_REF => UseBoundGenericArg::NameRef(NameRef { syntax }),
+            _ => return None,
+        };
+        Some(res)
+    }
+    #[inline]
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            UseBoundGenericArg::Lifetime(it) => &it.syntax,
+            UseBoundGenericArg::NameRef(it) => &it.syntax,
+        }
+    }
+}
 impl AnyHasArgList {
     #[inline]
     pub fn new<T: ast::HasArgList>(node: T) -> AnyHasArgList {
@@ -6570,6 +6635,11 @@ impl std::fmt::Display for Type {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for UseBoundGenericArg {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for Abi {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
@@ -7275,6 +7345,11 @@ impl std::fmt::Display for Use {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for UseBoundGenericArgs {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for UseTree {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 693bfe330b..11f5e662e3 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -795,7 +795,7 @@ pub enum TypeBoundKind {
     /// for<'a> ...
     ForType(ast::ForType),
     /// use
-    Use(ast::GenericParamList),
+    Use(ast::UseBoundGenericArgs),
     /// 'a
     Lifetime(ast::Lifetime),
 }
@@ -806,8 +806,8 @@ impl ast::TypeBound {
             TypeBoundKind::PathType(path_type)
         } else if let Some(for_type) = support::children(self.syntax()).next() {
             TypeBoundKind::ForType(for_type)
-        } else if let Some(generic_param_list) = self.generic_param_list() {
-            TypeBoundKind::Use(generic_param_list)
+        } else if let Some(args) = self.use_bound_generic_args() {
+            TypeBoundKind::Use(args)
         } else if let Some(lifetime) = self.lifetime() {
             TypeBoundKind::Lifetime(lifetime)
         } else {
diff --git a/crates/tt/src/buffer.rs b/crates/tt/src/buffer.rs
index acb7e2d6c5..1319739371 100644
--- a/crates/tt/src/buffer.rs
+++ b/crates/tt/src/buffer.rs
@@ -134,7 +134,7 @@ pub enum TokenTreeRef<'a, Span> {
     Leaf(&'a Leaf<Span>, &'a TokenTree<Span>),
 }
 
-impl<Span: Copy> TokenTreeRef<'_, Span> {
+impl<'a, Span: Copy> TokenTreeRef<'a, Span> {
     pub fn span(&self) -> Span {
         match self {
             TokenTreeRef::Subtree(subtree, _) => subtree.delimiter.open,
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index 234fe6ab02..0f2a758db4 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -446,7 +446,7 @@ export class Ctx implements RustAnalyzerExtensionApi {
                 return;
         }
         if (status.message) {
-            statusBar.tooltip.appendMarkdown(status.message);
+            statusBar.tooltip.appendText(status.message);
         }
         if (statusBar.tooltip.value) {
             statusBar.tooltip.appendMarkdown("\n\n---\n\n");
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index bc04b9474f..4c7b07c5e0 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -79,7 +79,7 @@ impl CommentBlock {
         let mut block = dummy_block.clone();
         for (line_num, line) in lines.enumerate() {
             match line.strip_prefix("//") {
-                Some(mut contents) if !contents.starts_with('/') => {
+                Some(mut contents) => {
                     if let Some('/' | '!') = contents.chars().next() {
                         contents = &contents[1..];
                         block.is_doc = true;
@@ -89,7 +89,7 @@ impl CommentBlock {
                     }
                     block.contents.push(contents.to_owned());
                 }
-                _ => {
+                None => {
                     if !block.contents.is_empty() {
                         let block = mem::replace(&mut block, dummy_block.clone());
                         res.push(block);


Test patch:
diff --git a/crates/parser/test_data/parser/inline/ok/precise_capturing.rast b/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
index cf52f1e479..f9c0a245af 100644
--- a/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
+++ b/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
@@ -50,16 +50,18 @@ SOURCE_FILE
           WHITESPACE " "
           TYPE_BOUND
             USE_KW "use"
-            GENERIC_PARAM_LIST
+            USE_BOUND_GENERIC_ARGS
               L_ANGLE "<"
-              LIFETIME_PARAM
-                LIFETIME
-                  LIFETIME_IDENT "'b"
+              LIFETIME
+                LIFETIME_IDENT "'b"
               COMMA ","
               WHITESPACE " "
-              TYPE_PARAM
-                NAME
-                  IDENT "T"
+              NAME_REF
+                IDENT "T"
+              COMMA ","
+              WHITESPACE " "
+              NAME_REF
+                SELF_TYPE_KW "Self"
               R_ANGLE ">"
     WHITESPACE " "
     BLOCK_EXPR
diff --git a/crates/parser/test_data/parser/inline/ok/precise_capturing.rs b/crates/parser/test_data/parser/inline/ok/precise_capturing.rs
index ec208d5062..9ac2305f3a 100644
--- a/crates/parser/test_data/parser/inline/ok/precise_capturing.rs
+++ b/crates/parser/test_data/parser/inline/ok/precise_capturing.rs
@@ -1,1 +1,1 @@
-fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T> {}
+fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}