Skip to content

Commit 7f39ee3

Browse files
authored
Merge pull request #18620 from Veykril/push-pyulxnouvxkq
fix: Parse lifetime bounds in lifetime param into TypeBoundList
2 parents 0b5f51a + f3d7415 commit 7f39ee3

File tree

14 files changed

+125
-85
lines changed

14 files changed

+125
-85
lines changed

crates/hir-def/src/item_tree/pretty.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -648,9 +648,9 @@ impl Printer<'_> {
648648
let (target, bound) = match pred {
649649
WherePredicate::TypeBound { target, bound } => (target, bound),
650650
WherePredicate::Lifetime { target, bound } => {
651-
wln!(
651+
w!(
652652
this,
653-
"{}: {},",
653+
"{}: {}",
654654
target.name.display(self.db.upcast(), edition),
655655
bound.name.display(self.db.upcast(), edition)
656656
);

crates/hir-def/src/item_tree/tests.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,8 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
351351
where
352352
T: Copy,
353353
T: 'a,
354-
T: 'b
354+
T: 'b,
355+
'b: 'a
355356
{
356357
pub(self) field: &'a &'b T,
357358
}
@@ -370,7 +371,8 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
370371
where
371372
T: Copy,
372373
T: 'a,
373-
T: 'b
374+
T: 'b,
375+
'b: 'a
374376
{
375377
// AstId: 9
376378
pub(self) fn f<G>(

crates/hir-ty/src/tests/traits.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1630,6 +1630,29 @@ fn test<'lifetime>(
16301630
);
16311631
}
16321632

1633+
#[test]
1634+
fn lifetime_bounds() {
1635+
check_infer(
1636+
r#"
1637+
//- minicore: sized, coerce_unsized
1638+
trait Trait<'a>: Sized {
1639+
fn f(&'a self) {}
1640+
}
1641+
fn test<'a, 'b: 'a>(it: impl Trait<'a>){
1642+
it.f();
1643+
}
1644+
"#,
1645+
expect![[r#"
1646+
38..42 'self': &'a Self
1647+
44..46 '{}': ()
1648+
69..71 'it': impl Trait<'a>
1649+
88..103 '{ it.f(); }': ()
1650+
94..96 'it': impl Trait<'a>
1651+
94..100 'it.f()': ()
1652+
"#]],
1653+
);
1654+
}
1655+
16331656
#[test]
16341657
fn error_bound_chalk() {
16351658
check_types(

crates/hir/src/semantics.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,6 +2026,10 @@ impl SemanticsScope<'_> {
20262026
)
20272027
}
20282028

2029+
pub fn generic_def(&self) -> Option<crate::GenericDef> {
2030+
self.resolver.generic_def().map(|id| id.into())
2031+
}
2032+
20292033
pub fn extern_crates(&self) -> impl Iterator<Item = (Name, Module)> + '_ {
20302034
self.resolver.extern_crates_in_scope().map(|(name, id)| (name, Module { id }))
20312035
}

crates/ide-completion/src/completions/lifetime.rs

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
//! show up for normal completions, or they won't show completions other than lifetimes depending
99
//! on the fixture input.
1010
use hir::{sym, Name, ScopeDef};
11-
use syntax::{ast, ToSmolStr, TokenText};
1211

1312
use crate::{
1413
completions::Completions,
@@ -21,33 +20,24 @@ pub(crate) fn complete_lifetime(
2120
ctx: &CompletionContext<'_>,
2221
lifetime_ctx: &LifetimeContext,
2322
) {
24-
let (lp, lifetime) = match lifetime_ctx {
25-
LifetimeContext { kind: LifetimeKind::Lifetime, lifetime } => (None, lifetime),
26-
LifetimeContext {
27-
kind: LifetimeKind::LifetimeParam { is_decl: false, param },
28-
lifetime,
29-
} => (Some(param), lifetime),
30-
_ => return,
31-
};
32-
let param_lifetime = match (lifetime, lp.and_then(|lp| lp.lifetime())) {
33-
(Some(lt), Some(lp)) if lp == lt.clone() => return,
34-
(Some(_), Some(lp)) => Some(lp),
35-
_ => None,
23+
let &LifetimeContext { kind: LifetimeKind::Lifetime { in_lifetime_param_bound, def }, .. } =
24+
lifetime_ctx
25+
else {
26+
return;
3627
};
37-
let param_lifetime = param_lifetime.as_ref().map(ast::Lifetime::text);
38-
let param_lifetime = param_lifetime.as_ref().map(TokenText::as_str);
3928

4029
ctx.process_all_names_raw(&mut |name, res| {
41-
if matches!(
42-
res,
43-
ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_))
44-
if param_lifetime != Some(&*name.display_no_db(ctx.edition).to_smolstr())
45-
) {
30+
if matches!(res, ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_))) {
4631
acc.add_lifetime(ctx, name);
4732
}
4833
});
49-
if param_lifetime.is_none() {
50-
acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static.clone()));
34+
acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static.clone()));
35+
if !in_lifetime_param_bound
36+
&& def.is_some_and(|def| {
37+
!matches!(def, hir::GenericDef::Function(_) | hir::GenericDef::Impl(_))
38+
})
39+
{
40+
acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_underscore.clone()));
5141
}
5242
}
5343

