Skip to content

Commit af00627

Browse files
committed
[Completion] Complete ownership specifiers in parameters
Complete ownership specifiers such as `consuming`, `borrowing`, and `inout` in parameter type position. While here, also complete `isolated`. rdar://127261573
1 parent d8c7440 commit af00627

File tree

7 files changed

+86
-3
lines changed

7 files changed

+86
-3
lines changed

include/swift/IDE/CodeCompletionResult.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ enum class CompletionKind : uint8_t {
197197
PostfixExpr,
198198
KeyPathExprObjC,
199199
KeyPathExprSwift,
200+
TypePossibleFunctionParamBeginning,
200201
TypeDeclResultBeginning,
201202
TypeBeginning,
202203
TypeSimpleOrComposition,

include/swift/Parse/IDEInspectionCallbacks.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ class CodeCompletionCallbacks {
178178
/// #keyPath argument have been parsed yet.
179179
virtual void completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) {};
180180

181+
/// Complete the beginning of the type for a parameter of a
182+
/// func/subscript/closure, or the type for a parameter in a function type.
183+
/// For the latter, we cannot know for sure whether the user is trying to
184+
/// write a function type, so will complete for e.g `let x: (#^COMPLETE^#`.
185+
virtual void completeTypePossibleFunctionParamBeginning() {}
186+
181187
/// Complete the beginning of the type of result of func/var/let/subscript.
182188
virtual void completeTypeDeclResultBeginning() {};
183189

lib/IDE/CodeCompletion.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks,
259259
void completePostfixExpr(CodeCompletionExpr *E, bool hasSpace) override;
260260
void completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) override;
261261

262+
void completeTypePossibleFunctionParamBeginning() override;
262263
void completeTypeDeclResultBeginning() override;
263264
void completeTypeBeginning() override;
264265
void completeTypeSimpleOrComposition() override;
@@ -430,6 +431,11 @@ void CodeCompletionCallbacksImpl::completePoundAvailablePlatform() {
430431
CurDeclContext = P.CurDeclContext;
431432
}
432433

434+
void CodeCompletionCallbacksImpl::completeTypePossibleFunctionParamBeginning() {
435+
Kind = CompletionKind::TypePossibleFunctionParamBeginning;
436+
CurDeclContext = P.CurDeclContext;
437+
}
438+
433439
void CodeCompletionCallbacksImpl::completeTypeDeclResultBeginning() {
434440
Kind = CompletionKind::TypeDeclResultBeginning;
435441
CurDeclContext = P.CurDeclContext;
@@ -1058,6 +1064,12 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
10581064
}
10591065
break;
10601066

1067+
case CompletionKind::TypePossibleFunctionParamBeginning:
1068+
addKeyword(Sink, "inout", CodeCompletionKeywordKind::kw_inout);
1069+
addKeyword(Sink, "borrowing", CodeCompletionKeywordKind::None);
1070+
addKeyword(Sink, "consuming", CodeCompletionKeywordKind::None);
1071+
addKeyword(Sink, "isolated", CodeCompletionKeywordKind::None);
1072+
LLVM_FALLTHROUGH;
10611073
case CompletionKind::TypeBeginning:
10621074
addKeyword(Sink, "repeat", CodeCompletionKeywordKind::None);
10631075
LLVM_FALLTHROUGH;
@@ -1262,6 +1274,7 @@ void swift::ide::postProcessCompletionResults(
12621274
// names at non-type name position are "rare".
12631275
if (result->getKind() == CodeCompletionResultKind::Declaration &&
12641276
result->getAssociatedDeclKind() == CodeCompletionDeclKind::Protocol &&
1277+
Kind != CompletionKind::TypePossibleFunctionParamBeginning &&
12651278
Kind != CompletionKind::TypeBeginning &&
12661279
Kind != CompletionKind::TypeSimpleOrComposition &&
12671280
Kind != CompletionKind::TypeSimpleBeginning &&
@@ -1755,6 +1768,7 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
17551768
break;
17561769
}
17571770

1771+
case CompletionKind::TypePossibleFunctionParamBeginning:
17581772
case CompletionKind::TypeDeclResultBeginning:
17591773
case CompletionKind::TypeBeginning:
17601774
case CompletionKind::TypeSimpleOrComposition:

lib/Parse/ParsePattern.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,22 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
355355
.fixItReplace(Tok.getLoc(), "`" + Tok.getText().str() + "`");
356356
}
357357

