Skip to content

Commit 026cb41

Browse files
authored
Merge pull request #74633 from hamishknight/sending-completion
[Completion] Add completion for `sending` specifier
2 parents d50aaf4 + f842cba commit 026cb41

File tree

6 files changed

+94
-53
lines changed

6 files changed

+94
-53
lines changed

include/swift/Parse/Parser.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1249,7 +1249,7 @@ class Parser {
12491249
if (next.isAny(tok::at_sign, tok::kw_inout, tok::l_paren,
12501250
tok::identifier, tok::l_square, tok::kw_Any,
12511251
tok::kw_Self, tok::kw__, tok::kw_var,
1252-
tok::kw_let))
1252+
tok::kw_let, tok::code_complete))
12531253
return true;
12541254

12551255
if (next.is(tok::oper_prefix) && next.getText() == "~")
@@ -1619,6 +1619,11 @@ class Parser {
16191619
/// Whether we are at the start of a parameter name when parsing a parameter.
16201620
bool startsParameterName(bool isClosure);
16211621

1622+
/// Attempts to perform code completion for the possible start of a function
1623+
/// parameter type, returning the source location of the consumed completion
1624+
/// token, or a null location if there is no completion token.
1625+
SourceLoc tryCompleteFunctionParamTypeBeginning();
1626+
16221627
/// Parse a parameter-clause.
16231628
///
16241629
/// \verbatim

lib/IDE/CodeCompletion.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,10 +1073,14 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
10731073
addKeyword(Sink, "consuming", CodeCompletionKeywordKind::None);
10741074
addKeyword(Sink, "isolated", CodeCompletionKeywordKind::None);
10751075
LLVM_FALLTHROUGH;
1076+
case CompletionKind::TypeDeclResultBeginning:
1077+
addKeyword(Sink, "sending", CodeCompletionKeywordKind::None);
1078+
LLVM_FALLTHROUGH;
10761079
case CompletionKind::TypeBeginning:
1077-
addKeyword(Sink, "repeat", CodeCompletionKeywordKind::None);
1080+
// Not technically allowed after '->', since you need to write in parens.
1081+
if (Kind != CompletionKind::TypeDeclResultBeginning)
1082+
addKeyword(Sink, "repeat", CodeCompletionKeywordKind::None);
10781083
LLVM_FALLTHROUGH;
1079-
case CompletionKind::TypeDeclResultBeginning:
10801084
case CompletionKind::TypeSimpleOrComposition:
10811085
addKeyword(Sink, "some", CodeCompletionKeywordKind::None);
10821086
addKeyword(Sink, "any", CodeCompletionKeywordKind::None);

lib/Parse/ParsePattern.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,27 @@ bool Parser::startsParameterName(bool isClosure) {
154154
return isClosure;
155155
}
156156

157+
SourceLoc Parser::tryCompleteFunctionParamTypeBeginning() {
158+
if (!L->isCodeCompletion())
159+
return SourceLoc();
160+
161+
// Skip over any starting parameter specifiers.
162+
{
163+
CancellableBacktrackingScope backtrack(*this);
164+
ParsedTypeAttributeList attrs;
165+
attrs.parse(*this);
166+
if (!Tok.is(tok::code_complete))
167+
return SourceLoc();
168+
169+
backtrack.cancelBacktrack();
170+
}
171+
172+
if (CodeCompletionCallbacks)
173+
CodeCompletionCallbacks->completeTypePossibleFunctionParamBeginning();
174+
175+
return consumeToken(tok::code_complete);
176+
}
177+
157178
ParserStatus
158179
Parser::parseParameterClause(SourceLoc &leftParenLoc,
159180
SmallVectorImpl<ParsedParameter> &params,
@@ -360,14 +381,11 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
360381
// Currently none of the parameter type completions are relevant for
361382
// enum cases, so don't include them. We'll complete for a regular type
362383
// beginning instead.
363-
if (Tok.is(tok::code_complete) &&
364-
paramContext != ParameterContextKind::EnumElement) {
365-
if (CodeCompletionCallbacks)
366-
CodeCompletionCallbacks->completeTypePossibleFunctionParamBeginning();
367-
368-
auto CCLoc = consumeToken(tok::code_complete);
369-
auto *ET = ErrorTypeRepr::create(Context, CCLoc);
370-
return makeParserCodeCompletionResult<TypeRepr>(ET);
384+
if (paramContext != ParameterContextKind::EnumElement) {
385+
if (auto CCLoc = tryCompleteFunctionParamTypeBeginning()) {
386+
auto *ET = ErrorTypeRepr::create(Context, CCLoc);
387+
return makeParserCodeCompletionResult<TypeRepr>(ET);
388+
}
371389
}
372390
return parseType(diag::expected_parameter_type);
373391
};

lib/Parse/ParseType.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,15 +1203,10 @@ ParserResult<TypeRepr> Parser::parseTypeTupleBody() {
12031203
}
12041204
Backtracking.reset();
12051205

1206-
// If we have a code completion token, treat this as a possible parameter
1207-
// type since the user may be writing this as a function type.
1208-
if (Tok.is(tok::code_complete)) {
1209-
if (CodeCompletionCallbacks)
1210-
CodeCompletionCallbacks->completeTypePossibleFunctionParamBeginning();
1211-
1212-
consumeToken();
1206+
// Try complete the start of a parameter type since the user may be writing
1207+
// this as a function type.
1208+
if (tryCompleteFunctionParamTypeBeginning())
12131209
return makeParserCodeCompletionStatus();
1214-
}
12151210

12161211
// Parse the type annotation.
12171212
auto type = parseType(diag::expected_type);

test/IDE/complete_ownership_specifier.swift

Lines changed: 0 additions & 34 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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 = { (x: consuming #CLOSURE_PARAM2?check=SPECIFIER#) in }
6+
let fn3: (#^CLOSURE_PARAM_TY_COMPLETE?check=SPECIFIER^#) -> Void
7+
let fn4: (borrowing #^CLOSURE_PARAM_TY_COMPLETE2?check=SPECIFIER^#) -> Void
8+
let fn5: (#^CLOSURE_PARAM_TY_INCOMPLETE?check=SPECIFIER^#
9+
let fn6: (inout #^CLOSURE_PARAM_TY_INCOMPLETE2?check=SPECIFIER^#
10+
}
11+
12+
func bar(_ x: borrowing #^FUNC_PARAM_2?check=SPECIFIER^#) {}
13+
14+
struct S {
15+
init(x: #^INIT_PARAM?check=SPECIFIER^#) {}
16+
subscript(x: #SUBSCRIPT_PARAM?check=SPECIFIER#) -> #^SUBSCRIPT_RET?check=RESULT;check=RESULT_NOT^# {}
17+
}
18+
19+
// Don't complete for enum cases.
20+
enum E {
21+
case e(#^ENUM_CASE_TY?check=SPECIFIER_NOT^#)
22+
case f(x: #^ENUM_CASE_LABELED_TY?check=SPECIFIER_NOT^#)
23+
}
24+
25+
// Don't complete the parameter specifiers for a variable type.
26+
//
27+
// Note that we will still complete 'sending' here, even though it isn't
28+
// currently supported for computed properties (it is supported for functions
29+
// and subscripts though).
30+
let x: #^VAR_TY?check=RESULT;check=RESULT_NOT^#
31+
var y: #^VAR_TY2?check=RESULT;check=RESULT_NOT^#
32+
33+
// Or for a return type.
34+
func bar() -> #^RESULT_TY?check=RESULT;check=RESULT_NOT^# {}
35+
36+
// SPECIFIER-DAG: Keyword[inout]/None: inout; name=inout
37+
// SPECIFIER-DAG: Keyword/None: consuming; name=consuming
38+
// SPECIFIER-DAG: Keyword/None: borrowing; name=borrowing
39+
// SPECIFIER-DAG: Keyword/None: isolated; name=isolated
40+
// SPECIFIER-DAG: Keyword/None: sending; name=sending
41+
42+
// SPECIFIER_NOT-NOT: Keyword[inout]/None: inout
43+
// SPECIFIER_NOT-NOT: Keyword/None: consuming
44+
// SPECIFIER_NOT-NOT: Keyword/None: borrowing
45+
// SPECIFIER_NOT-NOT: Keyword/None: isolated
46+
// SPECIFIER_NOT-NOT: Keyword/None: sending
47+
48+
// RESULT_NOT-NOT: Keyword[inout]/None: inout
49+
// RESULT_NOT-NOT: Keyword/None: consuming
50+
// RESULT_NOT-NOT: Keyword/None: borrowing
51+
// RESULT_NOT-NOT: Keyword/None: isolated
52+
53+
// RESULT-DAG: Keyword/None: sending

0 commit comments

Comments
 (0)