Skip to content

Commit ddaad60

Browse files
authored
Merge pull request #30368 from rintaro/ide-completion-callasfunction-rdar59792682
[CodeCompletion] Support SE-0253 callAsFunction()
2 parents a3979da + fbc79d2 commit ddaad60

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3120,6 +3120,17 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
31203120
}
31213121

31223122
addMethodCall(FD, Reason, dynamicLookupInfo);
3123+
3124+
// SE-0253: Callable values of user-defined nominal types.
3125+
if (FD->isCallAsFunctionMethod() && !HaveDot &&
3126+
!ExprType->is<AnyMetatypeType>()) {
3127+
Type funcType = getTypeOfMember(FD, dynamicLookupInfo)
3128+
->castTo<AnyFunctionType>()
3129+
->getResult();
3130+
addFunctionCallPattern(
3131+
funcType->castTo<AnyFunctionType>(), FD,
3132+
getSemanticContext(FD, Reason, dynamicLookupInfo));
3133+
}
31233134
return;
31243135
}
31253136

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,11 @@ static bool collectPossibleCalleesForApply(
445445
collectPossibleCalleesByQualifiedLookup(
446446
DC, fnExpr, DeclNameRef::createConstructor(), candidates);
447447
}
448+
} else {
449+
// Otherwise, look for `callAsFunction` (SE-0253).
450+
collectPossibleCalleesByQualifiedLookup(
451+
DC, fnExpr, DeclNameRef(DC.getASTContext().Id_callAsFunction),
452+
candidates);
448453
}
449454

