Skip to content

Commit b5fbcc6

Browse files
Merge pull request #21166 from A4-Tacks/fly-closure-this-param
Support undotted-self for `this` param closure
2 parents cbc18ae + 2f8f6e7 commit b5fbcc6

File tree

4 files changed

+165
-12
lines changed

4 files changed

+165
-12
lines changed

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

Lines changed: 102 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::ops::ControlFlow;
44

55
use hir::{Complete, Function, HasContainer, ItemContainer, MethodCandidateCallback};
66
use ide_db::FxHashSet;
7+
use itertools::Either;
78
use syntax::SmolStr;
89

910
use crate::{
@@ -146,11 +147,14 @@ pub(crate) fn complete_undotted_self(
146147
_ => return,
147148
};
148149

149-
let ty = self_param.ty(ctx.db);
150+
let (param_name, ty) = match self_param {
151+
Either::Left(self_param) => ("self", &self_param.ty(ctx.db)),
152+
Either::Right(this_param) => ("this", this_param.ty()),
153+
};
150154
complete_fields(
151155
acc,
152156
ctx,
153-
&ty,
157+
ty,
154158
|acc, field, ty| {
155159
acc.add_field(
156160
ctx,
@@ -163,15 +167,17 @@ pub(crate) fn complete_undotted_self(
163167
in_breakable: expr_ctx.in_breakable,
164168
},
165169
},
166-
Some(SmolStr::new_static("self")),
170+
Some(SmolStr::new_static(param_name)),
167171
field,
168172
&ty,
169173
)
170174
},
171-
|acc, field, ty| acc.add_tuple_field(ctx, Some(SmolStr::new_static("self")), field, &ty),
175+
|acc, field, ty| {
176+
acc.add_tuple_field(ctx, Some(SmolStr::new_static(param_name)), field, &ty)
177+
},
172178
false,
173179
);
174-
complete_methods(ctx, &ty, &ctx.traits_in_scope(), |func| {
180+
complete_methods(ctx, ty, &ctx.traits_in_scope(), |func| {
175181
acc.add_method(
176182
ctx,
177183
&DotAccess {
@@ -184,7 +190,7 @@ pub(crate) fn complete_undotted_self(
184190
},
185191
},
186192
func,
187-
Some(SmolStr::new_static("self")),
193+
Some(SmolStr::new_static(param_name)),
188194
None,
189195
)
190196
});
@@ -1073,6 +1079,96 @@ impl Foo { fn foo(&mut self) { $0 } }"#,
10731079
);
10741080
}
10751081