@@ -222,6 +212,8 @@ fn foo<'footime, 'lifetime: 'a$0>() {}
222212
"#,
223213
expect![[r#"
224214
lt 'footime
215+
lt 'lifetime
216+
lt 'static
225217
"#]],
226218
);
227219
}

crates/ide-completion/src/context.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,15 +290,14 @@ pub(crate) struct ParamContext {
290290
/// The state of the lifetime we are completing.
291291
#[derive(Debug)]
292292
pub(crate) struct LifetimeContext {
293-
pub(crate) lifetime: Option<ast::Lifetime>,
294293
pub(crate) kind: LifetimeKind,
295294
}
296295

297296
/// The kind of lifetime we are completing.
298297
#[derive(Debug)]
299298
pub(crate) enum LifetimeKind {
300-
LifetimeParam { is_decl: bool, param: ast::LifetimeParam },
301-
Lifetime,
299+
LifetimeParam,
300+
Lifetime { in_lifetime_param_bound: bool, def: Option<hir::GenericDef> },
302301
LabelRef,
303302
LabelDef,
304303
}

crates/ide-completion/src/context/analysis.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ fn expected_type_and_name(
562562
}
563563

564564
fn classify_lifetime(
565-
_sema: &Semantics<'_, RootDatabase>,
565+
sema: &Semantics<'_, RootDatabase>,
566566
original_file: &SyntaxNode,
567567
lifetime: ast::Lifetime,
568568
) -> Option<LifetimeContext> {
@@ -571,21 +571,22 @@ fn classify_lifetime(
571571
return None;
572572
}
573573

574+
let lifetime =
575+
find_node_at_offset::<ast::Lifetime>(original_file, lifetime.syntax().text_range().start());
574576
let kind = match_ast! {
575577
match parent {
576-
ast::LifetimeParam(param) => LifetimeKind::LifetimeParam {
577-
is_decl: param.lifetime().as_ref() == Some(&lifetime),
578-
param
579-
},
578+
ast::LifetimeParam(_) => LifetimeKind::LifetimeParam,
580579
ast::BreakExpr(_) => LifetimeKind::LabelRef,
581580
ast::ContinueExpr(_) => LifetimeKind::LabelRef,
582581
ast::Label(_) => LifetimeKind::LabelDef,
583-
_ => LifetimeKind::Lifetime,
582+
_ => {
583+
let def = lifetime.as_ref().and_then(|lt| sema.scope(lt.syntax())?.generic_def());
584+
LifetimeKind::Lifetime { in_lifetime_param_bound: ast::TypeBound::can_cast(parent.kind()), def }
585+
},
584586
}
585587
};
586-
let lifetime = find_node_at_offset(original_file, lifetime.syntax().text_range().start());
587588

588-
Some(LifetimeContext { lifetime, kind })
589+
Some(LifetimeContext { kind })
589590
}
590591

591592
fn classify_name(

crates/ide-db/src/defs.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -772,16 +772,6 @@ impl NameRefClass {
772772
.map(GenericParam::LifetimeParam)
773773
.map(Definition::GenericParam)
774774
.map(NameRefClass::Definition),
775-
// lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check
776-
// if our lifetime is in a LifetimeParam without being the constrained lifetime
777-
_ if ast::LifetimeParam::cast(parent).and_then(|param| param.lifetime()).as_ref()
778-
!= Some(lifetime) =>
779-
{
780-
sema.resolve_lifetime_param(lifetime)
781-
.map(GenericParam::LifetimeParam)
782-
.map(Definition::GenericParam)
783-
.map(NameRefClass::Definition)
784-
}
785775
_ => None,
786776
}
787777
}

crates/intern/src/symbol/symbols.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ define_symbols! {
8080
self_ = "self",
8181
Self_ = "Self",
8282
tick_static = "'static",
83+
tick_underscore = "'_",
8384
dollar_crate = "$crate",
8485
MISSING_NAME = "[missing name]",
8586
fn_ = "fn",

crates/parser/src/grammar/generic_params.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ fn generic_param(p: &mut Parser<'_>, m: Marker) -> bool {
5656
fn lifetime_param(p: &mut Parser<'_>, m: Marker) {
5757
assert!(p.at(LIFETIME_IDENT));
5858
lifetime(p);
59-
if p.at(T![:]) {
59+
if p.eat(T![:]) {
6060
lifetime_bounds(p);
6161
}
6262
m.complete(p, LIFETIME_PARAM);
@@ -106,14 +106,19 @@ fn const_param(p: &mut Parser<'_>, m: Marker) {
106106
}
107107

108108
fn lifetime_bounds(p: &mut Parser<'_>) {
109-
assert!(p.at(T![:]));
110-
p.bump(T![:]);
111-
while p.at(LIFETIME_IDENT) {
112-
lifetime(p);
109+
let marker = p.start();
110+
while {
111+
if !matches!(p.current(), LIFETIME_IDENT | T![>] | T![,]) {
112+
p.error("expected lifetime");
113+
}
114+
115+
type_bound(p)
116+
} {
113117
if !p.eat(T![+]) {
114118
break;
115119
}
116120
}
121+
marker.complete(p, TYPE_BOUND_LIST);
117122
}
118123

119124
// test type_param_bounds

0 commit comments

Comments
 (0)