about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2024-12-05 17:06:02 +0000
committerGitHub <noreply@github.com>2024-12-05 17:06:02 +0000
commit0d8e5113d5b1171422dc7b235a2a76415147b4d6 (patch)
treee1922f527a2c93477d17268472e1e1c166a63cda
parentf9351a86eefaec10fb0eb1dd8d2dc6f619b84e13 (diff)
parent085ea34357f27b3ed8d94deb0555416e95aca8d6 (diff)
downloadrust-0d8e5113d5b1171422dc7b235a2a76415147b4d6.tar.gz
rust-0d8e5113d5b1171422dc7b235a2a76415147b4d6.zip
Merge pull request #18620 from Veykril/push-pyulxnouvxkq
fix: Parse lifetime bounds in lifetime param into TypeBoundList
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs36
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs10
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast12
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast48
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast23
14 files changed, 125 insertions, 85 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index 0c5e3a3620a..70bf2f13c88 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -648,9 +648,9 @@ impl Printer<'_> {
                 let (target, bound) = match pred {
                     WherePredicate::TypeBound { target, bound } => (target, bound),
                     WherePredicate::Lifetime { target, bound } => {
-                        wln!(
+                        w!(
                             this,
-                            "{}: {},",
+                            "{}: {}",
                             target.name.display(self.db.upcast(), edition),
                             bound.name.display(self.db.upcast(), edition)
                         );
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
index 5c07369f4b5..0f53969d6c7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
@@ -351,7 +351,8 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
             where
                 T: Copy,
                 T: 'a,
-                T: 'b
+                T: 'b,
+                'b: 'a
             {
                 pub(self) field: &'a &'b T,
             }
@@ -370,7 +371,8 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
             where
                 T: Copy,
                 T: 'a,
-                T: 'b
+                T: 'b,
+                'b: 'a
             {
                 // AstId: 9
                 pub(self) fn f<G>(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 624148cab20..b62672d21e8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -1631,6 +1631,29 @@ fn test<'lifetime>(
 }
 
 #[test]
+fn lifetime_bounds() {
+    check_infer(
+        r#"
+//- minicore: sized, coerce_unsized
+trait Trait<'a>: Sized {
+    fn f(&'a self) {}
+}
+fn test<'a, 'b: 'a>(it: impl Trait<'a>){
+    it.f();
+}
+"#,
+        expect![[r#"
+            38..42 'self': &'a Self
+            44..46 '{}': ()
+            69..71 'it': impl Trait<'a>
+            88..103 '{     it.f(); }': ()
+            94..96 'it': impl Trait<'a>
+            94..100 'it.f()': ()
+        "#]],
+    );
+}
+
+#[test]
 fn error_bound_chalk() {
     check_types(
         r#"
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 65470d061b3..0b09cf27926 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -2026,6 +2026,10 @@ impl SemanticsScope<'_> {
         )
     }
 
+    pub fn generic_def(&self) -> Option<crate::GenericDef> {
+        self.resolver.generic_def().map(|id| id.into())
+    }
+
     pub fn extern_crates(&self) -> impl Iterator<Item = (Name, Module)> + '_ {
         self.resolver.extern_crates_in_scope().map(|(name, id)| (name, Module { id }))
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs
index 9efc52428ef..0692446381b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs
@@ -8,7 +8,6 @@
 //! show up for normal completions, or they won't show completions other than lifetimes depending
 //! on the fixture input.
 use hir::{sym, Name, ScopeDef};
-use syntax::{ast, ToSmolStr, TokenText};
 
 use crate::{
     completions::Completions,
@@ -21,33 +20,24 @@ pub(crate) fn complete_lifetime(
     ctx: &CompletionContext<'_>,
     lifetime_ctx: &LifetimeContext,
 ) {
-    let (lp, lifetime) = match lifetime_ctx {
-        LifetimeContext { kind: LifetimeKind::Lifetime, lifetime } => (None, lifetime),
-        LifetimeContext {
-            kind: LifetimeKind::LifetimeParam { is_decl: false, param },
-            lifetime,
-        } => (Some(param), lifetime),
-        _ => return,
-    };
-    let param_lifetime = match (lifetime, lp.and_then(|lp| lp.lifetime())) {
-        (Some(lt), Some(lp)) if lp == lt.clone() => return,
-        (Some(_), Some(lp)) => Some(lp),
-        _ => None,
+    let &LifetimeContext { kind: LifetimeKind::Lifetime { in_lifetime_param_bound, def }, .. } =
+        lifetime_ctx
+    else {
+        return;
     };
-    let param_lifetime = param_lifetime.as_ref().map(ast::Lifetime::text);
-    let param_lifetime = param_lifetime.as_ref().map(TokenText::as_str);
 
     ctx.process_all_names_raw(&mut |name, res| {
-        if matches!(
-            res,
-            ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_))
-                 if param_lifetime != Some(&*name.display_no_db(ctx.edition).to_smolstr())
-        ) {
+        if matches!(res, ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_))) {
             acc.add_lifetime(ctx, name);
         }
     });
-    if param_lifetime.is_none() {
-        acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static.clone()));
+    acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static.clone()));
+    if !in_lifetime_param_bound
+        && def.is_some_and(|def| {
+            !matches!(def, hir::GenericDef::Function(_) | hir::GenericDef::Impl(_))
+        })
+    {
+        acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_underscore.clone()));
     }
 }
 