450455
return !candidates.empty();
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_NO_DOT | %FileCheck %s -check-prefix=INSTANCE_NO_DOT
2+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_DOT | %FileCheck %s -check-prefix=INSTANCE_DOT
3+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_PAREN | %FileCheck %s -check-prefix=INSTANCE_PAREN
4+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_ARG2 | %FileCheck %s -check-prefix=INSTANCE_ARG2
5+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_NO_DOT | %FileCheck %s -check-prefix=METATYPE_NO_DOT
6+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_DOT | %FileCheck %s -check-prefix=METATYPE_DOT
7+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_PAREN | %FileCheck %s -check-prefix=METATYPE_PAREN
8+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPEEXPR_NO_DOT | %FileCheck %s -check-prefix=TYPEEXPR_NO_DOT
9+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPEEXPR_DOT | %FileCheck %s -check-prefix=TYPEEXPR_DOT
10+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPEEXPR_PAREN | %FileCheck %s -check-prefix=TYPEEXPR_PAREN
11+
12+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOADED_PAREN | %FileCheck %s -check-prefix=OVERLOADED_PAREN
13+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOADED_ARG2_LABEL | %FileCheck %s -check-prefix=OVERLOADED_ARG2_LABEL
14+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOADED_ARG2_VALUE | %FileCheck %s -check-prefix=OVERLOADED_ARG2_VALUE
15+
16+
struct Adder {
17+
private var base: Int
18+
init(base: Int) { self.base = base }
19+
func callAsFunction(x : Int, y : Int) -> Int { base + x + y }
20+
}
21+
func testCallAsFunction(add: Adder, addTy: Adder.Type) {
22+
let _ = add#^INSTANCE_NO_DOT^#;
23+
// INSTANCE_NO_DOT: Begin completions, 3 items
24+
// INSTANCE_NO_DOT-DAG: Decl[InstanceMethod]/CurrNominal: .callAsFunction({#x: Int#}, {#y: Int#})[#Int#];
25+
// INSTANCE_NO_DOT-DAG: Decl[InstanceMethod]/CurrNominal: ({#x: Int#}, {#y: Int#})[#Int#];
26+
// INSTANCE_NO_DOT-DAG: Keyword[self]/CurrNominal: .self[#Adder#];
27+
// INSTANCE_NO_DOT: End completions
28+
29+
let _ = add.#^INSTANCE_DOT^#;
30+
// INSTANCE_DOT: Begin completions, 2 items
31+
// INSTANCE_DOT-DAG: Decl[InstanceMethod]/CurrNominal: callAsFunction({#x: Int#}, {#y: Int#})[#Int#];
32+
// INSTANCE_DOT-DAG: Keyword[self]/CurrNominal: self[#Adder#];
33+
// INSTANCE_DOT: End completions
34+
35+
let _ = add(#^INSTANCE_PAREN^#)
36+
// INSTANCE_PAREN: Begin completions, 1 items
37+
// INSTANCE_PAREN-DAG: Decl[InstanceMethod]/CurrNominal: ['(']{#x: Int#}, {#y: Int#}[')'][#Int#];
38+
// INSTANCE_PAREN: End completions
39+
40+
let _ = add(x: 12, #^INSTANCE_ARG2^#)
41+
// INSTANCE_ARG2: Begin completions, 1 items
42+
// INSTANCE_ARG2: Keyword/ExprSpecific: y: [#Argument name#];
43+
// INSTANCE_ARG2: End completions
44+
45+
let _ = addTy#^METATYPE_NO_DOT^#;
46+
// METATYPE_NO_DOT: Begin completions, 3 items
47+
// METATYPE_NO_DOT-NOT: {#x: Int#}, {#y: Int#}
48+
// METATYPE_NO_DOT-DAG: Decl[InstanceMethod]/CurrNominal: .callAsFunction({#(self): Adder#})[#(x: Int, y: Int) -> Int#];
49+
// METATYPE_NO_DOT-DAG: Decl[Constructor]/CurrNominal: .init({#base: Int#})[#Adder#];
50+
// METATYPE_NO_DOT-DAG: Keyword[self]/CurrNominal: .self[#Adder.Type#];
51+
// METATYPE_NO_DOT: End completions
52+
53+
let _ = addTy.#^METATYPE_DOT^#;
54+
// METATYPE_DOT: Begin completions, 3 items
55+
// METATYPE_DOT-NOT: {#x: Int#}, {#y: Int#}
56+
// METATYPE_DOT-DAG: Decl[InstanceMethod]/CurrNominal: callAsFunction({#(self): Adder#})[#(x: Int, y: Int) -> Int#];
57+
// METATYPE_DOT-DAG: Decl[Constructor]/CurrNominal: init({#base: Int#})[#Adder#];
58+
// METATYPE_DOT-DAG: Keyword[self]/CurrNominal: self[#Adder.Type#];
59+
// METATYPE_DOT: End completions
60+
61+
let _ = addTy(#^METATYPE_PAREN^#)
62+
// METATYPE_PAREN: Begin completions
63+
// METATYPE_PAREN-NOT: {#x: Int#}, {#y: Int#}
64+
// METATYPE_PAREN-NOT: {#base: Int#}
65+
// METATYPE_PAREN: End completions
66+
67+
let _ = Adder#^TYPEEXPR_NO_DOT^#;
68+
// TYPEEXPR_NO_DOT: Begin completions, 4 items
69+
// TYPEEXPR_NO_DOT-NOT: {#x: Int#}, {#y: Int#}
70+
// TYPEEXPR_NO_DOT-DAG: Decl[Constructor]/CurrNominal: ({#base: Int#})[#Adder#]; name=(base: Int)
71+
// TYPEEXPR_NO_DOT-DAG: Decl[InstanceMethod]/CurrNominal: .callAsFunction({#(self): Adder#})[#(x: Int, y: Int) -> Int#];
72+
// TYPEEXPR_NO_DOT-DAG: Keyword[self]/CurrNominal: .self[#Adder.Type#];
73+
// TYPEEXPR_NO_DOT-DAG: Keyword/CurrNominal: .Type[#Adder.Type#];
74+
// TYPEEXPR_NO_DOT: End completions
75+
76+
let _ = Adder.#^TYPEEXPR_DOT^#;
77+
// TYPEEXPR_DOT: Begin completions, 4 items
78+
// TYPEEXPR_DOT-NOT: {#x: Int#}, {#y: Int#}
79+
// TYPEEXPR_DOT-DAG: Decl[InstanceMethod]/CurrNominal: callAsFunction({#(self): Adder#})[#(x: Int, y: Int) -> Int#];
80+
// TYPEEXPR_DOT-DAG: Decl[Constructor]/CurrNominal: init({#base: Int#})[#Adder#];
81+
// TYPEEXPR_DOT-DAG: Keyword[self]/CurrNominal: self[#Adder.Type#];
82+
// TYPEEXPR_DOT-DAG: Keyword/CurrNominal: Type[#Adder.Type#];
83+
// TYPEEXPR_DOT: End completions
84+
85+
let _ = Adder(#^TYPEEXPR_PAREN^#)
86+
// TYPEEXPR_PAREN: Begin completions, 1 items
87+
// TYPEEXPR_PAREN-NOT: {#x: Int#}, {#y: Int#}
88+
// TYPEEXPR_PAREN-DAG: Decl[Constructor]/CurrNominal: ['(']{#base: Int#}[')'][#Adder#];
89+
// TYPEEXPR_PAREN: End completions
90+
}
91+
92+
struct Functor {
93+
enum Horizontal { case left, right }
94+
enum Vertical { case up, down }
95+
func callAsFunction(h: Horizontal, v: Vertical) {}
96+
func callAsFunction(v: Vertical, h: Horizontal) {}
97+
}
98+
func testCallAsFunctionOverloaded(fn: Functor) {
99+
fn(#^OVERLOADED_PAREN^#)
100+
//OVERLOADED_PAREN: Begin completions, 2 items
101+
//OVERLOADED_PAREN-DAG: Decl[InstanceMethod]/CurrNominal: ['(']{#h: Functor.Horizontal#}, {#v: Functor.Vertical#}[')'][#Void#];
102+
//OVERLOADED_PAREN-DAG: Decl[InstanceMethod]/CurrNominal: ['(']{#v: Functor.Vertical#}, {#h: Functor.Horizontal#}[')'][#Void#];
103+
//OVERLOADED_PAREN: End completions
104+
105+
fn(h: .left, #^OVERLOADED_ARG2_LABEL^#)
106+
// FIXME: Should only suggest 'v:' (rdar://problem/60346573).
107+
//OVERLOADED_ARG2_LABEL: Begin completions, 2 items
108+
//OVERLOADED_ARG2_LABEL-DAG: Keyword/ExprSpecific: v: [#Argument name#];
109+
//OVERLOADED_ARG2_LABEL-DAG: Keyword/ExprSpecific: h: [#Argument name#];
110+
//OVERLOADED_ARG2_LABEL: End completions
111+
112+
fn(h: .left, v: .#^OVERLOADED_ARG2_VALUE^#)
113+
// FIXME: Should only suggest 'up' and 'down' (rdar://problem/60346573).
114+
//OVERLOADED_ARG2_VALUE: Begin completions, 4 items
115+
//OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: up[#Functor.Vertical#];
116+
//OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: down[#Functor.Vertical#];
117+
//OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: left[#Functor.Horizontal#];
118+
//OVERLOADED_ARG2_VALUE-DAG: Decl[EnumElement]/ExprSpecific/TypeRelation[Identical]: right[#Functor.Horizontal#];
119+
//OVERLOADED_ARG2_VALUE: End completions
120+
}

0 commit comments

Comments
 (0)