mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 06:03:58 +00:00
Merge pull request #18620 from Veykril/push-pyulxnouvxkq
fix: Parse lifetime bounds in lifetime param into TypeBoundList
This commit is contained in:
commit
7f39ee3fce
14 changed files with 125 additions and 85 deletions
|
@ -648,9 +648,9 @@ impl Printer<'_> {
|
||||||
let (target, bound) = match pred {
|
let (target, bound) = match pred {
|
||||||
WherePredicate::TypeBound { target, bound } => (target, bound),
|
WherePredicate::TypeBound { target, bound } => (target, bound),
|
||||||
WherePredicate::Lifetime { target, bound } => {
|
WherePredicate::Lifetime { target, bound } => {
|
||||||
wln!(
|
w!(
|
||||||
this,
|
this,
|
||||||
"{}: {},",
|
"{}: {}",
|
||||||
target.name.display(self.db.upcast(), edition),
|
target.name.display(self.db.upcast(), edition),
|
||||||
bound.name.display(self.db.upcast(), edition)
|
bound.name.display(self.db.upcast(), edition)
|
||||||
);
|
);
|
||||||
|
|
|
@ -351,7 +351,8 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
T: 'a,
|
T: 'a,
|
||||||
T: 'b
|
T: 'b,
|
||||||
|
'b: 'a
|
||||||
{
|
{
|
||||||
pub(self) field: &'a &'b T,
|
pub(self) field: &'a &'b T,
|
||||||
}
|
}
|
||||||
|
@ -370,7 +371,8 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
T: 'a,
|
T: 'a,
|
||||||
T: 'b
|
T: 'b,
|
||||||
|
'b: 'a
|
||||||
{
|
{
|
||||||
// AstId: 9
|
// AstId: 9
|
||||||
pub(self) fn f<G>(
|
pub(self) fn f<G>(
|
||||||
|
|
|
@ -1630,6 +1630,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]
|
#[test]
|
||||||
fn error_bound_chalk() {
|
fn error_bound_chalk() {
|
||||||
check_types(
|
check_types(
|
||||||
|
|
|
@ -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)> + '_ {
|
pub fn extern_crates(&self) -> impl Iterator<Item = (Name, Module)> + '_ {
|
||||||
self.resolver.extern_crates_in_scope().map(|(name, id)| (name, Module { id }))
|
self.resolver.extern_crates_in_scope().map(|(name, id)| (name, Module { id }))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
//! show up for normal completions, or they won't show completions other than lifetimes depending
|
//! show up for normal completions, or they won't show completions other than lifetimes depending
|
||||||
//! on the fixture input.
|
//! on the fixture input.
|
||||||
use hir::{sym, Name, ScopeDef};
|
use hir::{sym, Name, ScopeDef};
|
||||||
use syntax::{ast, ToSmolStr, TokenText};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
completions::Completions,
|
completions::Completions,
|
||||||
|
@ -21,33 +20,24 @@ pub(crate) fn complete_lifetime(
|
||||||
ctx: &CompletionContext<'_>,
|
ctx: &CompletionContext<'_>,
|
||||||
lifetime_ctx: &LifetimeContext,
|
lifetime_ctx: &LifetimeContext,
|
||||||
) {
|
) {
|
||||||
let (lp, lifetime) = match lifetime_ctx {
|
let &LifetimeContext { kind: LifetimeKind::Lifetime { in_lifetime_param_bound, def }, .. } =
|
||||||
LifetimeContext { kind: LifetimeKind::Lifetime, lifetime } => (None, lifetime),
|
lifetime_ctx
|
||||||
LifetimeContext {
|
else {
|
||||||
kind: LifetimeKind::LifetimeParam { is_decl: false, param },
|
return;
|
||||||
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 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| {
|
ctx.process_all_names_raw(&mut |name, res| {
|
||||||
if matches!(
|
if matches!(res, ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_))) {
|
||||||
res,
|
|
||||||
ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_))
|
|
||||||
if param_lifetime != Some(&*name.display_no_db(ctx.edition).to_smolstr())
|
|
||||||
) {
|
|
||||||
acc.add_lifetime(ctx, name);
|
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#"
|
expect![[r#"
|
||||||
lt 'footime
|
lt 'footime
|
||||||
|
lt 'lifetime
|
||||||
|
lt 'static
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,15 +290,14 @@ pub(crate) struct ParamContext {
|
||||||
/// The state of the lifetime we are completing.
|
/// The state of the lifetime we are completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct LifetimeContext {
|
pub(crate) struct LifetimeContext {
|
||||||
pub(crate) lifetime: Option<ast::Lifetime>,
|
|
||||||
pub(crate) kind: LifetimeKind,
|
pub(crate) kind: LifetimeKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The kind of lifetime we are completing.
|
/// The kind of lifetime we are completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum LifetimeKind {
|
pub(crate) enum LifetimeKind {
|
||||||
LifetimeParam { is_decl: bool, param: ast::LifetimeParam },
|
LifetimeParam,
|
||||||
Lifetime,
|
Lifetime { in_lifetime_param_bound: bool, def: Option<hir::GenericDef> },
|
||||||
LabelRef,
|
LabelRef,
|
||||||
LabelDef,
|
LabelDef,
|
||||||
}
|
}
|
||||||
|
|
|
@ -562,7 +562,7 @@ fn expected_type_and_name(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn classify_lifetime(
|
fn classify_lifetime(
|
||||||
_sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
original_file: &SyntaxNode,
|
original_file: &SyntaxNode,
|
||||||
lifetime: ast::Lifetime,
|
lifetime: ast::Lifetime,
|
||||||
) -> Option<LifetimeContext> {
|
) -> Option<LifetimeContext> {
|
||||||
|
@ -571,21 +571,22 @@ fn classify_lifetime(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let lifetime =
|
||||||
|
find_node_at_offset::<ast::Lifetime>(original_file, lifetime.syntax().text_range().start());
|
||||||
let kind = match_ast! {
|
let kind = match_ast! {
|
||||||
match parent {
|
match parent {
|
||||||
ast::LifetimeParam(param) => LifetimeKind::LifetimeParam {
|
ast::LifetimeParam(_) => LifetimeKind::LifetimeParam,
|
||||||
is_decl: param.lifetime().as_ref() == Some(&lifetime),
|
|
||||||
param
|
|
||||||
},
|
|
||||||
ast::BreakExpr(_) => LifetimeKind::LabelRef,
|
ast::BreakExpr(_) => LifetimeKind::LabelRef,
|
||||||
ast::ContinueExpr(_) => LifetimeKind::LabelRef,
|
ast::ContinueExpr(_) => LifetimeKind::LabelRef,
|
||||||
ast::Label(_) => LifetimeKind::LabelDef,
|
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(
|
fn classify_name(
|
||||||
|
|
|
@ -772,16 +772,6 @@ impl NameRefClass {
|
||||||
.map(GenericParam::LifetimeParam)
|
.map(GenericParam::LifetimeParam)
|
||||||
.map(Definition::GenericParam)
|
.map(Definition::GenericParam)
|
||||||
.map(NameRefClass::Definition),
|
.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,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@ define_symbols! {
|
||||||
self_ = "self",
|
self_ = "self",
|
||||||
Self_ = "Self",
|
Self_ = "Self",
|
||||||
tick_static = "'static",
|
tick_static = "'static",
|
||||||
|
tick_underscore = "'_",
|
||||||
dollar_crate = "$crate",
|
dollar_crate = "$crate",
|
||||||
MISSING_NAME = "[missing name]",
|
MISSING_NAME = "[missing name]",
|
||||||
fn_ = "fn",
|
fn_ = "fn",
|
||||||
|
|
|
@ -56,7 +56,7 @@ fn generic_param(p: &mut Parser<'_>, m: Marker) -> bool {
|
||||||
fn lifetime_param(p: &mut Parser<'_>, m: Marker) {
|
fn lifetime_param(p: &mut Parser<'_>, m: Marker) {
|
||||||
assert!(p.at(LIFETIME_IDENT));
|
assert!(p.at(LIFETIME_IDENT));
|
||||||
lifetime(p);
|
lifetime(p);
|
||||||
if p.at(T![:]) {
|
if p.eat(T![:]) {
|
||||||
lifetime_bounds(p);
|
lifetime_bounds(p);
|
||||||
}
|
}
|
||||||
m.complete(p, LIFETIME_PARAM);
|
m.complete(p, LIFETIME_PARAM);
|
||||||
|
@ -106,14 +106,19 @@ fn const_param(p: &mut Parser<'_>, m: Marker) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lifetime_bounds(p: &mut Parser<'_>) {
|
fn lifetime_bounds(p: &mut Parser<'_>) {
|
||||||
assert!(p.at(T![:]));
|
let marker = p.start();
|
||||||
p.bump(T![:]);
|
while {
|
||||||
while p.at(LIFETIME_IDENT) {
|
if !matches!(p.current(), LIFETIME_IDENT | T![>] | T![,]) {
|
||||||
lifetime(p);
|
p.error("expected lifetime");
|
||||||
|
}
|
||||||
|
|
||||||
|
type_bound(p)
|
||||||
|
} {
|
||||||
if !p.eat(T![+]) {
|
if !p.eat(T![+]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
marker.complete(p, TYPE_BOUND_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
// test type_param_bounds
|
// test type_param_bounds
|
||||||
|
|
|
@ -11,6 +11,8 @@ SOURCE_FILE
|
||||||
LIFETIME_IDENT "'a"
|
LIFETIME_IDENT "'a"
|
||||||
COLON ":"
|
COLON ":"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
TYPE_BOUND_LIST
|
||||||
|
TYPE_BOUND
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'b"
|
LIFETIME_IDENT "'b"
|
||||||
R_ANGLE ">"
|
R_ANGLE ">"
|
||||||
|
|
|
@ -11,6 +11,8 @@ SOURCE_FILE
|
||||||
LIFETIME_IDENT "'a"
|
LIFETIME_IDENT "'a"
|
||||||
COLON ":"
|
COLON ":"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
TYPE_BOUND_LIST
|
||||||
|
TYPE_BOUND
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'a"
|
LIFETIME_IDENT "'a"
|
||||||
COMMA ","
|
COMMA ","
|
||||||
|
@ -20,6 +22,8 @@ SOURCE_FILE
|
||||||
LIFETIME_IDENT "'b"
|
LIFETIME_IDENT "'b"
|
||||||
COLON ":"
|
COLON ":"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
TYPE_BOUND_LIST
|
||||||
|
TYPE_BOUND
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'b"
|
LIFETIME_IDENT "'b"
|
||||||
COMMA ","
|
COMMA ","
|
||||||
|
|
|
@ -96,6 +96,7 @@ SOURCE_FILE
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'a"
|
LIFETIME_IDENT "'a"
|
||||||
COLON ":"
|
COLON ":"
|
||||||
|
TYPE_BOUND_LIST
|
||||||
R_ANGLE ">"
|
R_ANGLE ">"
|
||||||
SEMICOLON ";"
|
SEMICOLON ";"
|
||||||
WHITESPACE "\n"
|
WHITESPACE "\n"
|
||||||
|
@ -111,6 +112,8 @@ SOURCE_FILE
|
||||||
LIFETIME_IDENT "'a"
|
LIFETIME_IDENT "'a"
|
||||||
COLON ":"
|
COLON ":"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
TYPE_BOUND_LIST
|
||||||
|
TYPE_BOUND
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'b"
|
LIFETIME_IDENT "'b"
|
||||||
R_ANGLE ">"
|
R_ANGLE ">"
|
||||||
|
@ -128,6 +131,8 @@ SOURCE_FILE
|
||||||
LIFETIME_IDENT "'a"
|
LIFETIME_IDENT "'a"
|
||||||
COLON ":"
|
COLON ":"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
TYPE_BOUND_LIST
|
||||||
|
TYPE_BOUND
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'b"
|
LIFETIME_IDENT "'b"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
@ -148,11 +153,14 @@ SOURCE_FILE
|
||||||
LIFETIME_IDENT "'a"
|
LIFETIME_IDENT "'a"
|
||||||
COLON ":"
|
COLON ":"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
TYPE_BOUND_LIST
|
||||||
|
TYPE_BOUND
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'b"
|
LIFETIME_IDENT "'b"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
PLUS "+"
|
PLUS "+"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
TYPE_BOUND
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'c"
|
LIFETIME_IDENT "'c"
|
||||||
R_ANGLE ">"
|
R_ANGLE ">"
|
||||||
|
@ -202,6 +210,8 @@ SOURCE_FILE
|
||||||
LIFETIME_IDENT "'a"
|
LIFETIME_IDENT "'a"
|
||||||
COLON ":"
|
COLON ":"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
TYPE_BOUND_LIST
|
||||||
|
TYPE_BOUND
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'b"
|
LIFETIME_IDENT "'b"
|
||||||
PLUS "+"
|
PLUS "+"
|
||||||
|
@ -212,6 +222,8 @@ SOURCE_FILE
|
||||||
LIFETIME_IDENT "'b"
|
LIFETIME_IDENT "'b"
|
||||||
COLON ":"
|
COLON ":"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
TYPE_BOUND_LIST
|
||||||
|
TYPE_BOUND
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'c"
|
LIFETIME_IDENT "'c"
|
||||||
COMMA ","
|
COMMA ","
|
||||||
|
|
|
@ -237,6 +237,8 @@ SOURCE_FILE
|
||||||
LIFETIME_IDENT "'a"
|
LIFETIME_IDENT "'a"
|
||||||
COLON ":"
|
COLON ":"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
TYPE_BOUND_LIST
|
||||||
|
TYPE_BOUND
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'d"
|
LIFETIME_IDENT "'d"
|
||||||
COMMA ","
|
COMMA ","
|
||||||
|
@ -246,11 +248,14 @@ SOURCE_FILE
|
||||||
LIFETIME_IDENT "'d"
|
LIFETIME_IDENT "'d"
|
||||||
COLON ":"
|
COLON ":"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
TYPE_BOUND_LIST
|
||||||
|
TYPE_BOUND
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'a"
|
LIFETIME_IDENT "'a"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
PLUS "+"
|
PLUS "+"
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
|
TYPE_BOUND
|
||||||
LIFETIME
|
LIFETIME
|
||||||
LIFETIME_IDENT "'b"
|
LIFETIME_IDENT "'b"
|
||||||
COMMA ","
|
COMMA ","
|
||||||
|
|
Loading…
Reference in a new issue