Skip to content

Commit f1a5e89

Browse files
committed
[CodeCompletion] Add keyword completion for 'some', 'any', 'repeat', and 'each'
The implementation is not 100% perfect but I don’t think it’s worth putting too much effort into it passing more information down in the parser if 'repeat' and 'each' are valid if we are going to remove the current parser anyway. rdar://95725895
1 parent 9b10ab3 commit f1a5e89

File tree

8 files changed

+90
-47
lines changed

8 files changed

+90
-47
lines changed

include/swift/IDE/CodeCompletionResult.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ enum class CompletionKind : uint8_t {
199199
KeyPathExprObjC,
200200
KeyPathExprSwift,
201201
TypeDeclResultBeginning,
202+
TypeBeginning,
203+
TypeSimpleOrComposition,
202204
TypeSimpleBeginning,
203205
TypeSimpleWithDot,
204206
TypeSimpleWithoutDot,

include/swift/Parse/IDEInspectionCallbacks.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@ class CodeCompletionCallbacks {
185185
/// Complete the beginning of the type of result of func/var/let/subscript.
186186
virtual void completeTypeDeclResultBeginning() {};
187187

188+
/// Same as `completeTypeSimpleOrComposition` but also allows `repeat`.
189+
virtual void completeTypeBeginning(){};
190+
191+
/// Same as `completeTypeSimpleBeginning` but also allows `any`, `some` and
192+
/// `each`.
193+
virtual void completeTypeSimpleOrComposition(){};
194+
188195
/// Complete the beginning of type-simple -- no tokens provided
189196
/// by user.
190197
virtual void completeTypeSimpleBeginning() {};

lib/IDE/CodeCompletion.cpp

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks,
263263
void completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) override;
264264

265265
void completeTypeDeclResultBeginning() override;
266+
void completeTypeBeginning() override;
267+
void completeTypeSimpleOrComposition() override;
266268
void completeTypeSimpleBeginning() override;
267269
void completeTypeSimpleWithDot(TypeRepr *TR) override;
268270
void completeTypeSimpleWithoutDot(TypeRepr *TR) override;
@@ -462,6 +464,16 @@ void CodeCompletionCallbacksImpl::completeTypeDeclResultBeginning() {
462464
CurDeclContext = P.CurDeclContext;
463465
}
464466

467+
void CodeCompletionCallbacksImpl::completeTypeBeginning() {
468+
Kind = CompletionKind::TypeBeginning;
469+
CurDeclContext = P.CurDeclContext;
470+
}
471+
472+
void CodeCompletionCallbacksImpl::completeTypeSimpleOrComposition() {
473+
Kind = CompletionKind::TypeSimpleOrComposition;
474+
CurDeclContext = P.CurDeclContext;
475+
}
476+
465477
void CodeCompletionCallbacksImpl::completeTypeSimpleBeginning() {
466478
Kind = CompletionKind::TypeSimpleBeginning;
467479
CurDeclContext = P.CurDeclContext;
@@ -961,10 +973,6 @@ void swift::ide::addSuperKeyword(CodeCompletionResultSink &Sink,
961973
Builder.addTypeAnnotation(ST, PrintOptions());
962974
}
963975

964-
static void addOpaqueTypeKeyword(CodeCompletionResultSink &Sink) {
965-
addKeyword(Sink, "some", CodeCompletionKeywordKind::None, "some");
966-
}
967-
968976
static void addAnyTypeKeyword(CodeCompletionResultSink &Sink, Type T) {
969977
CodeCompletionResultBuilder Builder(Sink, CodeCompletionResultKind::Keyword,
970978
SemanticContextKind::None);
@@ -1094,16 +1102,15 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
10941102
}
10951103
break;
10961104

1097-
case CompletionKind::TypeDeclResultBeginning: {
1098-
auto DC = CurDeclContext;
1099-
if (ParsedDecl && ParsedDecl == CurDeclContext->getAsDecl())
1100-
DC = ParsedDecl->getDeclContext();
1101-
if (!isa<ProtocolDecl>(DC))
1102-
if (DC->isTypeContext() || isa_and_nonnull<FuncDecl>(ParsedDecl))
1103-
addOpaqueTypeKeyword(Sink);
1104-
1105+
case CompletionKind::TypeBeginning:
1106+
addKeyword(Sink, "repeat", CodeCompletionKeywordKind::None);
1107+
LLVM_FALLTHROUGH;
1108+
case CompletionKind::TypeDeclResultBeginning:
1109+
case CompletionKind::TypeSimpleOrComposition:
1110+
addKeyword(Sink, "some", CodeCompletionKeywordKind::None);
1111+
addKeyword(Sink, "any", CodeCompletionKeywordKind::None);
1112+
addKeyword(Sink, "each", CodeCompletionKeywordKind::None);
11051113
LLVM_FALLTHROUGH;
1106-
}
11071114
case CompletionKind::TypeSimpleBeginning:
11081115
addAnyTypeKeyword(Sink, CurDeclContext->getASTContext().TheAnyType);
11091116
break;
@@ -1299,6 +1306,8 @@ void swift::ide::postProcessCompletionResults(
12991306
// names at non-type name position are "rare".
13001307
if (result->getKind() == CodeCompletionResultKind::Declaration &&
13011308
result->getAssociatedDeclKind() == CodeCompletionDeclKind::Protocol &&
1309+
Kind != CompletionKind::TypeBeginning &&
1310+
Kind != CompletionKind::TypeSimpleOrComposition &&
13021311
Kind != CompletionKind::TypeSimpleBeginning &&
13031312
Kind != CompletionKind::TypeSimpleWithoutDot &&
13041313
Kind != CompletionKind::TypeSimpleWithDot &&
@@ -1828,6 +1837,8 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
18281837
}
18291838

18301839
case CompletionKind::TypeDeclResultBeginning:
1840+
case CompletionKind::TypeBeginning:
1841+
case CompletionKind::TypeSimpleOrComposition:
18311842
case CompletionKind::TypeSimpleBeginning: {
18321843
auto Loc = Context.SourceMgr.getIDEInspectionTargetLoc();
18331844
Lookup.getTypeCompletionsInDeclContext(Loc);

lib/Parse/ParseType.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,12 @@ Parser::parseType(Diag<> MessageID, ParseTypeReason reason, bool fromASTGen) {
632632

633633
return makeParserResult(ty,
634634
new (Context) PackExpansionTypeRepr(repeatLoc, ty.get()));
635+
} else if (Tok.is(tok::code_complete)) {
636+
if (CodeCompletionCallbacks) {
637+
CodeCompletionCallbacks->completeTypeBeginning();
638+
}
639+
return makeParserCodeCompletionResult<TypeRepr>(
640+
ErrorTypeRepr::create(Context, consumeToken(tok::code_complete)));
635641
}
636642

637643
ty = parseTypeScalar(MessageID, reason);
@@ -954,6 +960,12 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, ParseTypeReason reason) {
954960

955961
auto *typeRepr = new (Context) PackElementTypeRepr(eachLoc, packElt.get());
956962
return makeParserResult(ParserStatus(packElt), typeRepr);
963+
} else if (Tok.is(tok::code_complete)) {
964+
if (CodeCompletionCallbacks) {
965+
CodeCompletionCallbacks->completeTypeSimpleOrComposition();
966+
}
967+
return makeParserCodeCompletionResult<TypeRepr>(
968+
ErrorTypeRepr::create(Context, consumeToken(tok::code_complete)));
957969
}
958970

959971
auto applyOpaque = [&](TypeRepr *type) -> TypeRepr * {

test/IDE/complete_generic_param.swift

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
1-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INHERIT1 | %FileCheck %s -check-prefix=INHERIT
2-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INHERIT2 | %FileCheck %s -check-prefix=INHERIT
3-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INHERIT3 | %FileCheck %s -check-prefix=INHERIT
4-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INHERIT4 | %FileCheck %s -check-prefix=INHERIT
5-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INHERIT5 | %FileCheck %s -check-prefix=INHERIT
6-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INHERIT6 | %FileCheck %s -check-prefix=INHERIT
7-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GENERIC_TYPE_PARAM
8-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SECOND_GENERIC_TYPE_PARAM | %FileCheck %s -check-prefix=GENERIC_TYPE_PARAM
9-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GENERIC_PARAM_ON_NESTED_TYPE_GLOBAL_VAR | %FileCheck %s -check-prefix=GENERIC_PARAM_ON_NESTED_TYPE
10-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GENERIC_PARAM_ON_NESTED_TYPE_LOCAL_VAR | %FileCheck %s -check-prefix=GENERIC_PARAM_ON_NESTED_TYPE
1+
// RUN: %batch-code-completion
112

123
class C1{}
134
protocol P1{}
@@ -17,17 +8,17 @@ let ValueInt1 = 1
178
let ValueString2 = ""
189
func TopLevelFunc() {}
1910

20-
func f1<S : #^INHERIT1^#>(p : S) {}
21-
func f2<S : #^INHERIT2^#
11+
func f1<S : #^INHERIT1?check=INHERIT^#>(p : S) {}
12+
func f2<S : #^INHERIT2?check=INHERIT^#
2213

2314
class C2 {
24-
func f1<S : #^INHERIT3^#>(p : S) {}
25-
func f2<S : #^INHERIT4^#
15+
func f1<S : #^INHERIT3?check=INHERIT^#>(p : S) {}
16+
func f2<S : #^INHERIT4?check=INHERIT^#
2617
}
2718

2819
class C3 {
29-
func f1<S1: P1, S2 : #^INHERIT5^#>(p : S1) {}
30-
func f2<S1: P1, S2 : #^INHERIT6^#
20+
func f1<S1: P1, S2 : #^INHERIT5?check=INHERIT^#>(p : S1) {}
21+
func f2<S1: P1, S2 : #^INHERIT6?check=INHERIT^#
3122
}
3223

3324
// INHERIT-DAG: Decl[Class]/CurrModule: C1[#C1#]{{; name=.+$}}
@@ -44,7 +35,7 @@ class C3 {
4435
class C4<T, U> {}
4536

4637
_ = C4<#^GENERIC_TYPE_PARAM^# >()
47-
_ = C4<SomeType, #^SECOND_GENERIC_TYPE_PARAM^# >()
38+
_ = C4<SomeType, #^SECOND_GENERIC_TYPE_PARAM?check=GENERIC_TYPE_PARAM^# >()
4839
// GENERIC_TYPE_PARAM-DAG: Decl[Class]/CurrModule: C1[#C1#];
4940

5041
// https://github.com/apple/swift/issues/56979
@@ -55,10 +46,10 @@ struct S2 {
5546
}
5647
}
5748

58-
var s2_globalVar = S2.Nested< #^GENERIC_PARAM_ON_NESTED_TYPE_GLOBAL_VAR^#>()
49+
var s2_globalVar = S2.Nested< #^GENERIC_PARAM_ON_NESTED_TYPE_GLOBAL_VAR?check=GENERIC_PARAM_ON_NESTED_TYPE^#>()
5950

6051
func someFunction() {
61-
var s2_localVar = S2.Nested< #^GENERIC_PARAM_ON_NESTED_TYPE_LOCAL_VAR^#>()
52+
var s2_localVar = S2.Nested< #^GENERIC_PARAM_ON_NESTED_TYPE_LOCAL_VAR?check=GENERIC_PARAM_ON_NESTED_TYPE^#>()
6253
}
6354

6455
// GENERIC_PARAM_ON_NESTED_TYPE-DAG: Decl[Struct]/CurrModule: S2[#S2#];

test/IDE/complete_opaque_result.swift

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,21 @@ struct ConcreteMyProtocol : MyProtocol {
1212

1313
// MARK: 'some' keyword.
1414

15-
// BEGINNING_WITH_SOME-DAG: Keyword/None: some[#some#]; name=some
15+
// BEGINNING_WITH_SOME-DAG: Keyword/None: some; name=some
1616
// BEGINNING_WITH_SOME-DAG: Keyword/None: Any[#Any#]; name=Any
1717
// BEGINNING_WITH_SOME-DAG: Decl[Enum]/CurrModule: MyEnum[#MyEnum#]; name=MyEnum
1818
// BEGINNING_WITH_SOME-DAG: Decl[Class]/CurrModule: MyClass[#MyClass#]; name=MyClass
1919
// BEGINNING_WITH_SOME-DAG: Decl[Protocol]/CurrModule: MyProtocol[#MyProtocol#]; name=MyProtocol
2020
// BEGINNING_WITH_SOME-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct
2121

22-
// BEGINNING_WITHOUT_SOME-NOT: Keyword/None: some
23-
// BEGINNING_WITHOUT_SOME-DAG: Keyword/None: Any[#Any#]; name=Any
24-
// BEGINNING_WITHOUT_SOME-DAG: Decl[Enum]/CurrModule: MyEnum[#MyEnum#]; name=MyEnum
25-
// BEGINNING_WITHOUT_SOME-DAG: Decl[Class]/CurrModule: MyClass[#MyClass#]; name=MyClass
26-
// BEGINNING_WITHOUT_SOME-DAG: Decl[Protocol]/CurrModule: MyProtocol[#MyProtocol#]; name=MyProtocol
27-
// BEGINNING_WITHOUT_SOME-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct
28-
// BEGINNING_WITHOUT_SOME-NOT: Keyword/None: some
29-
3022
func gloabalFunc() -> #^GLOBAL_FUNC?check=BEGINNING_WITH_SOME^#
31-
var globalVar: #^GLOBAL_VAR?check=BEGINNING_WITHOUT_SOME^#
23+
var globalVar: #^GLOBAL_VAR?check=BEGINNING_WITH_SOME^#
3224

3325
protocol SomeProto {
34-
associatedtype protoAssocTy: #^PROTOCOL_ASSOCIATEDTYPE?check=BEGINNING_WITHOUT_SOME^#
35-
func protoMethodReq() -> #^PROTOCOL_METHOD_REQUIREMENT?check=BEGINNING_WITHOUT_SOME^#
36-
var protoVarReq: #^PROTOCOL_VAR_REQUIREMENT?check=BEGINNING_WITHOUT_SOME^#
37-
subscript(req: Int) -> #^PROTOCOL_SUBSCRIPT_REQUIREMENT?check=BEGINNING_WITHOUT_SOME^#
26+
associatedtype protoAssocTy: #^PROTOCOL_ASSOCIATEDTYPE?check=BEGINNING_WITH_SOME^#
27+
func protoMethodReq() -> #^PROTOCOL_METHOD_REQUIREMENT?check=BEGINNING_WITH_SOME^#
28+
var protoVarReq: #^PROTOCOL_VAR_REQUIREMENT?check=BEGINNING_WITH_SOME^#
29+
subscript(req: Int) -> #^PROTOCOL_SUBSCRIPT_REQUIREMENT?check=BEGINNING_WITH_SOME^#
3830
}
3931

4032
extension SomeProto {
@@ -44,7 +36,7 @@ extension SomeProto {
4436
}
4537

4638
struct SomeStruct {
47-
typealias TyAlias = #^STRUCT_TYPEALIAS_RHS?check=BEGINNING_WITHOUT_SOME^#
39+
typealias TyAlias = #^STRUCT_TYPEALIAS_RHS?check=BEGINNING_WITH_SOME^#
4840
func structMethodExt() -> #^STRUCT_METHOD?check=BEGINNING_WITH_SOME^#
4941
var structVarExt: #^STRUCT_VAR?check=BEGINNING_WITH_SOME^#
5042
subscript(struct: Int) -> #^STRUCT_SUBSCRIPT?check=BEGINNING_WITH_SOME^#

test/IDE/complete_some_any.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %batch-code-completion
2+
3+
func test1(x: #^PARAM?check=HAS_SOME_ANY;check=HAS_REPEAT^#) {}
4+
// FIXME: 'repeat' is not valid here semantically but we allow it syntactically and can't (easily) tell in the parser whether 'repeat' is valid. Not worth fixing in the old parser.
5+
func test2() -> #^RESULT?check=HAS_SOME_ANY;check=HAS_REPEAT^# {}
6+
func test3() -> {
7+
// FIXME: 'repeat' is not valid here semantically but we allow it syntactically and can't (easily) tell in the parser whether 'repeat' is valid. Not worth fixing in the old parser.
8+
let a: [#^ARRAY_TYPE?check=HAS_SOME_ANY;check=HAS_REPEAT^#]
9+
let b: any #^AFTER_ANY?check=NO_SOME_ANY;check=NO_REPEAT^#
10+
}
11+
12+
func test4(x: repeat #^AFTER_REPEAT?check=HAS_SOME_ANY;check=NO_REPEAT^#) {}
13+
14+
// HAS_SOME_ANY-DAG: Keyword/None: some; name=some
15+
// HAS_SOME_ANY-DAG: Keyword/None: any; name=any
16+
// HAS_SOME_ANY-DAG: Keyword/None: each; name=each
17+
18+
// NO_SOME_ANY-NOT: Keyword/None: some; name=some
19+
// NO_SOME_ANY-NOT: Keyword/None: any; name=any
20+
// NO_SOME_ANY-NOT: Keyword/None: each; name=each
21+
22+
// HAS_REPEAT-DAG: Keyword/None: repeat; name=repeat
23+
24+
// NO_REPEAT-NOT: Keyword/None: repeat; name=repeat

tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ bool SourceKit::CodeCompletion::addCustomCompletions(
176176
}
177177
break;
178178
case CompletionKind::TypeDeclResultBeginning:
179+
case CompletionKind::TypeBeginning:
180+
case CompletionKind::TypeSimpleOrComposition:
179181
case CompletionKind::TypeSimpleBeginning:
180182
if (custom.Contexts.contains(CustomCompletionInfo::Type)) {
181183
changed = true;
@@ -451,6 +453,8 @@ void CodeCompletionOrganizer::Impl::addCompletionsWithFilter(
451453
bool hideLowPriority =
452454
options.hideLowPriority &&
453455
completionKind != CompletionKind::TypeDeclResultBeginning &&
456+
completionKind != CompletionKind::TypeBeginning &&
457+
completionKind != CompletionKind::TypeSimpleOrComposition &&
454458
completionKind != CompletionKind::TypeSimpleBeginning &&
455459
completionKind != CompletionKind::PostfixExpr;
456460
for (Completion *completion : completions) {

0 commit comments

Comments
 (0)