1082+
#[test]
1083+
fn completes_bare_fields_and_methods_in_this_closure() {
1084+
check_no_kw(
1085+
r#"
1086+
//- minicore: fn
1087+
struct Foo { field: i32 }
1088+
1089+
impl Foo { fn foo(&mut self) { let _: fn(&mut Self) = |this| { $0 } } }"#,
1090+
expect![[r#"
1091+
fd this.field i32
1092+
me this.foo() fn(&mut self)
1093+
lc self &mut Foo
1094+
lc this &mut Foo
1095+
md core
1096+
sp Self Foo
1097+
st Foo Foo
1098+
tt Fn
1099+
tt FnMut
1100+
tt FnOnce
1101+
bt u32 u32
1102+
"#]],
1103+
);
1104+
}
1105+
1106+
#[test]
1107+
fn completes_bare_fields_and_methods_in_other_closure() {
1108+
check_no_kw(
1109+
r#"
1110+
//- minicore: fn
1111+
struct Foo { field: i32 }
1112+
1113+
impl Foo { fn foo(&self) { let _: fn(&Self) = |foo| { $0 } } }"#,
1114+
expect![[r#"
1115+
fd self.field i32
1116+
me self.foo() fn(&self)
1117+
lc foo &Foo
1118+
lc self &Foo
1119+
md core
1120+
sp Self Foo
1121+
st Foo Foo
1122+
tt Fn
1123+
tt FnMut
1124+
tt FnOnce
1125+
bt u32 u32
1126+
"#]],
1127+
);
1128+
1129+
check_no_kw(
1130+
r#"
1131+
//- minicore: fn
1132+
struct Foo { field: i32 }
1133+
1134+
impl Foo { fn foo(&self) { let _: fn(&Self) = || { $0 } } }"#,
1135+
expect![[r#"
1136+
fd self.field i32
1137+
me self.foo() fn(&self)
1138+
lc self &Foo
1139+
md core
1140+
sp Self Foo
1141+
st Foo Foo
1142+
tt Fn
1143+
tt FnMut
1144+
tt FnOnce
1145+
bt u32 u32
1146+
"#]],
1147+
);
1148+
1149+
check_no_kw(
1150+
r#"
1151+
//- minicore: fn
1152+
struct Foo { field: i32 }
1153+
1154+
impl Foo { fn foo(&self) { let _: fn(&Self, &Self) = |foo, other| { $0 } } }"#,
1155+
expect![[r#"
1156+
fd self.field i32
1157+
me self.foo() fn(&self)
1158+
lc foo &Foo
1159+
lc other &Foo
1160+
lc self &Foo
1161+
md core
1162+
sp Self Foo
1163+
st Foo Foo
1164+
tt Fn
1165+
tt FnMut
1166+
tt FnOnce
1167+
bt u32 u32
1168+
"#]],
1169+
);
1170+
}
1171+
10761172
#[test]
10771173
fn macro_completion_after_dot() {
10781174
check_no_kw(

crates/ide-completion/src/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ pub(crate) struct PathExprCtx<'db> {
156156
pub(crate) after_amp: bool,
157157
/// The surrounding RecordExpression we are completing a functional update
158158
pub(crate) is_func_update: Option<ast::RecordExpr>,
159-
pub(crate) self_param: Option<hir::SelfParam>,
159+
pub(crate) self_param: Option<Either<hir::SelfParam, hir::Param<'db>>>,
160160
pub(crate) innermost_ret_ty: Option<hir::Type<'db>>,
161161
pub(crate) innermost_breakable_ty: Option<hir::Type<'db>>,
162162
pub(crate) impl_: Option<ast::Impl>,

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

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,10 +1319,26 @@ fn classify_name_ref<'db>(
13191319
)
13201320
}
13211321
};
1322-
let find_fn_self_param = |it| match it {
1323-
ast::Item::Fn(fn_) => Some(sema.to_def(&fn_).and_then(|it| it.self_param(sema.db))),
1324-
ast::Item::MacroCall(_) => None,
1325-
_ => Some(None),
1322+
let fn_self_param =
1323+
|fn_: ast::Fn| sema.to_def(&fn_).and_then(|it| it.self_param(sema.db));
1324+
let closure_this_param = |closure: ast::ClosureExpr| {
1325+
if closure.param_list()?.params().next()?.pat()?.syntax().text() != "this" {
1326+
return None;
1327+
}
1328+
sema.type_of_expr(&closure.into())
1329+
.and_then(|it| it.original.as_callable(sema.db))
1330+
.and_then(|it| it.params().into_iter().next())
1331+
};
1332+
let find_fn_self_param = |it: SyntaxNode| {
1333+
match_ast! {
1334+
match it {
1335+
ast::Fn(fn_) => Some(fn_self_param(fn_).map(Either::Left)),
1336+
ast::ClosureExpr(f) => closure_this_param(f).map(Either::Right).map(Some),
1337+
ast::MacroCall(_) => None,
1338+
ast::Item(_) => Some(None),
1339+
_ => None,
1340+
}
1341+
}
13261342
};
13271343

13281344
match find_node_in_file_compensated(sema, original_file, &expr) {
@@ -1335,7 +1351,6 @@ fn classify_name_ref<'db>(
13351351

13361352
let self_param = sema
13371353
.ancestors_with_macros(it.syntax().clone())
1338-
.filter_map(ast::Item::cast)
13391354
.find_map(find_fn_self_param)
13401355
.flatten();
13411356
(innermost_ret_ty, self_param)

crates/ide-completion/src/render.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3279,6 +3279,48 @@ impl S {
32793279
)
32803280
}
32813281

3282+
#[test]
3283+
fn field_access_includes_closure_this_param() {
3284+
check_edit(
3285+
"length",
3286+
r#"
3287+
//- minicore: fn
3288+
struct S {
3289+
length: i32
3290+
}
3291+
3292+
impl S {
3293+
fn pack(&mut self, f: impl FnOnce(&mut Self, i32)) {
3294+
self.length += 1;
3295+
f(self, 3);
3296+
self.length -= 1;
3297+
}
3298+
3299+
fn some_fn(&mut self) {
3300+
self.pack(|this, n| len$0);
3301+
}
3302+
}
3303+
"#,
3304+
r#"
3305+
struct S {
3306+
length: i32
3307+
}
3308+
3309+
impl S {
3310+
fn pack(&mut self, f: impl FnOnce(&mut Self, i32)) {
3311+
self.length += 1;
3312+
f(self, 3);
3313+
self.length -= 1;
3314+
}
3315+
3316+
fn some_fn(&mut self) {
3317+
self.pack(|this, n| this.length);
3318+
}
3319+
}
3320+
"#,
3321+
)
3322+
}
3323+
32823324
#[test]
32833325
fn notable_traits_method_relevance() {
32843326
check_kinds(

0 commit comments

Comments
 (0)