@@ -222,6 +212,8 @@ fn foo<'footime, 'lifetime: 'a$0>() {}
 "#,
             expect![[r#"
                 lt 'footime
+                lt 'lifetime
+                lt 'static
             "#]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 5b8d1c30a29..3a661706336 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -290,15 +290,14 @@ pub(crate) struct ParamContext {
 /// The state of the lifetime we are completing.
 #[derive(Debug)]
 pub(crate) struct LifetimeContext {
-    pub(crate) lifetime: Option<ast::Lifetime>,
     pub(crate) kind: LifetimeKind,
 }
 
 /// The kind of lifetime we are completing.
 #[derive(Debug)]
 pub(crate) enum LifetimeKind {
-    LifetimeParam { is_decl: bool, param: ast::LifetimeParam },
-    Lifetime,
+    LifetimeParam,
+    Lifetime { in_lifetime_param_bound: bool, def: Option<hir::GenericDef> },
     LabelRef,
     LabelDef,
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index a4e018b1800..4a678963b93 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -562,7 +562,7 @@ fn expected_type_and_name(
 }
 
 fn classify_lifetime(
-    _sema: &Semantics<'_, RootDatabase>,
+    sema: &Semantics<'_, RootDatabase>,
     original_file: &SyntaxNode,
     lifetime: ast::Lifetime,
 ) -> Option<LifetimeContext> {
@@ -571,21 +571,22 @@ fn classify_lifetime(
         return None;
     }
 
+    let lifetime =
+        find_node_at_offset::<ast::Lifetime>(original_file, lifetime.syntax().text_range().start());
     let kind = match_ast! {
         match parent {
-            ast::LifetimeParam(param) => LifetimeKind::LifetimeParam {
-                is_decl: param.lifetime().as_ref() == Some(&lifetime),
-                param
-            },
+            ast::LifetimeParam(_) => LifetimeKind::LifetimeParam,
             ast::BreakExpr(_) => LifetimeKind::LabelRef,
             ast::ContinueExpr(_) => LifetimeKind::LabelRef,
             ast::Label(_) => LifetimeKind::LabelDef,
-            _ => LifetimeKind::Lifetime,
+            _ => {
+                let def = lifetime.as_ref().and_then(|lt| sema.scope(lt.syntax())?.generic_def());
+                LifetimeKind::Lifetime { in_lifetime_param_bound: ast::TypeBound::can_cast(parent.kind()), def }
+            },
         }
     };
-    let lifetime = find_node_at_offset(original_file, lifetime.syntax().text_range().start());
 
-    Some(LifetimeContext { lifetime, kind })
+    Some(LifetimeContext { kind })
 }
 
 fn classify_name(
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index fdac4dd2efb..5eec33636be 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -772,16 +772,6 @@ impl NameRefClass {
                 .map(GenericParam::LifetimeParam)
                 .map(Definition::GenericParam)
                 .map(NameRefClass::Definition),
-            // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check
-            // if our lifetime is in a LifetimeParam without being the constrained lifetime
-            _ if ast::LifetimeParam::cast(parent).and_then(|param| param.lifetime()).as_ref()
-                != Some(lifetime) =>
-            {
-                sema.resolve_lifetime_param(lifetime)
-                    .map(GenericParam::LifetimeParam)
-                    .map(Definition::GenericParam)
-                    .map(NameRefClass::Definition)
-            }
             _ => None,
         }
     }
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index 8f79cf20079..ebc9c14059d 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -80,6 +80,7 @@ define_symbols! {
     self_ = "self",
     Self_ = "Self",
     tick_static = "'static",
+    tick_underscore = "'_",
     dollar_crate = "$crate",
     MISSING_NAME = "[missing name]",
     fn_ = "fn",
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
index 08b23cd92a6..9d4fdbfaf2e 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
@@ -56,7 +56,7 @@ fn generic_param(p: &mut Parser<'_>, m: Marker) -> bool {
 fn lifetime_param(p: &mut Parser<'_>, m: Marker) {
     assert!(p.at(LIFETIME_IDENT));
     lifetime(p);
-    if p.at(T![:]) {
+    if p.eat(T![:]) {
         lifetime_bounds(p);
     }
     m.complete(p, LIFETIME_PARAM);
@@ -106,14 +106,19 @@ fn const_param(p: &mut Parser<'_>, m: Marker) {
 }
 
 fn lifetime_bounds(p: &mut Parser<'_>) {
-    assert!(p.at(T![:]));
-    p.bump(T![:]);
-    while p.at(LIFETIME_IDENT) {
-        lifetime(p);
+    let marker = p.start();
+    while {
+        if !matches!(p.current(), LIFETIME_IDENT | T![>] | T![,]) {
+            p.error("expected lifetime");
+        }
+
+        type_bound(p)
+    } {
         if !p.eat(T![+]) {
             break;
         }
     }
+    marker.complete(p, TYPE_BOUND_LIST);
 }
 
 // test type_param_bounds
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast
index c595031f358..315200aca21 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast
@@ -11,8 +11,10 @@ SOURCE_FILE
           LIFETIME_IDENT "'a"
         COLON ":"
         WHITESPACE " "
-        LIFETIME
-          LIFETIME_IDENT "'b"
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'b"
       R_ANGLE ">"
     PARAM_LIST
       L_PAREN "("
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
index f9c0a245af8..5a67cc21766 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
@@ -11,8 +11,10 @@ SOURCE_FILE
           LIFETIME_IDENT "'a"
         COLON ":"
         WHITESPACE " "
-        LIFETIME
-          LIFETIME_IDENT "'a"
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'a"
       COMMA ","
       WHITESPACE " "
       LIFETIME_PARAM
@@ -20,8 +22,10 @@ SOURCE_FILE
           LIFETIME_IDENT "'b"
         COLON ":"
         WHITESPACE " "
-        LIFETIME
-          LIFETIME_IDENT "'b"
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'b"
       COMMA ","
       WHITESPACE " "
       TYPE_PARAM
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast
index 11ebc7efb9f..1e4eb156095 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast
@@ -96,6 +96,7 @@ SOURCE_FILE
         LIFETIME
           LIFETIME_IDENT "'a"
         COLON ":"
+        TYPE_BOUND_LIST
       R_ANGLE ">"
     SEMICOLON ";"
   WHITESPACE "\n"
@@ -111,8 +112,10 @@ SOURCE_FILE
           LIFETIME_IDENT "'a"
         COLON ":"
         WHITESPACE " "
-        LIFETIME
-          LIFETIME_IDENT "'b"
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'b"
       R_ANGLE ">"
     SEMICOLON ";"
   WHITESPACE "\n"
@@ -128,10 +131,12 @@ SOURCE_FILE
           LIFETIME_IDENT "'a"
         COLON ":"
         WHITESPACE " "
-        LIFETIME
-          LIFETIME_IDENT "'b"
-        WHITESPACE " "
-        PLUS "+"
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'b"
+          WHITESPACE " "
+          PLUS "+"
       WHITESPACE " "
       R_ANGLE ">"
     SEMICOLON ";"
@@ -148,13 +153,16 @@ SOURCE_FILE
           LIFETIME_IDENT "'a"
         COLON ":"
         WHITESPACE " "
-        LIFETIME
-          LIFETIME_IDENT "'b"
-        WHITESPACE " "
-        PLUS "+"
-        WHITESPACE " "
-        LIFETIME
-          LIFETIME_IDENT "'c"
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'b"
+          WHITESPACE " "
+          PLUS "+"
+          WHITESPACE " "
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'c"
       R_ANGLE ">"
     SEMICOLON ";"
   WHITESPACE "\n"
@@ -202,9 +210,11 @@ SOURCE_FILE
           LIFETIME_IDENT "'a"
         COLON ":"
         WHITESPACE " "
-        LIFETIME
-          LIFETIME_IDENT "'b"
-        PLUS "+"
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'b"
+          PLUS "+"
       COMMA ","
       WHITESPACE " "
       LIFETIME_PARAM
@@ -212,8 +222,10 @@ SOURCE_FILE
           LIFETIME_IDENT "'b"
         COLON ":"
         WHITESPACE " "
-        LIFETIME
-          LIFETIME_IDENT "'c"
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'c"
       COMMA ","
       R_ANGLE ">"
     SEMICOLON ";"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast
index 043a966ff97..448cf49446e 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast
@@ -237,8 +237,10 @@ SOURCE_FILE
           LIFETIME_IDENT "'a"
         COLON ":"
         WHITESPACE " "
-        LIFETIME
-          LIFETIME_IDENT "'d"
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'d"
       COMMA ","
       WHITESPACE " "
       LIFETIME_PARAM
@@ -246,13 +248,16 @@ SOURCE_FILE
           LIFETIME_IDENT "'d"
         COLON ":"
         WHITESPACE " "
-        LIFETIME
-          LIFETIME_IDENT "'a"
-        WHITESPACE " "
-        PLUS "+"
-        WHITESPACE " "
-        LIFETIME
-          LIFETIME_IDENT "'b"
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'a"
+          WHITESPACE " "
+          PLUS "+"
+          WHITESPACE " "
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'b"
       COMMA ","
       WHITESPACE " "
       TYPE_PARAM