mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-12-27 16:07:46 +00:00
Merge pull request #21166 from A4-Tacks/fly-closure-this-param
Support undotted-self for `this` param closure
This commit is contained in:
commit
b5fbcc6917
@ -4,6 +4,7 @@ use std::ops::ControlFlow;
|
||||
|
||||
use hir::{Complete, Function, HasContainer, ItemContainer, MethodCandidateCallback};
|
||||
use ide_db::FxHashSet;
|
||||
use itertools::Either;
|
||||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
@ -146,11 +147,14 @@ pub(crate) fn complete_undotted_self(
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let ty = self_param.ty(ctx.db);
|
||||
let (param_name, ty) = match self_param {
|
||||
Either::Left(self_param) => ("self", &self_param.ty(ctx.db)),
|
||||
Either::Right(this_param) => ("this", this_param.ty()),
|
||||
};
|
||||
complete_fields(
|
||||
acc,
|
||||
ctx,
|
||||
&ty,
|
||||
ty,
|
||||
|acc, field, ty| {
|
||||
acc.add_field(
|
||||
ctx,
|
||||
@ -163,15 +167,17 @@ pub(crate) fn complete_undotted_self(
|
||||
in_breakable: expr_ctx.in_breakable,
|
||||
},
|
||||
},
|
||||
Some(SmolStr::new_static("self")),
|
||||
Some(SmolStr::new_static(param_name)),
|
||||
field,
|
||||
&ty,
|
||||
)
|
||||
},
|
||||
|acc, field, ty| acc.add_tuple_field(ctx, Some(SmolStr::new_static("self")), field, &ty),
|
||||
|acc, field, ty| {
|
||||
acc.add_tuple_field(ctx, Some(SmolStr::new_static(param_name)), field, &ty)
|
||||
},
|
||||
false,
|
||||
);
|
||||
complete_methods(ctx, &ty, &ctx.traits_in_scope(), |func| {
|
||||
complete_methods(ctx, ty, &ctx.traits_in_scope(), |func| {
|
||||
acc.add_method(
|
||||
ctx,
|
||||
&DotAccess {
|
||||
@ -184,7 +190,7 @@ pub(crate) fn complete_undotted_self(
|
||||
},
|
||||
},
|
||||
func,
|
||||
Some(SmolStr::new_static("self")),
|
||||
Some(SmolStr::new_static(param_name)),
|
||||
None,
|
||||
)
|
||||
});
|
||||
@ -1073,6 +1079,96 @@ impl Foo { fn foo(&mut self) { $0 } }"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_bare_fields_and_methods_in_this_closure() {
|
||||
check_no_kw(
|
||||
r#"
|
||||
//- minicore: fn
|
||||
struct Foo { field: i32 }
|
||||
|
||||
impl Foo { fn foo(&mut self) { let _: fn(&mut Self) = |this| { $0 } } }"#,
|
||||
expect![[r#"
|
||||
fd this.field i32
|
||||
me this.foo() fn(&mut self)
|
||||
lc self &mut Foo
|
||||
lc this &mut Foo
|
||||
md core
|
||||
sp Self Foo
|
||||
st Foo Foo
|
||||
tt Fn
|
||||
tt FnMut
|
||||
tt FnOnce
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_bare_fields_and_methods_in_other_closure() {
|
||||
check_no_kw(
|
||||
r#"
|
||||
//- minicore: fn
|
||||
struct Foo { field: i32 }
|
||||
|
||||
impl Foo { fn foo(&self) { let _: fn(&Self) = |foo| { $0 } } }"#,
|
||||
expect![[r#"
|
||||
fd self.field i32
|
||||
me self.foo() fn(&self)
|
||||
lc foo &Foo
|
||||
lc self &Foo
|
||||
md core
|
||||
sp Self Foo
|
||||
st Foo Foo
|
||||
tt Fn
|
||||
tt FnMut
|
||||
tt FnOnce
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
|
||||
check_no_kw(
|
||||
r#"
|
||||
//- minicore: fn
|
||||
struct Foo { field: i32 }
|
||||
|
||||
impl Foo { fn foo(&self) { let _: fn(&Self) = || { $0 } } }"#,
|
||||
expect![[r#"
|
||||
fd self.field i32
|
||||
me self.foo() fn(&self)
|
||||
lc self &Foo
|
||||
md core
|
||||
sp Self Foo
|
||||
st Foo Foo
|
||||
tt Fn
|
||||
tt FnMut
|
||||
tt FnOnce
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
|
||||
check_no_kw(
|
||||
r#"
|
||||
//- minicore: fn
|
||||
struct Foo { field: i32 }
|
||||
|
||||
impl Foo { fn foo(&self) { let _: fn(&Self, &Self) = |foo, other| { $0 } } }"#,
|
||||
expect![[r#"
|
||||
fd self.field i32
|
||||
me self.foo() fn(&self)
|
||||
lc foo &Foo
|
||||
lc other &Foo
|
||||
lc self &Foo
|
||||
md core
|
||||
sp Self Foo
|
||||
st Foo Foo
|
||||
tt Fn
|
||||
tt FnMut
|
||||
tt FnOnce
|
||||
bt u32 u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_completion_after_dot() {
|
||||
check_no_kw(
|
||||
|
||||
@ -156,7 +156,7 @@ pub(crate) struct PathExprCtx<'db> {
|
||||
pub(crate) after_amp: bool,
|
||||
/// The surrounding RecordExpression we are completing a functional update
|
||||
pub(crate) is_func_update: Option<ast::RecordExpr>,
|
||||
pub(crate) self_param: Option<hir::SelfParam>,
|
||||
pub(crate) self_param: Option<Either<hir::SelfParam, hir::Param<'db>>>,
|
||||
pub(crate) innermost_ret_ty: Option<hir::Type<'db>>,
|
||||
pub(crate) innermost_breakable_ty: Option<hir::Type<'db>>,
|
||||
pub(crate) impl_: Option<ast::Impl>,
|
||||
|
||||
@ -1319,10 +1319,26 @@ fn classify_name_ref<'db>(
|
||||
)
|
||||
}
|
||||
};
|
||||
let find_fn_self_param = |it| match it {
|
||||
ast::Item::Fn(fn_) => Some(sema.to_def(&fn_).and_then(|it| it.self_param(sema.db))),
|
||||
ast::Item::MacroCall(_) => None,
|
||||
_ => Some(None),
|
||||
let fn_self_param =
|
||||
|fn_: ast::Fn| sema.to_def(&fn_).and_then(|it| it.self_param(sema.db));
|
||||
let closure_this_param = |closure: ast::ClosureExpr| {
|
||||
if closure.param_list()?.params().next()?.pat()?.syntax().text() != "this" {
|
||||
return None;
|
||||
}
|
||||
sema.type_of_expr(&closure.into())
|
||||
.and_then(|it| it.original.as_callable(sema.db))
|
||||
.and_then(|it| it.params().into_iter().next())
|
||||
};
|
||||
let find_fn_self_param = |it: SyntaxNode| {
|
||||
match_ast! {
|
||||
match it {
|
||||
ast::Fn(fn_) => Some(fn_self_param(fn_).map(Either::Left)),
|
||||
ast::ClosureExpr(f) => closure_this_param(f).map(Either::Right).map(Some),
|
||||
ast::MacroCall(_) => None,
|
||||
ast::Item(_) => Some(None),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match find_node_in_file_compensated(sema, original_file, &expr) {
|
||||
@ -1335,7 +1351,6 @@ fn classify_name_ref<'db>(
|
||||
|
||||
let self_param = sema
|
||||
.ancestors_with_macros(it.syntax().clone())
|
||||
.filter_map(ast::Item::cast)
|
||||
.find_map(find_fn_self_param)
|
||||
.flatten();
|
||||
(innermost_ret_ty, self_param)
|
||||
|
||||
@ -3279,6 +3279,48 @@ impl S {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn field_access_includes_closure_this_param() {
|
||||
check_edit(
|
||||
"length",
|
||||
r#"
|
||||
//- minicore: fn
|
||||
struct S {
|
||||
length: i32
|
||||
}
|
||||
|
||||
impl S {
|
||||
fn pack(&mut self, f: impl FnOnce(&mut Self, i32)) {
|
||||
self.length += 1;
|
||||
f(self, 3);
|
||||
self.length -= 1;
|
||||
}
|
||||
|
||||
fn some_fn(&mut self) {
|
||||
self.pack(|this, n| len$0);
|
||||
}
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct S {
|
||||
length: i32
|
||||
}
|
||||
|
||||
impl S {
|
||||
fn pack(&mut self, f: impl FnOnce(&mut Self, i32)) {
|
||||
self.length += 1;
|
||||
f(self, 3);
|
||||
self.length -= 1;
|
||||
}
|
||||
|
||||
fn some_fn(&mut self) {
|
||||
self.pack(|this, n| this.length);
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn notable_traits_method_relevance() {
|
||||
check_kinds(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user