358+
auto parseParamType = [&]() -> ParserResult<TypeRepr> {
359+
// Currently none of the parameter type completions are relevant for
360+
// enum cases, so don't include them. We'll complete for a regular type
361+
// beginning instead.
362+
if (Tok.is(tok::code_complete) &&
363+
paramContext != ParameterContextKind::EnumElement) {
364+
if (CodeCompletionCallbacks)
365+
CodeCompletionCallbacks->completeTypePossibleFunctionParamBeginning();
366+
367+
auto CCLoc = consumeToken(tok::code_complete);
368+
auto *ET = ErrorTypeRepr::create(Context, CCLoc);
369+
return makeParserCodeCompletionResult<TypeRepr>(ET);
370+
}
371+
return parseType(diag::expected_parameter_type);
372+
};
373+
358374
if (startsParameterName(isClosure)) {
359375
// identifier-or-none for the first name
360376
param.FirstNameLoc = consumeArgumentLabel(param.FirstName,
@@ -402,7 +418,7 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
402418
// (':' type)?
403419
if (consumeIf(tok::colon)) {
404420

405-
auto type = parseType(diag::expected_parameter_type);
421+
auto type = parseParamType();
406422
status |= type;
407423
param.Type = type.getPtrOrNull();
408424

@@ -425,7 +441,7 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
425441
}
426442

427443
if (isBareType && paramContext == ParameterContextKind::EnumElement) {
428-
auto type = parseType(diag::expected_parameter_type);
444+
auto type = parseParamType();
429445
status |= type;
430446
param.Type = type.getPtrOrNull();
431447
param.FirstName = Identifier();
@@ -440,7 +456,7 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
440456
// the user is about to type the parameter label and we shouldn't
441457
// suggest types.
442458
SourceLoc typeStartLoc = Tok.getLoc();
443-
auto type = parseType(diag::expected_parameter_type);
459+
auto type = parseParamType();
444460
status |= type;
445461
param.Type = type.getPtrOrNull();
446462

lib/Parse/ParseType.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,16 @@ ParserResult<TypeRepr> Parser::parseTypeTupleBody() {
12021202
}
12031203
Backtracking.reset();
12041204

1205+
// If we have a code completion token, treat this as a possible parameter
1206+
// type since the user may be writing this as a function type.
1207+
if (Tok.is(tok::code_complete)) {
1208+
if (CodeCompletionCallbacks)
1209+
CodeCompletionCallbacks->completeTypePossibleFunctionParamBeginning();
1210+
1211+
consumeToken();
1212+
return makeParserCodeCompletionStatus();
1213+
}
1214+
12051215
// Parse the type annotation.
12061216
auto type = parseType(diag::expected_type);
12071217
if (type.hasCodeCompletion())
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %batch-code-completion
2+
3+
func foo(x: #^FUNC_PARAM?check=SPECIFIER^#) {
4+
let fn1 = { (x: #CLOSURE_PARAM?check=SPECIFIER#) in }
5+
let fn2: (#^CLOSURE_PARAM_TY_COMPLETE?check=SPECIFIER^#) -> Void
6+
let fn3: (#^CLOSURE_PARAM_TY_INCOMPLETE?check=SPECIFIER^#
7+
}
8+
9+
struct S {
10+
init(x: #^INIT_PARAM?check=SPECIFIER^#) {}
11+
subscript(x: #SUBSCRIPT_PARAM?check=SPECIFIER#) {}
12+
}
13+
14+
// Don't complete for enum cases.
15+
enum E {
16+
case e(#^ENUM_CASE_TY?check=SPECIFIER_NOT^#)
17+
case f(x: #^ENUM_CASE_LABELED_TY?check=SPECIFIER_NOT^#)
18+
}
19+
20+
// Don't complete for a regular variable type.
21+
let x: #^VAR_TY?check=SPECIFIER_NOT^#
22+
23+
// Or for a return type.
24+
func bar() -> #^RETURN_TY?check=SPECIFIER_NOT^# {}
25+
26+
// SPECIFIER-DAG: Keyword[inout]/None: inout; name=inout
27+
// SPECIFIER-DAG: Keyword/None: consuming; name=consuming
28+
// SPECIFIER-DAG: Keyword/None: borrowing; name=borrowing
29+
// SPECIFIER-DAG: Keyword/None: isolated; name=isolated
30+
31+
// SPECIFIER_NOT-NOT: Keyword[inout]/None: inout
32+
// SPECIFIER_NOT-NOT: Keyword/None: consuming
33+
// SPECIFIER_NOT-NOT: Keyword/None: borrowing
34+
// SPECIFIER_NOT-NOT: Keyword/None: isolated

tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ bool SourceKit::CodeCompletion::addCustomCompletions(
175175
addCompletion(custom);
176176
}
177177
break;
178+
case CompletionKind::TypePossibleFunctionParamBeginning:
178179
case CompletionKind::TypeDeclResultBeginning:
179180
case CompletionKind::TypeBeginning:
180181
case CompletionKind::TypeSimpleOrComposition:
@@ -452,6 +453,7 @@ void CodeCompletionOrganizer::Impl::addCompletionsWithFilter(
452453
if (filterText.empty()) {
453454
bool hideLowPriority =
454455
options.hideLowPriority &&
456+
completionKind != CompletionKind::TypePossibleFunctionParamBeginning &&
455457
completionKind != CompletionKind::TypeDeclResultBeginning &&
456458
completionKind != CompletionKind::TypeBeginning &&
457459
completionKind != CompletionKind::TypeSimpleOrComposition &&

0 commit comments

Comments
 (0)